package db import ( "crypto/subtle" "database/sql" ) type AuthProvider interface { SaltedHash(username string) [32]byte Salt(username string) [16]byte UserExists(username string) bool } type DBAuthProvider struct { db *sql.DB } func NewDBAuthProvider(db *sql.DB) AuthProvider { provider := new(DBAuthProvider) provider.db = db return provider } func (dbAuth DBAuthProvider) Close() { dbAuth.db.Close() } func (dbAuth DBAuthProvider) SaltedHash(username string) [32]byte { row := dbAuth.db.QueryRow(` SELECT saltedhash FROM users WHERE username = ? `, username) buf := make([]byte, 32) should_copy := 1 saltedHash := [32]byte{0} err := row.Scan(&buf) if err != nil { should_copy = 0 } subtle.ConstantTimeCopy(should_copy, saltedHash[:], buf[:32]) return saltedHash } func (dbAuth DBAuthProvider) Salt(username string) [16]byte { row := dbAuth.db.QueryRow(` SELECT salt FROM users WHERE username = ? `, username) buf := make([]byte, 16) should_copy := 1 salt := [16]byte{0} err := row.Scan(&buf) if err != nil { should_copy = 0 } subtle.ConstantTimeCopy(should_copy, salt[:], buf[:16]) return salt } func (dbAuth DBAuthProvider) UserExists(username string) bool { row := dbAuth.db.QueryRow(` SELECT 1 FROM users WHERE username = ? `, username) err := row.Scan(new(int)) if err != nil { return false } return true }