diff --git a/README b/README index ea8b1d8..01e4398 100644 --- a/README +++ b/README @@ -16,10 +16,10 @@ Installation: USE messenger; # For new installation: - source sql/create.sql + source main/create.sql # For updating existing installation: - source sql/migrate.sql + source main/migrate.sql # Create user with password CREATE USER 'messenger'@'localhost' IDENTIFIED BY 'your_secure_password'; diff --git a/main/create.sql b/main/create.sql new file mode 100644 index 0000000..9ac08fb --- /dev/null +++ b/main/create.sql @@ -0,0 +1,29 @@ +CREATE TABLE messages ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL, + message TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + signature TEXT, + is_encrypted BOOLEAN DEFAULT FALSE, + INDEX idx_created_at (created_at) +); + +CREATE TABLE users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + pgp_key TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + is_moderator TINYINT(1) NOT NULL DEFAULT 0, + login_attempts INT NOT NULL DEFAULT 0, + last_attempt TIMESTAMP NULL, + is_blocked TINYINT(1) NOT NULL DEFAULT 0, + block_reason TEXT, + INDEX idx_username (username) +); + +CREATE TABLE registrations ( + id INT AUTO_INCREMENT PRIMARY KEY, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_created_at (created_at) +); \ No newline at end of file diff --git a/main/db.sql b/main/db.sql new file mode 100644 index 0000000..9a12755 --- /dev/null +++ b/main/db.sql @@ -0,0 +1,81 @@ +CREATE TABLE messages ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL, + message TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + signature TEXT, + is_encrypted BOOLEAN DEFAULT FALSE, + INDEX idx_created_at (created_at) +); + +CREATE TABLE users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + pgp_key TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + is_moderator TINYINT(1) NOT NULL DEFAULT 0, + login_attempts INT NOT NULL DEFAULT 0, + last_attempt TIMESTAMP NULL, + is_blocked TINYINT(1) NOT NULL DEFAULT 0, + block_reason TEXT, + INDEX idx_username (username) +); + +CREATE TABLE registrations ( + id INT AUTO_INCREMENT PRIMARY KEY, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_created_at (created_at) +); + +DELIMITER // +CREATE OR REPLACE PROCEDURE migrate_if_needed() +BEGIN + IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = 'messages') THEN + CREATE TABLE messages ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL, + message TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + signature TEXT, + is_encrypted BOOLEAN DEFAULT FALSE, + INDEX idx_created_at (created_at) + ); + END IF; + + IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = 'users') THEN + CREATE TABLE users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + pgp_key TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + is_moderator TINYINT(1) NOT NULL DEFAULT 0, + login_attempts INT NOT NULL DEFAULT 0, + last_attempt TIMESTAMP NULL, + is_blocked TINYINT(1) NOT NULL DEFAULT 0, + block_reason TEXT, + INDEX idx_username (username) + ); + END IF; + + IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = 'registrations') THEN + CREATE TABLE registrations ( + id INT AUTO_INCREMENT PRIMARY KEY, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_created_at (created_at) + ); + END IF; + + IF EXISTS ( + SELECT * FROM information_schema.columns + WHERE table_name = 'registrations' AND column_name = 'ip' + ) THEN + DROP INDEX IF EXISTS idx_ip_created ON registrations; + ALTER TABLE registrations DROP COLUMN ip; + END IF; +END // +DELIMITER ; + +CALL migrate_if_needed(); +DROP PROCEDURE IF EXISTS migrate_if_needed; \ No newline at end of file diff --git a/main/login.php b/main/login.php index ea7d549..f74ec5a 100644 --- a/main/login.php +++ b/main/login.php @@ -1,88 +1,124 @@ PDO::ERRMODE_EXCEPTION] - ); - - $stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?"); - $stmt->execute([$username]); - $user = $stmt->fetch(); - - if ($user && password_verify($password, $user['password'])) { - if ($user['is_blocked']) { - $error = "Аккаунт заблокирован: " . htmlspecialchars($user['block_reason']); - } else { - $_SESSION['user_id'] = $user['id']; - $_SESSION['username'] = $user['username']; - $_SESSION['is_moderator'] = $user['is_moderator']; - - $stmt = $pdo->prepare("UPDATE users SET login_attempts = 0, last_attempt = NULL WHERE id = ?"); - $stmt->execute([$user['id']]); - - header("Location: index.php"); - exit; - } - } else { + $db = new PDO( + "mysql:host={$config['db']['host']};dbname={$config['db']['name']}", + $config['db']['user'], + $config['db']['pass'] + ); + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $debug[] = "Database connected"; +} catch (PDOException $e) { + $debug[] = "Database error: " . $e->getMessage(); + die("Database connection error: " . $e->getMessage()); +} + +$error = ''; +$success = ''; + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING); + $password = filter_input(INPUT_POST, 'password', FILTER_SANITIZE_STRING); + + $debug[] = "Login attempt for: " . $username; + + if ($username && $password) { + try { + $stmt = $db->prepare('SELECT id, password, is_blocked, login_attempts, last_attempt FROM users WHERE username = ?'); + $stmt->execute([$username]); + $user = $stmt->fetch(PDO::FETCH_ASSOC); + + $debug[] = "User found: " . ($user ? 'yes' : 'no'); + if ($user) { - $stmt = $pdo->prepare("UPDATE users SET login_attempts = login_attempts + 1, last_attempt = CURRENT_TIMESTAMP WHERE id = ?"); - $stmt->execute([$user['id']]); - - if ($user['login_attempts'] >= 4) { - $stmt = $pdo->prepare("UPDATE users SET is_blocked = 1, block_reason = 'Превышено количество попыток входа' WHERE id = ?"); + if ($user['is_blocked']) { + $error = 'Account is blocked'; + $debug[] = "Account blocked"; + } else if ($user['login_attempts'] >= 5 && strtotime($user['last_attempt']) > strtotime('-15 minutes')) { + $error = 'Too many login attempts'; + $debug[] = "Too many attempts"; + } else if (password_verify($password, $user['password'])) { + $stmt = $db->prepare('UPDATE users SET login_attempts = 0, last_attempt = NOW() WHERE id = ?'); $stmt->execute([$user['id']]); - $error = "Аккаунт заблокирован из-за превышения количества попыток входа"; + $_SESSION['user_id'] = $user['id']; + $_SESSION['username'] = $username; + $debug[] = "Login successful"; + header('Location: index.php'); + exit; } else { - $error = "Неверный пароль"; + $stmt = $db->prepare('UPDATE users SET login_attempts = login_attempts + 1, last_attempt = NOW() WHERE id = ?'); + $stmt->execute([$user['id']]); + $error = 'Invalid password'; + $debug[] = "Invalid password"; } } else { - $error = "Пользователь не найден"; + $error = 'User not found'; + $debug[] = "User not found"; } + } catch (PDOException $e) { + $error = 'Server error'; + $debug[] = "SQL Error: " . $e->getMessage(); + $debug[] = "SQL State: " . $e->getCode(); } - } catch (PDOException $e) { - $error = "Ошибка сервера"; } } ?> - +
- - -Нет аккаунта? Зарегистрироваться
-Уже есть аккаунт? Войти
-