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.

u2f.go 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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 login
  5. import (
  6. "fmt"
  7. "code.gitea.io/gitea/models/db"
  8. "code.gitea.io/gitea/modules/log"
  9. "code.gitea.io/gitea/modules/timeutil"
  10. "github.com/tstranex/u2f"
  11. )
  12. // ____ ________________________________ .__ __ __ .__
  13. // | | \_____ \_ _____/\______ \ ____ ____ |__| _______/ |_____________ _/ |_|__| ____ ____
  14. // | | // ____/| __) | _// __ \ / ___\| |/ ___/\ __\_ __ \__ \\ __\ |/ _ \ / \
  15. // | | // \| \ | | \ ___// /_/ > |\___ \ | | | | \// __ \| | | ( <_> ) | \
  16. // |______/ \_______ \___ / |____|_ /\___ >___ /|__/____ > |__| |__| (____ /__| |__|\____/|___| /
  17. // \/ \/ \/ \/_____/ \/ \/ \/
  18. // ErrU2FRegistrationNotExist represents a "ErrU2FRegistrationNotExist" kind of error.
  19. type ErrU2FRegistrationNotExist struct {
  20. ID int64
  21. }
  22. func (err ErrU2FRegistrationNotExist) Error() string {
  23. return fmt.Sprintf("U2F registration does not exist [id: %d]", err.ID)
  24. }
  25. // IsErrU2FRegistrationNotExist checks if an error is a ErrU2FRegistrationNotExist.
  26. func IsErrU2FRegistrationNotExist(err error) bool {
  27. _, ok := err.(ErrU2FRegistrationNotExist)
  28. return ok
  29. }
  30. // U2FRegistration represents the registration data and counter of a security key
  31. type U2FRegistration struct {
  32. ID int64 `xorm:"pk autoincr"`
  33. Name string
  34. UserID int64 `xorm:"INDEX"`
  35. Raw []byte
  36. Counter uint32 `xorm:"BIGINT"`
  37. CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
  38. UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
  39. }
  40. func init() {
  41. db.RegisterModel(new(U2FRegistration))
  42. }
  43. // TableName returns a better table name for U2FRegistration
  44. func (reg U2FRegistration) TableName() string {
  45. return "u2f_registration"
  46. }
  47. // Parse will convert the db entry U2FRegistration to an u2f.Registration struct
  48. func (reg *U2FRegistration) Parse() (*u2f.Registration, error) {
  49. r := new(u2f.Registration)
  50. return r, r.UnmarshalBinary(reg.Raw)
  51. }
  52. func (reg *U2FRegistration) updateCounter(e db.Engine) error {
  53. _, err := e.ID(reg.ID).Cols("counter").Update(reg)
  54. return err
  55. }
  56. // UpdateCounter will update the database value of counter
  57. func (reg *U2FRegistration) UpdateCounter() error {
  58. return reg.updateCounter(db.GetEngine(db.DefaultContext))
  59. }
  60. // U2FRegistrationList is a list of *U2FRegistration
  61. type U2FRegistrationList []*U2FRegistration
  62. // ToRegistrations will convert all U2FRegistrations to u2f.Registrations
  63. func (list U2FRegistrationList) ToRegistrations() []u2f.Registration {
  64. regs := make([]u2f.Registration, 0, len(list))
  65. for _, reg := range list {
  66. r, err := reg.Parse()
  67. if err != nil {
  68. log.Error("parsing u2f registration: %v", err)
  69. continue
  70. }
  71. regs = append(regs, *r)
  72. }
  73. return regs
  74. }
  75. func getU2FRegistrationsByUID(e db.Engine, uid int64) (U2FRegistrationList, error) {
  76. regs := make(U2FRegistrationList, 0)
  77. return regs, e.Where("user_id = ?", uid).Find(&regs)
  78. }
  79. // GetU2FRegistrationByID returns U2F registration by id
  80. func GetU2FRegistrationByID(id int64) (*U2FRegistration, error) {
  81. return getU2FRegistrationByID(db.GetEngine(db.DefaultContext), id)
  82. }
  83. func getU2FRegistrationByID(e db.Engine, id int64) (*U2FRegistration, error) {
  84. reg := new(U2FRegistration)
  85. if found, err := e.ID(id).Get(reg); err != nil {
  86. return nil, err
  87. } else if !found {
  88. return nil, ErrU2FRegistrationNotExist{ID: id}
  89. }
  90. return reg, nil
  91. }
  92. // GetU2FRegistrationsByUID returns all U2F registrations of the given user
  93. func GetU2FRegistrationsByUID(uid int64) (U2FRegistrationList, error) {
  94. return getU2FRegistrationsByUID(db.GetEngine(db.DefaultContext), uid)
  95. }
  96. // HasU2FRegistrationsByUID returns whether a given user has U2F registrations
  97. func HasU2FRegistrationsByUID(uid int64) (bool, error) {
  98. return db.GetEngine(db.DefaultContext).Where("user_id = ?", uid).Exist(&U2FRegistration{})
  99. }
  100. func createRegistration(e db.Engine, userID int64, name string, reg *u2f.Registration) (*U2FRegistration, error) {
  101. raw, err := reg.MarshalBinary()
  102. if err != nil {
  103. return nil, err
  104. }
  105. r := &U2FRegistration{
  106. UserID: userID,
  107. Name: name,
  108. Counter: 0,
  109. Raw: raw,
  110. }
  111. _, err = e.InsertOne(r)
  112. if err != nil {
  113. return nil, err
  114. }
  115. return r, nil
  116. }
  117. // CreateRegistration will create a new U2FRegistration from the given Registration
  118. func CreateRegistration(userID int64, name string, reg *u2f.Registration) (*U2FRegistration, error) {
  119. return createRegistration(db.GetEngine(db.DefaultContext), userID, name, reg)
  120. }
  121. // DeleteRegistration will delete U2FRegistration
  122. func DeleteRegistration(reg *U2FRegistration) error {
  123. return deleteRegistration(db.GetEngine(db.DefaultContext), reg)
  124. }
  125. func deleteRegistration(e db.Engine, reg *U2FRegistration) error {
  126. _, err := e.Delete(reg)
  127. return err
  128. }