Skip to content

Commit b64b368

Browse files
authored
Merge branch 'main' into patch-17
2 parents 53e9c63 + f49d823 commit b64b368

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+586
-498
lines changed

models/auth/webauthn.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"code.gitea.io/gitea/modules/timeutil"
1313
"code.gitea.io/gitea/modules/util"
1414

15+
"github.com/go-webauthn/webauthn/protocol"
1516
"github.com/go-webauthn/webauthn/webauthn"
1617
)
1718

@@ -89,14 +90,33 @@ func (cred *WebAuthnCredential) AfterLoad() {
8990
// WebAuthnCredentialList is a list of *WebAuthnCredential
9091
type WebAuthnCredentialList []*WebAuthnCredential
9192

93+
// newCredentialFlagsFromAuthenticatorFlags is copied from https://github.com/go-webauthn/webauthn/pull/337
94+
// to convert protocol.AuthenticatorFlags to webauthn.CredentialFlags
95+
func newCredentialFlagsFromAuthenticatorFlags(flags protocol.AuthenticatorFlags) webauthn.CredentialFlags {
96+
return webauthn.CredentialFlags{
97+
UserPresent: flags.HasUserPresent(),
98+
UserVerified: flags.HasUserVerified(),
99+
BackupEligible: flags.HasBackupEligible(),
100+
BackupState: flags.HasBackupState(),
101+
}
102+
}
103+
92104
// ToCredentials will convert all WebAuthnCredentials to webauthn.Credentials
93-
func (list WebAuthnCredentialList) ToCredentials() []webauthn.Credential {
105+
func (list WebAuthnCredentialList) ToCredentials(defaultAuthFlags ...protocol.AuthenticatorFlags) []webauthn.Credential {
106+
// TODO: at the moment, Gitea doesn't store or check the flags
107+
// so we need to use the default flags from the authenticator to make the login validation pass
108+
// In the future, we should:
109+
// 1. store the flags when registering the credential
110+
// 2. provide the stored flags when converting the credentials (for login)
111+
// 3. for old users, still use this fallback to the default flags
112+
defAuthFlags := util.OptionalArg(defaultAuthFlags)
94113
creds := make([]webauthn.Credential, 0, len(list))
95114
for _, cred := range list {
96115
creds = append(creds, webauthn.Credential{
97116
ID: cred.CredentialID,
98117
PublicKey: cred.PublicKey,
99118
AttestationType: cred.AttestationType,
119+
Flags: newCredentialFlagsFromAuthenticatorFlags(defAuthFlags),
100120
Authenticator: webauthn.Authenticator{
101121
AAGUID: cred.AAGUID,
102122
SignCount: cred.SignCount,

models/db/engine.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ func SyncAllTables() error {
134134
func InitEngine(ctx context.Context) error {
135135
xormEngine, err := newXORMEngine()
136136
if err != nil {
137+
if strings.Contains(err.Error(), "SQLite3 support") {
138+
return fmt.Errorf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify%s%w`, "\n", err)
139+
}
137140
return fmt.Errorf("failed to connect to database: %w", err)
138141
}
139142

models/migrations/base/tests.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
"code.gitea.io/gitea/modules/setting"
1919
"code.gitea.io/gitea/modules/testlogger"
2020

21-
"github.com/stretchr/testify/assert"
21+
"github.com/stretchr/testify/require"
2222
"xorm.io/xorm"
2323
)
2424

@@ -33,15 +33,15 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu
3333
ourSkip := 2
3434
ourSkip += skip
3535
deferFn := testlogger.PrintCurrentTest(t, ourSkip)
36-
assert.NoError(t, unittest.SyncDirs(filepath.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
36+
require.NoError(t, unittest.SyncDirs(filepath.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
3737

3838
if err := deleteDB(); err != nil {
39-
t.Errorf("unable to reset database: %v", err)
39+
t.Fatalf("unable to reset database: %v", err)
4040
return nil, deferFn
4141
}
4242

4343
x, err := newXORMEngine()
44-
assert.NoError(t, err)
44+
require.NoError(t, err)
4545
if x != nil {
4646
oldDefer := deferFn
4747
deferFn = func() {

models/organization/org_list.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,31 @@ import (
1616
"xorm.io/builder"
1717
)
1818

19+
type OrgList []*Organization
20+
21+
func (orgs OrgList) LoadTeams(ctx context.Context) (map[int64]TeamList, error) {
22+
if len(orgs) == 0 {
23+
return map[int64]TeamList{}, nil
24+
}
25+
26+
orgIDs := make([]int64, len(orgs))
27+
for i, org := range orgs {
28+
orgIDs[i] = org.ID
29+
}
30+
31+
teams, err := GetTeamsByOrgIDs(ctx, orgIDs)
32+
if err != nil {
33+
return nil, err
34+
}
35+
36+
teamMap := make(map[int64]TeamList, len(orgs))
37+
for _, team := range teams {
38+
teamMap[team.OrgID] = append(teamMap[team.OrgID], team)
39+
}
40+
41+
return teamMap, nil
42+
}
43+
1944
// SearchOrganizationsOptions options to filter organizations
2045
type SearchOrganizationsOptions struct {
2146
db.ListOptions

models/organization/org_list_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,14 @@ func TestGetUserOrgsList(t *testing.T) {
6060
assert.EqualValues(t, 2, orgs[0].NumRepos)
6161
}
6262
}
63+
64+
func TestLoadOrgListTeams(t *testing.T) {
65+
assert.NoError(t, unittest.PrepareTestDatabase())
66+
orgs, err := organization.GetUserOrgsList(db.DefaultContext, &user_model.User{ID: 4})
67+
assert.NoError(t, err)
68+
assert.Len(t, orgs, 1)
69+
teamsMap, err := organization.OrgList(orgs).LoadTeams(db.DefaultContext)
70+
assert.NoError(t, err)
71+
assert.Len(t, teamsMap, 1)
72+
assert.Len(t, teamsMap[3], 5)
73+
}

models/organization/team_list.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,8 @@ func GetUserRepoTeams(ctx context.Context, orgID, userID, repoID int64) (teams T
126126
And("team_repo.repo_id=?", repoID).
127127
Find(&teams)
128128
}
129+
130+
func GetTeamsByOrgIDs(ctx context.Context, orgIDs []int64) (TeamList, error) {
131+
teams := make([]*Team, 0, 10)
132+
return teams, db.GetEngine(ctx).Where(builder.In("org_id", orgIDs)).Find(&teams)
133+
}

modules/auth/webauthn/webauthn.go

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
package webauthn
55

66
import (
7+
"context"
78
"encoding/binary"
89
"encoding/gob"
910

1011
"code.gitea.io/gitea/models/auth"
11-
"code.gitea.io/gitea/models/db"
1212
user_model "code.gitea.io/gitea/models/user"
1313
"code.gitea.io/gitea/modules/setting"
14+
"code.gitea.io/gitea/modules/util"
1415

1516
"github.com/go-webauthn/webauthn/protocol"
1617
"github.com/go-webauthn/webauthn/webauthn"
@@ -38,40 +39,42 @@ func Init() {
3839
}
3940
}
4041

41-
// User represents an implementation of webauthn.User based on User model
42-
type User user_model.User
42+
// user represents an implementation of webauthn.User based on User model
43+
type user struct {
44+
ctx context.Context
45+
User *user_model.User
46+
47+
defaultAuthFlags protocol.AuthenticatorFlags
48+
}
49+
50+
var _ webauthn.User = (*user)(nil)
51+
52+
func NewWebAuthnUser(ctx context.Context, u *user_model.User, defaultAuthFlags ...protocol.AuthenticatorFlags) webauthn.User {
53+
return &user{ctx: ctx, User: u, defaultAuthFlags: util.OptionalArg(defaultAuthFlags)}
54+
}
4355

4456
// WebAuthnID implements the webauthn.User interface
45-
func (u *User) WebAuthnID() []byte {
57+
func (u *user) WebAuthnID() []byte {
4658
id := make([]byte, 8)
47-
binary.PutVarint(id, u.ID)
59+
binary.PutVarint(id, u.User.ID)
4860
return id
4961
}
5062

5163
// WebAuthnName implements the webauthn.User interface
52-
func (u *User) WebAuthnName() string {
53-
if u.LoginName == "" {
54-
return u.Name
55-
}
56-
return u.LoginName
64+
func (u *user) WebAuthnName() string {
65+
return util.IfZero(u.User.LoginName, u.User.Name)
5766
}
5867

5968
// WebAuthnDisplayName implements the webauthn.User interface
60-
func (u *User) WebAuthnDisplayName() string {
61-
return (*user_model.User)(u).DisplayName()
62-
}
63-
64-
// WebAuthnIcon implements the webauthn.User interface
65-
func (u *User) WebAuthnIcon() string {
66-
return (*user_model.User)(u).AvatarLink(db.DefaultContext)
69+
func (u *user) WebAuthnDisplayName() string {
70+
return u.User.DisplayName()
6771
}
6872

6973
// WebAuthnCredentials implements the webauthn.User interface
70-
func (u *User) WebAuthnCredentials() []webauthn.Credential {
71-
dbCreds, err := auth.GetWebAuthnCredentialsByUID(db.DefaultContext, u.ID)
74+
func (u *user) WebAuthnCredentials() []webauthn.Credential {
75+
dbCreds, err := auth.GetWebAuthnCredentialsByUID(u.ctx, u.User.ID)
7276
if err != nil {
7377
return nil
7478
}
75-
76-
return dbCreds.ToCredentials()
79+
return dbCreds.ToCredentials(u.defaultAuthFlags)
7780
}

0 commit comments

Comments
 (0)