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

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