package repository import ( "database/sql" "errors" "strconv" "gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/storage" "gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/utils" "golang.org/x/crypto/bcrypt" ) // Repository wraps a SQLite database connection. type Repository struct { DB *sql.DB } // New creates a new Repository. func New(db *sql.DB) *Repository { return &Repository{DB: db} } var ErrNotFound = errors.New("not found") // Init creates the tokens table if it does not exist. func (r *Repository) Init() error { _, err := r.DB.Exec(storage.CreateSqlite) return err } // CreateToken inserts a new user record with hashed password and generated token. func (r *Repository) CreateToken(tc TokenCreate) (string, error) { hashed, err := bcrypt.GenerateFromPassword([]byte(tc.Password), bcrypt.DefaultCost) if err != nil { return "", err } token, err := utils.RandomToken() if err != nil { return "", err } result, err := r.DB.Exec( `INSERT INTO tokens (name, last_name, login, password, token, permission_view, permission_manage_agent, permission_admin) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, tc.Name, tc.LastName, tc.Login, string(hashed), token, tc.PermissionView, tc.PermissionManage, tc.PermissionAdmin, ) if err != nil { return "", err } id, err := result.LastInsertId() if err != nil { return "", err } return strconv.FormatInt(id, 10), nil } // Login authenticates by login/password, generates a new token, and returns LoginResponse. func (r *Repository) Login(login, password string) (*LoginResponse, error) { var t Tokens var hashedPassword string err := r.DB.QueryRow( `SELECT id, name, last_name, login, password, token, permission_view, permission_manage_agent, permission_admin FROM tokens WHERE login = ?`, login, ).Scan(&t.ID, &t.Name, &t.LastName, &t.Login, &hashedPassword, &t.Token, &t.PermissionView, &t.PermissionManage, &t.PermissionAdmin) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } return nil, err } if err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)); err != nil { return nil, ErrNotFound } // Generate new token on each login newToken, err := utils.RandomToken() if err != nil { return nil, err } _, err = r.DB.Exec(`UPDATE tokens SET token = ? WHERE id = ?`, newToken, t.ID) if err != nil { return nil, err } return &LoginResponse{ Token: newToken, Name: t.Name, LastName: t.LastName, Login: t.Login, PermissionView: t.PermissionView, PermissionManage: t.PermissionManage, PermissionAdmin: t.PermissionAdmin, }, nil } // GetTokenByToken retrieves a user record by token value. func (r *Repository) GetToken(token string) (*Tokens, error) { var t Tokens err := r.DB.QueryRow( `SELECT id, name, last_name, login, token, permission_view, permission_manage_agent, permission_admin FROM tokens WHERE token = ?`, token, ).Scan(&t.ID, &t.Name, &t.LastName, &t.Login, &t.Token, &t.PermissionView, &t.PermissionManage, &t.PermissionAdmin) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } return nil, err } return &t, nil } // ListTokens returns all users without password and token. func (r *Repository) ListTokens() ([]Tokens, error) { rows, err := r.DB.Query( `SELECT id, name, last_name, login, permission_view, permission_manage_agent, permission_admin FROM tokens`, ) if err != nil { return nil, err } defer rows.Close() var tokens []Tokens for rows.Next() { var t Tokens if err := rows.Scan(&t.ID, &t.Name, &t.LastName, &t.Login, &t.PermissionView, &t.PermissionManage, &t.PermissionAdmin); err != nil { return nil, err } tokens = append(tokens, t) } return tokens, rows.Err() } // DeleteToken deletes a user by token value. func (r *Repository) DeleteToken(token string) error { result, err := r.DB.Exec(`DELETE FROM tokens WHERE token = ?`, token) if err != nil { return err } affected, err := result.RowsAffected() if err != nil { return err } if affected == 0 { return ErrNotFound } return nil } // DeleteTokenByLogin deletes a user by login. func (r *Repository) DeleteTokenByLogin(login string) error { result, err := r.DB.Exec(`DELETE FROM tokens WHERE login = ?`, login) if err != nil { return err } affected, err := result.RowsAffected() if err != nil { return err } if affected == 0 { return ErrNotFound } return nil } // ExistsByLogin checks if a user with given login exists. func (r *Repository) ExistsByLogin(login string) bool { var count int err := r.DB.QueryRow(`SELECT COUNT(*) FROM tokens WHERE login = ?`, login).Scan(&count) if err != nil { return false } return count > 0 }