Commit dfcaba37 authored by Sven Franck's avatar Sven Franck

added default client-side form securing

parent e37a3956
...@@ -285,9 +285,12 @@ html body .ui-btn.flag.ui-icon-flag-en:after {background-position: 0px -18px; } ...@@ -285,9 +285,12 @@ html body .ui-btn.flag.ui-icon-flag-en:after {background-position: 0px -18px; }
.ribbon:after { .ribbon:after {
right: 0; right: 0;
} }
/* ====================== recaptcha =================================== */ /* ====================== recaptcha/form spamhandling=================================== */
/* needed to prevent captcha CSS being overriden by ERP5 td height 34px */ /* needed to prevent captcha CSS being overriden by ERP5 td height 34px */
html body div#recaptcha_area table#recaptcha_table th, html body div#recaptcha_area table#recaptcha_table th,
html body div#recaptcha_area table#recaptcha_table td { html body div#recaptcha_area table#recaptcha_table td {
height: 6px; height: 6px;
}
html body form input.secure_form {
display: none;
} }
\ No newline at end of file
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
"class_list": "responsive", "class_list": "responsive",
"property_dict": { "property_dict": {
"editable": true, "editable": true,
"captcha": "captcha", "secure": "default",
"secret_hash": "foo",
"public_key": "6Ldpb-oSAAAAAGwriKpk4ol1n4yjN_as6M4xv0zA" "public_key": "6Ldpb-oSAAAAAGwriKpk4ol1n4yjN_as6M4xv0zA"
}, },
"children": [{ "children": [{
......
...@@ -13,11 +13,89 @@ ...@@ -13,11 +13,89 @@
erp5 = {}, erp5 = {},
// JQM content erateerator // JQM content erateerator
factory = {}, factory = {},
// Shims
shim_dict = {},
// renderJS // renderJS
javascript_registration_dict = {}, javascript_registration_dict = {},
renderJS = {}; renderJS = {};
/* ====================================================================== */
/* SHIMS */
/* ====================================================================== */
// NOTE: to support IE8+/Windows Mobile where possible, test via modernizr
// https://gist.github.com/yahiko/229984
shim_dict.Base64 = {
characters: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" ,
/**
* Shim for atob (not available on IE8+9+Windows Mobile?)
* @method Base64.encode
* @param {string} string String to be hashed
* @return {string} encoded string
*/
encode: function( string ) {
var characters = shim_dict.Base64.characters;
var result = '';
var i = 0;
do {
var a = string.charCodeAt(i++);
var b = string.charCodeAt(i++);
var c = string.charCodeAt(i++);
a = a ? a : 0;
b = b ? b : 0;
c = c ? c : 0;
var b1 = ( a >> 2 ) & 0x3F;
var b2 = ( ( a & 0x3 ) << 4 ) | ( ( b >> 4 ) & 0xF );
var b3 = ( ( b & 0xF ) << 2 ) | ( ( c >> 6 ) & 0x3 );
var b4 = c & 0x3F;
if( ! b ) {
b3 = b4 = 64;
} else if( ! c ) {
b4 = 64;
}
result += characters.charAt( b1 ) + characters.charAt( b2 ) +
characters.charAt( b3 ) + characters.charAt( b4 );
} while ( i < string.length );
return result;
},
/**
* Shim for btoa (not available on IE8+9+Windows Mobile?)
* @method Base64.decode
* @param {string} string String to be hashed
* @return {string} encoded string
*/
decode: function( string ) {
var characters = shim_dict.Base64.characters;
var result = '';
var i = 0;
do {
var b1 = characters.indexOf( string.charAt(i++) );
var b2 = characters.indexOf( string.charAt(i++) );
var b3 = characters.indexOf( string.charAt(i++) );
var b4 = characters.indexOf( string.charAt(i++) );
var a = ( ( b1 & 0x3F ) << 2 ) | ( ( b2 >> 4 ) & 0x3 );
var b = ( ( b2 & 0xF ) << 4 ) | ( ( b3 >> 2 ) & 0xF );
var c = ( ( b3 & 0x3 ) << 6 ) | ( b4 & 0x3F );
result += String.fromCharCode(a) + (b?String.fromCharCode(b):'') + (c?String.fromCharCode(c):'');
} while( i < string.length );
return result;
}
};
/* ====================================================================== */ /* ====================================================================== */
/* MAPPING ERP5 */ /* MAPPING ERP5 */
/* ====================================================================== */ /* ====================================================================== */
...@@ -1374,6 +1452,7 @@ ...@@ -1374,6 +1452,7 @@
* @return controlgroup * @return controlgroup
*/ */
// TODO: crap to use both layout and children! // TODO: crap to use both layout and children!
// NOTE: securing ? http://nedbatchelder.com/text/stopbots.html
factory.generateForm = function (spec) { factory.generateForm = function (spec) {
var i, var i,
j, j,
...@@ -1388,14 +1467,16 @@ ...@@ -1388,14 +1467,16 @@
doc, doc,
config, config,
value, value,
secure = spec.property_dict.captcha, stamp,
encode,
secure = spec.property_dict.secure,
safety_box, safety_box,
noscript, noscript,
fragment = factory.util.wrapInForm(spec), fragment = factory.util.wrapInForm(spec),
wrap = function (area, captcha) { wrap = function (area, captcha) {
var keys = {}; var keys = {};
// set key so it can be retrieved when binding the form // set optional captcha config
if (captcha) { if (captcha) {
keys.id = spec.id + "_captcha"; keys.id = spec.id + "_captcha";
keys["data-key"] = spec.property_dict.public_key; keys["data-key"] = spec.property_dict.public_key;
...@@ -1409,7 +1490,7 @@ ...@@ -1409,7 +1490,7 @@
); );
}; };
// form fields = layout // loop over form layout sections
for (i = 0; i < spec.layout.length; i += 1) { for (i = 0; i < spec.layout.length; i += 1) {
layout = spec.layout[i]; layout = spec.layout[i];
area = layout.position === "center" ? 2 : 1; area = layout.position === "center" ? 2 : 1;
...@@ -1444,23 +1525,69 @@ ...@@ -1444,23 +1525,69 @@
true, true,
position position
)); ));
// secure
if (j === 0 && secure === "default") {
stamp = new Date().getTime();
encode = window.atob || shim_dict.Base64.encode;
container.appendChild(factory.generateFormElement(
{
"type": "input",
"direct": {
"type": "text",
"value": "",
"className": "secure_form"
},
"attributes": {"data-enhanced":"true"},
"logic": {
"plain_element": true,
"label":"Please do not fill out this field",
"label_i18n": "global.form_helpers.secure_blank"
}
}
));
container.appendChild(factory.generateElement(
"input",
{
"type":"hidden",
"value":spec.property_dict.secret_hash,
"id": spec.id + "_not_a_secret"
},
{
"data-created": stamp
}
));
container.appendChild(factory.generateFormElement(
{
"type": "input",
"direct": {
"type": "text",
"value": encode(
stamp.toString() + spec.property_dict.secret_hash
),
"className": "secure_form"
},
"attributes": {"data-enhanced":"true"},
"logic": {
"plain_element": true,
"label":"Please leave this value unchanged",
"label_i18n": "global.form_helpers.secure_filled"
}
}
));
}
} }
fragment.appendChild(container); fragment.appendChild(container);
} }
// set captcha or anti spam protection // set captcha or anti spam protection
switch (secure) { if (secure === "captcha") {
case "default": if (spec.property_dict.public_key) {
console.log("secure silently") safety_box = wrap(1, true);
break; fragment.appendChild(safety_box);
case "captcha": } else {
if (spec.property_dict.public_key) { util.errorHandler({"error": "Captcha - No public key supplied"});
safety_box = wrap(1, true); }
fragment.appendChild(safety_box);
} else {
util.errorHandler({"error": "Captcha - No public key supplied"});
}
break;
} }
// children (default to 1 or 2? crap!) // children (default to 1 or 2? crap!)
...@@ -2646,7 +2773,9 @@ ...@@ -2646,7 +2773,9 @@
disabled + readonly + (action || "") + (clear || "") + (theme || ""); disabled + readonly + (action || "") + (clear || "") + (theme || "");
// container // container
if (config.type === "textarea" || config.logic.type === "hidden") { if (config.type === "textarea" ||
config.direct.type === "hidden" ||
config.logic.plain_element) {
container = wrapper; container = wrapper;
} else { } else {
wrap_in_container = true; wrap_in_container = true;
...@@ -2686,7 +2815,9 @@ ...@@ -2686,7 +2815,9 @@
// NOTE: for checkboxRadio validation, the label needs to be AFTER // NOTE: for checkboxRadio validation, the label needs to be AFTER
// the input, otherwise CSS sibling selector will not work. This saves // the input, otherwise CSS sibling selector will not work. This saves
// doing "invalid" handler with javascript // doing "invalid" handler with javascript
if (need_text_node === undefined && !label_inside) { if (need_text_node === undefined &&
!label_inside &&
config.logic.plain_element === undefined) {
label_target.appendChild(addLabel(config, label_class_list)); label_target.appendChild(addLabel(config, label_class_list));
} }
...@@ -3896,7 +4027,7 @@ ...@@ -3896,7 +4027,7 @@
form_element = form_list[j]; form_element = form_list[j];
captcha = document.getElementById(form_element.id + "_captcha"); captcha = document.getElementById(form_element.id + "_captcha");
// add captcha // captcha
if (captcha) { if (captcha) {
renderJS.declareJS( renderJS.declareJS(
"http://www.google.com/recaptcha/api/js/recaptcha_ajax.js" "http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"
......
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
"no_items": "No items found", "no_items": "No items found",
"back": "Back", "back": "Back",
"clear": "Delete" "clear": "Delete"
},
"form_helpers": {
"secure_blank": "Please do not fill out this field",
"secure_filled": "Please leave this value unchanged"
} }
}, },
"pages": { "pages": {
......
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
"no_items": "无法找到该项目", "no_items": "无法找到该项目",
"back": "后退", "back": "后退",
"clear": "删除" "clear": "删除"
},
"form_helpers": {
"secure_blank": "Please do not fill out this field",
"secure_filled": "Please leave this value unchanged"
} }
}, },
"pages": { "pages": {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment