|  | <?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(); | 
        
          |  | } | 
        
          |  | ?> |