changeset 1228:db85ff22ae97

mod_register_web: Add a simple fallback captcha
author Kim Alvefur <zash@zash.se>
date Sat, 30 Nov 2013 19:00:38 +0100
parents 6015434f0e05
children 12e3bc0fd6ed
files mod_register_web/mod_register_web.lua mod_register_web/templates/simplecaptcha.html
diffstat 2 files changed, 65 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/mod_register_web/mod_register_web.lua	Sat Nov 30 18:57:54 2013 +0100
+++ b/mod_register_web/mod_register_web.lua	Sat Nov 30 19:00:38 2013 +0100
@@ -21,35 +21,72 @@
 
 local register_tpl = get_template "register";
 local success_tpl = get_template "success";
-local recaptcha_tpl = get_template "recaptcha";
+
+if next(captcha_options) ~= nil then
+	local recaptcha_tpl = get_template "recaptcha";
 
-function generate_captcha(display_options)
-	return recaptcha_tpl.apply(setmetatable({
-  		recaptcha_display_error = display_options and display_options.recaptcha_error
-  			and ("&error="..display_options.recaptcha_error) or "";
-  	}, {
-  		__index = function (t, k)
-  			if captcha_options[k] then return captcha_options[k]; end
-  			module:log("error", "Missing parameter from captcha_options: %s", k);
+	function generate_captcha(display_options)
+		return recaptcha_tpl.apply(setmetatable({
+	  		recaptcha_display_error = display_options and display_options.recaptcha_error
+	  			and ("&error="..display_options.recaptcha_error) or "";
+	  	}, {
+	  		__index = function (t, k)
+	  			if captcha_options[k] then return captcha_options[k]; end
+	  			module:log("error", "Missing parameter from captcha_options: %s", k);
+			end
+		}));
+	end
+	function verify_captcha(form, callback)
+		http.request("https://www.google.com/recaptcha/api/verify", {
+			body = http.formencode {
+				privatekey = captcha_options.recaptcha_private_key;
+				remoteip = request.conn:ip();
+				challenge = form.recaptcha_challenge_field;
+				response = form.recaptcha_response_field;
+			};
+		}, function (verify_result, code)
+			local verify_ok, verify_err = verify_result:match("^([^\n]+)\n([^\n]+)");
+			if verify_ok == "true" then
+				callback(true);
+			else
+				callback(false, verify_err)
+			end
+		end);
+	end
+else
+	module:log("debug", "No Recaptcha options set, using fallback captcha")
+	local hmac_sha1 = require "util.hashes".hmac_sha1;
+	local secret = require "util.uuid".generate()
+	local ops = { '+', '-' };
+	local captcha_tpl = get_template "simplecaptcha";
+	function generate_captcha()
+		local op = ops[math.random(1, #ops)];
+		local x, y = math.random(1, 9)
+		repeat
+			y = math.random(1, 9);
+		until x ~= y;
+		local answer;
+		if op == '+' then
+			answer = x + y;
+		elseif op == '-' then
+			if x < y then
+				-- Avoid negative numbers
+				x, y = y, x;
+			end
+			answer = x - y;
 		end
-	}));
-end
-function verify_captcha(form, callback)
-	http.request("https://www.google.com/recaptcha/api/verify", {
-		body = http.formencode {
-			privatekey = captcha_options.recaptcha_private_key;
-			remoteip = request.conn:ip();
-			challenge = form.recaptcha_challenge_field;
-			response = form.recaptcha_response_field;
+		local challenge = hmac_sha1(secret, answer, true);
+		return captcha_tpl.apply {
+			op = op, x = x, y = y, challenge = challenge;
 		};
-	}, function (verify_result, code)
-		local verify_ok, verify_err = verify_result:match("^([^\n]+)\n([^\n]+)");
-		if verify_ok == "true" then
+	end
+	function verify_captcha(form, callback)
+		if hmac_sha1(secret, form.captcha_reply, true) == form.captcha_challenge then
 			callback(true);
 		else
-			callback(false, verify_err)
+			callback(false, "Captcha verification failed");
 		end
-	end);
+	end
 end
 
 function generate_page(event, display_options)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_register_web/templates/simplecaptcha.html	Sat Nov 30 19:00:38 2013 +0100
@@ -0,0 +1,5 @@
+<tr>
+  <th>What is {x} {op} {y}?</th><td>
+    <input name="captcha_challenge" type="hidden" value="{challenge}">
+    <input name="captcha_reply" pattern="[0-9]+" required type="number">
+  </td></tr>