|
<?php |
|
/** |
|
* PoWCaptcha - proof of work captcha |
|
* GitHub @pabloko (gists) |
|
*/ |
|
|
|
// BEGIN CONFIGURE |
|
|
|
$PRIV_TOKEN = "@@Your private and secret token@@"; // used as salt for integrity check |
|
$HASH_COUNT = 5; // amount of bytes to calculate on the proof-of-work |
|
$VALID_TIME = 3600; // time in seconds while token remains valid |
|
$ENABLE_API = true; //weather to allow api via GET |
|
|
|
// END CONFIGURE |
|
|
|
// Utility... |
|
function generateRandomString($length = 4) |
|
{ |
|
$characters = '0123456789abcdef'; |
|
$charactersLength = strlen($characters); |
|
$randomString = ''; |
|
for ($i = 0; $i < $length; $i++) |
|
$randomString .= $characters[random_int(0, $charactersLength - 1)]; |
|
return $randomString; |
|
} |
|
|
|
// Generate a fresh token valid for configured period of time |
|
function generateHashString() |
|
{ |
|
global $PRIV_TOKEN; global $HASH_COUNT; |
|
$rnd = generateRandomString(16); |
|
$timestamp = time(); |
|
$expectedPart = generateRandomString($HASH_COUNT); |
|
return base64_encode($rnd . ";" . $timestamp . ";" . sha1($rnd . ";" . $timestamp . ";" . $PRIV_TOKEN . ";" . $expectedPart) . ";" . $expectedPart . ";X-Response-Hash;"); |
|
} |
|
|
|
// Validate a PoW recalculated token with data |
|
function validateHashString($token) |
|
{ |
|
global $PRIV_TOKEN; global $VALID_TIME; |
|
$decodedString = base64_decode($token); |
|
$parts = explode(";", $decodedString); |
|
if (count($parts) !== 6) return null; |
|
$timeCheck = time() - (int)$parts[1]; |
|
// check is valid in time |
|
if ($timeCheck > $VALID_TIME || $timeCheck < 0) return null; |
|
// do integrity check |
|
if ($parts[2] !== sha1($parts[0] . ";" . (int)$parts[1] . ";" . $PRIV_TOKEN . ";" . $parts[3])) return null; |
|
// do proof-of-work verification |
|
if (!str_ends_with(sha1($parts[2] . $parts[5] . (int)$parts[4]), $parts[3])) return null; |
|
return base64_decode($parts[5]); |
|
} |
|
|
|
// simple API |
|
|
|
// obtain a fresh token |
|
// PoWCaptcha.php?getToken |
|
if ($ENABLE_API && isset($_GET['getToken'])) |
|
{ |
|
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); |
|
header("Cache-Control: post-check=0, pre-check=0", false); |
|
header("Pragma: no-cache"); |
|
|
|
die(generateHashString()); |
|
} |
|
|
|
// check a PoW recalculated token and output data or http error |
|
// PoWCaptcha.php?validateToken=XXXX... |
|
if ($ENABLE_API && isset($_GET['validateToken'])) |
|
{ |
|
header('Content-Type: application/json'); |
|
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); |
|
header("Cache-Control: post-check=0, pre-check=0", false); |
|
header("Pragma: no-cache"); |
|
|
|
$result = validateHashString($_GET['validateToken']); |
|
http_response_code($result ? 200 : 401); |
|
die($result); |
|
} |
|
|
|
// embeddable script output |
|
// PoWCaptcha.php?script |
|
if ($ENABLE_API && isset($_GET['script'])) |
|
{ |
|
header('Content-Type: application/javascript'); |
|
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); |
|
header("Cache-Control: post-check=0, pre-check=0", false); |
|
header("Pragma: no-cache"); |
|
|
|
?>/** |
|
* PoWCaptcha - proof of work captcha |
|
* GitHub @pabloko (gists) |
|
*/ |
|
<?php |
|
// function PoWCaptcha(data, callback) |
|
// { |
|
// var _token = '< ?php echo generateHashString(); ? >' |
|
// function createWorker(fn) |
|
// { |
|
// var blob = new Blob(['self.onmessage = ', fn.toString()], { type: 'text/javascript' }); |
|
// var url = window.URL.createObjectURL(blob); |
|
// return new Worker(url); |
|
// } |
|
// function tPoW(e) |
|
// { |
|
// function SHA1(f){function $(f,$){return f<<$|f>>>32-$}function r(f){var $,r,o,e="";for($=0;$<=6;$+=2)r=f>>>4*$+4&15,o=f>>>4*$&15,e+=r.toString(16)+o.toString(16);return e}function o(f){var $,r,o="";for($=7;$>=0;$--)o+=(r=f>>>4*$&15).toString(16);return o}var e,_,t,a,C,h,x,n,c,d=Array(80),A=1732584193,u=4023233417,s=2562383102,i=271733878,g=3285377520,m=(f=function f($){$=$.replace(/\r\n/g,"\n");for(var r="",o=0;o<$.length;o++){var e=$.charCodeAt(o);e<128?r+=String.fromCharCode(e):e>127&&e<2048?(r+=String.fromCharCode(e>>6|192),r+=String.fromCharCode(63&e|128)):(r+=String.fromCharCode(e>>12|224),r+=String.fromCharCode(e>>6&63|128),r+=String.fromCharCode(63&e|128))}return r}(f)).length,p=[];for(_=0;_<m-3;_+=4)t=f.charCodeAt(_)<<24|f.charCodeAt(_+1)<<16|f.charCodeAt(_+2)<<8|f.charCodeAt(_+3),p.push(t);switch(m%4){case 0:_=2147483648;break;case 1:_=f.charCodeAt(m-1)<<24|8388608;break;case 2:_=f.charCodeAt(m-2)<<24|f.charCodeAt(m-1)<<16|32768;break;case 3:_=f.charCodeAt(m-3)<<24|f.charCodeAt(m-2)<<16|f.charCodeAt(m-1)<<8|128}for(p.push(_);p.length%16!=14;)p.push(0);for(p.push(m>>>29),p.push(m<<3&4294967295),e=0;e<p.length;e+=16){for(_=0;_<16;_++)d[_]=p[e+_];for(_=16;_<=79;_++)d[_]=$(d[_-3]^d[_-8]^d[_-14]^d[_-16],1);for(_=0,a=A,C=u,h=s,x=i,n=g;_<=19;_++)c=$(a,5)+(C&h|~C&x)+n+d[_]+1518500249&4294967295,n=x,x=h,h=$(C,30),C=a,a=c;for(_=20;_<=39;_++)c=$(a,5)+(C^h^x)+n+d[_]+1859775393&4294967295,n=x,x=h,h=$(C,30),C=a,a=c;for(_=40;_<=59;_++)c=$(a,5)+(C&h|C&x|h&x)+n+d[_]+2400959708&4294967295,n=x,x=h,h=$(C,30),C=a,a=c;for(_=60;_<=79;_++)c=$(a,5)+(C^h^x)+n+d[_]+3395469782&4294967295,n=x,x=h,h=$(C,30),C=a,a=c;A=A+a&4294967295,u=u+C&4294967295,s=s+h&4294967295,i=i+x&4294967295,g=g+n&4294967295}var c=o(A)+o(u)+o(s)+o(i)+o(g);return c.toLowerCase()} |
|
// var pow = "" |
|
// try { |
|
// var part = atob(e.data).split(';') |
|
// if (part.length != 6 && part[4] !== "X-Response-Hash") return null; |
|
// var i = 0; |
|
// while(!SHA1(part[2] + part[5] + i).endsWith(part[3])) {i++;} |
|
// part[4] = i |
|
// pow = btoa(part.join(';')) |
|
// } catch (ex) { /*console.error(ex);*/ } |
|
// self.postMessage(pow) |
|
// } |
|
// var tPoWworker = createWorker(tPoW) |
|
// tPoWworker.postMessage(btoa(atob(_token) + btoa(JSON.stringify(data)))) |
|
// tPoWworker.onmessage = function (e) |
|
// { |
|
// if (callback) callback(e.data == "" ? null : e.data) |
|
// tPoWworker.terminate(); |
|
// } |
|
// } |
|
?>function PoWCaptcha(r,e){var t,o,a,n=(t=function r(e){function t(r){function e(r,e){return r<<e|r>>>32-e}function t(r){var e,t,o,a="";for(e=0;e<=6;e+=2)t=r>>>4*e+4&15,o=r>>>4*e&15,a+=t.toString(16)+o.toString(16);return a}function o(r){var e,t,o="";for(e=7;e>=0;e--)o+=(t=r>>>4*e&15).toString(16);return o}var a,n,_,h,c,f,s,$,C,i=Array(80),d=1732584193,u=4023233417,g=2562383102,p=271733878,l=3285377520,v=(r=function r(e){e=e.replace(/\r\n/g,"\n");for(var t="",o=0;o<e.length;o++){var a=e.charCodeAt(o);a<128?t+=String.fromCharCode(a):a>127&&a<2048?(t+=String.fromCharCode(a>>6|192),t+=String.fromCharCode(63&a|128)):(t+=String.fromCharCode(a>>12|224),t+=String.fromCharCode(a>>6&63|128),t+=String.fromCharCode(63&a|128))}return t}(r)).length,A=[];for(n=0;n<v-3;n+=4)_=r.charCodeAt(n)<<24|r.charCodeAt(n+1)<<16|r.charCodeAt(n+2)<<8|r.charCodeAt(n+3),A.push(_);switch(v%4){case 0:n=2147483648;break;case 1:n=r.charCodeAt(v-1)<<24|8388608;break;case 2:n=r.charCodeAt(v-2)<<24|r.charCodeAt(v-1)<<16|32768;break;case 3:n=r.charCodeAt(v-3)<<24|r.charCodeAt(v-2)<<16|r.charCodeAt(v-1)<<8|128}for(A.push(n);A.length%16!=14;)A.push(0);for(A.push(v>>>29),A.push(v<<3&4294967295),a=0;a<A.length;a+=16){for(n=0;n<16;n++)i[n]=A[a+n];for(n=16;n<=79;n++)i[n]=e(i[n-3]^i[n-8]^i[n-14]^i[n-16],1);for(n=0,h=d,c=u,f=g,s=p,$=l;n<=19;n++)C=e(h,5)+(c&f|~c&s)+$+i[n]+1518500249&4294967295,$=s,s=f,f=e(c,30),c=h,h=C;for(n=20;n<=39;n++)C=e(h,5)+(c^f^s)+$+i[n]+1859775393&4294967295,$=s,s=f,f=e(c,30),c=h,h=C;for(n=40;n<=59;n++)C=e(h,5)+(c&f|c&s|f&s)+$+i[n]+2400959708&4294967295,$=s,s=f,f=e(c,30),c=h,h=C;for(n=60;n<=79;n++)C=e(h,5)+(c^f^s)+$+i[n]+3395469782&4294967295,$=s,s=f,f=e(c,30),c=h,h=C;d=d+h&4294967295,u=u+c&4294967295,g=g+f&4294967295,p=p+s&4294967295,l=l+$&4294967295}var C=o(d)+o(u)+o(g)+o(p)+o(l);return C.toLowerCase()}var o="";try{var a=atob(e.data).split(";");if(6!=a.length&&"X-Response-Hash"!==a[4])return null;for(var n=0;!t(a[2]+a[5]+n).endsWith(a[3]);)n++;a[4]=n,o=btoa(a.join(";"))}catch(_){}self.postMessage(o)},o=new Blob(["self.onmessage = ",t.toString()],{type:"text/javascript"}),a=window.URL.createObjectURL(o),new Worker(a));n.postMessage(btoa(atob("<?php echo generateHashString(); ?>")+btoa(JSON.stringify(r)))),n.onmessage=function(r){e&&e(""==r.data?null:r.data),n.terminate()}}<?php |
|
die(); |
|
} |
|
?> |