本站源代码
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.

211 line
5.1KB

  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package setting
  6. import (
  7. "bytes"
  8. "encoding/base64"
  9. "html/template"
  10. "image/png"
  11. "strings"
  12. "code.gitea.io/gitea/models"
  13. "code.gitea.io/gitea/modules/auth"
  14. "code.gitea.io/gitea/modules/context"
  15. "code.gitea.io/gitea/modules/setting"
  16. "github.com/pquerna/otp"
  17. "github.com/pquerna/otp/totp"
  18. )
  19. // RegenerateScratchTwoFactor regenerates the user's 2FA scratch code.
  20. func RegenerateScratchTwoFactor(ctx *context.Context) {
  21. ctx.Data["Title"] = ctx.Tr("settings")
  22. ctx.Data["PageIsSettingsSecurity"] = true
  23. t, err := models.GetTwoFactorByUID(ctx.User.ID)
  24. if err != nil {
  25. ctx.ServerError("SettingsTwoFactor", err)
  26. return
  27. }
  28. token, err := t.GenerateScratchToken()
  29. if err != nil {
  30. ctx.ServerError("SettingsTwoFactor", err)
  31. return
  32. }
  33. if err = models.UpdateTwoFactor(t); err != nil {
  34. ctx.ServerError("SettingsTwoFactor", err)
  35. return
  36. }
  37. ctx.Flash.Success(ctx.Tr("settings.twofa_scratch_token_regenerated", token))
  38. ctx.Redirect(setting.AppSubURL + "/user/settings/security")
  39. }
  40. // DisableTwoFactor deletes the user's 2FA settings.
  41. func DisableTwoFactor(ctx *context.Context) {
  42. ctx.Data["Title"] = ctx.Tr("settings")
  43. ctx.Data["PageIsSettingsSecurity"] = true
  44. t, err := models.GetTwoFactorByUID(ctx.User.ID)
  45. if err != nil {
  46. ctx.ServerError("SettingsTwoFactor", err)
  47. return
  48. }
  49. if err = models.DeleteTwoFactorByID(t.ID, ctx.User.ID); err != nil {
  50. ctx.ServerError("SettingsTwoFactor", err)
  51. return
  52. }
  53. ctx.Flash.Success(ctx.Tr("settings.twofa_disabled"))
  54. ctx.Redirect(setting.AppSubURL + "/user/settings/security")
  55. }
  56. func twofaGenerateSecretAndQr(ctx *context.Context) bool {
  57. var otpKey *otp.Key
  58. var err error
  59. uri := ctx.Session.Get("twofaUri")
  60. if uri != nil {
  61. otpKey, err = otp.NewKeyFromURL(uri.(string))
  62. if err != nil {
  63. ctx.ServerError("SettingsTwoFactor: NewKeyFromURL: ", err)
  64. return false
  65. }
  66. }
  67. // Filter unsafe character ':' in issuer
  68. issuer := strings.Replace(setting.AppName+" ("+setting.Domain+")", ":", "", -1)
  69. if otpKey == nil {
  70. otpKey, err = totp.Generate(totp.GenerateOpts{
  71. SecretSize: 40,
  72. Issuer: issuer,
  73. AccountName: ctx.User.Name,
  74. })
  75. if err != nil {
  76. ctx.ServerError("SettingsTwoFactor", err)
  77. return false
  78. }
  79. }
  80. ctx.Data["TwofaSecret"] = otpKey.Secret()
  81. img, err := otpKey.Image(320, 240)
  82. if err != nil {
  83. ctx.ServerError("SettingsTwoFactor", err)
  84. return false
  85. }
  86. var imgBytes bytes.Buffer
  87. if err = png.Encode(&imgBytes, img); err != nil {
  88. ctx.ServerError("SettingsTwoFactor", err)
  89. return false
  90. }
  91. ctx.Data["QrUri"] = template.URL("data:image/png;base64," + base64.StdEncoding.EncodeToString(imgBytes.Bytes()))
  92. err = ctx.Session.Set("twofaSecret", otpKey.Secret())
  93. if err != nil {
  94. ctx.ServerError("SettingsTwoFactor", err)
  95. return false
  96. }
  97. err = ctx.Session.Set("twofaUri", otpKey.String())
  98. if err != nil {
  99. ctx.ServerError("SettingsTwoFactor", err)
  100. return false
  101. }
  102. return true
  103. }
  104. // EnrollTwoFactor shows the page where the user can enroll into 2FA.
  105. func EnrollTwoFactor(ctx *context.Context) {
  106. ctx.Data["Title"] = ctx.Tr("settings")
  107. ctx.Data["PageIsSettingsSecurity"] = true
  108. t, err := models.GetTwoFactorByUID(ctx.User.ID)
  109. if t != nil {
  110. // already enrolled
  111. ctx.ServerError("SettingsTwoFactor", err)
  112. return
  113. }
  114. if err != nil && !models.IsErrTwoFactorNotEnrolled(err) {
  115. ctx.ServerError("SettingsTwoFactor", err)
  116. return
  117. }
  118. if !twofaGenerateSecretAndQr(ctx) {
  119. return
  120. }
  121. ctx.HTML(200, tplSettingsTwofaEnroll)
  122. }
  123. // EnrollTwoFactorPost handles enrolling the user into 2FA.
  124. func EnrollTwoFactorPost(ctx *context.Context, form auth.TwoFactorAuthForm) {
  125. ctx.Data["Title"] = ctx.Tr("settings")
  126. ctx.Data["PageIsSettingsSecurity"] = true
  127. t, err := models.GetTwoFactorByUID(ctx.User.ID)
  128. if t != nil {
  129. // already enrolled
  130. ctx.ServerError("SettingsTwoFactor", err)
  131. return
  132. }
  133. if err != nil && !models.IsErrTwoFactorNotEnrolled(err) {
  134. ctx.ServerError("SettingsTwoFactor", err)
  135. return
  136. }
  137. if ctx.HasError() {
  138. if !twofaGenerateSecretAndQr(ctx) {
  139. return
  140. }
  141. ctx.HTML(200, tplSettingsTwofaEnroll)
  142. return
  143. }
  144. secret := ctx.Session.Get("twofaSecret").(string)
  145. if !totp.Validate(form.Passcode, secret) {
  146. if !twofaGenerateSecretAndQr(ctx) {
  147. return
  148. }
  149. ctx.Flash.Error(ctx.Tr("settings.passcode_invalid"))
  150. ctx.HTML(200, tplSettingsTwofaEnroll)
  151. return
  152. }
  153. t = &models.TwoFactor{
  154. UID: ctx.User.ID,
  155. }
  156. err = t.SetSecret(secret)
  157. if err != nil {
  158. ctx.ServerError("SettingsTwoFactor", err)
  159. return
  160. }
  161. token, err := t.GenerateScratchToken()
  162. if err != nil {
  163. ctx.ServerError("SettingsTwoFactor", err)
  164. return
  165. }
  166. if err = models.NewTwoFactor(t); err != nil {
  167. ctx.ServerError("SettingsTwoFactor", err)
  168. return
  169. }
  170. err = ctx.Session.Delete("twofaSecret")
  171. if err != nil {
  172. ctx.ServerError("SettingsTwoFactor", err)
  173. return
  174. }
  175. err = ctx.Session.Delete("twofaUri")
  176. if err != nil {
  177. ctx.ServerError("SettingsTwoFactor", err)
  178. return
  179. }
  180. ctx.Flash.Success(ctx.Tr("settings.twofa_enrolled", token))
  181. ctx.Redirect(setting.AppSubURL + "/user/settings/security")
  182. }
上海开阖软件有限公司 沪ICP备12045867号-1