60 lines
2.1 KiB
Go
60 lines
2.1 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"rmm-openwrt/server/internal/authn"
|
|
)
|
|
|
|
func VerificationCodeHash(code string) (string, error) {
|
|
return authn.HashPassword("verification:" + strings.TrimSpace(code))
|
|
}
|
|
|
|
func (s *Store) BeginContactVerification(ctx context.Context, userID, channel, destination, codeHash string, expiresAt time.Time) error {
|
|
_, err := s.db.ExecContext(ctx, `
|
|
INSERT INTO contact_verifications (user_id, channel, destination, code_hash, expires_at, verified_at, created_at)
|
|
VALUES (?, ?, ?, ?, ?, NULL, ?)
|
|
ON CONFLICT(user_id, channel) DO UPDATE SET
|
|
destination = excluded.destination, code_hash = excluded.code_hash,
|
|
expires_at = excluded.expires_at, verified_at = NULL, created_at = excluded.created_at
|
|
`, userID, channel, destination, codeHash, notificationTimeText(expiresAt), nowText())
|
|
return err
|
|
}
|
|
|
|
func (s *Store) ConfirmContactVerification(ctx context.Context, userID, channel, code string) (string, bool, error) {
|
|
var destination, expected, expires string
|
|
err := s.db.QueryRowContext(ctx, `
|
|
SELECT destination, code_hash, expires_at FROM contact_verifications
|
|
WHERE user_id = ? AND channel = ? AND verified_at IS NULL
|
|
`, userID, channel).Scan(&destination, &expected, &expires)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return "", false, nil
|
|
}
|
|
if err != nil {
|
|
return "", false, err
|
|
}
|
|
if time.Now().UTC().After(parseTime(expires)) ||
|
|
!authn.VerifyPassword(expected, "verification:"+strings.TrimSpace(code)) {
|
|
return "", false, nil
|
|
}
|
|
_, err = s.db.ExecContext(ctx, `
|
|
UPDATE contact_verifications SET verified_at = ? WHERE user_id = ? AND channel = ?
|
|
`, nowText(), userID, channel)
|
|
return destination, err == nil, err
|
|
}
|
|
|
|
func (s *Store) ContactVerified(ctx context.Context, userID, channel, destination string) (bool, error) {
|
|
var verified bool
|
|
err := s.db.QueryRowContext(ctx, `
|
|
SELECT EXISTS(
|
|
SELECT 1 FROM contact_verifications
|
|
WHERE user_id = ? AND channel = ? AND destination = ? AND verified_at IS NOT NULL
|
|
)
|
|
`, userID, channel, strings.TrimSpace(destination)).Scan(&verified)
|
|
return verified, err
|
|
}
|