-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsignup.php
More file actions
193 lines (165 loc) · 8.1 KB
/
Copy pathsignup.php
File metadata and controls
193 lines (165 loc) · 8.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
<?php
require_once __DIR__ . '/autoload.php';
use App\Core\Bootstrap;
use App\Helpers\SecurityHelper;
Bootstrap::init();
if (isset($_SESSION['user_id'])) {
header("Location: dashboard.php");
exit();
}
$error = "";
$success = "";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
SecurityHelper::verifyCsrfToken($_POST['csrf_token'] ?? '');
// Rate Limiting / Cooldown
$last_attempt = $_SESSION['last_signup_attempt'] ?? 0;
if (time() - $last_attempt < 5) { // 5 second cooldown for registration
$error = "Too many attempts. Please slow down.";
} else {
$_SESSION['last_signup_attempt'] = time();
$name = trim($_POST['name']);
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$family_name = trim($_POST['family_name']);
$password = $_POST['password'];
// Server-side password strength validation
if (!empty($password)) {
if (strlen($password) < 8) {
$error = "Password must be at least 8 characters long.";
} elseif (!preg_match('/[A-Za-z]/', $password)) {
$error = "Password must contain at least one letter.";
} elseif (!preg_match('/[0-9]/', $password)) {
$error = "Password must contain at least one number.";
}
}
}
if (!empty($error)) {
// already set above — fall through to display
} elseif (empty($name) || !$email || empty($family_name) || empty($password)) {
$error = "Please fill in all fields correctly.";
} else {
try {
// Check if email exists
$stmt = $pdo->prepare("SELECT COUNT(*) FROM users WHERE email = ?");
$stmt->execute([$email]);
if ($stmt->fetchColumn() > 0) {
$error = "Email already registered.";
} else {
$pdo->beginTransaction();
// 1. Create Tenant
$stmt = $pdo->prepare("INSERT INTO tenants (family_name) VALUES (?)");
$stmt->execute([$family_name]);
$tenant_id = $pdo->lastInsertId();
// 2. Create User as Family Admin
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (name, email, password, role, tenant_id, permission) VALUES (?, ?, ?, 'family_admin', ?, 'edit')");
$stmt->execute([$name, $email, $hashed_password, $tenant_id]);
// 3. Optional: Create default User Preferences for the new user
$new_user_id = $pdo->lastInsertId();
$stmt = $pdo->prepare("INSERT INTO user_preferences (user_id, base_currency) VALUES (?, 'AED')");
$stmt->execute([$new_user_id]);
$pdo->commit();
$success = "Registration successful! You can now sign in.";
}
} catch (Exception $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
error_log("Signup Error: " . $e->getMessage());
$error = "An error occurred during registration.";
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sign Up | Expense Manager</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<div class="container-fluid">
<div class="auth-wrapper">
<div class="glass-panel auth-card">
<div class="text-center mb-4">
<div class="brand-logo justify-content-center mb-0">
<i class="fa-solid fa-wallet"></i> ExpenseMngr
</div>
</div>
<h2 class="auth-title text-center">Join the Family</h2>
<p class="auth-subtitle text-center">Create your family account and start tracking.</p>
<?php if ($error): ?>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<?php echo htmlspecialchars($error); ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<?php if ($success): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<?php echo htmlspecialchars($success); ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<form method="POST">
<input type="hidden" name="csrf_token" value="<?php echo SecurityHelper::generateCsrfToken(); ?>">
<div class="form-floating mb-3">
<input type="text" class="form-control" id="nameInput" name="name" placeholder="John Doe"
required>
<label for="nameInput">Full Name</label>
</div>
<div class="form-floating mb-3">
<input type="email" class="form-control" id="emailInput" name="email"
placeholder="name@example.com" required>
<label for="emailInput">Email address</label>
</div>
<div class="form-floating mb-3">
<input type="text" class="form-control" id="familyInput" name="family_name"
placeholder="The Does" required>
<label for="familyInput">Family Name (e.g., The Ibrahim Family)</label>
</div>
<div class="mb-4">
<div class="form-floating">
<input type="password" class="form-control" id="passwordInput" name="password"
placeholder="Password" required oninput="checkPasswordStrength(this.value)">
<label for="passwordInput">Password</label>
</div>
<div id="pwRequirements" class="mt-1 small" style="display:none;">
<span id="pwLen" class="me-2">✗ 8+ characters</span>
<span id="pwLet" class="me-2">✗ letter</span>
<span id="pwNum" class="me-2">✗ number</span>
</div>
</div>
<button type="submit" class="btn btn-primary w-100 py-3 mb-3">Create Family Account</button>
<div class="text-center">
<span class="text-muted small">Already have an account? </span>
<a href="index.php" class="text-decoration-none small fw-bold"
style="color: var(--primary-color);">Sign in</a>
</div>
</form>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script nonce="<?php echo $GLOBALS['csp_nonce'] ?? ''; ?>">
var _pwLabels = { pwLen: '8+ characters', pwLet: 'letter', pwNum: 'number' };
function checkPasswordStrength(val) {
var box = document.getElementById('pwRequirements');
box.style.display = val.length > 0 ? 'block' : 'none';
var checks = {
pwLen: val.length >= 8,
pwLet: /[A-Za-z]/.test(val),
pwNum: /[0-9]/.test(val)
};
for (var id in checks) {
var ok = checks[id];
var el = document.getElementById(id);
el.style.color = ok ? 'green' : 'red';
el.textContent = (ok ? '✓' : '✗') + ' ' + _pwLabels[id];
}
}
</script>
</body>
</html>