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

security_u2f.go 3.0 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // Copyright 2018 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package setting
  5. import (
  6. "errors"
  7. "code.gitea.io/gitea/models"
  8. "code.gitea.io/gitea/modules/auth"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/modules/log"
  11. "code.gitea.io/gitea/modules/setting"
  12. "github.com/tstranex/u2f"
  13. )
  14. // U2FRegister initializes the u2f registration procedure
  15. func U2FRegister(ctx *context.Context, form auth.U2FRegistrationForm) {
  16. if form.Name == "" {
  17. ctx.Error(409)
  18. return
  19. }
  20. challenge, err := u2f.NewChallenge(setting.U2F.AppID, setting.U2F.TrustedFacets)
  21. if err != nil {
  22. ctx.ServerError("NewChallenge", err)
  23. return
  24. }
  25. if err := ctx.Session.Set("u2fChallenge", challenge); err != nil {
  26. ctx.ServerError("Unable to set session key for u2fChallenge", err)
  27. return
  28. }
  29. regs, err := models.GetU2FRegistrationsByUID(ctx.User.ID)
  30. if err != nil {
  31. ctx.ServerError("GetU2FRegistrationsByUID", err)
  32. return
  33. }
  34. for _, reg := range regs {
  35. if reg.Name == form.Name {
  36. ctx.Error(409, "Name already taken")
  37. return
  38. }
  39. }
  40. if err := ctx.Session.Set("u2fName", form.Name); err != nil {
  41. ctx.ServerError("Unable to set session key for u2fName", err)
  42. return
  43. }
  44. // Here we're just going to try to release the session early
  45. if err := ctx.Session.Release(); err != nil {
  46. // we'll tolerate errors here as they *should* get saved elsewhere
  47. log.Error("Unable to save changes to the session: %v", err)
  48. }
  49. ctx.JSON(200, u2f.NewWebRegisterRequest(challenge, regs.ToRegistrations()))
  50. }
  51. // U2FRegisterPost receives the response of the security key
  52. func U2FRegisterPost(ctx *context.Context, response u2f.RegisterResponse) {
  53. challSess := ctx.Session.Get("u2fChallenge")
  54. u2fName := ctx.Session.Get("u2fName")
  55. if challSess == nil || u2fName == nil {
  56. ctx.ServerError("U2FRegisterPost", errors.New("not in U2F session"))
  57. return
  58. }
  59. challenge := challSess.(*u2f.Challenge)
  60. name := u2fName.(string)
  61. config := &u2f.Config{
  62. // Chrome 66+ doesn't return the device's attestation
  63. // certificate by default.
  64. SkipAttestationVerify: true,
  65. }
  66. reg, err := u2f.Register(response, *challenge, config)
  67. if err != nil {
  68. ctx.ServerError("u2f.Register", err)
  69. return
  70. }
  71. if _, err = models.CreateRegistration(ctx.User, name, reg); err != nil {
  72. ctx.ServerError("u2f.Register", err)
  73. return
  74. }
  75. ctx.Status(200)
  76. }
  77. // U2FDelete deletes an security key by id
  78. func U2FDelete(ctx *context.Context, form auth.U2FDeleteForm) {
  79. reg, err := models.GetU2FRegistrationByID(form.ID)
  80. if err != nil {
  81. if models.IsErrU2FRegistrationNotExist(err) {
  82. ctx.Status(200)
  83. return
  84. }
  85. ctx.ServerError("GetU2FRegistrationByID", err)
  86. return
  87. }
  88. if reg.UserID != ctx.User.ID {
  89. ctx.Status(401)
  90. return
  91. }
  92. if err := models.DeleteRegistration(reg); err != nil {
  93. ctx.ServerError("DeleteRegistration", err)
  94. return
  95. }
  96. ctx.JSON(200, map[string]interface{}{
  97. "redirect": setting.AppSubURL + "/user/settings/security",
  98. })
  99. }