public bool Update(int idUser, EmailConfirmCode emailConfirmCode) { string[] attributes = { "code:string", "status:bool" }; bool result = UpdateEntity(emailConfirmCode, "id_users", idUser.ToString(), attributes); Close(); return(result); }
public int Create(EmailConfirmCode emailConfirmCode) { string[] attributes = { "code:string", "id_users:int" }; int id = CreateEntity(emailConfirmCode, attributes); Close(); return(id); }
/// <summary> /// Allows a token to be requested using basic login information /// </summary> public async Task <TokenResponse> RequestStandardToken(string email, string password) { var result = await UserManager.ValidateAsync(CredentialType.PASSWORD, email, password); // If the verification failed, forward the failure if (!result.Result.Success) { return(new TokenResponse(null, result.Result)); } // Otherwise, get the user we just verified User user = result.User; if (!user.Verified_Email) { EmailConfirmCode confirmCode = await Context.EmailConfirmCodes.FindAsync(password); // Someone using another person's verification is a little // worrying, and we don't want them to know it worked, so we'll // send the same error either way. if (confirmCode == null || confirmCode.User_Id != user.Id) { return(new TokenResponse(null, new TaskResult(false, "The email associated with this account needs to be verified! Please log in using the code " + "that was emailed as your password."))); } // At this point the email has been confirmed user.Verified_Email = true; Context.EmailConfirmCodes.Remove(confirmCode); await Context.SaveChangesAsync(); } // We now have to create a token for the user AuthToken token = new AuthToken() { App_Id = "VALOUR", Id = Guid.NewGuid().ToString(), Time = DateTime.UtcNow, Expires = DateTime.UtcNow.AddDays(7), Scope = Permission.FullControl.Value, User_Id = user.Id }; using (ValourDB context = new ValourDB(ValourDB.DBOptions)) { await context.AuthTokens.AddAsync(token); await context.SaveChangesAsync(); } return(new TokenResponse(token.Id, new TaskResult(true, "Successfully verified and retrieved token!"))); }
/// <summary> /// Verifies the user email /// </summary> public async Task <TaskResult> VerifyEmail(string code) { EmailConfirmCode confirmCode = await Context.EmailConfirmCodes.Include(x => x.User).ThenInclude(x => x.Email).FirstOrDefaultAsync(x => x.Code == code); if (confirmCode == null) { return(new TaskResult(false, "Could not find a valid code!")); } var emailObj = confirmCode.User.Email; // At this point the email has been confirmed emailObj.Verified = true; Context.EmailConfirmCodes.Remove(confirmCode); await Context.SaveChangesAsync(); return(new TaskResult(true, "Successfully verified email.")); }
/// <summary> /// Registers a new user and adds them to the database /// </summary> public async Task <TaskResult> RegisterUser(string username, string email, string password) { // Ensure unique username if (await Context.Users.AnyAsync(x => x.Username.ToLower() == username.ToLower())) { return(new TaskResult(false, $"Failed: There was already a user named {username}")); } // Ensure unique email if (await Context.Users.AnyAsync(x => x.Email.ToLower() == email.ToLower())) { return(new TaskResult(false, $"Failed: There was already a user using the email {email}")); } // Test password complexity TaskResult passwordResult = PasswordManager.TestComplexity(password); // Enforce password tests if (!passwordResult.Success) { return(passwordResult); } // At this point the safety checks are complete // Generate random salt byte[] salt = new byte[32]; PasswordManager.GenerateSalt(salt); // Generate password hash byte[] hash = PasswordManager.GetHashForPassword(password, salt); // Create user object User user = new User() { Username = username, Join_DateTime = DateTime.UtcNow, Email = email, Verified_Email = false }; // An error here would be really bad so we'll be careful and catch any exceptions try { await Context.Users.AddAsync(user); await Context.SaveChangesAsync(); } catch (System.Exception e) { return(new TaskResult(false, $"A critical error occured adding the user.")); } Credential cred = new Credential() { Credential_Type = CredentialType.PASSWORD, Identifier = email, Salt = salt, Secret = hash, User_Id = user.Id // We need to find what the user's assigned ID is (auto-filled by EF?) }; // An error here would be really bad so we'll be careful and catch any exceptions try { await Context.Credentials.AddAsync(cred); await Context.SaveChangesAsync(); } catch (System.Exception e) { return(new TaskResult(false, $"A critical error occured adding the credentials.")); } string code = Guid.NewGuid().ToString(); EmailConfirmCode emailConfirm = new EmailConfirmCode() { Code = code, User_Id = user.Id }; // An error here would be really bad so we'll be careful and catch any exceptions try { await Context.EmailConfirmCodes.AddAsync(emailConfirm); await Context.SaveChangesAsync(); } catch (System.Exception e) { return(new TaskResult(false, $"A critical error occured adding the email confirmation code.")); } // Send registration email string emsg = $@"<body style='background-color:#040D14'> <h2 style='font-family:Helvetica; color:white'> Welcome to Valour! </h2> <p style='font-family:Helvetica; color:white'> To verify your new account, please use this code as your password the first time you log in: </p> <p style='font-family:Helvetica; color:#88ffff'> {code} </p> </body>"; string rawmsg = $"Welcome to Valour!\nTo verify your new account, please use this code as your password the first time you log in:\n{code}"; await EmailManager.SendEmailAsync(email, "Valour Registration", rawmsg, emsg); return(new TaskResult(true, $"Successfully created user {username}")); }
private static async Task RegisterUser(HttpContext ctx, ValourDB db, string username, string email, string password, string referrer) { if (username != null) { username = username.TrimEnd(); } // Prevent duplicates if (await db.Users.AnyAsync(x => x.Username.ToLower() == username.ToLower())) { await BadRequest("Username taken", ctx); return; } if (await db.UserEmails.AnyAsync(x => x.Email.ToLower() == email.ToLower())) { await BadRequest("Email taken", ctx); return; } // Test email TaskResult <string> emailResult = User.TestEmail(email); if (!emailResult.Success) { await BadRequest(emailResult.Message, ctx); return; } // This may fix broken email formatting email = emailResult.Data; // Test username TaskResult usernameResult = User.TestUsername(username); if (!usernameResult.Success) { await BadRequest(usernameResult.Message, ctx); return; } // Test password complexity TaskResult passwordResult = User.TestPasswordComplexity(password); // Enforce password tests if (!passwordResult.Success) { await BadRequest(passwordResult.Message, ctx); return; } // Manage referral Referral refer = null; if (!string.IsNullOrWhiteSpace(referrer)) { User referUser = await db.Users.FirstOrDefaultAsync(x => x.Username.ToLower() == referrer.ToLower()); if (referUser == null) { await BadRequest($"Could not find referrer {referrer}", ctx); return; } refer = new Referral() { Referrer_Id = referUser.Id }; } // At this point the safety checks are complete // Generate random salt byte[] salt = new byte[32]; PasswordManager.GenerateSalt(salt); // Generate password hash byte[] hash = PasswordManager.GetHashForPassword(password, salt); // Create user object ServerUser user = new ServerUser() { Id = IdManager.Generate(), Username = username, Join_DateTime = DateTime.UtcNow, Last_Active = DateTime.UtcNow }; // An error here would be really bad so we'll be careful and catch any exceptions try { await db.Users.AddAsync(user); await db.SaveChangesAsync(); } catch (System.Exception e) { Console.WriteLine(e.Message); await BadRequest("A critical error occured adding the user.", ctx); return; } // Create email object UserEmail emailObj = new UserEmail() { Email = email, Verified = false, User_Id = user.Id }; try { // Pray something doesnt break between these await db.UserEmails.AddAsync(emailObj); await db.SaveChangesAsync(); } catch (System.Exception e) { Console.WriteLine(e.Message); await BadRequest("A critical error occured adding the email.", ctx); return; } Credential cred = new Credential() { Credential_Type = CredentialType.PASSWORD, Identifier = email, Salt = salt, Secret = hash, User_Id = user.Id // We need to find what the user's assigned ID is (auto-filled by EF) }; // An error here would be really bad so we'll be careful and catch any exceptions try { await db.Credentials.AddAsync(cred); await db.SaveChangesAsync(); } catch (System.Exception e) { Console.WriteLine(e.Message); await BadRequest("A critical error occured adding the credentials.", ctx); return; } string code = Guid.NewGuid().ToString(); EmailConfirmCode emailConfirm = new EmailConfirmCode() { Code = code, User_Id = user.Id }; if (refer != null) { refer.User_Id = user.Id; await db.Referrals.AddAsync(refer); await db.SaveChangesAsync(); } // An error here would be really bad so we'll be careful and catch any exceptions try { await db.EmailConfirmCodes.AddAsync(emailConfirm); await db.SaveChangesAsync(); } catch (System.Exception e) { Console.WriteLine(e.Message); await BadRequest("A critical error occured adding the email confirmation code.", ctx); return; } // Send registration email string emsg = $@"<body> <h2 style='font-family:Helvetica;'> Welcome to Valour! </h2> <p style='font-family:Helvetica;> To verify your new account, please use the following link: </p> <p style='font-family:Helvetica;'> <a href='https://valour.gg/VerifyEmail/{code}'>Verify</a> </p> </body>"; string rawmsg = $"Welcome to Valour!\nTo verify your new account, please go to the following link:\nhttps://valour.gg/VerifyEmail/{code}"; await EmailManager.SendEmailAsync(email, "Valour Registration", rawmsg, emsg); ctx.Response.StatusCode = 200; await ctx.Response.WriteAsync("Success"); }
/// <summary> /// Allows a token to be requested using basic login information /// </summary> public async Task <TaskResult <string> > RequestStandardToken(string email, string password) { UserEmail emailObj = await Context.UserEmails.FindAsync(email.ToLower()); if (emailObj == null) { return(new TaskResult <string>(false, "There was no user found with that email.", null)); } User user = await emailObj.GetUserAsync(); if (user.Disabled) { return(new TaskResult <string>(false, "Your account has been disabled.", null)); } bool authorized = false; if (!emailObj.Verified) { EmailConfirmCode confirmCode = await Context.EmailConfirmCodes.FindAsync(password); // Someone using another person's verification is a little // worrying, and we don't want them to know it worked, so we'll // send the same error either way. if (confirmCode == null || confirmCode.User_Id != user.Id) { return(new TaskResult <string>(false, "The email associated with this account needs to be verified! Please log in using the code " + "that was emailed as your password.", null)); } // At this point the email has been confirmed emailObj.Verified = true; Context.EmailConfirmCodes.Remove(confirmCode); await Context.SaveChangesAsync(); authorized = true; } else { var result = await UserManager.ValidateAsync(CredentialType.PASSWORD, email, password); if (result.Data != null && user.Id != result.Data.Id) { return(new TaskResult <string>(false, "A critical error occured. This should not be possible. Seek help immediately.", null)); } if (!result.Success) { Console.WriteLine($"Failed password validation for {email}"); return(new TaskResult <string>(false, result.Message, null)); } authorized = true; } // If the verification failed, forward the failure if (!authorized) { return(new TaskResult <string>(false, "Failed to authorize user.", null)); } // Check if there are any tokens already AuthToken token = null; token = await Context.AuthTokens.FirstOrDefaultAsync(x => x.App_Id == "VALOUR" && x.User_Id == user.Id && x.Scope == Permission.FullControl.Value); if (token == null) { // We now have to create a token for the user token = new AuthToken() { App_Id = "VALOUR", Id = Guid.NewGuid().ToString(), Time = DateTime.UtcNow, Expires = DateTime.UtcNow.AddDays(7), Scope = Permission.FullControl.Value, User_Id = user.Id }; using (ValourDB context = new ValourDB(ValourDB.DBOptions)) { await context.AuthTokens.AddAsync(token); await context.SaveChangesAsync(); } } else { token.Time = DateTime.UtcNow; token.Expires = DateTime.UtcNow.AddDays(7); using (ValourDB context = new ValourDB(ValourDB.DBOptions)) { context.AuthTokens.Update(token); await context.SaveChangesAsync(); } } return(new TaskResult <string>(true, "Successfully verified and retrieved token!", token.Id)); }