xgit simple git

nexus

nexus

clone git clone https://kb.hax.al/nexus

auth/register.php

1 <?php
2 require_once __DIR__ . '/../includes/bootstrap.php';
3 if ($USER) go('/');
4 if (cfg('allow_reg','1') !== '1') $disabled = true;
5 
6 $errs = [];
7 
8 // IMPORTANT: Only generate a NEW captcha on GET requests (page load).
9 // On POST requests, verify FIRST against the stored session answer,
10 // then generate a new one only if needed for re-display.
11 if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
12     $captcha = captcha_generate();
13 } else {
14     // On POST: we don't overwrite the session answer yet.
15     // captcha_verify() will read and unset it.
16     $captcha = ['q' => ''];  // placeholder, overwritten below if needed
17 }
18 
19 if ($_SERVER['REQUEST_METHOD'] === 'POST' && !isset($disabled)) {
20     if (!csrf_ok()) {
21         $errs[]  = 'Invalid request. Please refresh and try again.';
22         $captcha = captcha_generate();
23     } else {
24         $name  = sanitise(post('username'));
25         $email = sanitise(post('email'));
26         $pass  = post('password');
27         $pass2 = post('password2');
28         $cap   = post('captcha');
29 
30         // Verify captcha FIRST before anything else
31         if (!captcha_verify($cap)) {
32             $errs[]  = 'Incorrect answer to the security question. Please try again.';
33             $captcha = captcha_generate(); // generate fresh question for retry
34         }
35 
36         // Only run other validation if captcha passed
37         if (!$errs) {
38             if (strlen($name) < 3 || strlen($name) > 30)          $errs[] = 'Username must be 3โ€“30 characters.';
39             if (!preg_match('/^[a-zA-Z0-9_\-]+$/', $name))         $errs[] = 'Username: letters, numbers, _ and - only.';
40             if (!filter_var($email, FILTER_VALIDATE_EMAIL))         $errs[] = 'Invalid email address.';
41             if (strlen($pass) < 8)                                  $errs[] = 'Password must be at least 8 characters.';
42             if ($pass !== $pass2)                                   $errs[] = 'Passwords do not match.';
43         }
44 
45         if (!$errs) {
46             if (DB::row('SELECT id FROM users WHERE username=? OR email=?', [$name, $email])) {
47                 $errs[] = 'Username or email is already taken.';
48                 $captcha = captcha_generate(); // fresh question after failed attempt
49             } else {
50                 $id = DB::insert(
51                     'INSERT INTO users (username, email, password) VALUES (?, ?, ?)',
52                     [$name, $email, password_hash($pass, PASSWORD_BCRYPT, ['cost' => 12])]
53                 );
54                 addon_hook('after_user_registered', ['user_id'=>$id,'username'=>$name,'email'=>$email]);
55                 login_user($id);
56                 go('/');
57             }
58         }
59 
60         // If we have errors but captcha already passed (errs from other fields),
61         // generate a fresh captcha for the re-shown form
62         if ($errs && empty(array_filter($errs, fn($e) => str_contains($e, 'security')))) {
63             if (!isset($captcha['q']) || $captcha['q'] === '') {
64                 $captcha = captcha_generate();
65             }
66         }
67     }
68 }
69 ?><!DOCTYPE html>
70 <html lang="en">
71 <head>
72   <meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
73   <title>Sign Up โ€” <?= e(cfg('site_name','Nexus Forum')) ?></title>
74   <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
75   <link rel="stylesheet" href="<?= asset('css/main.css') ?>">
76 </head>
77 <body class="auth-body">
78 <div class="auth-page">
79   <div class="auth-card">
80     <a href="<?= u('/') ?>" class="auth-logo">
81       <div class="logo-mark"><?= e(substr(cfg('site_name','N'),0,1)) ?></div>
82       <span><?= e(cfg('site_name','Nexus Forum')) ?></span>
83     </a>
84     <h1>Create an account</h1>
85     <p class="auth-sub">Join the community</p>
86 
87     <?php if (!empty($errs)): ?>
88       <div class="alert err"><?= implode('<br>', array_map('e', $errs)) ?></div>
89     <?php endif; ?>
90 
91     <?php if (isset($disabled)): ?>
92       <div class="alert warn">Registration is currently disabled.</div>
93     <?php else: ?>
94     <form method="POST" autocomplete="off">
95       <?= csrf_input() ?>
96       <div class="fg">
97         <label>Username</label>
98         <input type="text" name="username" class="fi" required autofocus
99                value="<?= e($_POST['username'] ?? '') ?>"
100                placeholder="your_username" minlength="3" maxlength="30">
101         <span class="hint">Letters, numbers, _ and - only</span>
102       </div>
103       <div class="fg">
104         <label>Email</label>
105         <input type="email" name="email" class="fi" required
106                value="<?= e($_POST['email'] ?? '') ?>" placeholder="you@example.com">
107       </div>
108       <div class="fg">
109         <label>Password</label>
110         <div class="pw-row">
111           <input type="password" id="pw1" name="password" class="fi" required
112                  placeholder="Min. 8 characters" minlength="8">
113           <button type="button" class="pw-eye" onclick="togglePwd('pw1')">๐Ÿ‘</button>
114         </div>
115         <div class="pw-bar"><div class="pw-fill" id="pwFill"></div></div>
116         <span class="hint" id="pwHint"></span>
117       </div>
118       <div class="fg">
119         <label>Confirm Password</label>
120         <div class="pw-row">
121           <input type="password" id="pw2" name="password2" class="fi" required
122                  placeholder="Repeat password">
123           <button type="button" class="pw-eye" onclick="togglePwd('pw2')">๐Ÿ‘</button>
124         </div>
125       </div>
126 
127       <!-- Math Captcha -->
128       <div class="captcha-box">
129         <div class="captcha-label">
130           ๐Ÿ”’ Security check โ€” What is
131           <strong class="captcha-q"><?= e($captcha['q']) ?></strong>
132         </div>
133         <input type="number" name="captcha" class="fi captcha-input"
134                required placeholder="Your answer" autocomplete="off">
135         <span class="hint">Solve this simple math problem to continue</span>
136       </div>
137 
138       <button type="submit" class="btn-primary btn-block" style="margin-top:16px">
139         Create Account
140       </button>
141     </form>
142     <?php endif; ?>
143     <p class="auth-foot">Have an account? <a href="<?= u('auth/login.php') ?>">Sign in โ†’</a></p>
144   </div>
145   <p class="auth-back"><a href="<?= u('/') ?>">โ† Back to forum</a></p>
146 </div>
147 <script>
148 function togglePwd(id) {
149   var e = document.getElementById(id);
150   e.type = e.type === 'password' ? 'text' : 'password';
151 }
152 var pw = document.getElementById('pw1');
153 if (pw) pw.addEventListener('input', function() {
154   var p=this.value, f=document.getElementById('pwFill'), h=document.getElementById('pwHint'), s=0;
155   if (p.length >= 8)  s++;
156   if (p.length >= 12) s++;
157   if (/[A-Z]/.test(p)) s++;
158   if (/[0-9]/.test(p)) s++;
159   if (/[^A-Za-z0-9]/.test(p)) s++;
160   f.style.width = (s / 5 * 100) + '%';
161   var cols = ['','#ef4444','#f59e0b','#f59e0b','#22c55e','#22c55e'];
162   f.style.background = cols[s] || '#22c55e';
163   h.textContent = ['','Weak','Fair','Good','Strong','Very strong'][s] || '';
164   h.style.color = f.style.background;
165 });
166 </script>
167 </body>
168 </html>