/// <summary> /// Create a pending user in the DB. /// /// Returns the authCode and token necessary to complete registration via e-mail. /// /// If an error occurs, returns false and sets a user displayable message in `error`. /// </summary> public static bool CreatePendingUser(string email, string password, string realname, out string token, out string authCode, out string error) { if (Models.User.FindUserByEmail(email) != null) { token = null; authCode = null; error = "Email already in use."; return false; } var db = Current.WriteDB; string pwSalt; string pwHash = Current.SecureHash(password, out pwSalt); token = Current.UniqueId().ToString(); authCode = Current.MakeAuthCode(new { email, token, realname }); var pendingUser = new PendingUser { AuthCode = authCode, CreationDate = Current.Now, PasswordHash = pwHash, PasswordSalt = pwSalt }; db.PendingUsers.InsertOnSubmit(pendingUser); db.SubmitChanges(); error = null; return true; }
/// <summary> /// Create a pending user in the DB. /// /// Returns the authCode and token necessary to complete registration via e-mail. /// /// If an error occurs, returns false and sets a user displayable message in `error`. /// </summary> public static bool CreatePendingUser(string email, string password, string realname, out string token, out string authCode, out string error) { if (Models.User.FindUserByEmail(email) != null) { token = null; authCode = null; error = "Email already in use."; return(false); } var db = Current.WriteDB; string pwSalt; string pwHash = Current.SecureHash(password, out pwSalt); token = Current.UniqueId().ToString(); authCode = Current.MakeAuthCode(new { email, token, realname }); var pendingUser = new PendingUser { AuthCode = authCode, CreationDate = Current.Now, PasswordHash = pwHash, PasswordSalt = pwSalt }; db.PendingUsers.InsertOnSubmit(pendingUser); db.SubmitChanges(); error = null; return(true); }
partial void DeletePendingUser(PendingUser instance);
partial void UpdatePendingUser(PendingUser instance);
partial void InsertPendingUser(PendingUser instance);
/// <summary> /// Create a new account given an email and password /// </summary> public static bool CreateAccount(string email, PendingUser pendingUser, DateTime now, string vanity, string realname, out User created, out string errorMessage) { email = email.ToLowerInvariant(); if (vanity.HasValue() && !Models.User.IsValidVanityId(vanity, out errorMessage)) { created = null; return(false); } var db = Current.WriteDB; // Quick check to make sure the vanity id is not in use elsewhere if (vanity.HasValue() && db.Users.Any(u => u.VanityProviderId == vanity)) { created = null; errorMessage = "That Vanity OpenId is already in use"; return(false); } var provider = Current.UniqueId(); // Odds of colision are miniscule, but might as well check while (db.Users.Any(u => u.ProviderId == provider)) { provider = Current.UniqueId(); } // We need to compute these way before we use them for some length checks byte emailVersion; string emailIV, emailHMAC; var emailEncrypted = Current.Encrypt(email, out emailIV, out emailVersion, out emailHMAC); byte nameVersion = 0xFF; string nameEncrypted = null, nameIV = null, nameHMAC = null; if (realname.HasValue()) { nameEncrypted = Current.Encrypt(realname, out nameIV, out nameVersion, out nameHMAC); } if (emailEncrypted.Length > 267) { created = null; errorMessage = "Email is too long"; return(false); } if (nameEncrypted.HasValue() && nameEncrypted.Length > 267) { created = null; errorMessage = "Name is too long"; return(false); } string emailHash; byte emailSaltVersion; emailHash = Current.SystemHash(email, out emailSaltVersion); var newUser = new User { LastActivityDate = DateTime.UtcNow, EmailHash = emailHash, EmailSaltVersion = emailSaltVersion, ProviderId = provider, PasswordHash = pendingUser.PasswordHash, PasswordSalt = pendingUser.PasswordSalt, CreationDate = now, VanityProviderId = vanity, UserTypeId = Models.UserTypeId.Normal }; try { db.Users.InsertOnSubmit(newUser); db.SubmitChanges(); } catch (Exception e) { // Hack: There isn't really a nice way to detect a unique constraint conflict, // so... check the message. Checking for the constraint name so this isn't // *guaranteed* to break on non-English language systems... still not guaranteed // to work though. if (e is System.Data.SqlClient.SqlException && e.Message.Contains("Users_EmailHash_EmailSaltVersion")) { created = null; errorMessage = "Email address already registered."; return(false); } Current.LogException(e); created = null; errorMessage = "User account could not be created."; return(false); } // Open season on this user until the context is torn down. db.LiftUserRestrictionsOnId = newUser.Id; // Can't put a unique constrain on VanityProviderId (as its normally null), so // this is a hack to make sure no two users end up slipping in and getting the // same vanity id. if (vanity.HasValue() && db.Users.Count(u => u.VanityProviderId == vanity) != 1) { newUser.VanityProviderId = null; db.SubmitChanges(); } var emailAttr = new UserAttribute { UserId = newUser.Id, CreationDate = now, UserAttributeTypeId = UserAttributeTypeId.Email, Encrypted = emailEncrypted, IV = emailIV, KeyVersion = emailVersion, HMAC = emailHMAC }; db.UserAttributes.InsertOnSubmit(emailAttr); db.SubmitChanges(); if (realname.HasValue()) { var nameAttr = new UserAttribute { UserId = newUser.Id, CreationDate = now, UserAttributeTypeId = UserAttributeTypeId.RealName, Encrypted = nameEncrypted, IV = nameIV, KeyVersion = nameVersion, HMAC = nameHMAC }; db.UserAttributes.InsertOnSubmit(nameAttr); db.SubmitChanges(); } created = newUser; errorMessage = null; return(true); }
/// <summary> /// Create a new account given an email and password /// </summary> public static bool CreateAccount(string email, PendingUser pendingUser, DateTime now, string vanity, string realname, out User created, out string errorMessage) { email = email.ToLowerInvariant(); if (vanity.HasValue() && !Models.User.IsValidVanityId(vanity, out errorMessage)) { created = null; return false; } var db = Current.WriteDB; // Quick check to make sure the vanity id is not in use elsewhere if (vanity.HasValue() && db.Users.Any(u => u.VanityProviderId == vanity)) { created = null; errorMessage = "That Vanity OpenId is already in use"; return false; } var provider = Current.UniqueId(); // Odds of colision are miniscule, but might as well check while (db.Users.Any(u => u.ProviderId == provider)) provider = Current.UniqueId(); // We need to compute these way before we use them for some length checks byte emailVersion; string emailIV, emailHMAC; var emailEncrypted = Current.Encrypt(email, out emailIV, out emailVersion, out emailHMAC); byte nameVersion = 0xFF; string nameEncrypted= null, nameIV = null, nameHMAC = null; if (realname.HasValue()) { nameEncrypted = Current.Encrypt(realname, out nameIV, out nameVersion, out nameHMAC); } if (emailEncrypted.Length > 267) { created = null; errorMessage = "Email is too long"; return false; } if (nameEncrypted.HasValue() && nameEncrypted.Length > 267) { created = null; errorMessage = "Name is too long"; return false; } string emailHash; byte emailSaltVersion; emailHash = Current.SystemHash(email, out emailSaltVersion); var newUser = new User { LastActivityDate = DateTime.UtcNow, EmailHash = emailHash, EmailSaltVersion = emailSaltVersion, ProviderId = provider, PasswordHash = pendingUser.PasswordHash, PasswordSalt = pendingUser.PasswordSalt, CreationDate = now, VanityProviderId = vanity, UserTypeId = Models.UserTypeId.Normal }; try { db.Users.InsertOnSubmit(newUser); db.SubmitChanges(); } catch (Exception e) { // Hack: There isn't really a nice way to detect a unique constraint conflict, // so... check the message. Checking for the constraint name so this isn't // *guaranteed* to break on non-English language systems... still not guaranteed // to work though. if(e is System.Data.SqlClient.SqlException && e.Message.Contains("Users_EmailHash_EmailSaltVersion")) { created = null; errorMessage = "Email address already registered."; return false; } Current.LogException(e); created = null; errorMessage = "User account could not be created."; return false; } // Open season on this user until the context is torn down. db.LiftUserRestrictionsOnId = newUser.Id; // Can't put a unique constrain on VanityProviderId (as its normally null), so // this is a hack to make sure no two users end up slipping in and getting the // same vanity id. if (vanity.HasValue() && db.Users.Count(u => u.VanityProviderId == vanity) != 1) { newUser.VanityProviderId = null; db.SubmitChanges(); } var emailAttr = new UserAttribute { UserId = newUser.Id, CreationDate = now, UserAttributeTypeId = UserAttributeTypeId.Email, Encrypted = emailEncrypted, IV = emailIV, KeyVersion = emailVersion, HMAC = emailHMAC }; db.UserAttributes.InsertOnSubmit(emailAttr); db.SubmitChanges(); if (realname.HasValue()) { var nameAttr = new UserAttribute { UserId = newUser.Id, CreationDate = now, UserAttributeTypeId = UserAttributeTypeId.RealName, Encrypted = nameEncrypted, IV = nameIV, KeyVersion = nameVersion, HMAC = nameHMAC }; db.UserAttributes.InsertOnSubmit(nameAttr); db.SubmitChanges(); } created = newUser; errorMessage = null; return true; }
public void PendingUserUpdateDeletionDate() { var r = new Restrictions(); var pending = new PendingUser { Id = 1, DeletionDate = DateTime.Now }; var updates = new Dictionary<object, Restrictions.ShadowModifiedMember[]>(); updates[pending] = new Restrictions.ShadowModifiedMember[] { new Restrictions.ShadowModifiedMember { Member = typeof(PendingUser).GetProperty("DeletionDate"), CurrentValue = pending.DeletionDate, OriginalValue = null } }; string ignored; Assert.IsTrue(r.IsValidChangeSet(updates, new List<object>(), new List<object>(), new List<object>() { pending }, new List<int>(), out ignored)); }
public void NoPendingUserUpdateOnNonDeletionDate() { var r = new Restrictions(); var pending = new PendingUser { Id = 1 }; var updates = new Dictionary<object, Restrictions.ShadowModifiedMember[]>(); updates[pending] = new Restrictions.ShadowModifiedMember[] { new Restrictions.ShadowModifiedMember { Member = typeof(PendingUser).GetProperty("Id"), CurrentValue = pending.Id, OriginalValue = 2 } }; string ignored; Assert.IsFalse(r.IsValidChangeSet(updates, new List<object>(), new List<object>(), new List<object>(){pending}, new List<int>(), out ignored)); Assert.IsFalse(r.IsValidChangeSet(updates, new List<object>(), new List<object>(), new List<object>(){pending}, new List<int>() { 1 }, out ignored)); }
public void NoPendingUserInsert() { var r = new Restrictions(); var pending = new PendingUser { Id = 1 }; var updates = new Dictionary<object, Restrictions.ShadowModifiedMember[]>(); string ignored; Assert.IsFalse(r.IsValidChangeSet(updates, new List<object>(), new List<object>() { pending }, new List<object>(), new List<int>(), out ignored)); Assert.IsFalse(r.IsValidChangeSet(updates, new List<object>(), new List<object>() { pending }, new List<object>(), new List<int>() { 1 }, out ignored)); }