From 03b89786ecdcc3bb6777b7a6ba9c281b0b672051 Mon Sep 17 00:00:00 2001 From: "DESKTOP-GENO133\\IvanPlex" Date: Fri, 12 Jan 2024 23:54:12 -0700 Subject: [PATCH] make email address required for token generation and user registration. --- Controllers/AdminController.cs | 9 ++- .../Implementations/TokenRecordDataAccess.cs | 9 +++ .../Implementations/UserRecordDataAccess.cs | 9 +++ External/Interfaces/ITokenRecordDataAccess.cs | 1 + External/Interfaces/IUserRecordDataAccess.cs | 1 + Logic/LoginLogic.cs | 43 ++++++++++---- Middleware/Authen.cs | 2 +- Models/Login/LoginModel.cs | 1 + Models/Login/Token.cs | 1 + Models/Login/UserData.cs | 1 + Views/Admin/Index.cshtml | 59 +++++++++++++++---- Views/Login/Registration.cshtml | 4 ++ wwwroot/js/login.js | 3 +- 13 files changed, 119 insertions(+), 24 deletions(-) diff --git a/Controllers/AdminController.cs b/Controllers/AdminController.cs index be5dbf4..6197bba 100644 --- a/Controllers/AdminController.cs +++ b/Controllers/AdminController.cs @@ -22,9 +22,14 @@ namespace CarCareTracker.Controllers }; return View(viewModel); } - public IActionResult GenerateNewToken() + public IActionResult GenerateNewToken(string emailAddress) { - var result = _loginLogic.GenerateUserToken(); + var result = _loginLogic.GenerateUserToken(emailAddress); + return Json(result); + } + public IActionResult DeleteToken(int tokenId) + { + var result = _loginLogic.DeleteUserToken(tokenId); return Json(result); } } diff --git a/External/Implementations/TokenRecordDataAccess.cs b/External/Implementations/TokenRecordDataAccess.cs index 289a1c0..961f583 100644 --- a/External/Implementations/TokenRecordDataAccess.cs +++ b/External/Implementations/TokenRecordDataAccess.cs @@ -26,6 +26,15 @@ namespace CarCareTracker.External.Implementations return tokenRecord ?? new Token(); }; } + public Token GetTokenRecordByEmailAddress(string emailAddress) + { + using (var db = new LiteDatabase(dbName)) + { + var table = db.GetCollection(tableName); + var tokenRecord = table.FindOne(Query.EQ(nameof(Token.EmailAddress), emailAddress)); + return tokenRecord ?? new Token(); + }; + } public bool CreateNewToken(Token token) { using (var db = new LiteDatabase(dbName)) diff --git a/External/Implementations/UserRecordDataAccess.cs b/External/Implementations/UserRecordDataAccess.cs index 1586389..7e13f46 100644 --- a/External/Implementations/UserRecordDataAccess.cs +++ b/External/Implementations/UserRecordDataAccess.cs @@ -26,6 +26,15 @@ namespace CarCareTracker.External.Implementations return userRecord ?? new UserData(); }; } + public UserData GetUserRecordByEmailAddress(string emailAddress) + { + using (var db = new LiteDatabase(dbName)) + { + var table = db.GetCollection(tableName); + var userRecord = table.FindOne(Query.EQ(nameof(UserData.EmailAddress), emailAddress)); + return userRecord ?? new UserData(); + }; + } public UserData GetUserRecordById(int userId) { using (var db = new LiteDatabase(dbName)) diff --git a/External/Interfaces/ITokenRecordDataAccess.cs b/External/Interfaces/ITokenRecordDataAccess.cs index 231fa5c..d0dcca2 100644 --- a/External/Interfaces/ITokenRecordDataAccess.cs +++ b/External/Interfaces/ITokenRecordDataAccess.cs @@ -6,6 +6,7 @@ namespace CarCareTracker.External.Interfaces { public List GetTokens(); public Token GetTokenRecordByBody(string tokenBody); + public Token GetTokenRecordByEmailAddress(string emailAddress); public bool CreateNewToken(Token token); public bool DeleteToken(int tokenId); } diff --git a/External/Interfaces/IUserRecordDataAccess.cs b/External/Interfaces/IUserRecordDataAccess.cs index 3ba8ae9..971072d 100644 --- a/External/Interfaces/IUserRecordDataAccess.cs +++ b/External/Interfaces/IUserRecordDataAccess.cs @@ -6,6 +6,7 @@ namespace CarCareTracker.External.Interfaces { public List GetUsers(); public UserData GetUserRecordByUserName(string userName); + public UserData GetUserRecordByEmailAddress(string emailAddress); public UserData GetUserRecordById(int userId); public bool SaveUserRecord(UserData userRecord); public bool DeleteUserRecord(int userId); diff --git a/Logic/LoginLogic.cs b/Logic/LoginLogic.cs index b2aa44f..22a425c 100644 --- a/Logic/LoginLogic.cs +++ b/Logic/LoginLogic.cs @@ -10,7 +10,8 @@ namespace CarCareTracker.Logic { public interface ILoginLogic { - bool GenerateUserToken(); + bool GenerateUserToken(string emailAddress); + bool DeleteUserToken(int tokenId); OperationResponse RegisterNewUser(LoginModel credentials); OperationResponse ResetUserPassword(LoginModel credentials); UserData ValidateUserCredentials(LoginModel credentials); @@ -33,12 +34,12 @@ namespace CarCareTracker.Logic { //validate their token. var existingToken = _tokenData.GetTokenRecordByBody(credentials.Token); - if (existingToken.Id == default) + if (existingToken.Id == default || existingToken.EmailAddress != credentials.EmailAddress) { return new OperationResponse { Success = false, Message = "Invalid Token" }; } //token is valid, check if username and password is acceptable and that username is unique. - if (string.IsNullOrWhiteSpace(credentials.UserName) || string.IsNullOrWhiteSpace(credentials.Password)) + if (string.IsNullOrWhiteSpace(credentials.EmailAddress) || string.IsNullOrWhiteSpace(credentials.UserName) || string.IsNullOrWhiteSpace(credentials.Password)) { return new OperationResponse { Success = false, Message = "Neither username nor password can be blank" }; } @@ -47,6 +48,11 @@ namespace CarCareTracker.Logic { return new OperationResponse { Success = false, Message = "Username already taken" }; } + var existingUserWithEmail = _userData.GetUserRecordByEmailAddress(credentials.EmailAddress); + if (existingUserWithEmail.Id != default) + { + return new OperationResponse { Success = false, Message = "A user with that email already exists" }; + } //username is unique then we delete the token and create the user. _tokenData.DeleteToken(existingToken.Id); var newUser = new UserData() @@ -58,7 +64,8 @@ namespace CarCareTracker.Logic if (result) { return new OperationResponse { Success = true, Message = "You will be redirected to the login page briefly." }; - } else + } + else { return new OperationResponse { Success = false, Message = "Something went wrong, please try again later." }; } @@ -78,7 +85,8 @@ namespace CarCareTracker.Logic UserName = credentials.UserName, IsAdmin = true }; - } else + } + else { //authenticate via DB. var result = _userData.GetUserRecordByUserName(credentials.UserName); @@ -86,7 +94,8 @@ namespace CarCareTracker.Logic { result.Password = string.Empty; return result; - } else + } + else { return new UserData(); } @@ -103,15 +112,27 @@ namespace CarCareTracker.Logic var result = _tokenData.GetTokens(); return result; } - public bool GenerateUserToken() + public bool GenerateUserToken(string emailAddress) { + //check if email address already has a token attached to it. + var existingToken = _tokenData.GetTokenRecordByEmailAddress(emailAddress); + if (existingToken.Id != default) + { + return false; + } var token = new Token() { - Body = Guid.NewGuid().ToString().Substring(0, 8) + Body = Guid.NewGuid().ToString().Substring(0, 8), + EmailAddress = emailAddress }; var result = _tokenData.CreateNewToken(token); return result; } + public bool DeleteUserToken(int tokenId) + { + var result = _tokenData.DeleteToken(tokenId); + return result; + } public OperationResponse ResetUserPassword(LoginModel credentials) { //user might have forgotten their password. @@ -126,7 +147,8 @@ namespace CarCareTracker.Logic if (result) { return new OperationResponse { Success = true, Message = newPassword }; - } else + } + else { return new OperationResponse { Success = false, Message = "Something went wrong, please try again later." }; } @@ -150,7 +172,8 @@ namespace CarCareTracker.Logic File.WriteAllText(StaticHelper.UserConfigPath, JsonSerializer.Serialize(existingUserConfig)); return true; } - public bool DeleteRootUserCredentials() { + public bool DeleteRootUserCredentials() + { var configFileContents = File.ReadAllText(StaticHelper.UserConfigPath); var existingUserConfig = JsonSerializer.Deserialize(configFileContents); if (existingUserConfig is not null) diff --git a/Middleware/Authen.cs b/Middleware/Authen.cs index b486b59..4639980 100644 --- a/Middleware/Authen.cs +++ b/Middleware/Authen.cs @@ -99,7 +99,7 @@ namespace CarCareTracker.Middleware //if cookie is expired return AuthenticateResult.Fail("Expired credentials"); } - else if (authCookie.UserData.Id == default || string.IsNullOrWhiteSpace(authCookie.UserData.UserName)) + else if (authCookie.UserData is null || authCookie.UserData.Id == default || string.IsNullOrWhiteSpace(authCookie.UserData.UserName)) { return AuthenticateResult.Fail("Corrupted credentials"); } diff --git a/Models/Login/LoginModel.cs b/Models/Login/LoginModel.cs index a5424ed..167787e 100644 --- a/Models/Login/LoginModel.cs +++ b/Models/Login/LoginModel.cs @@ -4,6 +4,7 @@ { public string UserName { get; set; } public string Password { get; set; } + public string EmailAddress { get; set; } public string Token { get; set; } public bool IsPersistent { get; set; } = false; } diff --git a/Models/Login/Token.cs b/Models/Login/Token.cs index 1b438e1..78a7e19 100644 --- a/Models/Login/Token.cs +++ b/Models/Login/Token.cs @@ -4,5 +4,6 @@ { public int Id { get; set; } public string Body { get; set; } + public string EmailAddress { get; set; } } } diff --git a/Models/Login/UserData.cs b/Models/Login/UserData.cs index 8160473..29e5505 100644 --- a/Models/Login/UserData.cs +++ b/Models/Login/UserData.cs @@ -4,6 +4,7 @@ { public int Id { get; set; } public string UserName { get; set; } + public string EmailAddress { get; set; } public string Password { get; set; } public bool IsAdmin { get; set; } } diff --git a/Views/Admin/Index.cshtml b/Views/Admin/Index.cshtml index 6ea13d0..a9be61b 100644 --- a/Views/Admin/Index.cshtml +++ b/Views/Admin/Index.cshtml @@ -1,29 +1,36 @@ -@model AdminViewModel +@{ + ViewData["Title"] = "Admin"; +} +@model AdminViewModel
-
+
- - + + + @foreach (Token token in Model.Tokens) { - - - + + + + }
TokenDeleteTokenIssued ToDelete
@token.Body@token.Id
@token.Body@token.EmailAddress + +
-
+
@@ -52,11 +59,43 @@ function reloadPage() { window.location.reload(); } - function generateNewToken(){ - $.get('/Admin/GenerateNewToken', function (data) { + function deleteToken(tokenId) { + $.post(`/Admin/DeleteToken?tokenId=${tokenId}`, function (data) { if (data) { reloadPage(); } }); } + function copyToClipboard(e) { + var textToCopy = e.textContent; + navigator.clipboard.writeText(textToCopy); + successToast("Copied to Clipboard"); + } + function generateNewToken(){ + Swal.fire({ + title: 'Generate Token', + html: ` + + `, + confirmButtonText: 'Generate', + focusConfirm: false, + preConfirm: () => { + const emailAddress = $("#inputEmail").val(); + if (!emailAddress) { + Swal.showValidationMessage(`Please enter an email address`) + } + return { emailAddress } + }, + }).then(function (result) { + if (result.isConfirmed) { + $.get('/Admin/GenerateNewToken', {emailAddress: result.value.emailAddress}, function (data) { + if (data) { + reloadPage(); + } else { + errorToast("An error occurred, make sure the email address doesn't already have a token generated for it.") + } + }); + } + }); + } \ No newline at end of file diff --git a/Views/Login/Registration.cshtml b/Views/Login/Registration.cshtml index 2e12031..860e342 100644 --- a/Views/Login/Registration.cshtml +++ b/Views/Login/Registration.cshtml @@ -12,6 +12,10 @@ +
+ + +
diff --git a/wwwroot/js/login.js b/wwwroot/js/login.js index b2f002e..d737d40 100644 --- a/wwwroot/js/login.js +++ b/wwwroot/js/login.js @@ -14,7 +14,8 @@ function performRegistration() { var token = $("#inputToken").val(); var userName = $("#inputUserName").val(); var userPassword = $("#inputUserPassword").val(); - $.post('/Login/Register', { userName: userName, password: userPassword, token: token }, function (data) { + var userEmail = $("#inputEmail").val(); + $.post('/Login/Register', { userName: userName, password: userPassword, token: token, emailAddress: userEmail }, function (data) { if (data.success) { successToast(data.message); setTimeout(function () { window.location.href = '/Login/Index' }, 500);