xgit simple git

nexus

nexus

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

auth/register.php


1<?php
2require_once __DIR__ . '/../includes/bootstrap.php';
3if ($USER) go('/');
4if (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.
11if ($_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 
19if ($_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>
148function togglePwd(id) {
149  var e = document.getElementById(id);
150  e.type = e.type === 'password' ? 'text' : 'password';
151}
152var pw = document.getElementById('pw1');
153if (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>