package main import ( "context" "crypto/subtle" "errors" "github.com/jackc/pgx/v5" ) var dbConnection *pgx.Conn func InitDatabase(ctx context.Context) { conn, err := pgx.Connect(ctx, "postgres://master:secret@localhost:5432") if err != nil { panic(err) } _, err = conn.Exec(ctx, ` CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(20) UNIQUE NOT NULL, pass_hash VARCHAR(255) NOT NULL, color VARCHAR(3) NOT NULL ) `) if err != nil { panic(err) } dbConnection = conn } func AddNewUser(ctx context.Context, user User) (uint, error) { if len(user.name) == 0 || len(user.name) > 20 { return 0, errors.New("username bad length") } if user.isPasswordHashed { if len(user.password) != 255 { return 0, errors.New("password bad length") } } else { // TODO } if len(user.color) != 1 && len(user.color) != 3 { return 0, errors.New("color invalid") } var id uint err := dbConnection.QueryRow(ctx, ` INSERT INTO users (name, pass_hash, color) VALUES ($1, $2, $3) RETURNING id `, user.name, user.isPasswordHashed, user.color).Scan(&id) return id, err } func CheckPassword(ctx context.Context, id string, hash string) bool { var controlHash string err := dbConnection.QueryRow(ctx, "SELECT pass_hash FROM users WHERE id = $1", id).Scan(&controlHash) if err != nil { return false } return subtle.ConstantTimeCompare([]byte(controlHash), []byte(hash)) == 1 } func GetUserData(ctx context.Context, id string) (User, error) { var user User err := dbConnection.QueryRow(ctx, "SELECT id, name, pass_hash, color FROM users WHERE id = $1", id). Scan(&user.id, &user.name, &user.password, &user.color) if err != nil { return User{}, err } user.isPasswordHashed = true return user, nil }