gitea源码

account.go 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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. org_model "code.gitea.io/gitea/models/organization"
  10. packages_model "code.gitea.io/gitea/models/packages"
  11. repo_model "code.gitea.io/gitea/models/repo"
  12. user_model "code.gitea.io/gitea/models/user"
  13. "code.gitea.io/gitea/modules/auth/password"
  14. "code.gitea.io/gitea/modules/log"
  15. "code.gitea.io/gitea/modules/optional"
  16. "code.gitea.io/gitea/modules/setting"
  17. "code.gitea.io/gitea/modules/templates"
  18. "code.gitea.io/gitea/modules/timeutil"
  19. "code.gitea.io/gitea/modules/web"
  20. "code.gitea.io/gitea/services/auth"
  21. "code.gitea.io/gitea/services/auth/source/db"
  22. "code.gitea.io/gitea/services/auth/source/smtp"
  23. "code.gitea.io/gitea/services/context"
  24. "code.gitea.io/gitea/services/forms"
  25. "code.gitea.io/gitea/services/mailer"
  26. "code.gitea.io/gitea/services/user"
  27. )
  28. const (
  29. tplSettingsAccount templates.TplName = "user/settings/account"
  30. )
  31. // Account renders change user's password, user's email and user suicide page
  32. func Account(ctx *context.Context) {
  33. if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials, setting.UserFeatureDeletion) {
  34. ctx.NotFound(errors.New("account setting are not allowed to be changed"))
  35. return
  36. }
  37. ctx.Data["Title"] = ctx.Tr("settings.account")
  38. ctx.Data["PageIsSettingsAccount"] = true
  39. ctx.Data["Email"] = ctx.Doer.Email
  40. loadAccountData(ctx)
  41. ctx.HTML(http.StatusOK, tplSettingsAccount)
  42. }
  43. // AccountPost response for change user's password
  44. func AccountPost(ctx *context.Context) {
  45. if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) {
  46. ctx.NotFound(errors.New("password setting is not allowed to be changed"))
  47. return
  48. }
  49. form := web.GetForm(ctx).(*forms.ChangePasswordForm)
  50. ctx.Data["Title"] = ctx.Tr("settings")
  51. ctx.Data["PageIsSettingsAccount"] = true
  52. ctx.Data["Email"] = ctx.Doer.Email
  53. if ctx.HasError() {
  54. loadAccountData(ctx)
  55. ctx.HTML(http.StatusOK, tplSettingsAccount)
  56. return
  57. }
  58. if ctx.Doer.IsPasswordSet() && !ctx.Doer.ValidatePassword(form.OldPassword) {
  59. ctx.Flash.Error(ctx.Tr("settings.password_incorrect"))
  60. } else if form.Password != form.Retype {
  61. ctx.Flash.Error(ctx.Tr("form.password_not_match"))
  62. } else {
  63. opts := &user.UpdateAuthOptions{
  64. Password: optional.Some(form.Password),
  65. MustChangePassword: optional.Some(false),
  66. }
  67. if err := user.UpdateAuth(ctx, ctx.Doer, opts); err != nil {
  68. switch {
  69. case errors.Is(err, password.ErrMinLength):
  70. ctx.Flash.Error(ctx.Tr("auth.password_too_short", setting.MinPasswordLength))
  71. case errors.Is(err, password.ErrComplexity):
  72. ctx.Flash.Error(password.BuildComplexityError(ctx.Locale))
  73. case errors.Is(err, password.ErrIsPwned):
  74. ctx.Flash.Error(ctx.Tr("auth.password_pwned", "https://haveibeenpwned.com/Passwords"))
  75. case password.IsErrIsPwnedRequest(err):
  76. ctx.Flash.Error(ctx.Tr("auth.password_pwned_err"))
  77. default:
  78. ctx.ServerError("UpdateAuth", err)
  79. return
  80. }
  81. } else {
  82. ctx.Flash.Success(ctx.Tr("settings.change_password_success"))
  83. }
  84. }
  85. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  86. }
  87. // EmailPost response for change user's email
  88. func EmailPost(ctx *context.Context) {
  89. if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) {
  90. ctx.NotFound(errors.New("emails are not allowed to be changed"))
  91. return
  92. }
  93. form := web.GetForm(ctx).(*forms.AddEmailForm)
  94. ctx.Data["Title"] = ctx.Tr("settings")
  95. ctx.Data["PageIsSettingsAccount"] = true
  96. ctx.Data["Email"] = ctx.Doer.Email
  97. // Make email address primary.
  98. if ctx.FormString("_method") == "PRIMARY" {
  99. if err := user_model.MakeActiveEmailPrimary(ctx, ctx.FormInt64("id")); err != nil {
  100. ctx.ServerError("MakeEmailPrimary", err)
  101. return
  102. }
  103. log.Trace("Email made primary: %s", ctx.Doer.Name)
  104. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  105. return
  106. }
  107. // Send activation Email
  108. if ctx.FormString("_method") == "SENDACTIVATION" {
  109. var address string
  110. if ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName) {
  111. log.Error("Send activation: activation still pending")
  112. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  113. return
  114. }
  115. id := ctx.FormInt64("id")
  116. email, err := user_model.GetEmailAddressByID(ctx, ctx.Doer.ID, id)
  117. if err != nil {
  118. log.Error("GetEmailAddressByID(%d,%d) error: %v", ctx.Doer.ID, id, err)
  119. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  120. return
  121. }
  122. if email == nil {
  123. log.Warn("Send activation failed: EmailAddress[%d] not found for user: %-v", id, ctx.Doer)
  124. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  125. return
  126. }
  127. if email.IsActivated {
  128. log.Debug("Send activation failed: email %s is already activated for user: %-v", email.Email, ctx.Doer)
  129. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  130. return
  131. }
  132. if email.IsPrimary {
  133. if ctx.Doer.IsActive && !setting.Service.RegisterEmailConfirm {
  134. log.Debug("Send activation failed: email %s is already activated for user: %-v", email.Email, ctx.Doer)
  135. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  136. return
  137. }
  138. // Only fired when the primary email is inactive (Wrong state)
  139. mailer.SendActivateAccountMail(ctx.Locale, ctx.Doer)
  140. } else {
  141. mailer.SendActivateEmailMail(ctx.Doer, email.Email)
  142. }
  143. address = email.Email
  144. if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
  145. log.Error("Set cache(MailResendLimit) fail: %v", err)
  146. }
  147. ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", address, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)))
  148. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  149. return
  150. }
  151. if ctx.HasError() {
  152. loadAccountData(ctx)
  153. ctx.HTML(http.StatusOK, tplSettingsAccount)
  154. return
  155. }
  156. if err := user.AddEmailAddresses(ctx, ctx.Doer, []string{form.Email}); err != nil {
  157. if user_model.IsErrEmailAlreadyUsed(err) {
  158. loadAccountData(ctx)
  159. ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsAccount, &form)
  160. } else if user_model.IsErrEmailCharIsNotSupported(err) || user_model.IsErrEmailInvalid(err) {
  161. loadAccountData(ctx)
  162. ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSettingsAccount, &form)
  163. } else {
  164. ctx.ServerError("AddEmailAddresses", err)
  165. }
  166. return
  167. }
  168. // Send confirmation email
  169. if setting.Service.RegisterEmailConfirm {
  170. mailer.SendActivateEmailMail(ctx.Doer, form.Email)
  171. if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
  172. log.Error("Set cache(MailResendLimit) fail: %v", err)
  173. }
  174. ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", form.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)))
  175. } else {
  176. ctx.Flash.Success(ctx.Tr("settings.add_email_success"))
  177. }
  178. log.Trace("Email address added: %s", form.Email)
  179. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  180. }
  181. // DeleteEmail response for delete user's email
  182. func DeleteEmail(ctx *context.Context) {
  183. if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) {
  184. ctx.NotFound(errors.New("emails are not allowed to be changed"))
  185. return
  186. }
  187. email, err := user_model.GetEmailAddressByID(ctx, ctx.Doer.ID, ctx.FormInt64("id"))
  188. if err != nil || email == nil {
  189. ctx.ServerError("GetEmailAddressByID", err)
  190. return
  191. }
  192. if err := user.DeleteEmailAddresses(ctx, ctx.Doer, []string{email.Email}); err != nil {
  193. ctx.ServerError("DeleteEmailAddresses", err)
  194. return
  195. }
  196. log.Trace("Email address deleted: %s", ctx.Doer.Name)
  197. ctx.Flash.Success(ctx.Tr("settings.email_deletion_success"))
  198. ctx.JSONRedirect(setting.AppSubURL + "/user/settings/account")
  199. }
  200. // DeleteAccount render user suicide page and response for delete user himself
  201. func DeleteAccount(ctx *context.Context) {
  202. if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureDeletion) {
  203. ctx.HTTPError(http.StatusNotFound)
  204. return
  205. }
  206. ctx.Data["Title"] = ctx.Tr("settings")
  207. ctx.Data["PageIsSettingsAccount"] = true
  208. ctx.Data["Email"] = ctx.Doer.Email
  209. if _, _, err := auth.UserSignIn(ctx, ctx.Doer.Name, ctx.FormString("password")); err != nil {
  210. switch {
  211. case user_model.IsErrUserNotExist(err):
  212. loadAccountData(ctx)
  213. ctx.RenderWithErr(ctx.Tr("form.user_not_exist"), tplSettingsAccount, nil)
  214. case errors.Is(err, smtp.ErrUnsupportedLoginType):
  215. loadAccountData(ctx)
  216. ctx.RenderWithErr(ctx.Tr("form.unsupported_login_type"), tplSettingsAccount, nil)
  217. case errors.As(err, &db.ErrUserPasswordNotSet{}):
  218. loadAccountData(ctx)
  219. ctx.RenderWithErr(ctx.Tr("form.unset_password"), tplSettingsAccount, nil)
  220. case errors.As(err, &db.ErrUserPasswordInvalid{}):
  221. loadAccountData(ctx)
  222. ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_password"), tplSettingsAccount, nil)
  223. default:
  224. ctx.ServerError("UserSignIn", err)
  225. }
  226. return
  227. }
  228. // admin should not delete themself
  229. if ctx.Doer.IsAdmin {
  230. ctx.Flash.Error(ctx.Tr("form.admin_cannot_delete_self"))
  231. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  232. return
  233. }
  234. if err := user.DeleteUser(ctx, ctx.Doer, false); err != nil {
  235. switch {
  236. case repo_model.IsErrUserOwnRepos(err):
  237. ctx.Flash.Error(ctx.Tr("form.still_own_repo"))
  238. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  239. case org_model.IsErrUserHasOrgs(err):
  240. ctx.Flash.Error(ctx.Tr("form.still_has_org"))
  241. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  242. case packages_model.IsErrUserOwnPackages(err):
  243. ctx.Flash.Error(ctx.Tr("form.still_own_packages"))
  244. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  245. case user_model.IsErrDeleteLastAdminUser(err):
  246. ctx.Flash.Error(ctx.Tr("auth.last_admin"))
  247. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  248. default:
  249. ctx.ServerError("DeleteUser", err)
  250. }
  251. } else {
  252. log.Trace("Account deleted: %s", ctx.Doer.Name)
  253. ctx.Redirect(setting.AppSubURL + "/")
  254. }
  255. }
  256. func loadAccountData(ctx *context.Context) {
  257. emlist, err := user_model.GetEmailAddresses(ctx, ctx.Doer.ID)
  258. if err != nil {
  259. ctx.ServerError("GetEmailAddresses", err)
  260. return
  261. }
  262. type UserEmail struct {
  263. user_model.EmailAddress
  264. CanBePrimary bool
  265. }
  266. pendingActivation := ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName)
  267. emails := make([]*UserEmail, len(emlist))
  268. for i, em := range emlist {
  269. var email UserEmail
  270. email.EmailAddress = *em
  271. email.CanBePrimary = em.IsActivated
  272. emails[i] = &email
  273. }
  274. ctx.Data["Emails"] = emails
  275. ctx.Data["ActivationsPending"] = pendingActivation
  276. ctx.Data["CanAddEmails"] = !pendingActivation || !setting.Service.RegisterEmailConfirm
  277. ctx.Data["UserDisabledFeatures"] = user_model.DisabledFeaturesWithLoginType(ctx.Doer)
  278. if setting.Service.UserDeleteWithCommentsMaxTime != 0 {
  279. ctx.Data["UserDeleteWithCommentsMaxTime"] = setting.Service.UserDeleteWithCommentsMaxTime.String()
  280. ctx.Data["UserDeleteWithComments"] = ctx.Doer.CreatedUnix.AsTime().Add(setting.Service.UserDeleteWithCommentsMaxTime).After(time.Now())
  281. }
  282. }