shelves/internal/auth/auth.go
2024-11-16 14:31:32 -05:00

93 lines
2 KiB
Go

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)
}