package auth import ( "bytes" "database/sql" "math/rand/v2" "golang.org/x/crypto/argon2" ) type passwordInfo struct { hash []byte salt []byte } func queryGetOwnerSettingsPasswordInfo(db *sql.DB) (passwordInfo, error) { out := passwordInfo{} err := db.QueryRow(`select password_hash, password_salt from owner_settings`).Scan(&out.hash, &out.salt) return out, err } func queryCreateSession(db *sql.DB, sessionId string) error { _, err := db.Exec(`insert into session (session_id) values (?)`, sessionId) return err } func HashPassword(password []byte, salt []byte) []byte { passwordHash := argon2.IDKey(password, salt, 10, 7, 1, 64) return passwordHash } const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" const charsetLen = len(charset) func randomString(n int) string { b := make([]byte, n) for i := range b { ciIdx := rand.IntN(charsetLen) b[i] = charset[ciIdx] } return string(b) } func Login(db *sql.DB, password string) (bool, string, error) { info, err := queryGetOwnerSettingsPasswordInfo(db) if err != nil { return false, "", err } incomingHash := HashPassword([]byte(password), info.salt) if !bytes.Equal(incomingHash, info.hash) { return false, "", nil } sessionId := randomString(256) err = queryCreateSession(db, sessionId) return true, sessionId, err } func queryDeleteSession(db *sql.DB, sessionId string) error { _, err := db.Exec(`delete from session where session_id = ?`, sessionId) return err } func SessionDelete(db *sql.DB, sessionId string) error { return queryDeleteSession(db, sessionId) } type SessionInfo struct { IsAdmin bool SessionId string } func queryCheckAuth(db *sql.DB, sessionId string) (SessionInfo, error) { sessionCount := 0 err := db.QueryRow("select count(*) from session where session_id = ?", sessionId).Scan(&sessionCount) if err != nil { return SessionInfo{}, err } return SessionInfo{IsAdmin: sessionCount == 1, SessionId: sessionId}, nil } func SessionCheck(db *sql.DB, sessionId string) (SessionInfo, error) { return queryCheckAuth(db, sessionId) }