Skip to content

Commit 91e21d4

Browse files
authored
Move twofactor to models/login (#17143)
1 parent 6fb7fb6 commit 91e21d4

File tree

17 files changed

+131
-121
lines changed

17 files changed

+131
-121
lines changed

models/error.go

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,25 +1876,6 @@ func (err ErrTeamNotExist) Error() string {
18761876
return fmt.Sprintf("team does not exist [org_id %d, team_id %d, name: %s]", err.OrgID, err.TeamID, err.Name)
18771877
}
18781878

1879-
//
1880-
// Two-factor authentication
1881-
//
1882-
1883-
// ErrTwoFactorNotEnrolled indicates that a user is not enrolled in two-factor authentication.
1884-
type ErrTwoFactorNotEnrolled struct {
1885-
UID int64
1886-
}
1887-
1888-
// IsErrTwoFactorNotEnrolled checks if an error is a ErrTwoFactorNotEnrolled.
1889-
func IsErrTwoFactorNotEnrolled(err error) bool {
1890-
_, ok := err.(ErrTwoFactorNotEnrolled)
1891-
return ok
1892-
}
1893-
1894-
func (err ErrTwoFactorNotEnrolled) Error() string {
1895-
return fmt.Sprintf("user not enrolled in 2FA [uid: %d]", err.UID)
1896-
}
1897-
18981879
// ____ ___ .__ .___
18991880
// | | \______ | | _________ __| _/
19001881
// | | /\____ \| | / _ \__ \ / __ |
@@ -1959,28 +1940,6 @@ func (err ErrExternalLoginUserNotExist) Error() string {
19591940
return fmt.Sprintf("external login user link does not exists [userID: %d, loginSourceID: %d]", err.UserID, err.LoginSourceID)
19601941
}
19611942

1962-
// ____ ________________________________ .__ __ __ .__
1963-
// | | \_____ \_ _____/\______ \ ____ ____ |__| _______/ |_____________ _/ |_|__| ____ ____
1964-
// | | // ____/| __) | _// __ \ / ___\| |/ ___/\ __\_ __ \__ \\ __\ |/ _ \ / \
1965-
// | | // \| \ | | \ ___// /_/ > |\___ \ | | | | \// __ \| | | ( <_> ) | \
1966-
// |______/ \_______ \___ / |____|_ /\___ >___ /|__/____ > |__| |__| (____ /__| |__|\____/|___| /
1967-
// \/ \/ \/ \/_____/ \/ \/ \/
1968-
1969-
// ErrU2FRegistrationNotExist represents a "ErrU2FRegistrationNotExist" kind of error.
1970-
type ErrU2FRegistrationNotExist struct {
1971-
ID int64
1972-
}
1973-
1974-
func (err ErrU2FRegistrationNotExist) Error() string {
1975-
return fmt.Sprintf("U2F registration does not exist [id: %d]", err.ID)
1976-
}
1977-
1978-
// IsErrU2FRegistrationNotExist checks if an error is a ErrU2FRegistrationNotExist.
1979-
func IsErrU2FRegistrationNotExist(err error) bool {
1980-
_, ok := err.(ErrU2FRegistrationNotExist)
1981-
return ok
1982-
}
1983-
19841943
// .___ ________ .___ .__
19851944
// | | ______ ________ __ ____ \______ \ ____ ______ ____ ____ __| _/____ ____ ____ |__| ____ ______
19861945
// | |/ ___// ___/ | \_/ __ \ | | \_/ __ \\____ \_/ __ \ / \ / __ |/ __ \ / \_/ ___\| |/ __ \ / ___/

models/login/main_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ func TestMain(m *testing.M) {
1717
"oauth2_application.yml",
1818
"oauth2_authorization_code.yml",
1919
"oauth2_grant.yml",
20+
"u2f_registration.yml",
2021
)
2122
}

models/twofactor.go renamed to models/login/twofactor.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a MIT-style
33
// license that can be found in the LICENSE file.
44

5-
package models
5+
package login
66

77
import (
88
"crypto/md5"
@@ -21,6 +21,25 @@ import (
2121
"golang.org/x/crypto/pbkdf2"
2222
)
2323

24+
//
25+
// Two-factor authentication
26+
//
27+
28+
// ErrTwoFactorNotEnrolled indicates that a user is not enrolled in two-factor authentication.
29+
type ErrTwoFactorNotEnrolled struct {
30+
UID int64
31+
}
32+
33+
// IsErrTwoFactorNotEnrolled checks if an error is a ErrTwoFactorNotEnrolled.
34+
func IsErrTwoFactorNotEnrolled(err error) bool {
35+
_, ok := err.(ErrTwoFactorNotEnrolled)
36+
return ok
37+
}
38+
39+
func (err ErrTwoFactorNotEnrolled) Error() string {
40+
return fmt.Sprintf("user not enrolled in 2FA [uid: %d]", err.UID)
41+
}
42+
2443
// TwoFactor represents a two-factor authentication token.
2544
type TwoFactor struct {
2645
ID int64 `xorm:"pk autoincr"`
@@ -44,11 +63,12 @@ func (t *TwoFactor) GenerateScratchToken() (string, error) {
4463
return "", err
4564
}
4665
t.ScratchSalt, _ = util.RandomString(10)
47-
t.ScratchHash = hashToken(token, t.ScratchSalt)
66+
t.ScratchHash = HashToken(token, t.ScratchSalt)
4867
return token, nil
4968
}
5069

51-
func hashToken(token, salt string) string {
70+
// HashToken return the hashable salt
71+
func HashToken(token, salt string) string {
5272
tempHash := pbkdf2.Key([]byte(token), []byte(salt), 10000, 50, sha256.New)
5373
return fmt.Sprintf("%x", tempHash)
5474
}
@@ -58,7 +78,7 @@ func (t *TwoFactor) VerifyScratchToken(token string) bool {
5878
if len(token) == 0 {
5979
return false
6080
}
61-
tempHash := hashToken(token, t.ScratchSalt)
81+
tempHash := HashToken(token, t.ScratchSalt)
6282
return subtle.ConstantTimeCompare([]byte(t.ScratchHash), []byte(tempHash)) == 1
6383
}
6484

models/u2f.go renamed to models/login/u2f.go

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,40 @@
22
// Use of this source code is governed by a MIT-style
33
// license that can be found in the LICENSE file.
44

5-
package models
5+
package login
66

77
import (
8+
"fmt"
9+
810
"code.gitea.io/gitea/models/db"
911
"code.gitea.io/gitea/modules/log"
1012
"code.gitea.io/gitea/modules/timeutil"
1113

1214
"github.com/tstranex/u2f"
1315
)
1416

17+
// ____ ________________________________ .__ __ __ .__
18+
// | | \_____ \_ _____/\______ \ ____ ____ |__| _______/ |_____________ _/ |_|__| ____ ____
19+
// | | // ____/| __) | _// __ \ / ___\| |/ ___/\ __\_ __ \__ \\ __\ |/ _ \ / \
20+
// | | // \| \ | | \ ___// /_/ > |\___ \ | | | | \// __ \| | | ( <_> ) | \
21+
// |______/ \_______ \___ / |____|_ /\___ >___ /|__/____ > |__| |__| (____ /__| |__|\____/|___| /
22+
// \/ \/ \/ \/_____/ \/ \/ \/
23+
24+
// ErrU2FRegistrationNotExist represents a "ErrU2FRegistrationNotExist" kind of error.
25+
type ErrU2FRegistrationNotExist struct {
26+
ID int64
27+
}
28+
29+
func (err ErrU2FRegistrationNotExist) Error() string {
30+
return fmt.Sprintf("U2F registration does not exist [id: %d]", err.ID)
31+
}
32+
33+
// IsErrU2FRegistrationNotExist checks if an error is a ErrU2FRegistrationNotExist.
34+
func IsErrU2FRegistrationNotExist(err error) bool {
35+
_, ok := err.(ErrU2FRegistrationNotExist)
36+
return ok
37+
}
38+
1539
// U2FRegistration represents the registration data and counter of a security key
1640
type U2FRegistration struct {
1741
ID int64 `xorm:"pk autoincr"`
@@ -91,13 +115,13 @@ func GetU2FRegistrationsByUID(uid int64) (U2FRegistrationList, error) {
91115
return getU2FRegistrationsByUID(db.GetEngine(db.DefaultContext), uid)
92116
}
93117

94-
func createRegistration(e db.Engine, user *User, name string, reg *u2f.Registration) (*U2FRegistration, error) {
118+
func createRegistration(e db.Engine, userID int64, name string, reg *u2f.Registration) (*U2FRegistration, error) {
95119
raw, err := reg.MarshalBinary()
96120
if err != nil {
97121
return nil, err
98122
}
99123
r := &U2FRegistration{
100-
UserID: user.ID,
124+
UserID: userID,
101125
Name: name,
102126
Counter: 0,
103127
Raw: raw,
@@ -110,8 +134,8 @@ func createRegistration(e db.Engine, user *User, name string, reg *u2f.Registrat
110134
}
111135

112136
// CreateRegistration will create a new U2FRegistration from the given Registration
113-
func CreateRegistration(user *User, name string, reg *u2f.Registration) (*U2FRegistration, error) {
114-
return createRegistration(db.GetEngine(db.DefaultContext), user, name, reg)
137+
func CreateRegistration(userID int64, name string, reg *u2f.Registration) (*U2FRegistration, error) {
138+
return createRegistration(db.GetEngine(db.DefaultContext), userID, name, reg)
115139
}
116140

117141
// DeleteRegistration will delete U2FRegistration

models/u2f_test.go renamed to models/login/u2f_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
// Use of this source code is governed by a MIT-style
33
// license that can be found in the LICENSE file.
44

5-
package models
5+
package login
66

77
import (
88
"testing"
99

1010
"code.gitea.io/gitea/models/db"
11+
1112
"github.com/stretchr/testify/assert"
1213
"github.com/tstranex/u2f"
1314
)
@@ -55,14 +56,13 @@ func TestU2FRegistration_UpdateLargeCounter(t *testing.T) {
5556

5657
func TestCreateRegistration(t *testing.T) {
5758
assert.NoError(t, db.PrepareTestDatabase())
58-
user := db.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
5959

60-
res, err := CreateRegistration(user, "U2F Created Key", &u2f.Registration{Raw: []byte("Test")})
60+
res, err := CreateRegistration(1, "U2F Created Key", &u2f.Registration{Raw: []byte("Test")})
6161
assert.NoError(t, err)
6262
assert.Equal(t, "U2F Created Key", res.Name)
6363
assert.Equal(t, []byte("Test"), res.Raw)
6464

65-
db.AssertExistsIf(t, true, &U2FRegistration{Name: "U2F Created Key", UserID: user.ID})
65+
db.AssertExistsIf(t, true, &U2FRegistration{Name: "U2F Created Key", UserID: 1})
6666
}
6767

6868
func TestDeleteRegistration(t *testing.T) {

models/pull_sign.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package models
66

77
import (
88
"code.gitea.io/gitea/models/db"
9+
"code.gitea.io/gitea/models/login"
910
"code.gitea.io/gitea/modules/git"
1011
"code.gitea.io/gitea/modules/log"
1112
"code.gitea.io/gitea/modules/setting"
@@ -44,8 +45,8 @@ Loop:
4445
return false, "", nil, &ErrWontSign{pubkey}
4546
}
4647
case twofa:
47-
twofaModel, err := GetTwoFactorByUID(u.ID)
48-
if err != nil && !IsErrTwoFactorNotEnrolled(err) {
48+
twofaModel, err := login.GetTwoFactorByUID(u.ID)
49+
if err != nil && !login.IsErrTwoFactorNotEnrolled(err) {
4950
return false, "", nil, err
5051
}
5152
if twofaModel == nil {

models/repo_sign.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99

1010
"code.gitea.io/gitea/models/db"
11+
"code.gitea.io/gitea/models/login"
1112
"code.gitea.io/gitea/modules/git"
1213
"code.gitea.io/gitea/modules/log"
1314
"code.gitea.io/gitea/modules/process"
@@ -129,8 +130,8 @@ Loop:
129130
return false, "", nil, &ErrWontSign{pubkey}
130131
}
131132
case twofa:
132-
twofaModel, err := GetTwoFactorByUID(u.ID)
133-
if err != nil && !IsErrTwoFactorNotEnrolled(err) {
133+
twofaModel, err := login.GetTwoFactorByUID(u.ID)
134+
if err != nil && !login.IsErrTwoFactorNotEnrolled(err) {
134135
return false, "", nil, err
135136
}
136137
if twofaModel == nil {
@@ -165,8 +166,8 @@ Loop:
165166
return false, "", nil, &ErrWontSign{pubkey}
166167
}
167168
case twofa:
168-
twofaModel, err := GetTwoFactorByUID(u.ID)
169-
if err != nil && !IsErrTwoFactorNotEnrolled(err) {
169+
twofaModel, err := login.GetTwoFactorByUID(u.ID)
170+
if err != nil && !login.IsErrTwoFactorNotEnrolled(err) {
170171
return false, "", nil, err
171172
}
172173
if twofaModel == nil {
@@ -218,8 +219,8 @@ Loop:
218219
return false, "", nil, &ErrWontSign{pubkey}
219220
}
220221
case twofa:
221-
twofaModel, err := GetTwoFactorByUID(u.ID)
222-
if err != nil && !IsErrTwoFactorNotEnrolled(err) {
222+
twofaModel, err := login.GetTwoFactorByUID(u.ID)
223+
if err != nil && !login.IsErrTwoFactorNotEnrolled(err) {
223224
return false, "", nil, err
224225
}
225226
if twofaModel == nil {

models/token.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"time"
1212

1313
"code.gitea.io/gitea/models/db"
14+
"code.gitea.io/gitea/models/login"
1415
"code.gitea.io/gitea/modules/base"
1516
"code.gitea.io/gitea/modules/setting"
1617
"code.gitea.io/gitea/modules/timeutil"
@@ -67,7 +68,7 @@ func NewAccessToken(t *AccessToken) error {
6768
}
6869
t.TokenSalt = salt
6970
t.Token = base.EncodeSha1(gouuid.New().String())
70-
t.TokenHash = hashToken(t.Token, t.TokenSalt)
71+
t.TokenHash = login.HashToken(t.Token, t.TokenSalt)
7172
t.TokenLastEight = t.Token[len(t.Token)-8:]
7273
_, err = db.GetEngine(db.DefaultContext).Insert(t)
7374
return err
@@ -129,7 +130,7 @@ func GetAccessTokenBySHA(token string) (*AccessToken, error) {
129130
}
130131

131132
for _, t := range tokens {
132-
tempHash := hashToken(token, t.TokenSalt)
133+
tempHash := login.HashToken(token, t.TokenSalt)
133134
if subtle.ConstantTimeCompare([]byte(t.TokenHash), []byte(tempHash)) == 1 {
134135
if successfulAccessTokenCache != nil {
135136
successfulAccessTokenCache.Add(token, t.ID)

models/userlist.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99

1010
"code.gitea.io/gitea/models/db"
11+
"code.gitea.io/gitea/models/login"
1112
"code.gitea.io/gitea/modules/log"
1213
)
1314

@@ -79,13 +80,13 @@ func (users UserList) GetTwoFaStatus() map[int64]bool {
7980
return results
8081
}
8182

82-
func (users UserList) loadTwoFactorStatus(e db.Engine) (map[int64]*TwoFactor, error) {
83+
func (users UserList) loadTwoFactorStatus(e db.Engine) (map[int64]*login.TwoFactor, error) {
8384
if len(users) == 0 {
8485
return nil, nil
8586
}
8687

8788
userIDs := users.getUserIDs()
88-
tokenMaps := make(map[int64]*TwoFactor, len(userIDs))
89+
tokenMaps := make(map[int64]*login.TwoFactor, len(userIDs))
8990
err := e.
9091
In("uid", userIDs).
9192
Find(&tokenMaps)

modules/context/api.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"strings"
1515

1616
"code.gitea.io/gitea/models"
17+
"code.gitea.io/gitea/models/login"
1718
"code.gitea.io/gitea/modules/git"
1819
"code.gitea.io/gitea/modules/log"
1920
"code.gitea.io/gitea/modules/setting"
@@ -219,9 +220,9 @@ func (ctx *APIContext) CheckForOTP() {
219220
}
220221

221222
otpHeader := ctx.Req.Header.Get("X-Gitea-OTP")
222-
twofa, err := models.GetTwoFactorByUID(ctx.Context.User.ID)
223+
twofa, err := login.GetTwoFactorByUID(ctx.Context.User.ID)
223224
if err != nil {
224-
if models.IsErrTwoFactorNotEnrolled(err) {
225+
if login.IsErrTwoFactorNotEnrolled(err) {
225226
return // No 2FA enrollment for this user
226227
}
227228
ctx.Context.Error(http.StatusInternalServerError)

modules/context/auth.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ package context
88
import (
99
"net/http"
1010

11-
"code.gitea.io/gitea/models"
11+
"code.gitea.io/gitea/models/login"
1212
"code.gitea.io/gitea/modules/log"
1313
"code.gitea.io/gitea/modules/setting"
1414
"code.gitea.io/gitea/modules/web/middleware"
@@ -154,9 +154,9 @@ func ToggleAPI(options *ToggleOptions) func(ctx *APIContext) {
154154
if skip, ok := ctx.Data["SkipLocalTwoFA"]; ok && skip.(bool) {
155155
return // Skip 2FA
156156
}
157-
twofa, err := models.GetTwoFactorByUID(ctx.User.ID)
157+
twofa, err := login.GetTwoFactorByUID(ctx.User.ID)
158158
if err != nil {
159-
if models.IsErrTwoFactorNotEnrolled(err) {
159+
if login.IsErrTwoFactorNotEnrolled(err) {
160160
return // No 2FA enrollment for this user
161161
}
162162
ctx.InternalServerError(err)

0 commit comments

Comments
 (0)