BAEL-1973 (#5059)
* BAEL-1973 * Modified CSS Background * removed unnecessary comment
This commit is contained in:
parent
8b805cad04
commit
a42dfbcf12
|
@ -1,2 +1,3 @@
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
- [Intro to Security and WebSockets](http://www.baeldung.com/spring-security-websockets)
|
- [Intro to Security and WebSockets](http://www.baeldung.com/spring-security-websockets)
|
||||||
|
- [Spring WebSockets: Specific User Chat](http://www.baeldung.com/spring-websocket-specific-user-chat)
|
|
@ -11,9 +11,9 @@
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baeldung</groupId>
|
<groupId>com.baeldung</groupId>
|
||||||
<artifactId>parent-spring-5</artifactId>
|
<artifactId>parent-spring-4</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<relativePath>../parent-spring-5</relativePath>
|
<relativePath>../parent-spring-4</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -177,9 +177,11 @@
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<hibernate-core.version>5.2.10.Final</hibernate-core.version>
|
<hibernate-core.version>5.2.10.Final</hibernate-core.version>
|
||||||
|
<spring-security.version>4.2.3.RELEASE</spring-security.version>
|
||||||
<spring-data-jpa.version>1.11.3.RELEASE</spring-data-jpa.version>
|
<spring-data-jpa.version>1.11.3.RELEASE</spring-data-jpa.version>
|
||||||
<h2database.version>1.4.196</h2database.version>
|
<h2database.version>1.4.196</h2database.version>
|
||||||
<logback-classic.version>1.2.3</logback-classic.version>
|
<logback-classic.version>1.2.3</logback-classic.version>
|
||||||
|
<jackson.version>2.8.7</jackson.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.baeldung.springsecuredsockets;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
public static final String SECURED_CHAT_HISTORY = "/secured/history";
|
||||||
|
public static final String SECURED_CHAT = "/secured/chat";
|
||||||
|
public static final String SECURED_CHAT_ROOM = "/secured/room";
|
||||||
|
public static final String SECURED_CHAT_SPECIFIC_USER = "/secured/user/queue/specific-user";
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||||
import org.springframework.web.servlet.resource.PathResourceResolver;
|
import org.springframework.web.servlet.resource.PathResourceResolver;
|
||||||
import org.springframework.web.servlet.view.JstlView;
|
import org.springframework.web.servlet.view.JstlView;
|
||||||
import org.springframework.web.servlet.view.UrlBasedViewResolver;
|
import org.springframework.web.servlet.view.UrlBasedViewResolver;
|
||||||
|
@ -20,7 +20,7 @@ import java.sql.SQLException;
|
||||||
@EnableJpaRepositories
|
@EnableJpaRepositories
|
||||||
@ComponentScan("com.baeldung.springsecuredsockets")
|
@ComponentScan("com.baeldung.springsecuredsockets")
|
||||||
@Import({ SecurityConfig.class, DataStoreConfig.class, SocketBrokerConfig.class, SocketSecurityConfig.class })
|
@Import({ SecurityConfig.class, DataStoreConfig.class, SocketBrokerConfig.class, SocketSecurityConfig.class })
|
||||||
public class AppConfig implements WebMvcConfigurer {
|
public class AppConfig extends WebMvcConfigurerAdapter {
|
||||||
|
|
||||||
public void addViewControllers(ViewControllerRegistry registry) {
|
public void addViewControllers(ViewControllerRegistry registry) {
|
||||||
registry.addViewController("/").setViewName("index");
|
registry.addViewController("/").setViewName("index");
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.antMatchers("/", "/index", "/authenticate")
|
.antMatchers("/", "/index", "/authenticate")
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.antMatchers("/secured/**/**", "/secured/socket", "/secured/success")
|
.antMatchers("/secured/**/**", "/secured/**/**/**", "/secured/socket", "/secured/success")
|
||||||
.authenticated()
|
.authenticated()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
.and()
|
.and()
|
||||||
|
|
|
@ -1,27 +1,33 @@
|
||||||
package com.baeldung.springsecuredsockets.config;
|
package com.baeldung.springsecuredsockets.config;
|
||||||
|
|
||||||
|
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT;
|
||||||
|
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_HISTORY;
|
||||||
|
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_ROOM;
|
||||||
|
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_SPECIFIC_USER;
|
||||||
|
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||||
|
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
|
||||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSocketMessageBroker
|
@EnableWebSocketMessageBroker
|
||||||
@ComponentScan("com.baeldung.springsecuredsockets.controllers")
|
@ComponentScan("com.baeldung.springsecuredsockets.controllers")
|
||||||
public class SocketBrokerConfig implements WebSocketMessageBrokerConfigurer {
|
public class SocketBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configureMessageBroker(MessageBrokerRegistry config) {
|
public void configureMessageBroker(MessageBrokerRegistry config) {
|
||||||
config.enableSimpleBroker("/secured/history");
|
config.enableSimpleBroker(SECURED_CHAT_HISTORY, SECURED_CHAT_SPECIFIC_USER);
|
||||||
config.setApplicationDestinationPrefixes("/spring-security-mvc-socket");
|
config.setApplicationDestinationPrefixes("/spring-security-mvc-socket");
|
||||||
|
config.setUserDestinationPrefix("/secured/user");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||||
registry.addEndpoint("/secured/chat").withSockJS();
|
registry.addEndpoint(SECURED_CHAT_ROOM).withSockJS();
|
||||||
|
registry.addEndpoint(SECURED_CHAT).withSockJS();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ public class SocketSecurityConfig extends AbstractSecurityWebSocketMessageBroker
|
||||||
@Override
|
@Override
|
||||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||||
messages
|
messages
|
||||||
.simpDestMatchers("/secured/**").authenticated()
|
.simpDestMatchers("/secured/**", "/secured/**/**").authenticated()
|
||||||
.anyMessage().authenticated();
|
.anyMessage().authenticated();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,11 +1,19 @@
|
||||||
package com.baeldung.springsecuredsockets.controllers;
|
package com.baeldung.springsecuredsockets.controllers;
|
||||||
|
|
||||||
|
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT;
|
||||||
|
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_HISTORY;
|
||||||
|
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_ROOM;
|
||||||
|
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_SPECIFIC_USER;
|
||||||
|
|
||||||
import com.baeldung.springsecuredsockets.transfer.socket.Message;
|
import com.baeldung.springsecuredsockets.transfer.socket.Message;
|
||||||
import com.baeldung.springsecuredsockets.transfer.socket.OutputMessage;
|
import com.baeldung.springsecuredsockets.transfer.socket.OutputMessage;
|
||||||
|
import java.security.Principal;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.messaging.handler.annotation.Header;
|
||||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||||
|
import org.springframework.messaging.handler.annotation.Payload;
|
||||||
import org.springframework.messaging.handler.annotation.SendTo;
|
import org.springframework.messaging.handler.annotation.SendTo;
|
||||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
@ -19,10 +27,19 @@ public class SocketController {
|
||||||
private SimpMessagingTemplate simpMessagingTemplate;
|
private SimpMessagingTemplate simpMessagingTemplate;
|
||||||
private static final Logger log = LoggerFactory.getLogger(SocketController.class);
|
private static final Logger log = LoggerFactory.getLogger(SocketController.class);
|
||||||
|
|
||||||
@MessageMapping("/secured/chat")
|
@MessageMapping(SECURED_CHAT)
|
||||||
@SendTo("/secured/history")
|
@SendTo(SECURED_CHAT_HISTORY)
|
||||||
public OutputMessage send(Message msg) throws Exception {
|
public OutputMessage sendAll(Message msg) throws Exception {
|
||||||
OutputMessage out = new OutputMessage(msg.getFrom(), msg.getText(), new SimpleDateFormat("HH:mm").format(new Date()));
|
OutputMessage out = new OutputMessage(msg.getFrom(), msg.getText(), new SimpleDateFormat("HH:mm").format(new Date()));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example of sending message to specific user using 'convertAndSendToUser()' and '/queue'
|
||||||
|
*/
|
||||||
|
@MessageMapping(SECURED_CHAT_ROOM)
|
||||||
|
public void sendSpecific(@Payload Message msg, Principal user, @Header("simpSessionId") String sessionId) throws Exception {
|
||||||
|
OutputMessage out = new OutputMessage(msg.getFrom(), msg.getText(), new SimpleDateFormat("HH:mm").format(new Date()));
|
||||||
|
simpMessagingTemplate.convertAndSendToUser(msg.getTo(), SECURED_CHAT_SPECIFIC_USER, out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.baeldung.springsecuredsockets.transfer.socket;
|
||||||
public class Message {
|
public class Message {
|
||||||
|
|
||||||
private String from;
|
private String from;
|
||||||
|
private String to;
|
||||||
private String text;
|
private String text;
|
||||||
|
|
||||||
public String getFrom() {
|
public String getFrom() {
|
||||||
|
@ -11,6 +12,13 @@ public class Message {
|
||||||
public void setFrom(String from) {
|
public void setFrom(String from) {
|
||||||
this.from = from;
|
this.from = from;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTo() {
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
public void setTo(String to) {
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,20 @@
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
|
||||||
<title>Spring Secured Sockets</title>
|
<head>
|
||||||
<link href="<c:url value="/resources/styles/style.css"/>" rel="stylesheet">
|
<title>Spring Secured Sockets</title>
|
||||||
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
|
<link href="<c:url value="/resources/styles/app.css"/>" rel="stylesheet">
|
||||||
</head>
|
<link href="<c:url value="/resources/styles/denied.css"/>" rel="stylesheet">
|
||||||
<body>
|
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
|
||||||
<h1>ACCESS DENIED!</h1>
|
</head>
|
||||||
<br/>
|
|
||||||
<br/>
|
<body>
|
||||||
<a href="${pageContext.request.contextPath}/login">Click to login.</a>
|
<main>
|
||||||
</body>
|
<div class="wrapper">
|
||||||
|
<h1>ACCESS DENIED!</h1>
|
||||||
|
<a href="${pageContext.request.contextPath}/login">Click to login.</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -4,27 +4,32 @@
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html ng-app='angularApp'>
|
<html ng-app='angularApp'>
|
||||||
<head>
|
|
||||||
<title>Spring Secured Sockets</title>
|
|
||||||
<link href="<c:url value="/resources/styles/style.css"/>" rel="stylesheet">
|
|
||||||
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script>
|
|
||||||
|
|
||||||
<script src="<c:url value="/resources/scripts/app.js" />"></script>
|
<head>
|
||||||
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
|
<title>Spring Secured Sockets</title>
|
||||||
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
|
<link href="<c:url value="/resources/styles/app.css"/>" rel="stylesheet">
|
||||||
<script src="<c:url value="/resources/scripts/controllers/loginController.js" />"></script>
|
<link href="<c:url value="/resources/styles/index.css"/>" rel="stylesheet">
|
||||||
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
|
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
|
||||||
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
|
<script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script>
|
||||||
</head>
|
<script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script>
|
||||||
<body ng-controller="indexController">
|
|
||||||
<h1>Welcome!</h1>
|
<script src="<c:url value="/resources/scripts/app.js" />"></script>
|
||||||
<br />
|
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
|
||||||
<span>{{greeting}}</span>
|
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
|
||||||
<br />
|
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
|
||||||
<br />
|
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
|
||||||
<a href="${pageContext.request.contextPath}/login">Click to login.</a>
|
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
|
||||||
</body>
|
</head>
|
||||||
|
|
||||||
|
<body ng-controller="indexController">
|
||||||
|
<main>
|
||||||
|
<div class="wrapper">
|
||||||
|
<h1>Welcome!</h1>
|
||||||
|
<span>{{greeting}}</span>
|
||||||
|
<a href="${pageContext.request.contextPath}/login">Click to login.</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -4,42 +4,50 @@
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html ng-app='angularApp'>
|
<html ng-app='angularApp'>
|
||||||
<head>
|
|
||||||
<title>Spring Secured Sockets</title>
|
|
||||||
<link href="<c:url value="/resources/styles/style.css"/>" rel="stylesheet">
|
|
||||||
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script>
|
|
||||||
|
|
||||||
<script src="<c:url value="/resources/scripts/app.js" />"></script>
|
<head>
|
||||||
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
|
<title>Spring Secured Sockets</title>
|
||||||
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
|
<link href="<c:url value="/resources/styles/app.css"/>" rel="stylesheet">
|
||||||
<script src="<c:url value="/resources/scripts/controllers/loginController.js" />"></script>
|
<link href="<c:url value="/resources/styles/login.css"/>" rel="stylesheet">
|
||||||
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
|
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
|
||||||
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
|
<script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script>
|
||||||
</head>
|
<script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script>
|
||||||
<body ng-controller="loginController">
|
|
||||||
<c:set var="context" scope="session" value="${pageContext.request.contextPath}"/>
|
<script src="<c:url value="/resources/scripts/app.js" />"></script>
|
||||||
<!-- Must match the endpoint specified in security config -->
|
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
|
||||||
<h1>JSP Login Form</h1><br/>
|
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
|
||||||
<form name='f' action="authenticate" method='POST'>
|
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
|
||||||
<table>
|
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
|
||||||
<tr>
|
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
|
||||||
<td>User:</td>
|
</head>
|
||||||
<td><input type="text" name="username"/></td>
|
|
||||||
</tr>
|
<body>
|
||||||
<tr>
|
<c:set var="context" scope="session" value="${pageContext.request.contextPath}"/>
|
||||||
<td>Password:</td>
|
<main>
|
||||||
<td><input type="password" name="password"/></td>
|
<div class="wrapper">
|
||||||
</tr>
|
<!-- Must match the endpoint specified in security config -->
|
||||||
<tr>
|
<h1>JSP Login Form</h1>
|
||||||
<td><input name="submit" type="submit" value="submit"/></td>
|
<form name='f' action="authenticate" method='POST'>
|
||||||
</tr>
|
<table>
|
||||||
</table>
|
<tr>
|
||||||
</form>
|
<td>User:</td>
|
||||||
|
<td><input type="text" name="username" placeholder="k everyperson"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Password:</td>
|
||||||
|
<td><input type="password" name="password" placeholder="1234abcd"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input name="submit" type="submit" value="submit"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<!-- CSRF Token -->
|
||||||
|
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
<!-- CSRF Token -->
|
|
||||||
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
|
@ -4,48 +4,56 @@
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html ng-app='angularApp'>
|
<html ng-app='angularApp'>
|
||||||
<head>
|
|
||||||
<title>Spring Secured Sockets</title>
|
|
||||||
<link href="<c:url value="/resources/styles/style.css"/>" rel="stylesheet">
|
|
||||||
<script src="<c:url value="/resources/vendor/sockjs/sockjs.min.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/vendor/stomp/stomp.min.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script>
|
|
||||||
|
|
||||||
<script src="<c:url value="/resources/scripts/app.js" />"></script>
|
<head>
|
||||||
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
|
<title>Spring Secured Sockets</title>
|
||||||
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
|
<link href="<c:url value="/resources/styles/app.css"/>" rel="stylesheet">
|
||||||
<script src="<c:url value="/resources/scripts/controllers/loginController.js" />"></script>
|
<link href="<c:url value="/resources/styles/socket.css"/>" rel="stylesheet">
|
||||||
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
|
|
||||||
</head>
|
|
||||||
<body ng-controller="socketController">
|
|
||||||
<h1>Socket Chat</h1>
|
|
||||||
<c:set var = "context" scope = "session" value = "${pageContext.request.contextPath}"/>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<input type="text" id="from" placeholder="Choose a nickname"/>
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
<div>
|
|
||||||
<button id="connect" ng-click="connect('${context}');">Connect</button>
|
|
||||||
<button id="subscribe" ng-click="subscribe();">Subscribe</button>
|
|
||||||
<button id="disconnect" disabled="disabled" ng-click="disconnect();">Disconnect</button>
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
<div id="conversationDiv">
|
|
||||||
<input type="text" id="text" placeholder="Write a message..."/>
|
|
||||||
<button id="sendMessage" ng-click="sendMessage('${context}');">Send</button>
|
|
||||||
<p id="response"></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a href="${context}/secured/success">Click to go back!</a>
|
<script src="<c:url value="/resources/vendor/sockjs/sockjs.min.js" />"></script>
|
||||||
<a href="${context}/">Click to start over (you will still be authenticated)!</a>
|
<script src="<c:url value="/resources/vendor/stomp/stomp.min.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script>
|
||||||
|
|
||||||
|
<script src="<c:url value="/resources/scripts/app.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body ng-controller="socketController">
|
||||||
|
<c:set var="context" scope="session" value="${pageContext.request.contextPath}"/>
|
||||||
|
<main>
|
||||||
|
<div class="wrapper">
|
||||||
|
<h1>Socket Chat</h1>
|
||||||
|
<div id="all">
|
||||||
|
<h3>(Chat With Everyone)</h3>
|
||||||
|
<input type="text" id="from" placeholder="Choose Your Username"/>
|
||||||
|
<button id="connectAll" ng-click="connectAll('${context}');">Connect All</button>
|
||||||
|
<button id="subscribeAll" ng-click="subscribeAll();">Subscribe All</button>
|
||||||
|
</div>
|
||||||
|
<div id="specific">
|
||||||
|
<h3>(Chat With A Specific User)</h3>
|
||||||
|
<input type="text" id="to" placeholder="Choose a Recipient"/>
|
||||||
|
<button id="connectSpecific" ng-click="connectSpecific('${context}');">Connect Specific</button>
|
||||||
|
<button id="subscribeSpecific" ng-click="subscribeSpecific();">Subscribe Specific</button>
|
||||||
|
</div>
|
||||||
|
<div id="conversationDiv">
|
||||||
|
<h3>(Send and See Messages)</h3>
|
||||||
|
<input type="text" id="text" placeholder="Write a message..."/>
|
||||||
|
<button id="sendMessage" ng-click="sendMessage('${context}');">Send</button>
|
||||||
|
<div id="response"></div>
|
||||||
|
<button id="disconnect" disabled="disabled" ng-click="disconnect();">Disconnect</button>
|
||||||
|
</div>
|
||||||
|
<a href="${context}/secured/success">Click to go back!</a>
|
||||||
|
<a href="${context}/">Click to start over (you will still be authenticated)!</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<!-- CSRF Token -->
|
||||||
|
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
<!-- CSRF Token -->
|
|
||||||
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
|
@ -4,28 +4,33 @@
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html ng-app='angularApp'>
|
<html ng-app='angularApp'>
|
||||||
<head>
|
|
||||||
<title>Spring Secured Sockets</title>
|
|
||||||
<link href="<c:url value="/resources/styles/style.css"/>" rel="stylesheet">
|
|
||||||
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script>
|
|
||||||
|
|
||||||
<script src="<c:url value="/resources/scripts/app.js" />"></script>
|
<head>
|
||||||
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
|
<title>Spring Secured Sockets</title>
|
||||||
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
|
<link href="<c:url value="/resources/styles/app.css"/>" rel="stylesheet">
|
||||||
<script src="<c:url value="/resources/scripts/controllers/loginController.js" />"></script>
|
<link href="<c:url value="/resources/styles/success.css"/>" rel="stylesheet">
|
||||||
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
|
|
||||||
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
|
|
||||||
</head>
|
|
||||||
<body ng-controller="successController">
|
|
||||||
<h1>Congrats! You've logged in.</h1>
|
|
||||||
|
|
||||||
<a href="${pageContext.request.contextPath}/secured/socket">Click to chat!</a>
|
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
|
||||||
<a href="${pageContext.request.contextPath}/">Click to start over (you will still be authenticated)!</a>
|
<script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script>
|
||||||
|
|
||||||
<!-- CSRF Token -->
|
<script src="<c:url value="/resources/scripts/app.js" />"></script>
|
||||||
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
|
||||||
</body>
|
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
|
||||||
|
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body ng-controller="successController">
|
||||||
|
<main>
|
||||||
|
<div class="wrapper">
|
||||||
|
<h1>Congrats! You've logged in.</h1>
|
||||||
|
<a href="${pageContext.request.contextPath}/secured/socket">Click to chat!</a>
|
||||||
|
<a href="${pageContext.request.contextPath}/">Click to start over (you will still be authenticated)!</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<!-- CSRF Token -->
|
||||||
|
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -1,12 +1,13 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angularApp
|
angularApp
|
||||||
.controller('indexController', function ($scope) {
|
.controller('indexController', function ($scope) {
|
||||||
$scope.greeting = '';
|
|
||||||
|
|
||||||
$scope.initialize = function () {
|
$scope.greeting = '';
|
||||||
$scope.greeting = "Howdy!"
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.initialize();
|
$scope.initialize = function () {
|
||||||
});
|
$scope.greeting = "Howdy!"
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.initialize();
|
||||||
|
});
|
|
@ -1,6 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
angularApp
|
|
||||||
.controller('loginController', function ($scope) {
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,37 +1,52 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angularApp
|
angularApp
|
||||||
.controller('socketController', function ($scope, SocketService) {
|
.controller('socketController', function ($scope, SocketService) {
|
||||||
|
|
||||||
$scope.stompClient = null;
|
/**
|
||||||
$scope.sendEndpoint = '/secured/chat';
|
* URL mapping endpoints.
|
||||||
$scope.subscribeEndpoint = '/secured/history';
|
*/
|
||||||
$scope.elems = {
|
|
||||||
connect: 'connect',
|
|
||||||
from: 'from',
|
|
||||||
text: 'text',
|
|
||||||
disconnect: 'disconnect',
|
|
||||||
conversationDiv: 'conversationDiv',
|
|
||||||
response: 'response'
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.connect = function (context) {
|
var SECURED_CHAT = '/secured/chat';
|
||||||
$scope.sendEndpoint = '/secured/chat';
|
var SECURED_CHAT_HISTORY = '/secured/history';
|
||||||
$scope.sendEndpoint = context + $scope.sendEndpoint ;
|
var SECURED_CHAT_ROOM = '/secured/room';
|
||||||
$scope.stompClient = SocketService.connect($scope.sendEndpoint, $scope.elems);
|
var SECURED_CHAT_SPECIFIC_USER = '/secured/user/queue/specific-user';
|
||||||
};
|
|
||||||
|
|
||||||
$scope.subscribe = function () {
|
var opts = {
|
||||||
$scope.stompClient.subscribe($scope.subscribeEndpoint, function (msgOut) {
|
from: 'from',
|
||||||
SocketService.messageOut(JSON.parse(msgOut.body), $scope.elems);
|
to: 'to',
|
||||||
});
|
text: 'text',
|
||||||
};
|
disconnect: 'disconnect',
|
||||||
|
conversationDiv: 'conversationDiv',
|
||||||
|
response: 'response'
|
||||||
|
};
|
||||||
|
|
||||||
$scope.disconnect = function () {
|
$scope.sendEndpoint = '';
|
||||||
SocketService.disconnect($scope.elems, $scope.stompClient);
|
$scope.stompClient = null;
|
||||||
};
|
|
||||||
|
|
||||||
$scope.sendMessage = function () {
|
/**
|
||||||
SocketService.sendMessage( $scope.elems, $scope.stompClient, $scope.sendEndpoint);
|
* Broadcast to All Users.
|
||||||
};
|
*/
|
||||||
});
|
|
||||||
|
$scope.connectAll = function (context) {
|
||||||
|
$scope.sendEndpoint = context + SECURED_CHAT;
|
||||||
|
$scope.stompClient = SocketService.connect($scope.sendEndpoint , opts, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.subscribeAll = function () { SocketService.subscribeToAll($scope.stompClient, SECURED_CHAT_HISTORY, opts); };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast to Specific User.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$scope.connectSpecific = function (context) {
|
||||||
|
$scope.sendEndpoint = context + SECURED_CHAT_ROOM;
|
||||||
|
$scope.stompClient = SocketService.connect(context + SECURED_CHAT_ROOM, opts, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.subscribeSpecific = function () { SocketService.subscribeToSpecific($scope.stompClient, SECURED_CHAT_SPECIFIC_USER, opts); };
|
||||||
|
|
||||||
|
$scope.disconnect = function () { SocketService.disconnect(opts, $scope.stompClient); };
|
||||||
|
|
||||||
|
$scope.sendMessage = function () { SocketService.sendMessage(opts, $scope.stompClient, $scope.sendEndpoint); };
|
||||||
|
});
|
|
@ -1,13 +1,12 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angularApp
|
angularApp
|
||||||
.controller('successController', function ($scope) {
|
.controller('successController', function ($scope) {
|
||||||
|
$scope.successMsg = '';
|
||||||
|
|
||||||
$scope.successMsg = '';
|
$scope.initialize = function () {
|
||||||
|
$scope.successMsg = "You've logged in!";
|
||||||
|
};
|
||||||
|
|
||||||
$scope.initialize = function () {
|
$scope.initialize();
|
||||||
$scope.successMsg = "You've logged in!";
|
});
|
||||||
};
|
|
||||||
|
|
||||||
$scope.initialize();
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angularApp
|
angularApp
|
||||||
.config(function ($routeProvider) {
|
.config(function ($routeProvider) {
|
||||||
$routeProvider
|
$routeProvider
|
||||||
.when('/index', {
|
.when('/index', {
|
||||||
controller: 'indexController'
|
controller: 'indexController'
|
||||||
})
|
})
|
||||||
.when('/login', {
|
.when('/sockets', {
|
||||||
controller: 'loginController'
|
controller: 'socketController'
|
||||||
})
|
})
|
||||||
.when('/sockets', {
|
.when('/success', {
|
||||||
controller: 'socketController'
|
controller: 'successController'
|
||||||
})
|
})
|
||||||
.when('/success', {
|
.otherwise('/index');
|
||||||
controller: 'successController'
|
});
|
||||||
})
|
|
||||||
.otherwise('/index');
|
|
||||||
});
|
|
|
@ -1,46 +1,99 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var idHelper = function (context) {
|
||||||
|
return document.getElementById(context);
|
||||||
|
};
|
||||||
|
|
||||||
function SocketService() {
|
function SocketService() {
|
||||||
var that = this,
|
|
||||||
idHelper = function(context) {
|
|
||||||
return document.getElementById(context);
|
|
||||||
};
|
|
||||||
|
|
||||||
that.setConnected = function (elems, connected) {
|
var that = this;
|
||||||
idHelper(elems.connect).disabled = connected;
|
|
||||||
idHelper(elems.disconnect).disabled = !connected;
|
that.sessionId = '';
|
||||||
idHelper(elems.conversationDiv).style.visibility = connected ? 'visible' : 'hidden';
|
|
||||||
idHelper(elems.response).innerHTML = '';
|
/**
|
||||||
|
* Generic methods.
|
||||||
|
*/
|
||||||
|
|
||||||
|
that.setConnected = function (opts, connected) {
|
||||||
|
idHelper('connectAll').disabled = connected;
|
||||||
|
idHelper('connectSpecific').disabled = connected;
|
||||||
|
idHelper(opts.disconnect).disabled = !connected;
|
||||||
|
idHelper(opts.response).innerHTML = '';
|
||||||
|
idHelper('subscribeAll').disabled = !connected;
|
||||||
|
idHelper('subscribeSpecific').disabled = !connected;
|
||||||
|
};
|
||||||
|
|
||||||
|
that.connect = function (endpoint, opts, isBroadcastAll) {
|
||||||
|
var socket = new SockJS(endpoint), stompClient = Stomp.over(socket);
|
||||||
|
stompClient.connect({}, function (frame) {
|
||||||
|
that.setConnected(opts, true);
|
||||||
|
|
||||||
|
if (!isBroadcastAll) {
|
||||||
|
var url = stompClient.ws._transport.url;
|
||||||
|
console.log(stompClient.ws._transport.url);
|
||||||
|
url = url.replace("ws://localhost:8080/spring-security-mvc-socket/secured/room/", "");
|
||||||
|
url = url.replace("/websocket", "");
|
||||||
|
url = url.replace(/^[0-9]+\//, "");
|
||||||
|
console.log("Your current session is: " + url);
|
||||||
|
that.sessionId = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
return stompClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
that.disconnect = function (opts, stompClient) {
|
||||||
|
if (stompClient !== null && stompClient !== undefined) { stompClient.disconnect(); }
|
||||||
|
that.setConnected(opts, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
that.sendMessage = function (opts, stompClient, endpoint) {
|
||||||
|
var to = idHelper(opts.to).value;
|
||||||
|
var from = idHelper(opts.from).value;
|
||||||
|
|
||||||
|
var msg = {
|
||||||
|
'from': (from === undefined || from === null ) ? to : from,
|
||||||
|
'to': (to === undefined || to === null ) ? "ALL" : to,
|
||||||
|
'text': idHelper(opts.text).value
|
||||||
};
|
};
|
||||||
|
|
||||||
that.connect = function (endpoint, elems) {
|
console.log(JSON.stringify(msg));
|
||||||
var socket = new SockJS(endpoint), stompClient = Stomp.over(socket);
|
stompClient.send(endpoint, {}, JSON.stringify(msg));
|
||||||
stompClient.connect({}, function (frame) {
|
};
|
||||||
that.setConnected(elems, true);
|
|
||||||
});
|
|
||||||
return stompClient;
|
|
||||||
};
|
|
||||||
|
|
||||||
that.disconnect = function (elems, stompClient) {
|
that.messageOut = function (msg, opts) {
|
||||||
if (stompClient !== null && stompClient !== undefined) stompClient.disconnect();
|
var r = idHelper(opts.response), p = document.createElement('p');
|
||||||
that.setConnected(elems, false);
|
p.style.wordWrap = 'break-word';
|
||||||
};
|
p.appendChild(document.createTextNode(msg.from + ': ' + msg.text + ' (' + msg.time + ')'));
|
||||||
|
r.appendChild(p);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast to All Users.
|
||||||
|
*/
|
||||||
|
|
||||||
|
that.subscribeToAll = function(client, url, opts) {
|
||||||
|
idHelper('subscribeAll').disabled = true;
|
||||||
|
idHelper('subscribeSpecific').disabled = true;
|
||||||
|
client.subscribe(url, function (msgOut) {
|
||||||
|
that.messageOut(JSON.parse(msgOut.body), opts);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast to Specific User.
|
||||||
|
*/
|
||||||
|
|
||||||
|
that.subscribeToSpecific = function(client, url, opts) {
|
||||||
|
idHelper('subscribeAll').disabled = true;
|
||||||
|
idHelper('subscribeSpecific').disabled = true;
|
||||||
|
client.subscribe(url + "-user" + that.sessionId, function (msgOut) {
|
||||||
|
that.messageOut(JSON.parse(msgOut.body), opts);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
that.sendMessage = function (elems, stompClient, endpoint) {
|
|
||||||
stompClient.send(endpoint, {},
|
|
||||||
JSON.stringify({
|
|
||||||
'from': idHelper(elems.from).value,
|
|
||||||
'text': idHelper(elems.text).value
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
that.messageOut = function (msg, elems) {
|
|
||||||
var r = idHelper(elems.response), p = document.createElement('p');
|
|
||||||
p.style.wordWrap = 'break-word';
|
|
||||||
p.appendChild(document.createTextNode(msg.from + ': ' + msg.text + ' (' + msg.time + ')'));
|
|
||||||
r.appendChild(p);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
angularApp
|
angularApp
|
||||||
.service('SocketService', SocketService);
|
.service('SocketService', SocketService);
|
|
@ -0,0 +1,70 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Poiret+One');
|
||||||
|
|
||||||
|
html, body, main {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
color: white;
|
||||||
|
font-family: 'Poiret One', sans-serif;
|
||||||
|
opacity:.95;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
main > div.wrapper {
|
||||||
|
position: relative;
|
||||||
|
left: 15%;
|
||||||
|
top: 15%;
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 48px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span, a {
|
||||||
|
font-size: 24px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: lightgray;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 225px;
|
||||||
|
background: none !important;
|
||||||
|
border-radius: 25px;
|
||||||
|
background-color: #fff;
|
||||||
|
color: white;
|
||||||
|
outline: none;
|
||||||
|
margin-left: 2px;
|
||||||
|
padding-left: 25px;
|
||||||
|
padding-bottom: 9px;
|
||||||
|
padding-top: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100px;
|
||||||
|
align-content: center;
|
||||||
|
text-align: center;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 6px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
opacity: .6;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
main {
|
||||||
|
background-color: black;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
main {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
span, a {
|
||||||
|
top: 175px;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
main {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"] {
|
||||||
|
width: 100px;
|
||||||
|
align-content: center;
|
||||||
|
text-align: center;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 6px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"]:hover {
|
||||||
|
opacity:.6;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
main {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#all, div#specific, div#conversationDiv {
|
||||||
|
border: 1px solid white;
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 15px
|
||||||
|
}
|
||||||
|
|
||||||
|
button[disabled=true] {
|
||||||
|
color: lightgray;
|
||||||
|
border: 1px solid lightgray;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[disabled=true]:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
main {
|
||||||
|
background-color: black;
|
||||||
|
}
|
Loading…
Reference in New Issue