diff --git a/src/main/java/net/Broken/MainBot.java b/src/main/java/net/Broken/MainBot.java index 175ec5f..41b8891 100644 --- a/src/main/java/net/Broken/MainBot.java +++ b/src/main/java/net/Broken/MainBot.java @@ -2,6 +2,7 @@ package net.Broken; import net.Broken.Tools.Command.CommandParser; import net.Broken.Tools.EmbedMessageUtils; +import net.Broken.Tools.UserManager.UserRegister; import net.Broken.Tools.UserSpamUtils; import net.Broken.RestApi.ApiCommandLoader; import net.dv8tion.jda.core.JDA; @@ -34,10 +35,12 @@ public class MainBot { public static HashMap message_compteur =new HashMap<>(); public static boolean roleFlag = false; public static HashMap spamUtils = new HashMap<>(); + public static UserRegister userRegister = new UserRegister(); public static JDA jda; + public static int messageTimeOut = 10; diff --git a/src/main/java/net/Broken/RestApi/Data/CommandPostData.java b/src/main/java/net/Broken/RestApi/Data/CommandPostData.java index f08c26d..bb9a29f 100644 --- a/src/main/java/net/Broken/RestApi/Data/CommandPostData.java +++ b/src/main/java/net/Broken/RestApi/Data/CommandPostData.java @@ -7,4 +7,5 @@ public class CommandPostData { public String url; public int playlistLimit; public String chanelId; + public String name; } diff --git a/src/main/java/net/Broken/RestApi/Data/UserManager/CheckResposeData.java b/src/main/java/net/Broken/RestApi/Data/UserManager/CheckResposeData.java new file mode 100644 index 0000000..b169111 --- /dev/null +++ b/src/main/java/net/Broken/RestApi/Data/UserManager/CheckResposeData.java @@ -0,0 +1,15 @@ +package net.Broken.RestApi.Data.UserManager; + +public class CheckResposeData { + public boolean accepted; + public String name; + public String message; + public String id; + + public CheckResposeData(boolean accepted, String name, String message, String id) { + this.accepted = accepted; + this.name = name; + this.message = message; + this.id = id; + } +} diff --git a/src/main/java/net/Broken/RestApi/Data/UserManager/ConfirmData.java b/src/main/java/net/Broken/RestApi/Data/UserManager/ConfirmData.java new file mode 100644 index 0000000..9aad50b --- /dev/null +++ b/src/main/java/net/Broken/RestApi/Data/UserManager/ConfirmData.java @@ -0,0 +1,7 @@ +package net.Broken.RestApi.Data.UserManager; + +public class ConfirmData { + public String id; + public String checkToken; + +} diff --git a/src/main/java/net/Broken/RestApi/Data/UserManager/UserConnectionData.java b/src/main/java/net/Broken/RestApi/Data/UserManager/UserConnectionData.java new file mode 100644 index 0000000..755f6bf --- /dev/null +++ b/src/main/java/net/Broken/RestApi/Data/UserManager/UserConnectionData.java @@ -0,0 +1,13 @@ +package net.Broken.RestApi.Data.UserManager; + +public class UserConnectionData { + public boolean accepted; + public String token; + public String message; + + public UserConnectionData(boolean accepted, String token, String message) { + this.accepted = accepted; + this.token = token; + this.message = message; + } +} diff --git a/src/main/java/net/Broken/RestApi/Data/UserManager/UserInfoData.java b/src/main/java/net/Broken/RestApi/Data/UserManager/UserInfoData.java new file mode 100644 index 0000000..c5edf0e --- /dev/null +++ b/src/main/java/net/Broken/RestApi/Data/UserManager/UserInfoData.java @@ -0,0 +1,6 @@ +package net.Broken.RestApi.Data.UserManager; + +public class UserInfoData { + public String name; + public String password; +} diff --git a/src/main/java/net/Broken/RestApi/MusicWebAPIController.java b/src/main/java/net/Broken/RestApi/MusicWebAPIController.java index 309b837..b693c4e 100644 --- a/src/main/java/net/Broken/RestApi/MusicWebAPIController.java +++ b/src/main/java/net/Broken/RestApi/MusicWebAPIController.java @@ -6,6 +6,9 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; import net.Broken.Commands.Music; import net.Broken.MainBot; import net.Broken.RestApi.Data.*; +import net.Broken.RestApi.Data.UserManager.CheckResposeData; +import net.Broken.RestApi.Data.UserManager.UserInfoData; +import net.Broken.Tools.UserManager.Exceptions.UserNotFoundException; import net.Broken.audio.NotConectedException; import net.Broken.audio.NullMusicManager; import net.dv8tion.jda.core.entities.VoiceChannel; @@ -21,7 +24,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; -// import net.Broken.DB.SavedPlaylistRepository; +// import net.Broken.DB.Repository.SavedPlaylistRepository; @RestController @RequestMapping("/api/music/") @@ -85,7 +88,6 @@ public class MusicWebAPIController { @RequestMapping(value = "/getChanel", method = RequestMethod.GET) public List getChanel(){ List temp = new ArrayList<>(); - logger.info(MainBot.jda.getVoiceChannels().size()); for(VoiceChannel aChanel : MainBot.jda.getVoiceChannels()){ temp.add(new Chanel(aChanel.getName(),aChanel.getId(),aChanel.getPosition())); } @@ -95,6 +97,7 @@ public class MusicWebAPIController { + // DB Test Ignore it // @RequestMapping(value = "/test", method = RequestMethod.GET) diff --git a/src/main/java/net/Broken/RestApi/UserManagerAPIController.java b/src/main/java/net/Broken/RestApi/UserManagerAPIController.java new file mode 100644 index 0000000..a746e22 --- /dev/null +++ b/src/main/java/net/Broken/RestApi/UserManagerAPIController.java @@ -0,0 +1,83 @@ +package net.Broken.RestApi; + +import net.Broken.DB.Entity.PendingUserEntity; +import net.Broken.DB.Entity.UserEntity; +import net.Broken.DB.Repository.PendingUserRepository; +import net.Broken.DB.Repository.UserRepository; +import net.Broken.MainBot; +import net.Broken.RestApi.Data.UserManager.CheckResposeData; +import net.Broken.RestApi.Data.UserManager.ConfirmData; +import net.Broken.RestApi.Data.UserManager.UserConnectionData; +import net.Broken.RestApi.Data.UserManager.UserInfoData; +import net.Broken.Tools.UserManager.Exceptions.PasswordNotMatchException; +import net.Broken.Tools.UserManager.Exceptions.TokenNotMatch; +import net.Broken.Tools.UserManager.Exceptions.UserAlreadyRegistered; +import net.Broken.Tools.UserManager.Exceptions.UserNotFoundException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import sun.applet.Main; + +@RestController +@RequestMapping("/api/userManagement") +public class UserManagerAPIController { + Logger logger = LogManager.getLogger(); + @Autowired + PendingUserRepository pendingUserRepository; + + @Autowired + UserRepository userRepository; + + @Autowired + private PasswordEncoder passwordEncoder; + + + @RequestMapping(value = "/preRegister", method = RequestMethod.POST) + public ResponseEntity command(@RequestBody UserInfoData data){ + if(data != null && data.name != null) { + try { + String id = MainBot.userRegister.sendCheckToken(pendingUserRepository, userRepository, passwordEncoder, data); + return new ResponseEntity<>(new CheckResposeData(true, data.name, "Message sent", id), HttpStatus.OK); + } catch (UserNotFoundException e) { + logger.warn("User \"" + data.name + "\" not found!"); + return new ResponseEntity<>(new CheckResposeData(false, data.name, "User not found on server!",""), HttpStatus.NOT_FOUND); + } catch (PasswordNotMatchException userAlreadyRegistered) { + return new ResponseEntity<>(new CheckResposeData(false, data.name, "User already registered in pending database and password not match!",""), HttpStatus.NOT_ACCEPTABLE); + + } catch (UserAlreadyRegistered userAlreadyRegistered) { + return new ResponseEntity<>(new CheckResposeData(false, data.name, "User already registered in database!",""), HttpStatus.NOT_ACCEPTABLE); + } + } + else{ + return new ResponseEntity<>(new CheckResposeData(false, "", "Missing parameter(s)",""), HttpStatus.BAD_REQUEST); + } + } + + @RequestMapping(value = "/confirmAccount", method = RequestMethod.POST) + public ResponseEntity confirAccount(@RequestBody ConfirmData data){ + //TODO move pending user to accepted and return right things + try { + PendingUserEntity pUser = MainBot.userRegister.confirmCheckToken(pendingUserRepository, Integer.parseInt(data.id), data.checkToken); + UserEntity user = new UserEntity(pUser, MainBot.userRegister.generateApiToken()); + userRepository.save(user); + pendingUserRepository.delete(pUser); + + return new ResponseEntity<>(new UserConnectionData(true,"",""),HttpStatus.OK); + } catch (TokenNotMatch tokenNotMatch) { + logger.warn("Pre token not match for "+data.id+"!"); + return new ResponseEntity<>(new UserConnectionData(false,null,"Token not match!"),HttpStatus.NOT_ACCEPTABLE); + } catch (UserNotFoundException e) { + logger.warn("Id not found in DB ("+data.id+")"); + return new ResponseEntity<>(new UserConnectionData(false,null,"User not found on DB!"),HttpStatus.NOT_ACCEPTABLE); + } + } + + +} diff --git a/src/main/java/net/Broken/Tools/EmbedMessageUtils.java b/src/main/java/net/Broken/Tools/EmbedMessageUtils.java index db95c30..15ceaf7 100644 --- a/src/main/java/net/Broken/Tools/EmbedMessageUtils.java +++ b/src/main/java/net/Broken/Tools/EmbedMessageUtils.java @@ -1,5 +1,6 @@ package net.Broken.Tools; +import net.Broken.MainBot; import net.dv8tion.jda.core.EmbedBuilder; import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.MessageEmbed; @@ -67,5 +68,10 @@ public class EmbedMessageUtils { } + public static MessageEmbed getRegister(String message) { + return new EmbedBuilder().setTitle(":pencil: Web Registration :pencil:").setDescription(message).setColor(Color.green).setFooter("bot.seb6596.ovh", MainBot.jda.getSelfUser().getAvatarUrl()).build(); + } + + } \ No newline at end of file diff --git a/src/main/java/net/Broken/Tools/ResourceLoader.java b/src/main/java/net/Broken/Tools/ResourceLoader.java new file mode 100644 index 0000000..8b55b94 --- /dev/null +++ b/src/main/java/net/Broken/Tools/ResourceLoader.java @@ -0,0 +1,41 @@ +package net.Broken.Tools; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.util.Scanner; + + + +public class ResourceLoader { + + private Logger logger = LogManager.getLogger(); + + public String getFile(String fileName) { + + StringBuilder result = new StringBuilder(""); + + //Get file from resources folder + ClassLoader classLoader = getClass().getClassLoader(); + File file = new File(classLoader.getResource(fileName).getFile()); + + try (Scanner scanner = new Scanner(file)) { + + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + result.append(line).append("\n"); + } + + scanner.close(); + + } catch (IOException e) { + logger.catching(e); + } + + return result.toString(); + + } + +} diff --git a/src/main/java/net/Broken/Tools/UserManager/Exceptions/PasswordNotMatchException.java b/src/main/java/net/Broken/Tools/UserManager/Exceptions/PasswordNotMatchException.java new file mode 100644 index 0000000..0eeac2e --- /dev/null +++ b/src/main/java/net/Broken/Tools/UserManager/Exceptions/PasswordNotMatchException.java @@ -0,0 +1,4 @@ +package net.Broken.Tools.UserManager.Exceptions; + +public class PasswordNotMatchException extends Exception{ +} diff --git a/src/main/java/net/Broken/Tools/UserManager/Exceptions/TokenNotMatch.java b/src/main/java/net/Broken/Tools/UserManager/Exceptions/TokenNotMatch.java new file mode 100644 index 0000000..fc5d6e9 --- /dev/null +++ b/src/main/java/net/Broken/Tools/UserManager/Exceptions/TokenNotMatch.java @@ -0,0 +1,4 @@ +package net.Broken.Tools.UserManager.Exceptions; + +public class TokenNotMatch extends Exception { +} diff --git a/src/main/java/net/Broken/Tools/UserManager/Exceptions/UserAlreadyRegistered.java b/src/main/java/net/Broken/Tools/UserManager/Exceptions/UserAlreadyRegistered.java new file mode 100644 index 0000000..f945a30 --- /dev/null +++ b/src/main/java/net/Broken/Tools/UserManager/Exceptions/UserAlreadyRegistered.java @@ -0,0 +1,4 @@ +package net.Broken.Tools.UserManager.Exceptions; + +public class UserAlreadyRegistered extends Exception { +} diff --git a/src/main/java/net/Broken/Tools/UserManager/Exceptions/UserNotFoundException.java b/src/main/java/net/Broken/Tools/UserManager/Exceptions/UserNotFoundException.java new file mode 100644 index 0000000..232c53c --- /dev/null +++ b/src/main/java/net/Broken/Tools/UserManager/Exceptions/UserNotFoundException.java @@ -0,0 +1,4 @@ +package net.Broken.Tools.UserManager.Exceptions; + +public class UserNotFoundException extends Exception{ +} diff --git a/src/main/java/net/Broken/Tools/UserManager/PasswordUtils.java b/src/main/java/net/Broken/Tools/UserManager/PasswordUtils.java new file mode 100644 index 0000000..a965602 --- /dev/null +++ b/src/main/java/net/Broken/Tools/UserManager/PasswordUtils.java @@ -0,0 +1,14 @@ +package net.Broken.Tools.UserManager; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordUtils { + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/src/main/java/net/Broken/Tools/UserManager/UserRegister.java b/src/main/java/net/Broken/Tools/UserManager/UserRegister.java index c128820..3850322 100644 --- a/src/main/java/net/Broken/Tools/UserManager/UserRegister.java +++ b/src/main/java/net/Broken/Tools/UserManager/UserRegister.java @@ -1,14 +1,123 @@ package net.Broken.Tools.UserManager; +import net.Broken.DB.Entity.PendingUserEntity; +import net.Broken.DB.Repository.PendingUserRepository; +import net.Broken.DB.Repository.UserRepository; +import net.Broken.MainBot; +import net.Broken.RestApi.Data.UserManager.UserInfoData; +import net.Broken.Tools.EmbedMessageUtils; +import net.Broken.Tools.PrivateMessage; +import net.Broken.Tools.ResourceLoader; +import net.Broken.Tools.UserManager.Exceptions.PasswordNotMatchException; +import net.Broken.Tools.UserManager.Exceptions.TokenNotMatch; +import net.Broken.Tools.UserManager.Exceptions.UserAlreadyRegistered; +import net.Broken.Tools.UserManager.Exceptions.UserNotFoundException; +import net.dv8tion.jda.core.entities.MessageEmbed; +import net.dv8tion.jda.core.entities.User; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties; +import org.springframework.security.crypto.password.PasswordEncoder; + import java.security.SecureRandom; +import java.util.List; +import java.util.UUID; public class UserRegister { + private Logger logger = LogManager.getLogger(); - public String generateToken(){ + + public String sendCheckToken(PendingUserRepository pendingUserRepository, UserRepository userRepository, PasswordEncoder passwordEncoder, UserInfoData userInfo) throws UserNotFoundException, PasswordNotMatchException, UserAlreadyRegistered { + + logger.info("New registration for " + userInfo.name); + + List users = MainBot.jda.getUsersByName(userInfo.name,true); + if(users.size() < 1) + throw new UserNotFoundException(); + + User user = users.get(0); + logger.info("User found!"); + + PendingUserEntity pendingUserEntity = null; + String token = ""; + + //Test if exist on register user + if(userRepository.findByJdaId(user.getId()).size() > 0){ + logger.warn("User already registered!"); + throw new UserAlreadyRegistered(); + } + + + + //Check if exist in pading user Table + List pendingUsers = pendingUserRepository.findByJdaId(user.getId()); + if(pendingUsers.size() != 0){ + PendingUserEntity thisUser = pendingUsers.get(0); + if(passwordEncoder.matches(userInfo.password, thisUser.getPassword())){ + logger.info("Password matches"); + pendingUserEntity = thisUser; + token = thisUser.getCheckToken(); + }else{ + logger.warn("Password Not Match!"); + throw new PasswordNotMatchException(); + } + } + + + + logger.info("Generating check Token..."); + if(token.equals("")){ + token = generateCheckToken(); + } + + logger.info("Token generated: " + token); + if(pendingUserEntity == null) { + pendingUserEntity = new PendingUserEntity(user.getName(), user.getId(), token, passwordEncoder.encode(userInfo.password)); + pendingUserEntity = pendingUserRepository.save(pendingUserEntity); + } + + String message = new ResourceLoader().getFile("MessagesTemplates/RegisterMessage.md"); + + message = message.replace("%code",token); + + MessageEmbed ebM = EmbedMessageUtils.getRegister(message); + PrivateMessage.send(user,ebM,logger); + return pendingUserEntity.getId().toString(); + + } + + public PendingUserEntity confirmCheckToken(PendingUserRepository pendingUserRepository, int id, String checkToken ) throws TokenNotMatch, UserNotFoundException { + PendingUserEntity pendingUser = pendingUserRepository.findOne(id); + if(pendingUser != null) { + if(pendingUser.getCheckToken().equals(checkToken)){ + logger.info("Check Token match!"); + } + else{ + logger.warn("Check token not match!"); + throw new TokenNotMatch(); + } + } + else{ + logger.warn("Id not Found!"); + throw new UserNotFoundException(); + } + return pendingUser; + } + + + public String generateApiToken(){ + return UUID.randomUUID().toString(); + } + + public String generateCheckToken(){ SecureRandom random = new SecureRandom(); long longToken = Math.abs( random.nextLong() ); String randomStr = Long.toString( longToken, 16 ); + randomStr = randomStr.substring(0,4); + randomStr = randomStr.toUpperCase(); return randomStr; } + + } diff --git a/src/main/java/net/Broken/webView/ResisterWebView.java b/src/main/java/net/Broken/webView/ResisterWebView.java new file mode 100644 index 0000000..3c0c246 --- /dev/null +++ b/src/main/java/net/Broken/webView/ResisterWebView.java @@ -0,0 +1,16 @@ +package net.Broken.webView; + + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@Controller +public class ResisterWebView { + @RequestMapping("/register") + public String music(@RequestParam(value="id", required = true, defaultValue = "") String id, Model model){ + model.addAttribute("id", id); + return "register"; + } +} diff --git a/src/main/resources/MessagesTemplates/RegisterMessage.md b/src/main/resources/MessagesTemplates/RegisterMessage.md new file mode 100644 index 0000000..630fbf3 --- /dev/null +++ b/src/main/resources/MessagesTemplates/RegisterMessage.md @@ -0,0 +1,5 @@ + +Une tentative d'association à etait demandé. + +Voici le code de vérification: +**%code** diff --git a/src/main/resources/static/js/register.js b/src/main/resources/static/js/register.js new file mode 100644 index 0000000..f4023cb --- /dev/null +++ b/src/main/resources/static/js/register.js @@ -0,0 +1,165 @@ + +var ok_passwrd = false; +$(document).ready(function() { + var baseUrl = window.location.protocol + "//" +window.location.host + window.location.pathname; + console.log(baseUrl); + $('.button-collapse-1').sideNav({ + menuWidth: 400, // Default is 300 + edge: 'right', // Choose the horizontal origin + closeOnClick: false, // Closes side-nav on clicks, useful for Angular/Meteor + draggable: true // Choose whether you can drag to open on touch screens, + }); + + var sendBtn = $('#sendBtn'); + + + $('#name').on("input", function () { + if($('#name').val() === ""){ + if (!sendBtn.hasClass("disabled")) { + sendBtn.addClass("disabled"); + } + } + else{ + if (sendBtn.hasClass("disabled") && ok_passwrd) { + sendBtn.removeClass("disabled"); + } + } + }); + + + var passwrd = $('#passwrd'); + var confirm = $('#passwrd2'); + passwrd.on("input", function () { + if((passwrd.val() === confirm.val())&& passwrd.val() !== ''){ + if (passwrd.hasClass("invalid")) { + passwrd.addClass("valid"); + passwrd.removeClass("invalid"); + confirm.addClass("valid"); + confirm.removeClass("invalid"); + + + } + if($('#name').val() !== ""){ + if (sendBtn.hasClass("disabled")) { + sendBtn.removeClass("disabled"); + } + } + ok_passwrd = true; + } + else{ + if (!passwrd.hasClass("invalid")) { + passwrd.addClass("invalid"); + passwrd.removeClass("valid"); + confirm.addClass("invalid"); + confirm.removeClass("valid"); + + } + if (!sendBtn.hasClass("disabled")) { + sendBtn.addClass("disabled"); + } + ok_passwrd = false; + } + }); + + confirm.on("input", function () { + if((passwrd.val() === confirm.val())&& passwrd.val() !== ''){ + if (passwrd.hasClass("invalid")) { + passwrd.addClass("valid"); + passwrd.removeClass("invalid"); + confirm.addClass("valid"); + confirm.removeClass("invalid"); + + } + if($('#name').val() !== ""){ + if (sendBtn.hasClass("disabled")) { + sendBtn.removeClass("disabled"); + } + } + ok_passwrd = true; + } + else{ + if (!passwrd.hasClass("invalid")) { + passwrd.addClass("invalid"); + passwrd.removeClass("valid"); + confirm.addClass("invalid"); + confirm.removeClass("valid"); + } + + if (!sendBtn.hasClass("disabled")) { + sendBtn.addClass("disabled"); + } + ok_passwrd = false; + } + }); + + + $('#sendBtn').click(function () { + var name = $('#name').val(); + var password = $('#passwrd').val(); + + $.ajax({ + type: "POST", + dataType: 'json', + contentType: 'application/json', + url: "/api/userManagement/preRegister", + data: JSON.stringify({ name: name, password: password}), + success: function (data) { + console.log(data); + window.location.href = baseUrl + "?id="+data.id + } + + }).fail(function (data) { + console.log(data); + if(data.status === 404){ + alert("User Not Found!"); + $('#name').addClass("invalid"); + $('#name').removeClass("valid"); + + } + else{ + alert(data.responseJSON.message); + } + + }); + }); + + $('#modalToken').modal({dismissible: false}); + if(id !== ''){ + $('#modalToken').modal('open'); + } + + + $('#input_preToken').on("input", function () { + var sendBtn = $('#preTokenSend'); + if($('#input_preToken').val().length < 4){ + if (!sendBtn.hasClass("disabled")) { + sendBtn.addClass("disabled"); + } + } + else{ + if (sendBtn.hasClass("disabled")) { + sendBtn.removeClass("disabled"); + } + } + }); + $('#preTokenSend').click(function () { + $.ajax({ + type: "POST", + dataType: 'json', + contentType: 'application/json', + url: "/api/userManagement/confirmAccount", + data: JSON.stringify({ id: id.toString(), checkToken: $('#input_preToken').val()}), + success: function (data) { + console.log(data); + alert("Connection ok!") + } + + }).fail(function (data) { + console.log(data); + alert(data.responseJSON.message); + + }); + }); + + +}); diff --git a/src/main/resources/templates/register.html b/src/main/resources/templates/register.html new file mode 100644 index 0000000..a8f3e8b --- /dev/null +++ b/src/main/resources/templates/register.html @@ -0,0 +1,131 @@ + + + + + + User Registration - Discord Bot + + + + + + + + + + + + + +
+
+
+

Account Registration

+
+
+
+
+ assignment_ind + + +
+
+
+
+
+
+ security + + +
+
+
+
+
+
+ security + + +
+
+
+
+ Sendsend +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file