package db import "database/sql" import "time" type UserTOTP struct { SecretEncrypted string PendingSecretEncrypted string Enabled bool CreatedAt int64 UpdatedAt int64 } func (s *Store) GetUserTOTP(userID string) (UserTOTP, error) { var item UserTOTP var row *sql.Row var created time.Time var updated time.Time var err error row = s.QueryRow(` SELECT COALESCE(t.secret_encrypted, ''), COALESCE(t.pending_secret_encrypted, ''), COALESCE(t.enabled, 0), t.created_at, t.updated_at FROM user_totp t JOIN users u ON u.id = t.user_id WHERE u.public_id = ? `, userID) err = row.Scan(&item.SecretEncrypted, &item.PendingSecretEncrypted, &item.Enabled, &created, &updated) if err != nil { return item, err } item.CreatedAt = created.Unix() item.UpdatedAt = updated.Unix() return item, nil } func (s *Store) UserRequiresTOTP(userID string) (bool, error) { var row *sql.Row var required bool var err error row = s.QueryRow(` SELECT (u.totp_required OR EXISTS ( SELECT 1 FROM user_group_members m JOIN user_groups g ON g.id = m.group_id WHERE m.user_id = u.id AND g.disabled = 0 AND g.totp_required = 1 ) OR EXISTS ( SELECT 1 FROM user_groups g WHERE g.disabled = 0 AND g.totp_required = 1 AND g.scope = 'all_users' )) FROM users u WHERE u.public_id = ? AND u.disabled = 0 `, userID) err = row.Scan(&required) return required, err } func (s *Store) UpsertUserTOTPPending(userID string, pendingSecretEncrypted string) error { var err error var now time.Time now = time.Now().UTC() _, err = s.Exec(` INSERT INTO user_totp (user_id, secret_encrypted, pending_secret_encrypted, enabled, created_at, updated_at) VALUES ((SELECT id FROM users WHERE public_id = ?), '', ?, 0, ?, ?) ON CONFLICT(user_id) DO UPDATE SET pending_secret_encrypted = excluded.pending_secret_encrypted, updated_at = excluded.updated_at `, userID, pendingSecretEncrypted, now, now) return err } func (s *Store) EnableUserTOTP(userID string, secretEncrypted string) error { var err error var now time.Time now = time.Now().UTC() _, err = s.Exec(` INSERT INTO user_totp (user_id, secret_encrypted, pending_secret_encrypted, enabled, created_at, updated_at) VALUES ((SELECT id FROM users WHERE public_id = ?), ?, '', 1, ?, ?) ON CONFLICT(user_id) DO UPDATE SET secret_encrypted = excluded.secret_encrypted, pending_secret_encrypted = '', enabled = 1, updated_at = excluded.updated_at `, userID, secretEncrypted, now, now) return err } func (s *Store) DeleteUserTOTP(userID string) error { var err error _, err = s.Exec(`DELETE FROM user_totp WHERE user_id = (SELECT id FROM users WHERE public_id = ?)`, userID) return err }