170 lines
3.5 KiB
Go
170 lines
3.5 KiB
Go
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
|
||
}
|