package db import ( "database/sql" "errors" "fmt" _ "github.com/mattn/go-sqlite3" ) /** * @brief Структура пользователя */ type User struct { ID int Username string PasswordHash string FailedAttempts int Locked bool } var database *sql.DB /** * @brief Инициализация соединения с SQLite БД * @param path Путь к файлу базы данных * @return ошибка при неудаче */ func Init(path string) error { var err error database, err = sql.Open("sqlite3", path) if err != nil { return err } // Проверка соединения if err = database.Ping(); err != nil { return err } return createTables() } /** * @brief Закрытие соединения с БД */ func Close() { if database != nil { _ = database.Close() } } /** * @brief Создание таблиц при первом запуске */ func createTables() error { query := ` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password_hash TEXT NOT NULL, failed_attempts INTEGER DEFAULT 0, locked INTEGER DEFAULT 0 ); ` _, err := database.Exec(query) return err } /** * @brief Получить пользователя по имени * @param username Логин пользователя * @return структура User или ошибка */ func GetUser(username string) (*User, error) { query := ` SELECT id, username, password_hash, failed_attempts, locked FROM users WHERE username = ?; ` row := database.QueryRow(query, username) var user User var locked int err := row.Scan( &user.ID, &user.Username, &user.PasswordHash, &user.FailedAttempts, &locked, ) if err == sql.ErrNoRows { return nil, errors.New("пользователь не найден") } if err != nil { return nil, err } user.Locked = locked != 0 return &user, nil } /** * @brief Увеличить счётчик неудачных попыток входа * @param username Логин пользователя */ func IncrementFail(username string) error { query := ` UPDATE users SET failed_attempts = failed_attempts + 1 WHERE username = ?; ` _, err := database.Exec(query, username) return err } /** * @brief Сбросить счётчик неудачных попыток * @param username Логин пользователя */ func ResetFails(username string) error { query := ` UPDATE users SET failed_attempts = 0 WHERE username = ?; ` _, err := database.Exec(query, username) return err } /** * @brief Заблокировать пользователя * @param username Логин пользователя */ func LockUser(username string) error { query := ` UPDATE users SET locked = 1 WHERE username = ?; ` _, err := database.Exec(query) return err } /** * @brief Добавить нового пользователя (для инициализации) * @param username Логин * @param passwordHash Хеш пароля */ func CreateUser(username, passwordHash string) error { query := ` INSERT INTO users (username, password_hash) VALUES (?, ?); ` _, err := database.Exec(query, username, passwordHash) if err != nil { return fmt.Errorf("не удалось создать пользователя: %w", err) } return nil }