feat: HMAC-signed cookies for UI sessions, bcrypt hash for admin bootstrap, simplified NixOS module
This commit is contained in:
1 parent
56da3bae61
commit
5be2005f70
3 files changed
+51
-57
No files matched your search
@@ -106,15 +106,10 @@ func (s *sqliteStore) countUsers(ctx context.Context) (int, error) {
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (s *sqliteStore) createUser(ctx context.Context, username, password string) (*userRow, error) {
|
||||
h, err := hashPassword(password)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("hash password: %w", err)
|
||||
}
|
||||
|
||||
func (s *sqliteStore) createUserWithHash(ctx context.Context, username, passwordHash string) (*userRow, error) {
|
||||
result, err := s.db.ExecContext(ctx,
|
||||
`INSERT INTO users (username, password_hash) VALUES (?, ?)`,
|
||||
username, h,
|
||||
username, passwordHash,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("insert user: %w", err)
|
||||
@@ -404,14 +399,32 @@ func (s *sqliteStore) bootstrapAdmin(ctx context.Context, logger *zap.Logger) {
|
||||
}
|
||||
|
||||
username := getenvDefault("ADMIN_USERNAME", "admin")
|
||||
password := os.Getenv("ADMIN_PASSWORD")
|
||||
if password == "" {
|
||||
var password string
|
||||
var passwordHash string
|
||||
|
||||
if h := os.Getenv("ADMIN_PASSWORD_HASH"); h != "" {
|
||||
passwordHash = h
|
||||
} else if pw := os.Getenv("ADMIN_PASSWORD"); pw != "" {
|
||||
var err error
|
||||
passwordHash, err = hashPassword(pw)
|
||||
if err != nil {
|
||||
logger.Fatal("failed to hash admin password", zap.Error(err))
|
||||
}
|
||||
password = pw
|
||||
}
|
||||
|
||||
if passwordHash == "" {
|
||||
password = generateRandomPassword()
|
||||
logger.Warn("ADMIN_PASSWORD not set, generated random password",
|
||||
var err error
|
||||
passwordHash, err = hashPassword(password)
|
||||
if err != nil {
|
||||
logger.Fatal("failed to hash admin password", zap.Error(err))
|
||||
}
|
||||
logger.Warn("no admin password configured, generated random password",
|
||||
zap.String("password", password))
|
||||
}
|
||||
|
||||
admin, err := s.createUser(ctx, username, password)
|
||||
admin, err := s.createUserWithHash(ctx, username, passwordHash)
|
||||
if err != nil {
|
||||
logger.Fatal("failed to create admin user", zap.Error(err))
|
||||
}
|
||||
@@ -643,7 +656,14 @@ func createUserHandler(store *sqliteStore, logger *zap.Logger) http.HandlerFunc
|
||||
return
|
||||
}
|
||||
|
||||
user, err := store.createUser(r.Context(), body.Username, body.Password)
|
||||
h, err := hashPassword(body.Password)
|
||||
if err != nil {
|
||||
logger.Error("hash password", zap.Error(err))
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "internal error"})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := store.createUserWithHash(r.Context(), body.Username, h)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "UNIQUE constraint") {
|
||||
writeJSON(w, http.StatusConflict, map[string]string{"error": "username already exists"})
|
||||
|
||||
Reference in new issue
Block a user