You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

account.go 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 The Gitea Authors. All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. package setting
  5. import (
  6. "errors"
  7. "net/http"
  8. "time"
  9. "code.gitea.io/gitea/models"
  10. user_model "code.gitea.io/gitea/models/user"
  11. "code.gitea.io/gitea/modules/auth/password"
  12. "code.gitea.io/gitea/modules/base"
  13. "code.gitea.io/gitea/modules/context"
  14. "code.gitea.io/gitea/modules/log"
  15. "code.gitea.io/gitea/modules/setting"
  16. "code.gitea.io/gitea/modules/timeutil"
  17. "code.gitea.io/gitea/modules/web"
  18. "code.gitea.io/gitea/services/auth"
  19. "code.gitea.io/gitea/services/forms"
  20. "code.gitea.io/gitea/services/mailer"
  21. "code.gitea.io/gitea/services/user"
  22. )
  23. const (
  24. tplSettingsAccount base.TplName = "user/settings/account"
  25. )
  26. // Account renders change user's password, user's email and user suicide page
  27. func Account(ctx *context.Context) {
  28. ctx.Data["Title"] = ctx.Tr("settings.account")
  29. ctx.Data["PageIsSettingsAccount"] = true
  30. ctx.Data["Email"] = ctx.Doer.Email
  31. ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail
  32. loadAccountData(ctx)
  33. ctx.HTML(http.StatusOK, tplSettingsAccount)
  34. }
  35. // AccountPost response for change user's password
  36. func AccountPost(ctx *context.Context) {
  37. form := web.GetForm(ctx).(*forms.ChangePasswordForm)
  38. ctx.Data["Title"] = ctx.Tr("settings")
  39. ctx.Data["PageIsSettingsAccount"] = true
  40. if ctx.HasError() {
  41. loadAccountData(ctx)
  42. ctx.HTML(http.StatusOK, tplSettingsAccount)
  43. return
  44. }
  45. if len(form.Password) < setting.MinPasswordLength {
  46. ctx.Flash.Error(ctx.Tr("auth.password_too_short", setting.MinPasswordLength))
  47. } else if ctx.Doer.IsPasswordSet() && !ctx.Doer.ValidatePassword(form.OldPassword) {
  48. ctx.Flash.Error(ctx.Tr("settings.password_incorrect"))
  49. } else if form.Password != form.Retype {
  50. ctx.Flash.Error(ctx.Tr("form.password_not_match"))
  51. } else if !password.IsComplexEnough(form.Password) {
  52. ctx.Flash.Error(password.BuildComplexityError(ctx.Locale))
  53. } else if pwned, err := password.IsPwned(ctx, form.Password); pwned || err != nil {
  54. errMsg := ctx.Tr("auth.password_pwned")
  55. if err != nil {
  56. log.Error(err.Error())
  57. errMsg = ctx.Tr("auth.password_pwned_err")
  58. }
  59. ctx.Flash.Error(errMsg)
  60. } else {
  61. var err error
  62. if err = ctx.Doer.SetPassword(form.Password); err != nil {
  63. ctx.ServerError("UpdateUser", err)
  64. return
  65. }
  66. if err := user_model.UpdateUserCols(ctx, ctx.Doer, "salt", "passwd_hash_algo", "passwd"); err != nil {
  67. ctx.ServerError("UpdateUser", err)
  68. return
  69. }
  70. log.Trace("User password updated: %s", ctx.Doer.Name)
  71. ctx.Flash.Success(ctx.Tr("settings.change_password_success"))
  72. }
  73. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  74. }
  75. // EmailPost response for change user's email
  76. func EmailPost(ctx *context.Context) {
  77. form := web.GetForm(ctx).(*forms.AddEmailForm)
  78. ctx.Data["Title"] = ctx.Tr("settings")
  79. ctx.Data["PageIsSettingsAccount"] = true
  80. // Make emailaddress primary.
  81. if ctx.FormString("_method") == "PRIMARY" {
  82. if err := user_model.MakeEmailPrimary(ctx, &user_model.EmailAddress{ID: ctx.FormInt64("id")}); err != nil {
  83. ctx.ServerError("MakeEmailPrimary", err)
  84. return
  85. }
  86. log.Trace("Email made primary: %s", ctx.Doer.Name)
  87. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  88. return
  89. }
  90. // Send activation Email
  91. if ctx.FormString("_method") == "SENDACTIVATION" {
  92. var address string
  93. if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName) {
  94. log.Error("Send activation: activation still pending")
  95. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  96. return
  97. }
  98. id := ctx.FormInt64("id")
  99. email, err := user_model.GetEmailAddressByID(ctx, ctx.Doer.ID, id)
  100. if err != nil {
  101. log.Error("GetEmailAddressByID(%d,%d) error: %v", ctx.Doer.ID, id, err)
  102. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  103. return
  104. }
  105. if email == nil {
  106. log.Warn("Send activation failed: EmailAddress[%d] not found for user: %-v", id, ctx.Doer)
  107. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  108. return
  109. }
  110. if email.IsActivated {
  111. log.Debug("Send activation failed: email %s is already activated for user: %-v", email.Email, ctx.Doer)
  112. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  113. return
  114. }
  115. if email.IsPrimary {
  116. if ctx.Doer.IsActive && !setting.Service.RegisterEmailConfirm {
  117. log.Debug("Send activation failed: email %s is already activated for user: %-v", email.Email, ctx.Doer)
  118. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  119. return
  120. }
  121. // Only fired when the primary email is inactive (Wrong state)
  122. mailer.SendActivateAccountMail(ctx.Locale, ctx.Doer)
  123. } else {
  124. mailer.SendActivateEmailMail(ctx.Doer, email)
  125. }
  126. address = email.Email
  127. if setting.CacheService.Enabled {
  128. if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
  129. log.Error("Set cache(MailResendLimit) fail: %v", err)
  130. }
  131. }
  132. ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", address, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)))
  133. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  134. return
  135. }
  136. // Set Email Notification Preference
  137. if ctx.FormString("_method") == "NOTIFICATION" {
  138. preference := ctx.FormString("preference")
  139. if !(preference == user_model.EmailNotificationsEnabled ||
  140. preference == user_model.EmailNotificationsOnMention ||
  141. preference == user_model.EmailNotificationsDisabled ||
  142. preference == user_model.EmailNotificationsAndYourOwn) {
  143. log.Error("Email notifications preference change returned unrecognized option %s: %s", preference, ctx.Doer.Name)
  144. ctx.ServerError("SetEmailPreference", errors.New("option unrecognized"))
  145. return
  146. }
  147. if err := user_model.SetEmailNotifications(ctx, ctx.Doer, preference); err != nil {
  148. log.Error("Set Email Notifications failed: %v", err)
  149. ctx.ServerError("SetEmailNotifications", err)
  150. return
  151. }
  152. log.Trace("Email notifications preference made %s: %s", preference, ctx.Doer.Name)
  153. ctx.Flash.Success(ctx.Tr("settings.email_preference_set_success"))
  154. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  155. return
  156. }
  157. if ctx.HasError() {
  158. loadAccountData(ctx)
  159. ctx.HTML(http.StatusOK, tplSettingsAccount)
  160. return
  161. }
  162. email := &user_model.EmailAddress{
  163. UID: ctx.Doer.ID,
  164. Email: form.Email,
  165. IsActivated: !setting.Service.RegisterEmailConfirm,
  166. }
  167. if err := user_model.AddEmailAddress(ctx, email); err != nil {
  168. if user_model.IsErrEmailAlreadyUsed(err) {
  169. loadAccountData(ctx)
  170. ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsAccount, &form)
  171. return
  172. } else if user_model.IsErrEmailCharIsNotSupported(err) ||
  173. user_model.IsErrEmailInvalid(err) {
  174. loadAccountData(ctx)
  175. ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSettingsAccount, &form)
  176. return
  177. }
  178. ctx.ServerError("AddEmailAddress", err)
  179. return
  180. }
  181. // Send confirmation email
  182. if setting.Service.RegisterEmailConfirm {
  183. mailer.SendActivateEmailMail(ctx.Doer, email)
  184. if setting.CacheService.Enabled {
  185. if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
  186. log.Error("Set cache(MailResendLimit) fail: %v", err)
  187. }
  188. }
  189. ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)))
  190. } else {
  191. ctx.Flash.Success(ctx.Tr("settings.add_email_success"))
  192. }
  193. log.Trace("Email address added: %s", email.Email)
  194. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  195. }
  196. // DeleteEmail response for delete user's email
  197. func DeleteEmail(ctx *context.Context) {
  198. if err := user_model.DeleteEmailAddress(ctx, &user_model.EmailAddress{ID: ctx.FormInt64("id"), UID: ctx.Doer.ID}); err != nil {
  199. ctx.ServerError("DeleteEmail", err)
  200. return
  201. }
  202. log.Trace("Email address deleted: %s", ctx.Doer.Name)
  203. ctx.Flash.Success(ctx.Tr("settings.email_deletion_success"))
  204. ctx.JSONRedirect(setting.AppSubURL + "/user/settings/account")
  205. }
  206. // DeleteAccount render user suicide page and response for delete user himself
  207. func DeleteAccount(ctx *context.Context) {
  208. ctx.Data["Title"] = ctx.Tr("settings")
  209. ctx.Data["PageIsSettingsAccount"] = true
  210. if _, _, err := auth.UserSignIn(ctx, ctx.Doer.Name, ctx.FormString("password")); err != nil {
  211. if user_model.IsErrUserNotExist(err) {
  212. loadAccountData(ctx)
  213. ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_password"), tplSettingsAccount, nil)
  214. } else {
  215. ctx.ServerError("UserSignIn", err)
  216. }
  217. return
  218. }
  219. // admin should not delete themself
  220. if ctx.Doer.IsAdmin {
  221. ctx.Flash.Error(ctx.Tr("form.admin_cannot_delete_self"))
  222. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  223. return
  224. }
  225. if err := user.DeleteUser(ctx, ctx.Doer, false); err != nil {
  226. switch {
  227. case models.IsErrUserOwnRepos(err):
  228. ctx.Flash.Error(ctx.Tr("form.still_own_repo"))
  229. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  230. case models.IsErrUserHasOrgs(err):
  231. ctx.Flash.Error(ctx.Tr("form.still_has_org"))
  232. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  233. case models.IsErrUserOwnPackages(err):
  234. ctx.Flash.Error(ctx.Tr("form.still_own_packages"))
  235. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  236. case models.IsErrDeleteLastAdminUser(err):
  237. ctx.Flash.Error(ctx.Tr("auth.last_admin"))
  238. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  239. default:
  240. ctx.ServerError("DeleteUser", err)
  241. }
  242. } else {
  243. log.Trace("Account deleted: %s", ctx.Doer.Name)
  244. ctx.Redirect(setting.AppSubURL + "/")
  245. }
  246. }
  247. func loadAccountData(ctx *context.Context) {
  248. emlist, err := user_model.GetEmailAddresses(ctx, ctx.Doer.ID)
  249. if err != nil {
  250. ctx.ServerError("GetEmailAddresses", err)
  251. return
  252. }
  253. type UserEmail struct {
  254. user_model.EmailAddress
  255. CanBePrimary bool
  256. }
  257. pendingActivation := setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName)
  258. emails := make([]*UserEmail, len(emlist))
  259. for i, em := range emlist {
  260. var email UserEmail
  261. email.EmailAddress = *em
  262. email.CanBePrimary = em.IsActivated
  263. emails[i] = &email
  264. }
  265. ctx.Data["Emails"] = emails
  266. ctx.Data["EmailNotificationsPreference"] = ctx.Doer.EmailNotifications()
  267. ctx.Data["ActivationsPending"] = pendingActivation
  268. ctx.Data["CanAddEmails"] = !pendingActivation || !setting.Service.RegisterEmailConfirm
  269. if setting.Service.UserDeleteWithCommentsMaxTime != 0 {
  270. ctx.Data["UserDeleteWithCommentsMaxTime"] = setting.Service.UserDeleteWithCommentsMaxTime.String()
  271. ctx.Data["UserDeleteWithComments"] = ctx.Doer.CreatedUnix.AsTime().Add(setting.Service.UserDeleteWithCommentsMaxTime).After(time.Now())
  272. }
  273. }