idle
This commit is contained in:
@@ -17,11 +17,34 @@ func New(db *sql.DB) *DB {
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID uuid.UUID
|
||||
Email string
|
||||
DisplayName string
|
||||
CreatedAt time.Time
|
||||
LastLoginAt *time.Time
|
||||
ID uuid.UUID
|
||||
Email string
|
||||
Username string
|
||||
DisplayName string
|
||||
PasswordHash *string
|
||||
CreatedAt time.Time
|
||||
LastLoginAt *time.Time
|
||||
}
|
||||
|
||||
type Credential struct {
|
||||
ID string
|
||||
UserID uuid.UUID
|
||||
CredentialPublicKey []byte
|
||||
CredentialID []byte
|
||||
SignCount int64
|
||||
CreatedAt time.Time
|
||||
LastUsedAt *time.Time
|
||||
Transports []string
|
||||
}
|
||||
|
||||
type AuthChallenge struct {
|
||||
ID uuid.UUID
|
||||
UserID uuid.UUID
|
||||
Challenge []byte
|
||||
ChallengeType string
|
||||
CreatedAt time.Time
|
||||
ExpiresAt time.Time
|
||||
UsedAt *time.Time
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
@@ -218,3 +241,153 @@ func (db *DB) UpdateMemberRole(ctx context.Context, orgID, userID uuid.UUID, rol
|
||||
`, role, orgID, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
// Passkey-related methods
|
||||
|
||||
func (db *DB) CreateUser(ctx context.Context, username, email, displayName string, passwordHash *string) (*User, error) {
|
||||
var user User
|
||||
err := db.QueryRowContext(ctx, `
|
||||
INSERT INTO users (id, username, email, display_name, password_hash)
|
||||
VALUES (gen_random_uuid(), $1, $2, $3, $4)
|
||||
RETURNING id, username, email, display_name, password_hash, created_at, last_login_at
|
||||
`, username, email, displayName, passwordHash).Scan(&user.ID, &user.Username, &user.Email, &user.DisplayName, &user.PasswordHash, &user.CreatedAt, &user.LastLoginAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (db *DB) GetUserByUsername(ctx context.Context, username string) (*User, error) {
|
||||
var user User
|
||||
err := db.QueryRowContext(ctx, `
|
||||
SELECT id, username, email, display_name, password_hash, created_at, last_login_at
|
||||
FROM users
|
||||
WHERE username = $1
|
||||
`, username).Scan(&user.ID, &user.Username, &user.Email, &user.DisplayName, &user.PasswordHash, &user.CreatedAt, &user.LastLoginAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (db *DB) GetUserByEmail(ctx context.Context, email string) (*User, error) {
|
||||
var user User
|
||||
err := db.QueryRowContext(ctx, `
|
||||
SELECT id, username, email, display_name, password_hash, created_at, last_login_at
|
||||
FROM users
|
||||
WHERE email = $1
|
||||
`, email).Scan(&user.ID, &user.Username, &user.Email, &user.DisplayName, &user.PasswordHash, &user.CreatedAt, &user.LastLoginAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (db *DB) GetUserByID(ctx context.Context, userID uuid.UUID) (*User, error) {
|
||||
var user User
|
||||
err := db.QueryRowContext(ctx, `
|
||||
SELECT id, username, email, display_name, password_hash, created_at, last_login_at
|
||||
FROM users
|
||||
WHERE id = $1
|
||||
`, userID).Scan(&user.ID, &user.Username, &user.Email, &user.DisplayName, &user.PasswordHash, &user.CreatedAt, &user.LastLoginAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (db *DB) UpdateUserLastLogin(ctx context.Context, userID uuid.UUID) error {
|
||||
_, err := db.ExecContext(ctx, `
|
||||
UPDATE users
|
||||
SET last_login_at = NOW()
|
||||
WHERE id = $1
|
||||
`, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) CreateCredential(ctx context.Context, cred *Credential) error {
|
||||
_, err := db.ExecContext(ctx, `
|
||||
INSERT INTO credentials (id, user_id, credential_public_key, credential_id, sign_count, transports)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
`, cred.ID, cred.UserID, cred.CredentialPublicKey, cred.CredentialID, cred.SignCount, cred.Transports)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) GetCredentialByID(ctx context.Context, credentialID []byte) (*Credential, error) {
|
||||
var cred Credential
|
||||
err := db.QueryRowContext(ctx, `
|
||||
SELECT id, user_id, credential_public_key, credential_id, sign_count, created_at, last_used_at, transports
|
||||
FROM credentials
|
||||
WHERE credential_id = $1
|
||||
`, credentialID).Scan(&cred.ID, &cred.UserID, &cred.CredentialPublicKey, &cred.CredentialID, &cred.SignCount, &cred.CreatedAt, &cred.LastUsedAt, &cred.Transports)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cred, nil
|
||||
}
|
||||
|
||||
func (db *DB) GetUserCredentials(ctx context.Context, userID uuid.UUID) ([]Credential, error) {
|
||||
rows, err := db.QueryContext(ctx, `
|
||||
SELECT id, user_id, credential_public_key, credential_id, sign_count, created_at, last_used_at, transports
|
||||
FROM credentials
|
||||
WHERE user_id = $1
|
||||
ORDER BY created_at DESC
|
||||
`, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var credentials []Credential
|
||||
for rows.Next() {
|
||||
var cred Credential
|
||||
err := rows.Scan(&cred.ID, &cred.UserID, &cred.CredentialPublicKey, &cred.CredentialID, &cred.SignCount, &cred.CreatedAt, &cred.LastUsedAt, &cred.Transports)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
credentials = append(credentials, cred)
|
||||
}
|
||||
return credentials, rows.Err()
|
||||
}
|
||||
|
||||
func (db *DB) UpdateCredentialLastUsed(ctx context.Context, credentialID string) error {
|
||||
_, err := db.ExecContext(ctx, `
|
||||
UPDATE credentials
|
||||
SET last_used_at = NOW()
|
||||
WHERE id = $1
|
||||
`, credentialID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) CreateAuthChallenge(ctx context.Context, userID uuid.UUID, challenge []byte, challengeType string) error {
|
||||
_, err := db.ExecContext(ctx, `
|
||||
INSERT INTO auth_challenges (user_id, challenge, challenge_type, expires_at)
|
||||
VALUES ($1, $2, $3, NOW() + INTERVAL '15 minutes')
|
||||
`, userID, challenge, challengeType)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) VerifyAuthChallenge(ctx context.Context, userID uuid.UUID, challenge []byte, challengeType string) error {
|
||||
var count int
|
||||
err := db.QueryRowContext(ctx, `
|
||||
SELECT COUNT(*)
|
||||
FROM auth_challenges
|
||||
WHERE user_id = $1 AND challenge = $2 AND challenge_type = $3 AND expires_at > NOW() AND used_at IS NULL
|
||||
`, userID, challenge, challengeType).Scan(&count)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) MarkChallengeUsed(ctx context.Context, challenge []byte) error {
|
||||
_, err := db.ExecContext(ctx, `
|
||||
UPDATE auth_challenges
|
||||
SET used_at = NOW()
|
||||
WHERE challenge = $1 AND used_at IS NULL
|
||||
`, challenge)
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user