From dbb8e2ed722c71916664c9a0a9bd19cc5f5ff1f1 Mon Sep 17 00:00:00 2001 From: "branislav.radivojevic" Date: Thu, 3 Nov 2022 18:03:51 +0100 Subject: Back verification pages,pass reset, code cleanup --- Backend/Api/Api/Assets/VerifyFailed.html | 13 ++++++ Backend/Api/Api/Assets/VerifySuccess.html | 14 ++++++ Backend/Api/Api/Assets/logotima.png | Bin 0 -> 377184 bytes Backend/Api/Api/Controllers/AuthController.cs | 52 +++++++++++++++++---- Backend/Api/Api/Interfaces/IJwtService.cs | 3 +- Backend/Api/Api/Interfaces/IUserService.cs | 6 ++- Backend/Api/Api/Program.cs | 5 +- Backend/Api/Api/Services/JwtService.cs | 34 ++------------ Backend/Api/Api/Services/UserService.cs | 64 ++++++++++++++++++++++---- Backend/Api/Api/appsettings.json | 14 ++++-- 10 files changed, 145 insertions(+), 60 deletions(-) create mode 100644 Backend/Api/Api/Assets/VerifyFailed.html create mode 100644 Backend/Api/Api/Assets/VerifySuccess.html create mode 100644 Backend/Api/Api/Assets/logotima.png (limited to 'Backend') diff --git a/Backend/Api/Api/Assets/VerifyFailed.html b/Backend/Api/Api/Assets/VerifyFailed.html new file mode 100644 index 0000000..f1e41e4 --- /dev/null +++ b/Backend/Api/Api/Assets/VerifyFailed.html @@ -0,0 +1,13 @@ + + + + + Verification Failed + + +
+ +

Token timed out

+
+ + \ No newline at end of file diff --git a/Backend/Api/Api/Assets/VerifySuccess.html b/Backend/Api/Api/Assets/VerifySuccess.html new file mode 100644 index 0000000..50c01d2 --- /dev/null +++ b/Backend/Api/Api/Assets/VerifySuccess.html @@ -0,0 +1,14 @@ + + + + + Verification Successful + + +
+ +

Welcome to BrzoDoLokacije

+

We are glad to have you, {{name}} as a member.

+
+ + \ No newline at end of file diff --git a/Backend/Api/Api/Assets/logotima.png b/Backend/Api/Api/Assets/logotima.png new file mode 100644 index 0000000..85137ac Binary files /dev/null and b/Backend/Api/Api/Assets/logotima.png differ diff --git a/Backend/Api/Api/Controllers/AuthController.cs b/Backend/Api/Api/Controllers/AuthController.cs index d835d97..cbd5eb8 100644 --- a/Backend/Api/Api/Controllers/AuthController.cs +++ b/Backend/Api/Api/Controllers/AuthController.cs @@ -1,5 +1,6 @@ using Api.Interfaces; using Api.Models; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Api.Controllers @@ -8,12 +9,14 @@ namespace Api.Controllers public class AuthController : Controller { private readonly IUserService _userService; - public AuthController(IUserService userService) + private readonly IJwtService _jwtService; + public AuthController(IUserService userService,IJwtService jwtService) { _userService = userService; + _jwtService = jwtService; } - [HttpPost("register")] + [HttpPost("registerdeprecated")] public async Task> Register([FromBody] Register creds) { //this is beyond scuffed and will be cleaned up later, when users,login and controllers are made @@ -47,19 +50,26 @@ namespace Api.Controllers } return BadRequest("Pogresno uneti podaci"); } - [HttpPost("registeractual")] + [HttpPost("register")] public async Task> RegisterActual([FromBody] Register creds) { var msg = await _userService.Register(creds); - if (msg == "Email Exists") - return Forbid(msg); - if (msg == "Username Exists") - return Forbid(msg); - return Ok(msg); + switch (msg) + { + case "User Registered": + return Ok(msg); + default: + return BadRequest(msg); + } } [HttpPost("verify")] public async Task> VerifyEmail([FromBody] VerifyUser creds) { + var vrfchk = new Login(); + vrfchk.email = creds.email; + vrfchk.password = creds.password; + if (await _userService.CheckVerification(vrfchk)) + return Ok("User already verified"); var uspeh = await _userService.VerifyUser(creds); if (!uspeh) return BadRequest("Kod netacan ili istekao"); @@ -73,5 +83,31 @@ namespace Api.Controllers return BadRequest("Kod netacan ili istekao"); return Ok("Sifra uspesno resetovana"); } + [HttpPost("forgotpass")] + public async Task> ForgotPass([FromBody] JustMail justMail) + { + if (await _userService.ForgotPassword(justMail)) + return Ok("Email poslat"); + return BadRequest("Email nema registrovan nalog"); + } + [HttpGet("verifytoken/{token}")] + public async Task> VerifyEmailToken(string token) + { + var username =_jwtService.EmailTokenToClaim(token,"username"); + string html; + if (username == null) + { + html = await System.IO.File.ReadAllTextAsync(@"./Assets/VerifyFailed.html"); + return base.Content(html, "text/html"); + } + else + { + html = await System.IO.File.ReadAllTextAsync(@"./Assets/VerifySuccess.html"); + html = html.Replace("{{name}}", username); + + await _userService.VerifyFromToken(token); + return base.Content(html, "text/html"); + } + } } } diff --git a/Backend/Api/Api/Interfaces/IJwtService.cs b/Backend/Api/Api/Interfaces/IJwtService.cs index 6274bf9..8d0038f 100644 --- a/Backend/Api/Api/Interfaces/IJwtService.cs +++ b/Backend/Api/Api/Interfaces/IJwtService.cs @@ -7,7 +7,6 @@ namespace Api.Interfaces string GenToken(User user); string TokenToId(string token); public string GenEmailToken(User user); - public string EmailTokenToId(string token); - public string EmailTokenToKod(string token); + public string EmailTokenToClaim(string token,string claim); } } \ No newline at end of file diff --git a/Backend/Api/Api/Interfaces/IUserService.cs b/Backend/Api/Api/Interfaces/IUserService.cs index 5205028..218c67a 100644 --- a/Backend/Api/Api/Interfaces/IUserService.cs +++ b/Backend/Api/Api/Interfaces/IUserService.cs @@ -17,10 +17,12 @@ namespace Api.Interfaces Task Register(Register register); Task VerifyUser(VerifyUser login); Task UserIdFromJwt(); - Task ResendVerifyKod(Login login); - Boolean SendEmailKod(User user); + Task ResendVerifyEmail(Login login); + Boolean SendEmailKod(User user,int msgid); Task ForgotPassword(JustMail jm); Task ResetPassword(ResetPass rp); + Task CheckVerification(Login login); + Task VerifyFromToken(string token); } } diff --git a/Backend/Api/Api/Program.cs b/Backend/Api/Api/Program.cs index 4643937..6c96331 100644 --- a/Backend/Api/Api/Program.cs +++ b/Backend/Api/Api/Program.cs @@ -1,4 +1,3 @@ -using System.Text; using Api.Database; using Api.Interfaces; using Api.Services; @@ -6,6 +5,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using MongoDB.Driver; +using System.Text; var builder = WebApplication.CreateBuilder(args); @@ -30,7 +30,8 @@ builder.Services.AddHttpContextAccessor(); //Add Authentication builder.Services.AddAuthentication( - JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => { + JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => + { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, diff --git a/Backend/Api/Api/Services/JwtService.cs b/Backend/Api/Api/Services/JwtService.cs index 9d928f7..fbf5724 100644 --- a/Backend/Api/Api/Services/JwtService.cs +++ b/Backend/Api/Api/Services/JwtService.cs @@ -72,7 +72,7 @@ namespace Api.Services return tokenHandler.WriteToken(token); } - public string EmailTokenToId(string token) + public string EmailTokenToClaim(string token,string claim) { if (token == null) return null; @@ -90,41 +90,13 @@ namespace Api.Services }, out SecurityToken validatedToken); var jwtToken = (JwtSecurityToken)validatedToken; - var username = (jwtToken.Claims.First(x => x.Type == "username").Value.ToString()); - return username; + var result = (jwtToken.Claims.First(x => x.Type == claim).Value.ToString()); + return result; } catch { return null; } } - - public string EmailTokenToKod(string token) - { - if (token == null) - return null; - var tokenHandler = new JwtSecurityTokenHandler(); - var key = Encoding.ASCII.GetBytes(_config.GetSection("AppSettings:EmailToken").Value.ToString()); - try - { - tokenHandler.ValidateToken(token, new TokenValidationParameters - { - ValidateIssuerSigningKey = true, - IssuerSigningKey = new SymmetricSecurityKey(key), - ValidateIssuer = false, - ValidateAudience = false, - ClockSkew = TimeSpan.Zero - }, - out SecurityToken validatedToken); - var jwtToken = (JwtSecurityToken)validatedToken; - var kod = (jwtToken.Claims.First(x => x.Type == "kod").Value.ToString()); - return kod; - } - catch - { - return null; - } - } - } } diff --git a/Backend/Api/Api/Services/UserService.cs b/Backend/Api/Api/Services/UserService.cs index 3002f34..034c494 100644 --- a/Backend/Api/Api/Services/UserService.cs +++ b/Backend/Api/Api/Services/UserService.cs @@ -114,9 +114,16 @@ namespace Api.Services foreach(var usr in unverified) { //ako user nema validan emailtoken, a nije verifikovan prethodno, onda se brise iz baze - if (_jwtService.EmailTokenToId(usr.emailToken) == null) + if (_jwtService.EmailTokenToClaim(usr.emailToken,"id") == null) await _users.FindOneAndDeleteAsync(x => x._id == usr._id); } + foreach (var usr in unverified) + { + if (usr.email == register.email && _jwtService.EmailTokenToClaim(usr.emailToken,"id") != null) + return "Unverified Email Exists, check your inbox"; + if (usr.username == register.username && _jwtService.EmailTokenToClaim(usr.emailToken,"id") != null) + return "Unverified Username Exists, please select another"; + } } } @@ -133,7 +140,7 @@ namespace Api.Services user.emailToken = _jwtService.GenEmailToken(user); await _users.ReplaceOneAsync(x => x._id == user._id, user); - SendEmailKod(user); + SendEmailKod(user,1); return "User Registered"; } @@ -143,11 +150,12 @@ namespace Api.Services User user = await _users.FindAsync(x => x.email == login.email).Result.FirstOrDefaultAsync(); if (user != null && checkPassword(login.password, user.password)) { - var basekod = _jwtService.EmailTokenToKod(user.emailToken); + var basekod = _jwtService.EmailTokenToClaim(user.emailToken,"kod"); if (basekod != null) if (String.Compare(login.kod,basekod) == 0) { user.verified = true; + user.emailToken = ""; await _users.ReplaceOneAsync(x => x._id == user._id, user); return true; } @@ -188,33 +196,47 @@ namespace Api.Services return id; } - public async Task ResendVerifyKod(Login login) + public async Task ResendVerifyEmail(Login login) { User user = await _users.FindAsync(x => x.email == login.email).Result.FirstOrDefaultAsync(); if (user != null && checkPassword(login.password, user.password)) { user.emailToken = _jwtService.GenEmailToken(user); await _users.ReplaceOneAsync(x => x._id == user._id, user); - SendEmailKod(user); + SendEmailKod(user,1); return true; } return false; } - public Boolean SendEmailKod(User user) + + public Boolean SendEmailKod(User user,int msgid) //1 - email verification, 2 - password reset { MimeMessage message = new MimeMessage(); message.From.Add(new MailboxAddress("Tim Oddyssey", _configuration.GetSection("EmailCfg:Email").Value)); message.To.Add(MailboxAddress.Parse(user.email)); message.Subject = "Vas Oddyssey verifikacioni kod"; //think of something better yeah? - var kod = _jwtService.EmailTokenToKod(user.emailToken); + var kod = _jwtService.EmailTokenToClaim(user.emailToken,"kod"); if (kod == null) return false; var bodybuilder = new BodyBuilder(); - bodybuilder.HtmlBody = String.Format(@"

Verfikacioni kod:

"+kod+"


Kod traje 30 minuta

"); + switch(msgid){ + case 1: + //bodybuilder.HtmlBody = String.Format(@"

Verfikacioni kod:

" + kod + "


Kod traje 30 minuta

"); + bodybuilder.HtmlBody = String.Format(@"

Link za verifikaciju emaila:


" + + "
" + + "" + + "
" + + "

Link traje 30 minuta

"); + break; + case 2: + bodybuilder.HtmlBody = String.Format(@"

Verfikacioni kod:

" + kod + "


Kod traje 30 minuta

"); + break; + } + message.Body = bodybuilder.ToMessageBody(); SmtpClient client = new SmtpClient(); @@ -244,7 +266,7 @@ namespace Api.Services { user.emailToken = _jwtService.GenEmailToken(user); await _users.ReplaceOneAsync(x => x._id == user._id, user); - SendEmailKod(user); + SendEmailKod(user,2); return true; } @@ -256,16 +278,38 @@ namespace Api.Services User user = await _users.FindAsync(x => x.email == rp.email && x.verified == true).Result.FirstOrDefaultAsync(); if (user != null) { - var basekod = _jwtService.EmailTokenToKod(user.emailToken); + var basekod = _jwtService.EmailTokenToClaim(user.emailToken,"kod"); if (basekod != null) if (String.Compare(rp.kod, basekod) == 0) { user.password = hashPassword(rp.newpass); + user.emailToken = ""; await _users.ReplaceOneAsync(x => x._id == user._id, user); return true; } } return false; } + public async Task CheckVerification(Login login) + { + User user = await _users.FindAsync(x => x.email == login.email).Result.FirstOrDefaultAsync(); + if (user != null && checkPassword(login.password, user.password) && user.verified == true) + { + return true; + } + return false; + } + public async Task VerifyFromToken(string token) + { + User user = await _users.FindAsync(x => x.emailToken == token).Result.FirstOrDefaultAsync(); + if(user != null) + { + user.verified = true; + user.emailToken = ""; + await _users.ReplaceOneAsync(x => x._id == user._id, user); + return true; + } + return false; + } } } diff --git a/Backend/Api/Api/appsettings.json b/Backend/Api/Api/appsettings.json index 48086f3..74cfa27 100644 --- a/Backend/Api/Api/appsettings.json +++ b/Backend/Api/Api/appsettings.json @@ -18,9 +18,13 @@ "UserCollectionName": "users" }, - "EmailCfg": { - "Email": "oddyssey.brzodolokacije@gmail.com", - "SmtpServer": "smtp.gmail.com", - "Password": "nrokhfcwahfbqnpp" //msbs#556 - } + "EmailCfg": { + "Email": "oddyssey.brzodolokacije@gmail.com", + "SmtpServer": "smtp.gmail.com", + "Password": "nrokhfcwahfbqnpp" //msbs#556 + }, + "URLs": { + "localhost": "http://localhost:5279/", + "actual":"add url when back put onto server" + } } -- cgit v1.2.3