Add a simple CAPTCHA to the sign up form

Add a CAPTCHA to protect against automated account creation. The CAPTCHA
changes whenever three new accounts are registered.

Signed-off-by: Lukas Fleischer <lfleischer@archlinux.org>
This commit is contained in:
Lukas Fleischer 2019-09-06 14:34:38 -04:00
parent a66c7fa615
commit d6ae970785
3 changed files with 95 additions and 4 deletions

View file

@ -36,7 +36,12 @@ if (in_request("Action") == "NewAccount") {
0,
in_request("CN"),
in_request("UN"),
in_request("ON"));
in_request("ON"),
0,
"",
in_request("captcha_salt"),
in_request("captcha"),
);
print $message;
@ -59,7 +64,12 @@ if (in_request("Action") == "NewAccount") {
0,
in_request("CN"),
in_request("UN"),
in_request("ON"));
in_request("ON"),
0,
"",
in_request("captcha_salt"),
in_request("captcha")
);
}
} else {
print '<p>' . __("Use this form to create an account.") . '</p>';

View file

@ -62,17 +62,25 @@ function html_format_pgp_fingerprint($fingerprint) {
* @param string $ON Whether to notify of ownership changes
* @param string $UID The user ID of the displayed user
* @param string $N The username as present in the database
* @param string $captcha_salt The salt used for the CAPTCHA.
* @param string $captcha The CAPTCHA answer.
*
* @return void
*/
function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="",
$L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="") {
$L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="",$captcha_salt="",$captcha="") {
global $SUPPORTED_LANGS;
if ($TZ == "") {
$TZ = config_get("options", "default_timezone");
}
if ($captcha_salt != get_captcha_salt()) {
$captcha_salt = get_captcha_salt();
$captcha = "";
}
$captcha_challenge = get_captcha_challenge($captcha_salt);
include("account_edit_form.php");
return;
}
@ -103,11 +111,13 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R=""
* @param string $ON Whether to notify of ownership changes
* @param string $UID The user ID of the modified account
* @param string $N The username as present in the database
* @param string $captcha_salt The salt used for the CAPTCHA.
* @param string $captcha The CAPTCHA answer.
*
* @return array Boolean indicating success and message to be printed
*/
function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",
$R="",$L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="") {
$R="",$L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="",$captcha_salt="",$captcha="") {
global $SUPPORTED_LANGS;
$error = '';
@ -269,6 +279,18 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C=""
}
}
if (!$error && $TYPE == "new" && empty($captcha)) {
$error = __("The CAPTCHA is missing.");
}
if (!$error && $TYPE == "new" && $captcha_salt != get_captcha_salt()) {
$error = __("This CAPTCHA has expired. Please try again.");
}
if (!$error && $TYPE == "new" && $captcha != get_captcha_answer($captcha_salt)) {
$error = __("The entered CAPTCHA answer is invalid.");
}
if ($error) {
$message = "<ul class='errorlist'><li>".$error."</li></ul>\n";
return array(false, $message);
@ -1445,3 +1467,51 @@ function account_comments_count($uid) {
$result = $dbh->query($q);
return $result->fetchColumn();
}
/*
* Compute the CAPTCHA salt. The salt changes based on the number of registered
* users. This ensures that new users always use a different salt.
*
* @return string The current salt.
*/
function get_captcha_salt() {
$dbh = DB::connect();
$q = "SELECT count(*) FROM Users";
$result = $dbh->query($q);
$user_count = $result->fetchColumn();
return 'aurweb-' . floor($user_count / 3);
}
/*
* Return the CAPTCHA challenge for a given salt.
*
* @param string $salt The salt to be used for the CAPTCHA computation.
*
* @return string The challenge as a string.
*/
function get_captcha_challenge($salt) {
$token = substr(md5($salt), 0, 3);
return "LC_ALL=C pacman -V|sed -r 's#[0-9]+#" . $token . "#g'|md5sum|cut -c1-6";
}
/*
* Compute CAPTCHA answer for a given salt.
*
* @param string $salt The salt to be used for the CAPTCHA computation.
*
* @return string The correct answer as a string.
*/
function get_captcha_answer($salt) {
$token = substr(md5($salt), 0, 3);
$text = <<<EOD
.--. Pacman v$token.$token.$token - libalpm v$token.$token.$token
/ _.-' .-. .-. .-. Copyright (C) $token-$token Pacman Development Team
\ '-. '-' '-' '-' Copyright (C) $token-$token Judd Vinet
'--'
This program may be freely redistributed under
the terms of the GNU General Public License.
EOD;
return substr(md5($text . "\n"), 0, 6);
}

View file

@ -174,6 +174,17 @@
</p>
</fieldset>
<?php if ($A != "UpdateAccount"): ?>
<fieldset>
<legend><?= __("To protect the AUR against automated account creation, we kindly ask you to provide the output of the following command:") ?> <code><?= htmlspecialchars($captcha_challenge) ?></code></legend>
<p>
<label for="id_captcha"><?= __("Answer") ?>:</label>
<input type="text" size="30" maxlength="6" name="captcha" id="id_captcha" value="<?= htmlspecialchars($captcha, ENT_QUOTES) ?>" /> (<?= __("required") ?>)
<input type="hidden" name="captcha_salt" value="<?= htmlspecialchars($captcha_salt) ?>" />
</p>
</fieldset>
<?php endif; ?>
<fieldset>
<p>
<label></label>