148 lines
5.9 KiB
PHP
148 lines
5.9 KiB
PHP
<?php
|
|
$rootPath = dirname(dirname(__DIR__));
|
|
require_once($rootPath . "/src/config/env.php");
|
|
require_once($rootPath . "/src/config/session.php");
|
|
require_once($rootPath . "/src/config/connection.php");
|
|
require_once($rootPath . "/src/config/functions.php");
|
|
require_once($rootPath . "/vendor/autoload.php");
|
|
|
|
use GuzzleHttp\Client;
|
|
|
|
// Create connection
|
|
$conn = openDatabaseConnection();
|
|
|
|
// Check connection
|
|
if ($conn->connect_error) {
|
|
die("Connection failed: " . $conn->connect_error);
|
|
}
|
|
|
|
|
|
// Form processing
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
// CSRF Token Validation
|
|
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
|
auditLog(null, 'CSRF_VALIDATION_FAILED', 'users', null, ['endpoint' => 'register_user.php']);
|
|
echo json_encode(['status' => 'error', 'message' => 'Security token validation failed. Please try again.']);
|
|
exit();
|
|
}
|
|
|
|
// Check rate limiting on registration endpoint (by IP)
|
|
$ip = getClientIPAddress();
|
|
$cutoffTime = date('Y-m-d H:i:s', time() - (3600)); // Last hour
|
|
|
|
$stmt = $conn->prepare("SELECT COUNT(*) as count FROM audit_log WHERE action = 'REGISTRATION_ATTEMPT' AND ip_address = ? AND created_at > ?");
|
|
$stmt->bind_param('ss', $ip, $cutoffTime);
|
|
$stmt->execute();
|
|
$stmt->bind_result($regAttempts);
|
|
$stmt->fetch();
|
|
$stmt->close();
|
|
|
|
// Allow max 5 registration attempts per IP per hour
|
|
if ($regAttempts >= 5) {
|
|
auditLog(null, 'REGISTRATION_RATE_LIMIT_EXCEEDED', 'users', null, ['ip' => $ip, 'attempts' => $regAttempts]);
|
|
echo json_encode(['status' => 'error', 'message' => 'Too many registration attempts. Please try again later.']);
|
|
exit();
|
|
}
|
|
|
|
// Validate and sanitize first name
|
|
$first_name = validateName($_POST['first_name'] ?? '');
|
|
if ($first_name === false) {
|
|
auditLog(null, 'REGISTRATION_INVALID_FIRST_NAME', 'users');
|
|
echo json_encode(['status' => 'error', 'message' => 'Invalid first name. Only letters, spaces, hyphens, and apostrophes allowed (2-100 characters).']);
|
|
exit();
|
|
}
|
|
|
|
// Validate and sanitize last name
|
|
$last_name = validateName($_POST['last_name'] ?? '');
|
|
if ($last_name === false) {
|
|
auditLog(null, 'REGISTRATION_INVALID_LAST_NAME', 'users');
|
|
echo json_encode(['status' => 'error', 'message' => 'Invalid last name. Only letters, spaces, hyphens, and apostrophes allowed (2-100 characters).']);
|
|
exit();
|
|
}
|
|
|
|
// Validate and sanitize phone number
|
|
$phone_number = validatePhoneNumber($_POST['phone_number'] ?? '');
|
|
if ($phone_number === false) {
|
|
auditLog(null, 'REGISTRATION_INVALID_PHONE', 'users');
|
|
echo json_encode(['status' => 'error', 'message' => 'Invalid phone number format.']);
|
|
exit();
|
|
}
|
|
|
|
// Validate email
|
|
$email = validateEmail($_POST['email'] ?? '');
|
|
if ($email === false) {
|
|
auditLog(null, 'REGISTRATION_INVALID_EMAIL', 'users');
|
|
echo json_encode(['status' => 'error', 'message' => 'Invalid email format.']);
|
|
exit();
|
|
}
|
|
|
|
$password = $_POST['password'] ?? '';
|
|
$password_confirm = $_POST['password_confirm'] ?? '';
|
|
|
|
// Validate password strength (minimum 8 characters, must contain uppercase, lowercase, number, special char)
|
|
if (strlen($password) < 8) {
|
|
echo json_encode(['status' => 'error', 'message' => 'Password must be at least 8 characters long.']);
|
|
exit();
|
|
}
|
|
|
|
if (!preg_match('/[A-Z]/', $password) || !preg_match('/[a-z]/', $password) ||
|
|
!preg_match('/[0-9]/', $password) || !preg_match('/[!@#$%^&*]/', $password)) {
|
|
echo json_encode(['status' => 'error', 'message' => 'Password must contain uppercase, lowercase, number, and special character (!@#$%^&*).']);
|
|
exit();
|
|
}
|
|
|
|
if ($password !== $password_confirm) {
|
|
echo json_encode(['status' => 'error', 'message' => 'Passwords do not match.']);
|
|
exit();
|
|
}
|
|
|
|
// Check if the email is already registered
|
|
$stmt = $conn->prepare('SELECT user_id FROM users WHERE email = ?');
|
|
$stmt->bind_param('s', $email);
|
|
$stmt->execute();
|
|
$stmt->store_result();
|
|
|
|
if ($stmt->num_rows > 0) {
|
|
auditLog(null, 'REGISTRATION_EMAIL_EXISTS', 'users', null, ['email' => $email]);
|
|
echo json_encode(['status' => 'error', 'message' => 'Email is already registered.']);
|
|
$stmt->close();
|
|
$conn->close();
|
|
exit();
|
|
}
|
|
|
|
$stmt->close();
|
|
|
|
// Hash password
|
|
$hashed_password = password_hash($password, PASSWORD_BCRYPT);
|
|
|
|
// Generate email verification token
|
|
$token = bin2hex(random_bytes(50));
|
|
|
|
// Prepare and execute query
|
|
$stmt = $conn->prepare('INSERT INTO users (first_name, last_name, phone_number, email, password, token, is_verified, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
|
|
$is_verified = 0; // Not verified
|
|
$type = 'credentials';
|
|
$stmt->bind_param('ssssssis', $first_name, $last_name, $phone_number, $email, $hashed_password, $token, $is_verified, $type);
|
|
|
|
if ($stmt->execute()) {
|
|
$newUser_id = $conn->insert_id;
|
|
processLegacyMembership($newUser_id);
|
|
auditLog($newUser_id, 'USER_REGISTRATION', 'users', $newUser_id, ['email' => $email]);
|
|
|
|
if (sendVerificationEmail($email, $first_name . ' ' . $last_name, $token)) {
|
|
sendEmail($_ENV['ADMIN_EMAIL'], '4WDCSA: New User Registration', $first_name . ' ' . $last_name . ' (' . $email . ') has just created an account using Credentials.');
|
|
echo json_encode(['status' => 'success', 'message' => 'Registration successful. Please check your email to verify your account.']);
|
|
} else {
|
|
echo json_encode(['status' => 'error', 'message' => 'Failed to send verification email.']);
|
|
}
|
|
} else {
|
|
auditLog(null, 'REGISTRATION_DATABASE_ERROR', 'users', null, ['email' => $email]);
|
|
echo json_encode(['status' => 'error', 'message' => 'Failed to register user.']);
|
|
}
|
|
|
|
$stmt->close();
|
|
}
|
|
|
|
$conn->close();
|
|
|