summaryrefslogtreecommitdiff
blob: b8a60d6bac952cc7b311929738e8db93e2759ef7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
// Contains the model of the application data

package users

import (
	"crypto/rand"
	"errors"
	"github.com/duo-labs/webauthn/protocol"
	"github.com/duo-labs/webauthn/webauthn"
	"github.com/go-pg/pg/v9/orm"
	"golang.org/x/crypto/argon2"
	"strconv"
	"strings"
)

type User struct {
	Id int64 `pg:",pk,unique"`

	Email                   string `pg:",unique"`
	Nick                    string
	Name                    string
	Password                Argon2Parameters
	ForcePasswordChange     bool
	Role                    string
	TOTPSecret              string
	TOTPQRCode              string
	IsUsingTOTP             bool
	WebauthnCredentials     []webauthn.Credential
	WebauthnCredentialNames []*WebauthnCredentialName
	IsUsingWebAuthn         bool
	Show2FANotice           bool

	Permissions Permissions

	Badge Badge

	ForcePasswordRotation bool
	Force2FA              bool

	Disabled bool
}

type Argon2Parameters struct {
	Type    string
	Salt    []byte
	Time    uint32
	Memory  uint32
	Threads uint8
	KeyLen  uint32
	Hash    []byte
}

func (a *Argon2Parameters) GenerateSalt(n uint32) error {
	b := make([]byte, n)
	_, err := rand.Read(b)
	if err != nil {
		return err
	}
	a.Salt = b

	return nil
}

func (a *Argon2Parameters) GeneratePassword(password string) error {
	if a.Salt == nil || a.Time == 0 || a.Memory == 0 || a.Threads == 0 || a.KeyLen == 0 {
		return errors.New("Invalid parameters")
	}
	a.Hash = argon2.IDKey([]byte(password), a.Salt, a.Time, a.Memory, a.Threads, a.KeyLen)
	return nil
}

func (u *User) UpdatePassword(password string) error {
	err := u.Password.GeneratePassword(password)
	if err != nil {
		return err
	}
	return nil
}

func (u *User) CheckPassword(password string) bool {
	return string(u.Password.Hash) == string(argon2.IDKey(
		[]byte(password),
		u.Password.Salt,
		u.Password.Time,
		u.Password.Memory,
		u.Password.Threads,
		u.Password.KeyLen))
}

type Permissions struct {
	Glsa    GlsaPermissions
	CVETool CVEToolPermissions
	Admin   AdminPermissions
}

type GlsaPermissions struct {
	View           bool
	UpdateBugs     bool
	Comment        bool
	Create         bool
	Edit           bool
	Approve        bool
	ApproveOwnGlsa bool
	Decline        bool
	Delete         bool
	Release        bool
	Confidential   bool
}

type CVEToolPermissions struct {
	View        bool
	UpdateCVEs  bool
	Comment     bool
	AddPackage  bool
	ChangeState bool
	AssignBug   bool
	CreateBug   bool
}

type AdminPermissions struct {
	View            bool
	CreateTemplates bool
	ManageUsers     bool
	GlobalSettings  bool
}

type WebauthnCredentialName struct {
	Id   []byte
	Name string
}

type Badge struct {
	Name        string `pg:",pk"`
	Description string
	Color       string
}

func (u User) IsUsing2FA() bool {
	return u.IsUsingTOTP || u.IsUsingWebAuthn
}

// WebAuthnID returns the user's ID
func (u User) WebAuthnID() []byte {
	return []byte(strconv.FormatInt(u.Id, 10))
}

// WebAuthnName returns the user's username
func (u User) WebAuthnName() string {
	return strings.TrimRight(u.Nick, "@")
}

// WebAuthnDisplayName returns the user's display name
func (u User) WebAuthnDisplayName() string {
	return strings.TrimRight(u.Nick, "@")
}

// WebAuthnIcon is not (yet) implemented
func (u User) WebAuthnIcon() string {
	return ""
}

// WebAuthnCredentials returns credentials owned by the user
func (u User) WebAuthnCredentials() []webauthn.Credential {
	return u.WebauthnCredentials
}

// CredentialExcludeList returns a CredentialDescriptor array filled
// with all the user's credentials
func (u User) CredentialExcludeList() []protocol.CredentialDescriptor {

	credentialExcludeList := []protocol.CredentialDescriptor{}
	for _, cred := range u.WebauthnCredentials {
		descriptor := protocol.CredentialDescriptor{
			Type:         protocol.PublicKeyCredentialType,
			CredentialID: cred.ID,
		}
		credentialExcludeList = append(credentialExcludeList, descriptor)
	}

	return credentialExcludeList
}

// AddCredential associates the credential to the user
func (u *User) AddCredential(cred webauthn.Credential, credentialName string) {
	u.WebauthnCredentials = append(u.WebauthnCredentials, cred)

	webauthnCredentialName := &WebauthnCredentialName{
		Id:   cred.ID,
		Name: credentialName,
	}

	u.WebauthnCredentialNames = append(u.WebauthnCredentialNames, webauthnCredentialName)

}

func (u *User) CanEditCVEs() bool {
	return u.Role == "admin" || u.Role == "editor"
}

func (u *User) Confidential() string {
	confidential := "public"
	if u.Permissions.Glsa.Confidential {
		confidential = "confidential"
	}
	return confidential
}

func (u *User) CanAccess(query *orm.Query) *orm.Query {
	return query.WhereGroup(func(q *orm.Query) (*orm.Query, error) {
		q = q.WhereOr("permission = ?", "public").
			WhereOr("permission = ?", u.Confidential())
		return q, nil
	})
}