Add a CAPTCHA to protect against automated account creation. The CAPTCHA
changes whenever three new accounts are registered.
Signed-off-by: Lukas Fleischer <lfleischer(a)archlinux.org>
---
This is a first attempt to stop the recent wave of spammers. Other
counter-measures will be implemented if it is not effective.
web/html/register.php | 14 +++++-
web/lib/acctfuncs.inc.php | 74 +++++++++++++++++++++++++++++-
web/template/account_edit_form.php | 11 +++++
3 files changed, 95 insertions(+), 4 deletions(-)
diff --git a/web/html/register.php b/web/html/register.php
index 368999a..a426482 100644
--- a/web/html/register.php
+++ b/web/html/register.php
@@ -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>';
diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php
index dc44484..b0513c6 100644
--- a/web/lib/acctfuncs.inc.php
+++ b/web/lib/acctfuncs.inc.php
@@ -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 "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);
+}
diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php
index 38d5274..5e84aa7 100644
--- a/web/template/account_edit_form.php
+++ b/web/template/account_edit_form.php
@@ -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>
--
2.23.0