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.

security_u2f.go 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  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/setting"
  11. "github.com/tstranex/u2f"
  12. )
  13. // U2FRegister initializes the u2f registration procedure
  14. func U2FRegister(ctx *context.Context, form auth.U2FRegistrationForm) {
  15. if form.Name == "" {
  16. ctx.Error(409)
  17. return
  18. }
  19. challenge, err := u2f.NewChallenge(setting.U2F.AppID, setting.U2F.TrustedFacets)
  20. if err != nil {
  21. ctx.ServerError("NewChallenge", err)
  22. return
  23. }
  24. err = ctx.Session.Set("u2fChallenge", challenge)
  25. if err != nil {
  26. ctx.ServerError("Session.Set", 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. err = ctx.Session.Set("u2fName", form.Name)
  41. if err != nil {
  42. ctx.ServerError("", err)
  43. return
  44. }
  45. ctx.JSON(200, u2f.NewWebRegisterRequest(challenge, regs.ToRegistrations()))
  46. }
  47. // U2FRegisterPost receives the response of the security key
  48. func U2FRegisterPost(ctx *context.Context, response u2f.RegisterResponse) {
  49. challSess := ctx.Session.Get("u2fChallenge")
  50. u2fName := ctx.Session.Get("u2fName")
  51. if challSess == nil || u2fName == nil {
  52. ctx.ServerError("U2FRegisterPost", errors.New("not in U2F session"))
  53. return
  54. }
  55. challenge := challSess.(*u2f.Challenge)
  56. name := u2fName.(string)
  57. config := &u2f.Config{
  58. // Chrome 66+ doesn't return the device's attestation
  59. // certificate by default.
  60. SkipAttestationVerify: true,
  61. }
  62. reg, err := u2f.Register(response, *challenge, config)
  63. if err != nil {
  64. ctx.ServerError("u2f.Register", err)
  65. return
  66. }
  67. if _, err = models.CreateRegistration(ctx.User, name, reg); err != nil {
  68. ctx.ServerError("u2f.Register", err)
  69. return
  70. }
  71. ctx.Status(200)
  72. }
  73. // U2FDelete deletes an security key by id
  74. func U2FDelete(ctx *context.Context, form auth.U2FDeleteForm) {
  75. reg, err := models.GetU2FRegistrationByID(form.ID)
  76. if err != nil {
  77. if models.IsErrU2FRegistrationNotExist(err) {
  78. ctx.Status(200)
  79. return
  80. }
  81. ctx.ServerError("GetU2FRegistrationByID", err)
  82. return
  83. }
  84. if reg.UserID != ctx.User.ID {
  85. ctx.Status(401)
  86. return
  87. }
  88. if err := models.DeleteRegistration(reg); err != nil {
  89. ctx.ServerError("DeleteRegistration", err)
  90. return
  91. }
  92. ctx.JSON(200, map[string]interface{}{
  93. "redirect": setting.AppSubURL + "/user/settings/security",
  94. })
  95. }