-
Notifications
You must be signed in to change notification settings - Fork 0
/
adapter.go
355 lines (315 loc) · 13.5 KB
/
adapter.go
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
package adapters
import (
"context"
"encoding/gob"
"errors"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
func init() {
gob.Register(&GothAccount{})
gob.Register(&GothUser{})
gob.Register(&GothSession{})
gob.Register(&GothTeam{})
gob.Register(&GothVerificationToken{})
gob.Register(&GothCsrfToken{})
}
// CsrfTokenGenerator is a function that generates a CSRF token.
type CsrfTokenGenerator func() (string, error)
// DefaultCsrfTokenGenerator generates a new CSRF token.
func DefaultCsrfTokenGenerator() (string, error) {
token, err := uuid.NewV7()
if err != nil {
return "", err
}
return token.String(), nil
}
// AccountType represents the type of an account.
type AccountType string
// ErrUnimplemented is returned when a method is not implemented.
var ErrUnimplemented = errors.New("not implemented")
const (
// AccountTypeOAuth2 represents an OAuth2 account type.
AccountTypeOAuth2 AccountType = "oauth2"
// AccountTypeOIDC represents an OIDC account type.
AccountTypeOIDC AccountType = "oidc"
// AccountTypeSAML represents a SAML account type.
AccountTypeSAML AccountType = "saml"
// AccountTypeEmail represents an email account type.
AccountTypeEmail AccountType = "email"
// AccountTypeWebAuthn represents a WebAuthn account type.
AccountTypeWebAuthn AccountType = "webauthn"
)
// GothAccount represents an account in a third-party identity provider.
type GothAccount struct {
// ID is the unique identifier of the account.
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;column:id;default:gen_random_uuid();"`
// Type is the type of the account.
Type AccountType `json:"type" validate:"required"`
// Provider is the provider of the account.
Provider string `json:"provider" validate:"required"`
// ProviderAccountID is the account ID in the provider.
ProviderAccountID *string `json:"provider_account_id"`
// RefreshToken is the refresh token of the account.
RefreshToken *string `json:"refresh_token"`
// AccessToken is the access token of the account.
AccessToken *string `json:"access_token"`
// ExpiresAt is the expiry time of the account.
ExpiresAt *time.Time `json:"expires_at"`
// TokenType is the token type of the account.
TokenType *string `json:"token_type"`
// Scope is the scope of the account.
Scope *string `json:"scope"`
// IDToken is the ID token of the account.
IDToken *string `json:"id_token"`
// SessionState is the session state of the account.
SessionState string `json:"session_state"`
// UserID is the user ID of the account.
UserID *uuid.UUID `json:"user_id"`
// User is the user of the account.
User GothUser `json:"user" gorm:"foreignKey:UserID;constraint:OnDelete:CASCADE"`
// CreatedAt is the creation time of the account.
CreatedAt time.Time `json:"created_at"`
// UpdatedAt is the update time of the account.
UpdatedAt time.Time `json:"updated_at"`
// DeletedAt is the deletion time of the account.
DeletedAt gorm.DeletedAt `json:"deleted_at"`
}
// GothUser is a user of the application.
type GothUser struct {
// ID is the unique identifier of the user.
ID uuid.UUID `json:"id" gorm:"primaryKey;unique;type:uuid;column:id;default:gen_random_uuid()"`
// Name is the name of the user.
Name string `json:"name" validate:"required,max=255"`
// Email is the email of the user.
Email string `json:"email" gorm:"unique" validate:"required,email"`
// EmailVerified is true if the email is verified.
EmailVerified *bool `json:"email_verified"`
// Image is the image URL of the user.
Image *string `json:"image" validate:"url"`
// Password is the password of the user.
Accounts []GothAccount `json:"accounts" gorm:"foreignKey:UserID;constraint:OnDelete:CASCADE"`
// Sessions are the sessions of the user.
Sessions []GothSession `json:"sessions" gorm:"foreignKey:UserID;constraint:OnDelete:CASCADE"`
// Teams are the teams the user is a member of.
Teams *[]GothTeam `json:"teams" gorm:"many2many:goth_team_users"`
// CreatedAt is the creation time of the user.
CreatedAt time.Time `json:"created_at"`
// UpdatedAt is the update time of the user.
UpdatedAt time.Time `json:"updated_at"`
// DeletedAt is the deletion time of the user.
DeletedAt gorm.DeletedAt `json:"deleted_at"`
}
// TeamBySlug is returning the team with the given ID.
func (u GothUser) TeamBySlug(slug string) GothTeam {
for _, team := range *u.Teams {
if team.Slug == slug {
return team
}
}
return GothTeam{}
}
// GothSession is a session for a user.
type GothSession struct {
// ID is the unique identifier of the session.
ID uuid.UUID `json:"id" gorm:"primaryKey;unique;type:uuid;column:id;default:gen_random_uuid()"`
// SessionToken is the token of the session.
SessionToken string `json:"session_token"`
// CsrfToken is the CSRF token of the session.
CsrfToken GothCsrfToken `json:"csrf_token"`
// CsrfTokenID is the CSRF token ID of the session.
CsrfTokenID uuid.UUID `json:"csrf_token_id"`
// UserID is the user ID of the session.
UserID uuid.UUID `json:"user_id"`
// User is the user of the session.
User GothUser `json:"user"`
// ExpiresAt is the expiry time of the session.
ExpiresAt time.Time `json:"expires_at"`
// CreatedAt is the creation time of the session.
CreatedAt time.Time `json:"created_at"`
// UpdatedAt is the update time of the session.
UpdatedAt time.Time `json:"updated_at"`
// DeletedAt is the deletion time of the session.
DeletedAt gorm.DeletedAt `json:"deleted_at"`
}
// GothCsrfToken is a CSRF token for a user
type GothCsrfToken struct {
// ID is the unique identifier of the CSRF token.
ID uuid.UUID `json:"id" gorm:"primaryKey;unique;type:uuid;column:id;default:gen_random_uuid()"`
// Token is the unique identifier of the token.
Token string `json:"token"`
// ExpiresAt is the expiry time of the token.
ExpiresAt time.Time `json:"expires_at"`
// CreatedAt is the creation time of the token.
CreatedAt time.Time `json:"created_at"`
// UpdatedAt is the update time of the token.
UpdatedAt time.Time `json:"updated_at"`
// DeletedAt is the deletion time of the token.
DeletedAt gorm.DeletedAt `json:"deleted_at"`
}
// IsValid returns true if the session is valid.
func (s *GothSession) IsValid() bool {
return s.ExpiresAt.After(time.Now())
}
// GetCsrfToken returns the CSRF token.
func (s *GothSession) GetCsrfToken() string {
return s.CsrfToken.Token
}
// GothVerificationToken is a verification token for a user
type GothVerificationToken struct {
// Token is the unique identifier of the token.
Token string `json:"token" gorm:"primaryKey"`
// Identifier is the identifier of the token.
Identifier string `json:"identifier"`
// ExpiresAt is the expiry time of the token.
ExpiresAt time.Time `json:"expires_at"`
// CreatedAt is the creation time of the token.
CreatedAt time.Time `json:"created_at"`
// UpdatedAt is the update time of the token.
UpdatedAt time.Time `json:"updated_at"`
// DeletedAt is the deletion time of the token.
DeletedAt gorm.DeletedAt `json:"deleted_at"`
}
// GothTeam is a team in the application.
type GothTeam struct {
// ID is the unique identifier of the team.
ID uuid.UUID `json:"id" gorm:"primaryKey;unique;type:uuid;column:id;default:gen_random_uuid()"`
// Name is the name of the team.
Name string `json:"name" validate:"required,max=255"`
// Slug is the slug of the team.
Slug string `json:"slug" validate:"required,min=3,max=255"`
// Description is the description of the team.
Description string `json:"description" validate:"max=255"`
// Users are the users in the team.
Users []GothUser `json:"users" gorm:"many2many:goth_team_users"`
// Roles are the roles in the team.
Roles []GothRole `json:"roles" gorm:"foreignKey:TeamID;constraint:OnDelete:CASCADE"`
// CreatedAt is the creation time of the team.
CreatedAt time.Time `json:"created_at"`
// UpdatedAt is the update time of the team.
UpdatedAt time.Time `json:"updated_at"`
// DeletedAt is the deletion time of the team.
DeletedAt gorm.DeletedAt `json:"deleted_at"`
}
// GothRole is a role in the application.
type GothRole struct {
// ID is the unique identifier of the role.
ID uuid.UUID `json:"id" gorm:"primaryKey;unique;type:uuid;column:id;default:gen_random_uuid()"`
// Name is the name of the role.
Name string `json:"name" validate:"required,min=3,max=255"`
// Description is the description of the role.
Description string `json:"description" validate:"max=255"`
// TeamID is the team ID of the role.
TeamID uuid.UUID `json:"team_id"`
// Team is the team of the role.
Team GothTeam `json:"team"`
// CreatedAt is the creation time of the role.
CreatedAt time.Time `json:"created_at"`
// UpdatedAt is the update time of the role.
UpdatedAt time.Time `json:"updated_at"`
// DeletedAt is the deletion time of the role.
DeletedAt gorm.DeletedAt `json:"deleted_at"`
}
// Adapter is an interface that defines the methods for interacting with the underlying data storage.
type Adapter interface {
// CreateUser creates a new user.
CreateUser(ctx context.Context, user GothUser) (GothUser, error)
// GetUser retrieves a user by ID.
GetUser(ctx context.Context, id uuid.UUID) (GothUser, error)
// GetUserByEmail retrieves a user by email.
GetUserByEmail(ctx context.Context, email string) (GothUser, error)
// UpdateUser updates a user.
UpdateUser(ctx context.Context, user GothUser) (GothUser, error)
// DeleteUser deletes a user by ID.
DeleteUser(ctx context.Context, id uuid.UUID) error
// LinkAccount links an account to a user.
LinkAccount(ctx context.Context, accountID, userID uuid.UUID) error
// UnlinkAccount unlinks an account from a user.
UnlinkAccount(ctx context.Context, accountID, userID uuid.UUID) error
// CreateSession creates a new session.
CreateSession(ctx context.Context, userID uuid.UUID, expires time.Time) (GothSession, error)
// GetSession retrieves a session by session token.
GetSession(ctx context.Context, sessionToken string) (GothSession, error)
// UpdateSession updates a session.
UpdateSession(ctx context.Context, session GothSession) (GothSession, error)
// RefreshSession refreshes a session.
RefreshSession(ctx context.Context, session GothSession) (GothSession, error)
// DeleteSession deletes a session by session token.
DeleteSession(ctx context.Context, sessionToken string) error
// CreateVerificationToken creates a new verification token.
CreateVerificationToken(ctx context.Context, verficationToken GothVerificationToken) (GothVerificationToken, error)
// UseVerficationToken uses a verification token.
UseVerficationToken(ctx context.Context, identifier string, token string) (GothVerificationToken, error)
}
var _ Adapter = (*UnimplementedAdapter)(nil)
// UnimplementedAdapter is an adapter that does not implement any of the methods.
type UnimplementedAdapter struct{}
// CreateUser creates a new user.
func (a *UnimplementedAdapter) CreateUser(_ context.Context, user GothUser) (GothUser, error) {
return GothUser{}, ErrUnimplemented
}
// GetUser retrieves a user by ID.
func (a *UnimplementedAdapter) GetUser(_ context.Context, id uuid.UUID) (GothUser, error) {
return GothUser{}, ErrUnimplemented
}
// GetUserByEmail retrieves a user by email.
func (a *UnimplementedAdapter) GetUserByEmail(_ context.Context, email string) (GothUser, error) {
return GothUser{}, ErrUnimplemented
}
// GetUserByAccount retrieves a user by account.
func (a *UnimplementedAdapter) GetUserByAccount(_ context.Context, provider string, providerAccountID string) (GothUser, error) {
return GothUser{}, ErrUnimplemented
}
// UpdateUser updates a user.
func (a *UnimplementedAdapter) UpdateUser(_ context.Context, user GothUser) (GothUser, error) {
return GothUser{}, ErrUnimplemented
}
// DeleteUser deletes a user by ID.
func (a *UnimplementedAdapter) DeleteUser(_ context.Context, id uuid.UUID) error {
return ErrUnimplemented
}
// LinkAccount links an account to a user.
func (a *UnimplementedAdapter) LinkAccount(_ context.Context, accountID, userID uuid.UUID) error {
return ErrUnimplemented
}
// UnlinkAccount unlinks an account from a user.
func (a *UnimplementedAdapter) UnlinkAccount(_ context.Context, accountID, userID uuid.UUID) error {
return ErrUnimplemented
}
// CreateSession creates a new session.
func (a *UnimplementedAdapter) CreateSession(_ context.Context, userID uuid.UUID, expires time.Time) (GothSession, error) {
return GothSession{}, ErrUnimplemented
}
// GetSession retrieves a session by session token.
func (a *UnimplementedAdapter) GetSession(_ context.Context, sessionToken string) (GothSession, error) {
return GothSession{}, ErrUnimplemented
}
// UpdateSession updates a session.
func (a *UnimplementedAdapter) UpdateSession(_ context.Context, session GothSession) (GothSession, error) {
return GothSession{}, ErrUnimplemented
}
// RefreshSession refreshes a session.
func (a *UnimplementedAdapter) RefreshSession(_ context.Context, session GothSession) (GothSession, error) {
return GothSession{}, ErrUnimplemented
}
// DeleteSession deletes a session by session token.
func (a *UnimplementedAdapter) DeleteSession(_ context.Context, sessionToken string) error {
return ErrUnimplemented
}
// CreateVerificationToken creates a new verification token.
func (a *UnimplementedAdapter) CreateVerificationToken(_ context.Context, erficationToken GothVerificationToken) (GothVerificationToken, error) {
return GothVerificationToken{}, ErrUnimplemented
}
// UseVerficationToken uses a verification token.
func (a *UnimplementedAdapter) UseVerficationToken(_ context.Context, identifier string, token string) (GothVerificationToken, error) {
return GothVerificationToken{}, ErrUnimplemented
}
// StringPtr returns a pointer to the string value passed in.
func StringPtr(s string) *string {
return &s
}
// TimePtr returns a pointer to the time value passed in.
func TimePtr(t time.Time) *time.Time {
return &t
}