gitea源码

2fa.go 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package auth
  4. import (
  5. "errors"
  6. "net/http"
  7. "code.gitea.io/gitea/models/auth"
  8. user_model "code.gitea.io/gitea/models/user"
  9. "code.gitea.io/gitea/modules/session"
  10. "code.gitea.io/gitea/modules/setting"
  11. "code.gitea.io/gitea/modules/templates"
  12. "code.gitea.io/gitea/modules/web"
  13. "code.gitea.io/gitea/services/context"
  14. "code.gitea.io/gitea/services/forms"
  15. )
  16. var (
  17. tplTwofa templates.TplName = "user/auth/twofa"
  18. tplTwofaScratch templates.TplName = "user/auth/twofa_scratch"
  19. )
  20. // TwoFactor shows the user a two-factor authentication page.
  21. func TwoFactor(ctx *context.Context) {
  22. ctx.Data["Title"] = ctx.Tr("twofa")
  23. if CheckAutoLogin(ctx) {
  24. return
  25. }
  26. // Ensure user is in a 2FA session.
  27. if ctx.Session.Get("twofaUid") == nil {
  28. ctx.ServerError("UserSignIn", errors.New("not in 2FA session"))
  29. return
  30. }
  31. ctx.HTML(http.StatusOK, tplTwofa)
  32. }
  33. // TwoFactorPost validates a user's two-factor authentication token.
  34. func TwoFactorPost(ctx *context.Context) {
  35. form := web.GetForm(ctx).(*forms.TwoFactorAuthForm)
  36. ctx.Data["Title"] = ctx.Tr("twofa")
  37. // Ensure user is in a 2FA session.
  38. idSess := ctx.Session.Get("twofaUid")
  39. if idSess == nil {
  40. ctx.ServerError("UserSignIn", errors.New("not in 2FA session"))
  41. return
  42. }
  43. id := idSess.(int64)
  44. twofa, err := auth.GetTwoFactorByUID(ctx, id)
  45. if err != nil {
  46. ctx.ServerError("UserSignIn", err)
  47. return
  48. }
  49. // Validate the passcode with the stored TOTP secret.
  50. ok, err := twofa.ValidateTOTP(form.Passcode)
  51. if err != nil {
  52. ctx.ServerError("UserSignIn", err)
  53. return
  54. }
  55. if ok && twofa.LastUsedPasscode != form.Passcode {
  56. remember := ctx.Session.Get("twofaRemember").(bool)
  57. u, err := user_model.GetUserByID(ctx, id)
  58. if err != nil {
  59. ctx.ServerError("UserSignIn", err)
  60. return
  61. }
  62. if ctx.Session.Get("linkAccount") != nil {
  63. err = linkAccountFromContext(ctx, u)
  64. if err != nil {
  65. ctx.ServerError("UserSignIn", err)
  66. return
  67. }
  68. }
  69. twofa.LastUsedPasscode = form.Passcode
  70. if err = auth.UpdateTwoFactor(ctx, twofa); err != nil {
  71. ctx.ServerError("UserSignIn", err)
  72. return
  73. }
  74. _ = ctx.Session.Set(session.KeyUserHasTwoFactorAuth, true)
  75. handleSignIn(ctx, u, remember)
  76. return
  77. }
  78. ctx.RenderWithErr(ctx.Tr("auth.twofa_passcode_incorrect"), tplTwofa, forms.TwoFactorAuthForm{})
  79. }
  80. // TwoFactorScratch shows the scratch code form for two-factor authentication.
  81. func TwoFactorScratch(ctx *context.Context) {
  82. ctx.Data["Title"] = ctx.Tr("twofa_scratch")
  83. if CheckAutoLogin(ctx) {
  84. return
  85. }
  86. // Ensure user is in a 2FA session.
  87. if ctx.Session.Get("twofaUid") == nil {
  88. ctx.ServerError("UserSignIn", errors.New("not in 2FA session"))
  89. return
  90. }
  91. ctx.HTML(http.StatusOK, tplTwofaScratch)
  92. }
  93. // TwoFactorScratchPost validates and invalidates a user's two-factor scratch token.
  94. func TwoFactorScratchPost(ctx *context.Context) {
  95. form := web.GetForm(ctx).(*forms.TwoFactorScratchAuthForm)
  96. ctx.Data["Title"] = ctx.Tr("twofa_scratch")
  97. // Ensure user is in a 2FA session.
  98. idSess := ctx.Session.Get("twofaUid")
  99. if idSess == nil {
  100. ctx.ServerError("UserSignIn", errors.New("not in 2FA session"))
  101. return
  102. }
  103. id := idSess.(int64)
  104. twofa, err := auth.GetTwoFactorByUID(ctx, id)
  105. if err != nil {
  106. ctx.ServerError("UserSignIn", err)
  107. return
  108. }
  109. // Validate the passcode with the stored TOTP secret.
  110. if twofa.VerifyScratchToken(form.Token) {
  111. // Invalidate the scratch token.
  112. _, err = twofa.GenerateScratchToken()
  113. if err != nil {
  114. ctx.ServerError("UserSignIn", err)
  115. return
  116. }
  117. if err = auth.UpdateTwoFactor(ctx, twofa); err != nil {
  118. ctx.ServerError("UserSignIn", err)
  119. return
  120. }
  121. remember := ctx.Session.Get("twofaRemember").(bool)
  122. u, err := user_model.GetUserByID(ctx, id)
  123. if err != nil {
  124. ctx.ServerError("UserSignIn", err)
  125. return
  126. }
  127. handleSignInFull(ctx, u, remember, false)
  128. if ctx.Written() {
  129. return
  130. }
  131. ctx.Flash.Info(ctx.Tr("auth.twofa_scratch_used"))
  132. ctx.Redirect(setting.AppSubURL + "/user/settings/security")
  133. return
  134. }
  135. ctx.RenderWithErr(ctx.Tr("auth.twofa_scratch_token_incorrect"), tplTwofaScratch, forms.TwoFactorScratchAuthForm{})
  136. }