login handler

This commit is contained in:
lehel 2025-10-07 17:41:19 +02:00
parent 9f28daa4fa
commit d297afb04a
No known key found for this signature in database
GPG Key ID: 9C4F9D6111EE5CFA
7 changed files with 83 additions and 8 deletions

53
auth_test.go Normal file
View File

@ -0,0 +1,53 @@
package main
import (
"context"
"errors"
)
var ErrUserExists = errors.New("user already exists")
var ErrUserNotFound = errors.New("user not found")
// mockRepo implements ChatRepositoryAPI for auth tests
// Only implements methods needed for auth
type mockRepo struct {
users map[string]string // username: passwordHash
}
func (m *mockRepo) CountUsers(ctx context.Context) (int, error) {
return len(m.users), nil
}
func (m *mockRepo) CreateUser(ctx context.Context, username, passwordHash string) error {
if _, exists := m.users[username]; exists {
return ErrUserExists
}
m.users[username] = passwordHash
return nil
}
func (m *mockRepo) GetUserByUsername(ctx context.Context, username string) (*User, error) {
hash, ok := m.users[username]
if !ok {
return nil, ErrUserNotFound
}
return &User{Username: username, PasswordHash: hash}, nil
}
// Add stubs for all ChatRepositoryAPI methods not used in tests
func (m *mockRepo) SaveChatInteraction(ctx context.Context, rec ChatInteraction) error { return nil }
func (m *mockRepo) ListChatInteractions(ctx context.Context, limit, offset int) ([]ChatInteraction, error) {
return nil, nil
}
func (m *mockRepo) SaveLLMRawEvent(ctx context.Context, correlationID, phase, raw string) error {
return nil
}
func (m *mockRepo) ListLLMRawEvents(ctx context.Context, correlationID string, limit, offset int) ([]RawLLMEvent, error) {
return nil, nil
}
func (m *mockRepo) SaveKnowledgeModel(ctx context.Context, text string) error { return nil }
func (m *mockRepo) ListKnowledgeModels(ctx context.Context, limit, offset int) ([]knowledgeModelMeta, error) {
return nil, nil
}
func (m *mockRepo) GetKnowledgeModelText(ctx context.Context, id int64) (string, error) {
return "", nil
}

View File

@ -255,8 +255,7 @@ func AdminAuthMiddleware() gin.HandlerFunc {
// CreateInitialAdmin allows creation of the first admin user if none exist
func (ctrl *Controller) CreateInitialAdmin(c *gin.Context) {
// Only allow if no users exist
var count int
err := ctrl.repo.CountUsers(&count)
count, err := ctrl.repo.CountUsers(c.Request.Context())
if err != nil || count > 0 {
c.JSON(http.StatusForbidden, gin.H{"error": "Admin user already exists or error"})
return
@ -272,7 +271,7 @@ func (ctrl *Controller) CreateInitialAdmin(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
return
}
err = ctrl.repo.CreateUser(username, hash)
err = ctrl.repo.CreateUser(c.Request.Context(), username, hash)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
return

3
go.mod
View File

@ -10,6 +10,7 @@ require (
github.com/jackc/pgx/v5 v5.7.5
github.com/pressly/goose/v3 v3.26.0
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.11.1
golang.org/x/crypto v0.42.0
gopkg.in/yaml.v3 v3.0.1
)
@ -37,6 +38,7 @@ require (
github.com/bytedance/sonic v1.14.0 // indirect
github.com/bytedance/sonic/loader v0.3.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
@ -59,6 +61,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.54.0 // indirect
github.com/sethvargo/go-retry v0.3.0 // indirect

View File

@ -74,6 +74,20 @@ func (r *mapChatRepo) ListLLMRawEvents(ctx context.Context, correlationID string
}
return out, nil
}
func (r *mapChatRepo) CountUsers(ctx context.Context) (int, error) { return 0, nil }
func (r *mapChatRepo) CreateUser(ctx context.Context, username, passwordHash string) error {
return nil
}
func (r *mapChatRepo) GetUserByUsername(ctx context.Context, username string) (*User, error) {
return nil, nil
}
func (r *mapChatRepo) SaveKnowledgeModel(ctx context.Context, text string) error { return nil }
func (r *mapChatRepo) ListKnowledgeModels(ctx context.Context, limit, offset int) ([]knowledgeModelMeta, error) {
return nil, nil
}
func (r *mapChatRepo) GetKnowledgeModelText(ctx context.Context, id int64) (string, error) {
return "", nil
}
// testVisitDB2 replicates a minimal VisitDB for integration
// (avoids relying on real Bleve index)

View File

@ -35,6 +35,8 @@ type ChatRepositoryAPI interface {
ListKnowledgeModels(ctx context.Context, limit, offset int) ([]knowledgeModelMeta, error)
GetKnowledgeModelText(ctx context.Context, id int64) (string, error)
GetUserByUsername(ctx context.Context, username string) (*User, error)
CountUsers(ctx context.Context) (int, error)
CreateUser(ctx context.Context, username, passwordHash string) error
}
// RawLLMEvent represents a stored raw LLM exchange phase
@ -246,13 +248,18 @@ func (r *PGChatRepository) GetUserByUsername(ctx context.Context, username strin
}
// CountUsers returns the number of users in the users table
func (r *PGChatRepository) CountUsers(count *int) error {
return r.pool.QueryRow(context.Background(), "SELECT COUNT(*) FROM users").Scan(count)
func (r *PGChatRepository) CountUsers(ctx context.Context) (int, error) {
var count int
err := r.pool.QueryRow(ctx, "SELECT COUNT(*) FROM users").Scan(&count)
if err != nil {
return 0, err
}
return count, nil
}
// CreateUser inserts a new user with username and password hash
func (r *PGChatRepository) CreateUser(username, passwordHash string) error {
_, err := r.pool.Exec(context.Background(), "INSERT INTO users (username, password_hash) VALUES ($1, $2)", username, passwordHash)
func (r *PGChatRepository) CreateUser(ctx context.Context, username, passwordHash string) error {
_, err := r.pool.Exec(ctx, "INSERT INTO users (username, password_hash) VALUES ($1, $2)", username, passwordHash)
return err
}

View File

@ -1 +0,0 @@
{"storage":"boltdb","index_type":"scorch"}

Binary file not shown.