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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  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 auth
  5. import (
  6. "errors"
  7. "fmt"
  8. "net/http"
  9. "strings"
  10. "code.gitea.io/gitea/models/auth"
  11. "code.gitea.io/gitea/models/db"
  12. user_model "code.gitea.io/gitea/models/user"
  13. "code.gitea.io/gitea/modules/auth/password"
  14. "code.gitea.io/gitea/modules/base"
  15. "code.gitea.io/gitea/modules/context"
  16. "code.gitea.io/gitea/modules/eventsource"
  17. "code.gitea.io/gitea/modules/log"
  18. "code.gitea.io/gitea/modules/session"
  19. "code.gitea.io/gitea/modules/setting"
  20. "code.gitea.io/gitea/modules/timeutil"
  21. "code.gitea.io/gitea/modules/util"
  22. "code.gitea.io/gitea/modules/web"
  23. "code.gitea.io/gitea/modules/web/middleware"
  24. "code.gitea.io/gitea/routers/utils"
  25. auth_service "code.gitea.io/gitea/services/auth"
  26. "code.gitea.io/gitea/services/auth/source/oauth2"
  27. "code.gitea.io/gitea/services/externalaccount"
  28. "code.gitea.io/gitea/services/forms"
  29. "code.gitea.io/gitea/services/mailer"
  30. "github.com/markbates/goth"
  31. )
  32. const (
  33. // tplSignIn template for sign in page
  34. tplSignIn base.TplName = "user/auth/signin"
  35. // tplSignUp template path for sign up page
  36. tplSignUp base.TplName = "user/auth/signup"
  37. // TplActivate template path for activate user
  38. TplActivate base.TplName = "user/auth/activate"
  39. )
  40. // AutoSignIn reads cookie and try to auto-login.
  41. func AutoSignIn(ctx *context.Context) (bool, error) {
  42. if !db.HasEngine {
  43. return false, nil
  44. }
  45. uname := ctx.GetSiteCookie(setting.CookieUserName)
  46. if len(uname) == 0 {
  47. return false, nil
  48. }
  49. isSucceed := false
  50. defer func() {
  51. if !isSucceed {
  52. log.Trace("auto-login cookie cleared: %s", uname)
  53. ctx.DeleteSiteCookie(setting.CookieUserName)
  54. ctx.DeleteSiteCookie(setting.CookieRememberName)
  55. }
  56. }()
  57. u, err := user_model.GetUserByName(ctx, uname)
  58. if err != nil {
  59. if !user_model.IsErrUserNotExist(err) {
  60. return false, fmt.Errorf("GetUserByName: %w", err)
  61. }
  62. return false, nil
  63. }
  64. if val, ok := ctx.GetSuperSecureCookie(
  65. base.EncodeMD5(u.Rands+u.Passwd), setting.CookieRememberName); !ok || val != u.Name {
  66. return false, nil
  67. }
  68. isSucceed = true
  69. if err := updateSession(ctx, nil, map[string]any{
  70. // Set session IDs
  71. "uid": u.ID,
  72. "uname": u.Name,
  73. }); err != nil {
  74. return false, fmt.Errorf("unable to updateSession: %w", err)
  75. }
  76. if err := resetLocale(ctx, u); err != nil {
  77. return false, err
  78. }
  79. ctx.Csrf.DeleteCookie(ctx)
  80. return true, nil
  81. }
  82. func resetLocale(ctx *context.Context, u *user_model.User) error {
  83. // Language setting of the user overwrites the one previously set
  84. // If the user does not have a locale set, we save the current one.
  85. if len(u.Language) == 0 {
  86. u.Language = ctx.Locale.Language()
  87. if err := user_model.UpdateUserCols(ctx, u, "language"); err != nil {
  88. return err
  89. }
  90. }
  91. middleware.SetLocaleCookie(ctx.Resp, u.Language, 0)
  92. if ctx.Locale.Language() != u.Language {
  93. ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req)
  94. }
  95. return nil
  96. }
  97. func checkAutoLogin(ctx *context.Context) bool {
  98. // Check auto-login
  99. isSucceed, err := AutoSignIn(ctx)
  100. if err != nil {
  101. ctx.ServerError("AutoSignIn", err)
  102. return true
  103. }
  104. redirectTo := ctx.FormString("redirect_to")
  105. if len(redirectTo) > 0 {
  106. middleware.SetRedirectToCookie(ctx.Resp, redirectTo)
  107. } else {
  108. redirectTo = ctx.GetSiteCookie("redirect_to")
  109. }
  110. if isSucceed {
  111. middleware.DeleteRedirectToCookie(ctx.Resp)
  112. ctx.RedirectToFirst(redirectTo, setting.AppSubURL+string(setting.LandingPageURL))
  113. return true
  114. }
  115. return false
  116. }
  117. // SignIn render sign in page
  118. func SignIn(ctx *context.Context) {
  119. ctx.Data["Title"] = ctx.Tr("sign_in")
  120. // Check auto-login
  121. if checkAutoLogin(ctx) {
  122. return
  123. }
  124. orderedOAuth2Names, oauth2Providers, err := oauth2.GetActiveOAuth2Providers()
  125. if err != nil {
  126. ctx.ServerError("UserSignIn", err)
  127. return
  128. }
  129. ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names
  130. ctx.Data["OAuth2Providers"] = oauth2Providers
  131. ctx.Data["Title"] = ctx.Tr("sign_in")
  132. ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login"
  133. ctx.Data["PageIsSignIn"] = true
  134. ctx.Data["PageIsLogin"] = true
  135. ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled()
  136. if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin {
  137. context.SetCaptchaData(ctx)
  138. }
  139. ctx.HTML(http.StatusOK, tplSignIn)
  140. }
  141. // SignInPost response for sign in request
  142. func SignInPost(ctx *context.Context) {
  143. ctx.Data["Title"] = ctx.Tr("sign_in")
  144. orderedOAuth2Names, oauth2Providers, err := oauth2.GetActiveOAuth2Providers()
  145. if err != nil {
  146. ctx.ServerError("UserSignIn", err)
  147. return
  148. }
  149. ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names
  150. ctx.Data["OAuth2Providers"] = oauth2Providers
  151. ctx.Data["Title"] = ctx.Tr("sign_in")
  152. ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login"
  153. ctx.Data["PageIsSignIn"] = true
  154. ctx.Data["PageIsLogin"] = true
  155. ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled()
  156. if ctx.HasError() {
  157. ctx.HTML(http.StatusOK, tplSignIn)
  158. return
  159. }
  160. form := web.GetForm(ctx).(*forms.SignInForm)
  161. if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin {
  162. context.SetCaptchaData(ctx)
  163. context.VerifyCaptcha(ctx, tplSignIn, form)
  164. if ctx.Written() {
  165. return
  166. }
  167. }
  168. u, source, err := auth_service.UserSignIn(form.UserName, form.Password)
  169. if err != nil {
  170. if errors.Is(err, util.ErrNotExist) || errors.Is(err, util.ErrInvalidArgument) {
  171. ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
  172. log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
  173. } else if user_model.IsErrEmailAlreadyUsed(err) {
  174. ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignIn, &form)
  175. log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
  176. } else if user_model.IsErrUserProhibitLogin(err) {
  177. log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
  178. ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
  179. ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
  180. } else if user_model.IsErrUserInactive(err) {
  181. if setting.Service.RegisterEmailConfirm {
  182. ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
  183. ctx.HTML(http.StatusOK, TplActivate)
  184. } else {
  185. log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
  186. ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
  187. ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
  188. }
  189. } else {
  190. ctx.ServerError("UserSignIn", err)
  191. }
  192. return
  193. }
  194. // Now handle 2FA:
  195. // First of all if the source can skip local two fa we're done
  196. if skipper, ok := source.Cfg.(auth_service.LocalTwoFASkipper); ok && skipper.IsSkipLocalTwoFA() {
  197. handleSignIn(ctx, u, form.Remember)
  198. return
  199. }
  200. // If this user is enrolled in 2FA TOTP, we can't sign the user in just yet.
  201. // Instead, redirect them to the 2FA authentication page.
  202. hasTOTPtwofa, err := auth.HasTwoFactorByUID(u.ID)
  203. if err != nil {
  204. ctx.ServerError("UserSignIn", err)
  205. return
  206. }
  207. // Check if the user has webauthn registration
  208. hasWebAuthnTwofa, err := auth.HasWebAuthnRegistrationsByUID(u.ID)
  209. if err != nil {
  210. ctx.ServerError("UserSignIn", err)
  211. return
  212. }
  213. if !hasTOTPtwofa && !hasWebAuthnTwofa {
  214. // No two factor auth configured we can sign in the user
  215. handleSignIn(ctx, u, form.Remember)
  216. return
  217. }
  218. updates := map[string]any{
  219. // User will need to use 2FA TOTP or WebAuthn, save data
  220. "twofaUid": u.ID,
  221. "twofaRemember": form.Remember,
  222. }
  223. if hasTOTPtwofa {
  224. // User will need to use WebAuthn, save data
  225. updates["totpEnrolled"] = u.ID
  226. }
  227. if err := updateSession(ctx, nil, updates); err != nil {
  228. ctx.ServerError("UserSignIn: Unable to update session", err)
  229. return
  230. }
  231. // If we have WebAuthn redirect there first
  232. if hasWebAuthnTwofa {
  233. ctx.Redirect(setting.AppSubURL + "/user/webauthn")
  234. return
  235. }
  236. // Fallback to 2FA
  237. ctx.Redirect(setting.AppSubURL + "/user/two_factor")
  238. }
  239. // This handles the final part of the sign-in process of the user.
  240. func handleSignIn(ctx *context.Context, u *user_model.User, remember bool) {
  241. redirect := handleSignInFull(ctx, u, remember, true)
  242. if ctx.Written() {
  243. return
  244. }
  245. ctx.Redirect(redirect)
  246. }
  247. func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRedirect bool) string {
  248. if remember {
  249. days := 86400 * setting.LogInRememberDays
  250. ctx.SetSiteCookie(setting.CookieUserName, u.Name, days)
  251. ctx.SetSuperSecureCookie(base.EncodeMD5(u.Rands+u.Passwd),
  252. setting.CookieRememberName, u.Name, days)
  253. }
  254. if err := updateSession(ctx, []string{
  255. // Delete the openid, 2fa and linkaccount data
  256. "openid_verified_uri",
  257. "openid_signin_remember",
  258. "openid_determined_email",
  259. "openid_determined_username",
  260. "twofaUid",
  261. "twofaRemember",
  262. "linkAccount",
  263. }, map[string]any{
  264. "uid": u.ID,
  265. "uname": u.Name,
  266. }); err != nil {
  267. ctx.ServerError("RegenerateSession", err)
  268. return setting.AppSubURL + "/"
  269. }
  270. // Language setting of the user overwrites the one previously set
  271. // If the user does not have a locale set, we save the current one.
  272. if len(u.Language) == 0 {
  273. u.Language = ctx.Locale.Language()
  274. if err := user_model.UpdateUserCols(ctx, u, "language"); err != nil {
  275. ctx.ServerError("UpdateUserCols Language", fmt.Errorf("Error updating user language [user: %d, locale: %s]", u.ID, u.Language))
  276. return setting.AppSubURL + "/"
  277. }
  278. }
  279. middleware.SetLocaleCookie(ctx.Resp, u.Language, 0)
  280. if ctx.Locale.Language() != u.Language {
  281. ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req)
  282. }
  283. // Clear whatever CSRF cookie has right now, force to generate a new one
  284. ctx.Csrf.DeleteCookie(ctx)
  285. // Register last login
  286. u.SetLastLogin()
  287. if err := user_model.UpdateUserCols(ctx, u, "last_login_unix"); err != nil {
  288. ctx.ServerError("UpdateUserCols", err)
  289. return setting.AppSubURL + "/"
  290. }
  291. if redirectTo := ctx.GetSiteCookie("redirect_to"); len(redirectTo) > 0 && !utils.IsExternalURL(redirectTo) {
  292. middleware.DeleteRedirectToCookie(ctx.Resp)
  293. if obeyRedirect {
  294. ctx.RedirectToFirst(redirectTo)
  295. }
  296. return redirectTo
  297. }
  298. if obeyRedirect {
  299. ctx.Redirect(setting.AppSubURL + "/")
  300. }
  301. return setting.AppSubURL + "/"
  302. }
  303. func getUserName(gothUser *goth.User) string {
  304. switch setting.OAuth2Client.Username {
  305. case setting.OAuth2UsernameEmail:
  306. return strings.Split(gothUser.Email, "@")[0]
  307. case setting.OAuth2UsernameNickname:
  308. return gothUser.NickName
  309. default: // OAuth2UsernameUserid
  310. return gothUser.UserID
  311. }
  312. }
  313. // HandleSignOut resets the session and sets the cookies
  314. func HandleSignOut(ctx *context.Context) {
  315. _ = ctx.Session.Flush()
  316. _ = ctx.Session.Destroy(ctx.Resp, ctx.Req)
  317. ctx.DeleteSiteCookie(setting.CookieUserName)
  318. ctx.DeleteSiteCookie(setting.CookieRememberName)
  319. ctx.Csrf.DeleteCookie(ctx)
  320. middleware.DeleteRedirectToCookie(ctx.Resp)
  321. }
  322. // SignOut sign out from login status
  323. func SignOut(ctx *context.Context) {
  324. if ctx.Doer != nil {
  325. eventsource.GetManager().SendMessageBlocking(ctx.Doer.ID, &eventsource.Event{
  326. Name: "logout",
  327. Data: ctx.Session.ID(),
  328. })
  329. }
  330. HandleSignOut(ctx)
  331. ctx.Redirect(setting.AppSubURL + "/")
  332. }
  333. // SignUp render the register page
  334. func SignUp(ctx *context.Context) {
  335. ctx.Data["Title"] = ctx.Tr("sign_up")
  336. ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
  337. context.SetCaptchaData(ctx)
  338. ctx.Data["PageIsSignUp"] = true
  339. // Show Disabled Registration message if DisableRegistration or AllowOnlyExternalRegistration options are true
  340. ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration || setting.Service.AllowOnlyExternalRegistration
  341. ctx.HTML(http.StatusOK, tplSignUp)
  342. }
  343. // SignUpPost response for sign up information submission
  344. func SignUpPost(ctx *context.Context) {
  345. form := web.GetForm(ctx).(*forms.RegisterForm)
  346. ctx.Data["Title"] = ctx.Tr("sign_up")
  347. ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
  348. context.SetCaptchaData(ctx)
  349. ctx.Data["PageIsSignUp"] = true
  350. // Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true
  351. if setting.Service.DisableRegistration || setting.Service.AllowOnlyExternalRegistration {
  352. ctx.Error(http.StatusForbidden)
  353. return
  354. }
  355. if ctx.HasError() {
  356. ctx.HTML(http.StatusOK, tplSignUp)
  357. return
  358. }
  359. context.VerifyCaptcha(ctx, tplSignUp, form)
  360. if ctx.Written() {
  361. return
  362. }
  363. if !form.IsEmailDomainAllowed() {
  364. ctx.RenderWithErr(ctx.Tr("auth.email_domain_blacklisted"), tplSignUp, &form)
  365. return
  366. }
  367. if form.Password != form.Retype {
  368. ctx.Data["Err_Password"] = true
  369. ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplSignUp, &form)
  370. return
  371. }
  372. if len(form.Password) < setting.MinPasswordLength {
  373. ctx.Data["Err_Password"] = true
  374. ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplSignUp, &form)
  375. return
  376. }
  377. if !password.IsComplexEnough(form.Password) {
  378. ctx.Data["Err_Password"] = true
  379. ctx.RenderWithErr(password.BuildComplexityError(ctx.Locale), tplSignUp, &form)
  380. return
  381. }
  382. pwned, err := password.IsPwned(ctx, form.Password)
  383. if pwned {
  384. errMsg := ctx.Tr("auth.password_pwned")
  385. if err != nil {
  386. log.Error(err.Error())
  387. errMsg = ctx.Tr("auth.password_pwned_err")
  388. }
  389. ctx.Data["Err_Password"] = true
  390. ctx.RenderWithErr(errMsg, tplSignUp, &form)
  391. return
  392. }
  393. u := &user_model.User{
  394. Name: form.UserName,
  395. Email: form.Email,
  396. Passwd: form.Password,
  397. }
  398. if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, nil, false) {
  399. // error already handled
  400. return
  401. }
  402. ctx.Flash.Success(ctx.Tr("auth.sign_up_successful"))
  403. handleSignIn(ctx, u, false)
  404. }
  405. // createAndHandleCreatedUser calls createUserInContext and
  406. // then handleUserCreated.
  407. func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) bool {
  408. if !createUserInContext(ctx, tpl, form, u, overwrites, gothUser, allowLink) {
  409. return false
  410. }
  411. return handleUserCreated(ctx, u, gothUser)
  412. }
  413. // createUserInContext creates a user and handles errors within a given context.
  414. // Optionally a template can be specified.
  415. func createUserInContext(ctx *context.Context, tpl base.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) (ok bool) {
  416. if err := user_model.CreateUser(u, overwrites); err != nil {
  417. if allowLink && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) {
  418. if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingAuto {
  419. var user *user_model.User
  420. user = &user_model.User{Name: u.Name}
  421. hasUser, err := user_model.GetUser(user)
  422. if !hasUser || err != nil {
  423. user = &user_model.User{Email: u.Email}
  424. hasUser, err = user_model.GetUser(user)
  425. if !hasUser || err != nil {
  426. ctx.ServerError("UserLinkAccount", err)
  427. return
  428. }
  429. }
  430. // TODO: probably we should respect 'remember' user's choice...
  431. linkAccount(ctx, user, *gothUser, true)
  432. return // user is already created here, all redirects are handled
  433. } else if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingLogin {
  434. showLinkingLogin(ctx, *gothUser)
  435. return // user will be created only after linking login
  436. }
  437. }
  438. // handle error without template
  439. if len(tpl) == 0 {
  440. ctx.ServerError("CreateUser", err)
  441. return
  442. }
  443. // handle error with template
  444. switch {
  445. case user_model.IsErrUserAlreadyExist(err):
  446. ctx.Data["Err_UserName"] = true
  447. ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), tpl, form)
  448. case user_model.IsErrEmailAlreadyUsed(err):
  449. ctx.Data["Err_Email"] = true
  450. ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tpl, form)
  451. case user_model.IsErrEmailCharIsNotSupported(err):
  452. ctx.Data["Err_Email"] = true
  453. ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form)
  454. case user_model.IsErrEmailInvalid(err):
  455. ctx.Data["Err_Email"] = true
  456. ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form)
  457. case db.IsErrNameReserved(err):
  458. ctx.Data["Err_UserName"] = true
  459. ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(db.ErrNameReserved).Name), tpl, form)
  460. case db.IsErrNamePatternNotAllowed(err):
  461. ctx.Data["Err_UserName"] = true
  462. ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tpl, form)
  463. case db.IsErrNameCharsNotAllowed(err):
  464. ctx.Data["Err_UserName"] = true
  465. ctx.RenderWithErr(ctx.Tr("user.form.name_chars_not_allowed", err.(db.ErrNameCharsNotAllowed).Name), tpl, form)
  466. default:
  467. ctx.ServerError("CreateUser", err)
  468. }
  469. return
  470. }
  471. log.Trace("Account created: %s", u.Name)
  472. return true
  473. }
  474. // handleUserCreated does additional steps after a new user is created.
  475. // It auto-sets admin for the only user, updates the optional external user and
  476. // sends a confirmation email if required.
  477. func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.User) (ok bool) {
  478. // Auto-set admin for the only user.
  479. if user_model.CountUsers(nil) == 1 {
  480. u.IsAdmin = true
  481. u.IsActive = true
  482. u.SetLastLogin()
  483. if err := user_model.UpdateUserCols(ctx, u, "is_admin", "is_active", "last_login_unix"); err != nil {
  484. ctx.ServerError("UpdateUser", err)
  485. return
  486. }
  487. }
  488. // update external user information
  489. if gothUser != nil {
  490. if err := externalaccount.UpdateExternalUser(u, *gothUser); err != nil {
  491. if !errors.Is(err, util.ErrNotExist) {
  492. log.Error("UpdateExternalUser failed: %v", err)
  493. }
  494. }
  495. }
  496. // Send confirmation email
  497. if !u.IsActive && u.ID > 1 {
  498. if setting.Service.RegisterManualConfirm {
  499. ctx.Data["ManualActivationOnly"] = true
  500. ctx.HTML(http.StatusOK, TplActivate)
  501. return
  502. }
  503. mailer.SendActivateAccountMail(ctx.Locale, u)
  504. ctx.Data["IsSendRegisterMail"] = true
  505. ctx.Data["Email"] = u.Email
  506. ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)
  507. ctx.HTML(http.StatusOK, TplActivate)
  508. if setting.CacheService.Enabled {
  509. if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
  510. log.Error("Set cache(MailResendLimit) fail: %v", err)
  511. }
  512. }
  513. return
  514. }
  515. return true
  516. }
  517. // Activate render activate user page
  518. func Activate(ctx *context.Context) {
  519. code := ctx.FormString("code")
  520. if len(code) == 0 {
  521. ctx.Data["IsActivatePage"] = true
  522. if ctx.Doer == nil || ctx.Doer.IsActive {
  523. ctx.NotFound("invalid user", nil)
  524. return
  525. }
  526. // Resend confirmation email.
  527. if setting.Service.RegisterEmailConfirm {
  528. if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName) {
  529. ctx.Data["ResendLimited"] = true
  530. } else {
  531. ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)
  532. mailer.SendActivateAccountMail(ctx.Locale, ctx.Doer)
  533. if setting.CacheService.Enabled {
  534. if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
  535. log.Error("Set cache(MailResendLimit) fail: %v", err)
  536. }
  537. }
  538. }
  539. } else {
  540. ctx.Data["ServiceNotEnabled"] = true
  541. }
  542. ctx.HTML(http.StatusOK, TplActivate)
  543. return
  544. }
  545. user := user_model.VerifyUserActiveCode(code)
  546. // if code is wrong
  547. if user == nil {
  548. ctx.Data["IsCodeInvalid"] = true
  549. ctx.HTML(http.StatusOK, TplActivate)
  550. return
  551. }
  552. // if account is local account, verify password
  553. if user.LoginSource == 0 {
  554. ctx.Data["Code"] = code
  555. ctx.Data["NeedsPassword"] = true
  556. ctx.HTML(http.StatusOK, TplActivate)
  557. return
  558. }
  559. handleAccountActivation(ctx, user)
  560. }
  561. // ActivatePost handles account activation with password check
  562. func ActivatePost(ctx *context.Context) {
  563. code := ctx.FormString("code")
  564. if len(code) == 0 {
  565. ctx.Redirect(setting.AppSubURL + "/user/activate")
  566. return
  567. }
  568. user := user_model.VerifyUserActiveCode(code)
  569. // if code is wrong
  570. if user == nil {
  571. ctx.Data["IsCodeInvalid"] = true
  572. ctx.HTML(http.StatusOK, TplActivate)
  573. return
  574. }
  575. // if account is local account, verify password
  576. if user.LoginSource == 0 {
  577. password := ctx.FormString("password")
  578. if len(password) == 0 {
  579. ctx.Data["Code"] = code
  580. ctx.Data["NeedsPassword"] = true
  581. ctx.HTML(http.StatusOK, TplActivate)
  582. return
  583. }
  584. if !user.ValidatePassword(password) {
  585. ctx.Data["IsPasswordInvalid"] = true
  586. ctx.HTML(http.StatusOK, TplActivate)
  587. return
  588. }
  589. }
  590. handleAccountActivation(ctx, user)
  591. }
  592. func handleAccountActivation(ctx *context.Context, user *user_model.User) {
  593. user.IsActive = true
  594. var err error
  595. if user.Rands, err = user_model.GetUserSalt(); err != nil {
  596. ctx.ServerError("UpdateUser", err)
  597. return
  598. }
  599. if err := user_model.UpdateUserCols(ctx, user, "is_active", "rands"); err != nil {
  600. if user_model.IsErrUserNotExist(err) {
  601. ctx.NotFound("UpdateUserCols", err)
  602. } else {
  603. ctx.ServerError("UpdateUser", err)
  604. }
  605. return
  606. }
  607. if err := user_model.ActivateUserEmail(user.ID, user.Email, true); err != nil {
  608. log.Error("Unable to activate email for user: %-v with email: %s: %v", user, user.Email, err)
  609. ctx.ServerError("ActivateUserEmail", err)
  610. return
  611. }
  612. log.Trace("User activated: %s", user.Name)
  613. if err := updateSession(ctx, nil, map[string]any{
  614. "uid": user.ID,
  615. "uname": user.Name,
  616. }); err != nil {
  617. log.Error("Unable to regenerate session for user: %-v with email: %s: %v", user, user.Email, err)
  618. ctx.ServerError("ActivateUserEmail", err)
  619. return
  620. }
  621. if err := resetLocale(ctx, user); err != nil {
  622. ctx.ServerError("resetLocale", err)
  623. return
  624. }
  625. // Register last login
  626. user.SetLastLogin()
  627. if err := user_model.UpdateUserCols(ctx, user, "last_login_unix"); err != nil {
  628. ctx.ServerError("UpdateUserCols", err)
  629. return
  630. }
  631. ctx.Flash.Success(ctx.Tr("auth.account_activated"))
  632. ctx.Redirect(setting.AppSubURL + "/")
  633. }
  634. // ActivateEmail render the activate email page
  635. func ActivateEmail(ctx *context.Context) {
  636. code := ctx.FormString("code")
  637. emailStr := ctx.FormString("email")
  638. // Verify code.
  639. if email := user_model.VerifyActiveEmailCode(code, emailStr); email != nil {
  640. if err := user_model.ActivateEmail(email); err != nil {
  641. ctx.ServerError("ActivateEmail", err)
  642. }
  643. log.Trace("Email activated: %s", email.Email)
  644. ctx.Flash.Success(ctx.Tr("settings.add_email_success"))
  645. if u, err := user_model.GetUserByID(ctx, email.UID); err != nil {
  646. log.Warn("GetUserByID: %d", email.UID)
  647. } else if setting.CacheService.Enabled {
  648. // Allow user to validate more emails
  649. _ = ctx.Cache.Delete("MailResendLimit_" + u.LowerName)
  650. }
  651. }
  652. // FIXME: e-mail verification does not require the user to be logged in,
  653. // so this could be redirecting to the login page.
  654. // Should users be logged in automatically here? (consider 2FA requirements, etc.)
  655. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  656. }
  657. func updateSession(ctx *context.Context, deletes []string, updates map[string]any) error {
  658. if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil {
  659. return fmt.Errorf("regenerate session: %w", err)
  660. }
  661. sess := ctx.Session
  662. sessID := sess.ID()
  663. for _, k := range deletes {
  664. if err := sess.Delete(k); err != nil {
  665. return fmt.Errorf("delete %v in session[%s]: %w", k, sessID, err)
  666. }
  667. }
  668. for k, v := range updates {
  669. if err := sess.Set(k, v); err != nil {
  670. return fmt.Errorf("set %v in session[%s]: %w", k, sessID, err)
  671. }
  672. }
  673. if err := sess.Release(); err != nil {
  674. return fmt.Errorf("store session[%s]: %w", sessID, err)
  675. }
  676. return nil
  677. }