@@ -181,7 +181,8 @@ func (u *User) BeforeUpdate() {
181181 u .MaxRepoCreation = - 1
182182 }
183183
184- // Organization does not need email
184+ // FIXME: this email doesn't need to be in lowercase, because the emails are mainly managed by the email table with lower_email field
185+ // This trick could be removed in new releases to display the user inputed email as-is.
185186 u .Email = strings .ToLower (u .Email )
186187 if ! u .IsOrganization () {
187188 if len (u .AvatarEmail ) == 0 {
@@ -310,17 +311,6 @@ func (u *User) OrganisationLink() string {
310311 return setting .AppSubURL + "/org/" + url .PathEscape (u .Name )
311312}
312313
313- // GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
314- func (u * User ) GenerateEmailActivateCode (email string ) string {
315- code := base .CreateTimeLimitCode (
316- fmt .Sprintf ("%d%s%s%s%s" , u .ID , email , u .LowerName , u .Passwd , u .Rands ),
317- setting .Service .ActiveCodeLives , time .Now (), nil )
318-
319- // Add tail hex username
320- code += hex .EncodeToString ([]byte (u .LowerName ))
321- return code
322- }
323-
324314// GetUserFollowers returns range of user's followers.
325315func GetUserFollowers (ctx context.Context , u , viewer * User , listOptions db.ListOptions ) ([]* User , int64 , error ) {
326316 sess := db .GetEngine (ctx ).
@@ -863,12 +853,38 @@ func GetVerifyUser(ctx context.Context, code string) (user *User) {
863853 return nil
864854}
865855
866- // VerifyUserActiveCode verifies active code when active account
867- func VerifyUserActiveCode (ctx context.Context , code string ) (user * User ) {
856+ type TimeLimitCodePurpose string
857+
858+ const (
859+ TimeLimitCodeActivateAccount TimeLimitCodePurpose = "activate_account"
860+ TimeLimitCodeActivateEmail TimeLimitCodePurpose = "activate_email"
861+ TimeLimitCodeResetPassword TimeLimitCodePurpose = "reset_password"
862+ )
863+
864+ type TimeLimitCodeOptions struct {
865+ Purpose TimeLimitCodePurpose
866+ NewEmail string
867+ }
868+
869+ func makeTimeLimitCodeHashData (opts * TimeLimitCodeOptions , u * User ) string {
870+ return fmt .Sprintf ("%s|%d|%s|%s|%s|%s" , opts .Purpose , u .ID , strings .ToLower (util .IfZero (opts .NewEmail , u .Email )), u .LowerName , u .Passwd , u .Rands )
871+ }
872+
873+ // GenerateUserTimeLimitCode generates a time-limit code based on user information and given e-mail.
874+ // TODO: need to use cache or db to store it to make sure a code can only be consumed once
875+ func GenerateUserTimeLimitCode (opts * TimeLimitCodeOptions , u * User ) string {
876+ data := makeTimeLimitCodeHashData (opts , u )
877+ code := base .CreateTimeLimitCode (data , setting .Service .ActiveCodeLives , time .Now (), nil )
878+ code += hex .EncodeToString ([]byte (u .LowerName )) // Add tail hex username
879+ return code
880+ }
881+
882+ // VerifyUserTimeLimitCode verifies the time-limit code
883+ func VerifyUserTimeLimitCode (ctx context.Context , opts * TimeLimitCodeOptions , code string ) (user * User ) {
868884 if user = GetVerifyUser (ctx , code ); user != nil {
869885 // time limit code
870886 prefix := code [:base .TimeLimitCodeLength ]
871- data := fmt . Sprintf ( "%d%s%s%s%s" , user . ID , user . Email , user . LowerName , user . Passwd , user . Rands )
887+ data := makeTimeLimitCodeHashData ( opts , user )
872888 if base .VerifyTimeLimitCode (time .Now (), data , setting .Service .ActiveCodeLives , prefix ) {
873889 return user
874890 }
0 commit comments