Confirm and password emails sending
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
CREATE TABLE raid_builder.raid_instance_person_character_xref(
|
CREATE TABLE raid_builder.raid_instance_person_character_xref(
|
||||||
raid_instance_person_character_xref_id uuid PRIMARY KEY,
|
raid_instance_person_character_xref_id uuid PRIMARY KEY,
|
||||||
raid_instance_id uuid REFERENCES raid_builder.raid_instance(raid_instance_id) NOT NULL,
|
raid_instance_id uuid REFERENCES raid_builder.raid_instance(raid_instance_id) NOT NULL,
|
||||||
person_character_id uuid REFERENCES raid_builder.person_character(person_character_id) NOT NULL,
|
person_character_id uuid REFERENCES raid_builder.person_character(person_character_id),
|
||||||
group_number int NOT NULL,
|
group_number int NOT NULL,
|
||||||
position_number int NOT NULL,
|
position_number int NOT NULL,
|
||||||
|
|
||||||
|
|||||||
12
pom.xml
12
pom.xml
@@ -140,6 +140,18 @@
|
|||||||
<artifactId>disruptor</artifactId>
|
<artifactId>disruptor</artifactId>
|
||||||
<version>4.0.0</version>
|
<version>4.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!--! Email -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.angus</groupId>
|
||||||
|
<artifactId>angus-mail</artifactId>
|
||||||
|
<version>2.0.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
<version>1.18.0</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ public class SecurityConfig{
|
|||||||
auth.requestMatchers(HttpMethod.OPTIONS).permitAll()
|
auth.requestMatchers(HttpMethod.OPTIONS).permitAll()
|
||||||
.requestMatchers("/icons/**").permitAll()
|
.requestMatchers("/icons/**").permitAll()
|
||||||
.requestMatchers("/auth/refresh", "/auth/test").permitAll() //Permit refresh tokens
|
.requestMatchers("/auth/refresh", "/auth/test").permitAll() //Permit refresh tokens
|
||||||
.requestMatchers(HttpMethod.POST, "/auth/signup", "/auth/confirm").permitAll() //Permit signup operations
|
.requestMatchers(HttpMethod.POST, "/auth/signup", "/auth/confirm/*").permitAll() //Permit signup operations
|
||||||
.requestMatchers("/auth/forgot", "/auth/forgot/*").permitAll() //Permit forgot password operations
|
.requestMatchers(HttpMethod.POST, "/auth/forgot", "/auth/forgot/*").permitAll() //Permit forgot password operations
|
||||||
.anyRequest().authenticated();
|
.anyRequest().authenticated();
|
||||||
})
|
})
|
||||||
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
|
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ import com.mattrixwv.raidbuilder.entity.Account;
|
|||||||
import com.mattrixwv.raidbuilder.service.AccountService;
|
import com.mattrixwv.raidbuilder.service.AccountService;
|
||||||
import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.AccountPermissionType;
|
import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.AccountPermissionType;
|
||||||
import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.AccountStatus;
|
import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.AccountStatus;
|
||||||
|
import com.mattrixwv.raidbuilder.util.EmailUtil;
|
||||||
|
|
||||||
|
import jakarta.mail.internet.InternetAddress;
|
||||||
import jakarta.servlet.http.Cookie;
|
import jakarta.servlet.http.Cookie;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@@ -44,6 +46,8 @@ public class AuthenticationController{
|
|||||||
private final PasswordEncoder passwordEncoder;
|
private final PasswordEncoder passwordEncoder;
|
||||||
private final TokenService tokenService;
|
private final TokenService tokenService;
|
||||||
private final AccountService accountService;
|
private final AccountService accountService;
|
||||||
|
//Email
|
||||||
|
private final EmailUtil emailUtil;
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/token")
|
@GetMapping("/token")
|
||||||
@@ -121,8 +125,6 @@ public class AuthenticationController{
|
|||||||
returnNode.put("accountId", account.getAccountId().toString());
|
returnNode.put("accountId", account.getAccountId().toString());
|
||||||
returnNode.put("status", "success");
|
returnNode.put("status", "success");
|
||||||
|
|
||||||
//TODO: Send email
|
|
||||||
|
|
||||||
log.info("Successfully created account: {}", account.getAccountId());
|
log.info("Successfully created account: {}", account.getAccountId());
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@@ -136,10 +138,9 @@ public class AuthenticationController{
|
|||||||
return returnNode;
|
return returnNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/confirm")
|
@PostMapping("/confirm/{confirmToken}")
|
||||||
@AccountAuthorization(permissions = {})
|
@AccountAuthorization(permissions = {})
|
||||||
public ObjectNode confirm(@RequestBody ObjectNode confirmNode){
|
public ObjectNode confirm(@PathVariable("confirmToken") UUID confirmToken){
|
||||||
UUID confirmToken = UUID.fromString(confirmNode.get("confirmToken").asText());
|
|
||||||
log.info("Confirming account with token {}", confirmToken);
|
log.info("Confirming account with token {}", confirmToken);
|
||||||
|
|
||||||
|
|
||||||
@@ -164,14 +165,14 @@ public class AuthenticationController{
|
|||||||
|
|
||||||
@PostMapping("/forgot")
|
@PostMapping("/forgot")
|
||||||
@AccountAuthorization(permissions = {})
|
@AccountAuthorization(permissions = {})
|
||||||
public ObjectNode forgot(@RequestParam("loginId") String loginId){
|
public ObjectNode forgot(@RequestParam("username") String username){
|
||||||
log.info("Setting up user that forgot their password: {}", loginId);
|
log.info("Setting up user that forgot their password: {}", username);
|
||||||
|
|
||||||
|
|
||||||
ObjectNode returnNode = mapper.createObjectNode();
|
ObjectNode returnNode = mapper.createObjectNode();
|
||||||
|
|
||||||
//Verify the account exists
|
//Verify the account exists
|
||||||
Account account = accountService.getByUsername(loginId);
|
Account account = accountService.getByUsername(username);
|
||||||
if(account != null){
|
if(account != null){
|
||||||
//Setup token
|
//Setup token
|
||||||
UUID token = UUID.randomUUID();
|
UUID token = UUID.randomUUID();
|
||||||
@@ -181,24 +182,29 @@ public class AuthenticationController{
|
|||||||
|
|
||||||
account = accountService.updateAccount(account);
|
account = accountService.updateAccount(account);
|
||||||
|
|
||||||
//TODO: Send email
|
try{
|
||||||
|
emailUtil.sendPasswordResetEmail(new InternetAddress(account.getEmail()), token);
|
||||||
|
}
|
||||||
|
catch(Exception error){
|
||||||
|
log.error("Error sending email", error);
|
||||||
|
throw new RuntimeException("Error sending reset email", error);
|
||||||
|
}
|
||||||
|
|
||||||
returnNode.put("status", "success");
|
returnNode.put("status", "success");
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
ArrayNode errorsNode = mapper.createArrayNode();
|
ArrayNode errorsNode = mapper.createArrayNode();
|
||||||
errorsNode.add("Could not find account with login " + loginId);
|
errorsNode.add("Could not find account with login " + username);
|
||||||
returnNode.set("errors", errorsNode);
|
returnNode.set("errors", errorsNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnNode;
|
return returnNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/forgot/reset")
|
@PostMapping("/forgot/{forgotToken}")
|
||||||
@AccountAuthorization(permissions = {})
|
@AccountAuthorization(permissions = {})
|
||||||
public ObjectNode setNewPasswordForgot(@RequestBody ObjectNode forgotNode){
|
public ObjectNode setNewPasswordForgot(@PathVariable("forgotToken") UUID forgotToken, @RequestBody ObjectNode passwordNode){
|
||||||
UUID forgotToken = UUID.fromString(forgotNode.get("forgotToken").asText());
|
String newPassword = passwordNode.get("password").asText();
|
||||||
String newPassword = forgotNode.get("password").asText();
|
|
||||||
log.info("Confirming user reset password (forget) with token {}", forgotToken);
|
log.info("Confirming user reset password (forget) with token {}", forgotToken);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,15 @@ import com.mattrixwv.raidbuilder.repository.account.AccountRepository;
|
|||||||
import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.AccountPermissionType;
|
import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.AccountPermissionType;
|
||||||
import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.AccountStatus;
|
import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.AccountStatus;
|
||||||
import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.TutorialStatus;
|
import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.TutorialStatus;
|
||||||
|
import com.mattrixwv.raidbuilder.util.EmailUtil;
|
||||||
import com.mattrixwv.raidbuilder.util.UserPrincipal;
|
import com.mattrixwv.raidbuilder.util.UserPrincipal;
|
||||||
|
|
||||||
|
import jakarta.mail.internet.InternetAddress;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -39,6 +43,8 @@ public class AccountService implements UserDetailsService{
|
|||||||
private final AccountPermissionService accountPermissionService;
|
private final AccountPermissionService accountPermissionService;
|
||||||
private final GamePermissionService gamePermissionService;
|
private final GamePermissionService gamePermissionService;
|
||||||
private final RaidGroupPermissionService raidGroupPermissionService;
|
private final RaidGroupPermissionService raidGroupPermissionService;
|
||||||
|
//Emails
|
||||||
|
private final EmailUtil emailUtil;
|
||||||
//Fields
|
//Fields
|
||||||
@Value("${jwt.refreshTokenDuration}")
|
@Value("${jwt.refreshTokenDuration}")
|
||||||
private Duration refreshTokenDuration;
|
private Duration refreshTokenDuration;
|
||||||
@@ -71,6 +77,16 @@ public class AccountService implements UserDetailsService{
|
|||||||
accountTutorialStatus.setInstanceTutorialStatus(TutorialStatus.NOT_COMPLETED);
|
accountTutorialStatus.setInstanceTutorialStatus(TutorialStatus.NOT_COMPLETED);
|
||||||
accountTutorialStatus = accountTutorialStatusService.createAccountTutorialStatus(accountTutorialStatus);
|
accountTutorialStatus = accountTutorialStatusService.createAccountTutorialStatus(accountTutorialStatus);
|
||||||
|
|
||||||
|
|
||||||
|
//Send confirmation email
|
||||||
|
try{
|
||||||
|
emailUtil.sendConfirmationEmail(new InternetAddress(account.getEmail()), account.getRefreshToken());
|
||||||
|
}
|
||||||
|
catch(Exception error){
|
||||||
|
log.error(error.getMessage(), error);
|
||||||
|
throw new RuntimeException("Could not send confirmation email", error);
|
||||||
|
}
|
||||||
|
|
||||||
//Return the new account
|
//Return the new account
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|||||||
74
src/main/java/com/mattrixwv/raidbuilder/util/EmailUtil.java
Normal file
74
src/main/java/com/mattrixwv/raidbuilder/util/EmailUtil.java
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package com.mattrixwv.raidbuilder.util;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import jakarta.mail.Message;
|
||||||
|
import jakarta.mail.MessagingException;
|
||||||
|
import jakarta.mail.Session;
|
||||||
|
import jakarta.mail.Transport;
|
||||||
|
import jakarta.mail.internet.InternetAddress;
|
||||||
|
import jakarta.mail.internet.MimeMessage;
|
||||||
|
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class EmailUtil{
|
||||||
|
@Value("${email.username}")
|
||||||
|
private String username;
|
||||||
|
@Value("${email.password}")
|
||||||
|
private String password;
|
||||||
|
@Value("${email.from}")
|
||||||
|
private InternetAddress fromAddress;
|
||||||
|
|
||||||
|
|
||||||
|
public Session createSession(){
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.put("mail.smtp.host", "smtp.gmail.com");
|
||||||
|
props.put("mail.smtp.port", "465");
|
||||||
|
props.put("mail.smtp.auth", "true");
|
||||||
|
props.put("mail.smtp.socketFactory.port", "465");
|
||||||
|
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
|
||||||
|
|
||||||
|
return Session.getInstance(props, new jakarta.mail.Authenticator(){
|
||||||
|
@Override
|
||||||
|
protected jakarta.mail.PasswordAuthentication getPasswordAuthentication(){
|
||||||
|
return new jakarta.mail.PasswordAuthentication(username, password);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendConfirmationEmail(InternetAddress toAddress, UUID confirmationToken) throws MessagingException{
|
||||||
|
sendMessage(
|
||||||
|
createSession(),
|
||||||
|
toAddress,
|
||||||
|
fromAddress,
|
||||||
|
"Raid Builder Confirmation",
|
||||||
|
"<p>This is the confirmation email for your Raid Builder Account.<br/><a href=https://raidbuilder.mattrixwv.com/confirm/" + confirmationToken.toString() + ">Click Here</a> to confirm your account.</p>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendPasswordResetEmail(InternetAddress toAddress, UUID resetToken) throws MessagingException{
|
||||||
|
sendMessage(
|
||||||
|
createSession(),
|
||||||
|
toAddress,
|
||||||
|
fromAddress,
|
||||||
|
"Raid Builder Password Reset",
|
||||||
|
"<p>This is the password reset email for your Raid Builder Account.<br/><a href=https://raidBuilder.mattrixwv.com/forgotPassword/" + resetToken.toString() + ">Click Here</a> to reset your password.</p>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void sendMessage(Session session, InternetAddress toAddress, InternetAddress fromAddress, String subject, String body) throws MessagingException{
|
||||||
|
MimeMessage message = new MimeMessage(session);
|
||||||
|
message.setFrom(fromAddress);
|
||||||
|
message.setRecipient(Message.RecipientType.TO, toAddress);
|
||||||
|
message.setSubject(subject);
|
||||||
|
message.setText(body, "utf-8", "html");
|
||||||
|
|
||||||
|
Transport.send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,3 +23,9 @@ jwt.refreshTokenDuration=30d
|
|||||||
#Files
|
#Files
|
||||||
uploadFileDirectory=../raidBuilderIcons
|
uploadFileDirectory=../raidBuilderIcons
|
||||||
spring.servlet.multipart.max-file-size=10MB
|
spring.servlet.multipart.max-file-size=10MB
|
||||||
|
|
||||||
|
|
||||||
|
#Email
|
||||||
|
email.username=
|
||||||
|
email.password=
|
||||||
|
email.from=
|
||||||
|
|||||||
Reference in New Issue
Block a user