a692304748
New public register.php flow: email + a GD-rendered math CAPTCHA (no third-party service), a mailed temporary password doubling as email verification, forced password change on first login. Gated behind a new ALLOW_SELF_REGISTRATION toggle (default off). Login moves from username to email (falls back to username for pre-migration accounts without one yet, mirroring qr-vip's existing migration 006 pattern) - self-registration needs email as the identifier. New set_email.php interstitial for legacy accounts. Adds a small PHPMailer-based Mailer class (SMTP, with an unauthenticated-relay option via MAIL_SMTP_AUTH=false) since no mail infrastructure existed in this app before.
42 lines
1.6 KiB
PHP
42 lines
1.6 KiB
PHP
<?php
|
|
// Public endpoint (no auth): renders a self-hosted CAPTCHA image for register.php.
|
|
// No third-party service (reCAPTCHA/Turnstile/etc) - a simple math challenge drawn
|
|
// with GD onto a noisy background, expected answer kept server-side in the session.
|
|
require_once 'includes/bootstrap.php';
|
|
|
|
$a = random_int(1, 9);
|
|
$b = random_int(1, 9);
|
|
$_SESSION['captcha_answer'] = (string) ($a + $b);
|
|
$text = "{$a} + {$b} =";
|
|
|
|
$width = 160;
|
|
$height = 60;
|
|
$image = imagecreatetruecolor($width, $height);
|
|
$bg = imagecolorallocate($image, 245, 245, 245);
|
|
$fg = imagecolorallocate($image, 30, 30, 30);
|
|
imagefill($image, 0, 0, $bg);
|
|
|
|
// Noise: random lines behind the text, purely cosmetic distortion.
|
|
for ($i = 0; $i < 8; $i++) {
|
|
$lineColor = imagecolorallocate($image, random_int(180, 220), random_int(180, 220), random_int(180, 220));
|
|
imageline($image, random_int(0, $width), random_int(0, $height), random_int(0, $width), random_int(0, $height), $lineColor);
|
|
}
|
|
|
|
$fontFile = '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf';
|
|
if (is_file($fontFile) && function_exists('imagettftext')) {
|
|
$fontSize = 22;
|
|
$bbox = imagettfbbox($fontSize, 0, $fontFile, $text);
|
|
$textWidth = abs($bbox[2] - $bbox[0]);
|
|
$textHeight = abs($bbox[1] - $bbox[7]);
|
|
$x = (int) (($width - $textWidth) / 2);
|
|
$y = (int) (($height + $textHeight) / 2);
|
|
imagettftext($image, $fontSize, 0, $x, $y, $fg, $fontFile, $text);
|
|
} else {
|
|
imagestring($image, 5, 10, 20, $text, $fg);
|
|
}
|
|
|
|
header('Content-Type: image/png');
|
|
header('Cache-Control: no-store, no-cache, must-revalidate');
|
|
imagepng($image);
|
|
imagedestroy($image);
|