@cap.js/widget 0.0.21 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cap.compat.min.js +1 -1
- package/cap.min.js +1 -1
- package/package.json +1 -1
- package/src/cap.js +81 -99
package/cap.compat.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";function _classPrivateFieldLooseBase(e,t){if(!{}.hasOwnProperty.call(e,t))throw new TypeError("attempted to use private field on non-instance");return e}var id=0;function _classPrivateFieldLooseKey(e){return"__private_"+id+++"_"+e}!function(){let e;const t=function(e,t){return void 0===t&&(t=1e4),new Promise(((s,a)=>{const i=setTimeout((()=>{a(new Error("Initialize timeout"))}),t),r=()=>{e()?(clearTimeout(i),s()):setTimeout(r,500)};r()}))};var s=_classPrivateFieldLooseKey("workerUrl"),a=_classPrivateFieldLooseKey("resetTimer"),i=_classPrivateFieldLooseKey("workersCount"),r=_classPrivateFieldLooseKey("token"),o=_classPrivateFieldLooseKey("shadow"),n=_classPrivateFieldLooseKey("div"),c=_classPrivateFieldLooseKey("host"),l=_classPrivateFieldLooseKey("solving"),d=_classPrivateFieldLooseKey("eventHandlers");class h extends HTMLElement{static get observedAttributes(){return["onsolve","onprogress","onreset","onerror","workers"]}constructor(){super(),Object.defineProperty(this,s,{writable:!0,value:""}),Object.defineProperty(this,a,{writable:!0,value:null}),Object.defineProperty(this,i,{writable:!0,value:navigator.hardwareConcurrency||8}),Object.defineProperty(this,r,{writable:!0,value:null}),Object.defineProperty(this,o,{writable:!0,value:void 0}),Object.defineProperty(this,n,{writable:!0,value:void 0}),Object.defineProperty(this,c,{writable:!0,value:void 0}),Object.defineProperty(this,l,{writable:!0,value:!1}),Object.defineProperty(this,d,{writable:!0,value:void 0}),_classPrivateFieldLooseBase(this,d)[d]&&_classPrivateFieldLooseBase(this,d)[d].forEach(((e,t)=>{this.removeEventListener(t.slice(2),e)})),_classPrivateFieldLooseBase(this,d)[d]=new Map,this.boundHandleProgress=this.handleProgress.bind(this),this.boundHandleSolve=this.handleSolve.bind(this),this.boundHandleError=this.handleError.bind(this),this.boundHandleReset=this.handleReset.bind(this)}async initialize(){_classPrivateFieldLooseBase(this,s)[s]&&URL.revokeObjectURL(_classPrivateFieldLooseBase(this,s)[s]);try{await t((()=>!!e)),_classPrivateFieldLooseBase(this,s)[s]=URL.createObjectURL(new Blob([e],{type:"application/javascript"}))}catch(e){throw this.error("Failed to initialize worker"),e}}attributeChangedCallback(e,t,s){if(e.startsWith("on")){const t=e.slice(2),a=_classPrivateFieldLooseBase(this,d)[d].get(e);if(a&&this.removeEventListener(t,a),s){const s=t=>{const s=this.getAttribute(e);"function"==typeof window[s]&&window[s].call(this,t)};_classPrivateFieldLooseBase(this,d)[d].set(e,s),this.addEventListener(t,s)}}}async connectedCallback(){_classPrivateFieldLooseBase(this,c)[c]=this,_classPrivateFieldLooseBase(this,o)[o]=this.attachShadow({mode:"open"}),_classPrivateFieldLooseBase(this,n)[n]=document.createElement("div"),this.createUI(),this.addEventListeners(),await this.initialize(),_classPrivateFieldLooseBase(this,n)[n].removeAttribute("disabled");const e=this.getAttribute("data-cap-worker-count");this.setWorkersCount(parseInt(e)?parseInt(e,10):navigator.hardwareConcurrency||8),_classPrivateFieldLooseBase(this,c)[c].innerHTML='<input type="hidden" name="cap-token">'}async solve(){if(!_classPrivateFieldLooseBase(this,l)[l])try{_classPrivateFieldLooseBase(this,l)[l]=!0,this.updateUI("verifying","Verifying...",!0),await t((()=>!!_classPrivateFieldLooseBase(this,s)[s])),this.dispatchEvent("progress",{progress:0});try{const e=this.getAttribute("data-cap-api-endpoint");if(!e)throw new Error("Missing API endpoint");const{challenge:t,token:s}=await(await fetch(`${e}challenge`,{method:"POST"})).json(),i=await this.solveChallenges(t),o=await(await fetch(`${e}redeem`,{method:"POST",body:JSON.stringify({token:s,solutions:i}),headers:{"Content-Type":"application/json"}})).json();if(this.dispatchEvent("progress",{progress:100}),!o.success)throw new Error("Invalid solution");this.querySelector("input[name='cap-token']")&&(this.querySelector("input[name='cap-token']").value=o.token),this.dispatchEvent("solve",{token:o.token}),_classPrivateFieldLooseBase(this,r)[r]=o.token,_classPrivateFieldLooseBase(this,a)[a]&&clearTimeout(_classPrivateFieldLooseBase(this,a)[a]);const n=new Date(o.expires).getTime()-Date.now();return n>0&&n<864e5?_classPrivateFieldLooseBase(this,a)[a]=setTimeout((()=>this.reset()),n):this.error("Invalid expiration time"),{success:!0,token:_classPrivateFieldLooseBase(this,r)[r]}}catch(e){throw this.error(e.message),e}}finally{_classPrivateFieldLooseBase(this,l)[l]=!1}}async solveChallenges(e){const t=e.length;let a=0;const r=Array(_classPrivateFieldLooseBase(this,i)[i]).fill(null).map((()=>new Worker(_classPrivateFieldLooseBase(this,s)[s]))),o=(e,i)=>{let[o,n]=e;return new Promise(((e,c)=>{const l=r[i],d=setTimeout((()=>{l.terminate(),r[i]=new Worker(_classPrivateFieldLooseBase(this,s)[s]),c(new Error("Worker timeout"))}),3e4);l.onmessage=s=>{let{data:i}=s;i.found&&(clearTimeout(d),a++,this.dispatchEvent("progress",{progress:Math.round(a/t*100)}),e([o,n,i.nonce]))},l.onerror=e=>{clearTimeout(d),this.error(`Error in worker: ${e}`),c(e)},l.postMessage({salt:o,target:n})}))},n=[];try{for(let t=0;t<e.length;t+=_classPrivateFieldLooseBase(this,i)[i]){const s=e.slice(t,Math.min(t+_classPrivateFieldLooseBase(this,i)[i],e.length)),a=await Promise.all(s.map(((e,t)=>o(e,t))));n.push(...a)}}finally{r.forEach((e=>e.terminate()))}return n}setWorkersCount(e){const t=parseInt(e,10),s=Math.min(navigator.hardwareConcurrency||8,16);_classPrivateFieldLooseBase(this,i)[i]=!isNaN(t)&&t>0&&t<=s?t:navigator.hardwareConcurrency||8}createUI(){_classPrivateFieldLooseBase(this,n)[n].classList.add("captcha"),_classPrivateFieldLooseBase(this,n)[n].setAttribute("role","button"),_classPrivateFieldLooseBase(this,n)[n].setAttribute("tabindex","0"),_classPrivateFieldLooseBase(this,n)[n].setAttribute("disabled","true"),_classPrivateFieldLooseBase(this,n)[n].innerHTML='<div class="checkbox"></div><p>I\'m a human</p><a href="https://capjs.js.org/" class="credits" target="_blank" rel="follow noopener"><span>Secured by </span>Cap</a>',_classPrivateFieldLooseBase(this,o)[o].innerHTML='<style>.captcha{background-color:var(--cap-background);border:1px solid var(--cap-border-color);border-radius:var(--cap-border-radius);width:var(--cap-widget-width);display:flex;align-items:center;padding:var(--cap-widget-padding);gap:var(--cap-gap);cursor:pointer;transition:filter var(--cap-transition-duration),transform var(--cap-transition-duration);position:relative;-webkit-tap-highlight-color:rgba(255,255,255,0);overflow:hidden;color:var(--cap-color)}.captcha:hover{filter:var(--cap-hover-filter)}.captcha:not([disabled]):active{transform:scale(var(--cap-active-scale))}.checkbox{width:var(--cap-checkbox-size);height:var(--cap-checkbox-size);border:var(--cap-checkbox-border);border-radius:var(--cap-checkbox-border-radius);background-color:var(--cap-checkbox-background);transition:opacity var(--cap-transition-duration);margin-top:var(--cap-checkbox-margin);margin-bottom:var(--cap-checkbox-margin)}.captcha *{font-family:var(--cap-font)}.captcha p{margin:0;font-weight:500;font-size:15px;user-select:none;transition:opacity var(--cap-transition-duration)}.captcha[data-state=verifying] .checkbox{background: none;display:flex;align-items:center;justify-content:center;transform: scale(1.1);border: none;border-radius: 50%;background: conic-gradient(var(--cap-spinner-color) 0%, var(--cap-spinner-color) var(--progress, 0%), var(--cap-spinner-background-color) var(--progress, 0%), var(--cap-spinner-background-color) 100%);position: relative;}.captcha[data-state=verifying] .checkbox::after {content: "";background-color: var(--cap-background);width: calc(100% - var(--cap-spinner-thickness));height: calc(100% - var(--cap-spinner-thickness));border-radius: 50%;margin:calc(var(--cap-spinner-thickness) / 2)}.captcha[data-state=done] .checkbox{border:1px solid transparent;background-image:var(--cap-checkmark);background-size:cover}.captcha[data-state=error] .checkbox{border:1px solid transparent;background-image:var(--cap-error-cross);background-size:cover}.captcha[disabled]{\ncursor:not-allowed}.captcha[disabled][data-state=verifying]{cursor:progress}.captcha[disabled][data-state=done]{cursor:default}.captcha .credits{position:absolute;bottom:10px;right:10px;font-size:var(--cap-credits-font-size);color:var(--cap-color);opacity:var(--cap-opacity-hover)}.captcha .credits span{display:none;text-decoration:underline}.captcha .credits:hover span{display:inline-block}</style>',_classPrivateFieldLooseBase(this,o)[o].appendChild(_classPrivateFieldLooseBase(this,n)[n])}addEventListeners(){_classPrivateFieldLooseBase(this,n)[n].querySelector("a").addEventListener("click",(e=>{e.stopPropagation(),e.preventDefault(),window.open("https://capjs.js.org","_blank")})),_classPrivateFieldLooseBase(this,n)[n].addEventListener("click",(()=>{_classPrivateFieldLooseBase(this,n)[n].hasAttribute("disabled")||this.solve()})),_classPrivateFieldLooseBase(this,n)[n].addEventListener("keydown",(e=>{"Enter"!==e.key&&" "!==e.key||_classPrivateFieldLooseBase(this,n)[n].hasAttribute("disabled")||(e.preventDefault(),this.solve())})),this.addEventListener("progress",this.boundHandleProgress),this.addEventListener("solve",this.boundHandleSolve),this.addEventListener("error",this.boundHandleError),this.addEventListener("reset",this.boundHandleReset)}updateUI(e,t,s){void 0===s&&(s=!1),_classPrivateFieldLooseBase(this,n)[n].setAttribute("data-state",e),_classPrivateFieldLooseBase(this,n)[n].querySelector("p").innerText=t,s?_classPrivateFieldLooseBase(this,n)[n].setAttribute("disabled","true"):_classPrivateFieldLooseBase(this,n)[n].removeAttribute("disabled")}handleProgress(e){const t=_classPrivateFieldLooseBase(this,n)[n].querySelector("p");t&&(_classPrivateFieldLooseBase(this,n)[n].querySelector(".checkbox").style.setProperty("--progress",`${e.detail.progress}%`),t.innerText=`Verifying... ${e.detail.progress}%`),this.executeAttributeCode("onprogress",e)}handleSolve(e){this.updateUI("done","You're a human",!0),this.executeAttributeCode("onsolve",e)}handleError(e){this.updateUI("error","Error. Try again."),this.executeAttributeCode("onerror",e)}handleReset(e){this.updateUI("","I'm a human"),this.executeAttributeCode("onreset",e)}executeAttributeCode(e,t){const s=this.getAttribute(e);if(!s)return;new Function("event",s).call(this,t)}error(e){void 0===e&&(e="Unknown error"),console.error("[Cap] Error:",e),this.dispatchEvent("error",{isCap:!0,message:e})}dispatchEvent(e,t){void 0===t&&(t={});const s=new CustomEvent(e,{bubbles:!0,composed:!0,detail:t});super.dispatchEvent(s)}reset(){_classPrivateFieldLooseBase(this,a)[a]&&(clearTimeout(_classPrivateFieldLooseBase(this,a)[a]),_classPrivateFieldLooseBase(this,a)[a]=null),this.dispatchEvent("reset"),_classPrivateFieldLooseBase(this,r)[r]=null,this.querySelector("input[name='cap-token']")&&(this.querySelector("input[name='cap-token']").value="")}get token(){return _classPrivateFieldLooseBase(this,r)[r]}disconnectedCallback(){this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),_classPrivateFieldLooseBase(this,d)[d].forEach(((e,t)=>{this.removeEventListener(t.slice(2),e)})),_classPrivateFieldLooseBase(this,d)[d].clear(),_classPrivateFieldLooseBase(this,o)[o]&&(_classPrivateFieldLooseBase(this,o)[o].innerHTML=""),this.reset(),this.cleanup()}cleanup(){_classPrivateFieldLooseBase(this,a)[a]&&(clearTimeout(_classPrivateFieldLooseBase(this,a)[a]),_classPrivateFieldLooseBase(this,a)[a]=null),_classPrivateFieldLooseBase(this,s)[s]&&(URL.revokeObjectURL(_classPrivateFieldLooseBase(this,s)[s]),_classPrivateFieldLooseBase(this,s)[s]="")}}class p{constructor(e,t){void 0===e&&(e={});let s=t||document.createElement("cap-widget");if(Object.entries(e).forEach((e=>{let[t,a]=e;s.setAttribute(t,a)})),!e.apiEndpoint)throw s.remove(),new Error("Missing API endpoint");s.setAttribute("data-cap-api-endpoint",e.apiEndpoint),this.widget=s,this.solve=this.widget.solve.bind(this.widget),this.reset=this.widget.reset.bind(this.widget),this.addEventListener=this.widget.addEventListener.bind(this.widget),Object.defineProperty(this,"token",{get:()=>s.getToken(),configurable:!0,enumerable:!0}),t||(s.style.display="none",document.documentElement.appendChild(s))}}const v=new CSSStyleSheet;v.replaceSync('html{--cap-font:system,-apple-system,"BlinkMacSystemFont",".SFNSText-Regular","San Francisco","Roboto","Segoe UI","Helvetica Neue","Lucida Grande","Ubuntu","arial",sans-serif;--cap-color:#212121;--cap-background:#fdfdfd;--cap-border-color:#dddddd8f;--cap-border-radius:14px;--cap-checkbox-border:1px solid #aaaaaad1;--cap-checkbox-border-radius:6px;--cap-checkbox-background:#fafafa91;--cap-widget-width:240px;--cap-widget-padding:14px;--cap-checkbox-size:24px;--cap-checkbox-margin:2px;--cap-transition-duration:0.2s;--cap-gap:15px;--cap-opacity-hover:0.8;--cap-hover-filter:brightness(97%);--cap-active-scale:0.98;--cap-credits-font-size:12px;--cap-spinner-color:black;--cap-spinner-background-color:#eee;--cap-error-cross:url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'96\' height=\'96\' viewBox=\'0 0 24 24\'%3E%3Cpath fill=\'%23f55b50\' d=\'M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8\'/%3E%3C/svg%3E");--cap-checkmark:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E");--cap-spinner-thickness:5px;}'),document.adoptedStyleSheets.push(v);const u=function(){let e;self.onmessage=async t=>{let{data:{salt:s,target:a}}=t,i=0;const r=5e4;let o=0;const n=new TextEncoder;if("object"!=typeof WebAssembly||"function"!=typeof WebAssembly.instantiate){console.log("[cap] WASM not enabled, falling back to crypto.subtle\nThis is significanty slower than the WASM implementation");const e=new Uint8Array(a.length/2);for(let t=0;t<e.length;t++)e[t]=parseInt(a.substring(2*t,2*t+2),16);const t=e.length;for(;;)try{for(let a=0;a<r;a++){const a=s+i,r=n.encode(a),o=await crypto.subtle.digest("SHA-256",r),c=new Uint8Array(o,0,t);let l=!0;for(let s=0;s<t;s++)if(c[s]!==e[s]){l=!1;break}if(l)return void self.postMessage({nonce:i,found:!0});i++}o+=r}catch(e){return console.error("[cap] fallback worker error",e),void self.postMessage({found:!1,error:e.message})}}e||(e=await hashwasm.createSHA256());const c=new Uint8Array(128);for(;;)try{for(let t=0;t<r;t++){const t=s+i.toString(),r=n.encode(t);c.set(r),e.init(),e.update(c.subarray(0,r.length));if(e.digest("hex").startsWith(a))return void self.postMessage({nonce:i,found:!0});i++}o+=r}catch(e){return void self.postMessage({found:!1,error:e.message})}}};setTimeout((async function(){e=await(await fetch("https://cdn.jsdelivr.net/npm/@cap.js/widget/wasm-hashes.min.js")).text()+u.toString().replace(/^function\s*\([^\)]*\)\s*{|\}$/g,"").trim()}),1),window.Cap=p,customElements.get("cap-widget")?console.warn("The cap-widget element has already been defined. Skipping re-defining it."):customElements.define("cap-widget",h),"object"==typeof exports&&"undefined"!=typeof module?module.exports=p:"function"==typeof define&&define.amd&&define([],(function(){return p})),"undefined"!=typeof exports&&(exports.default=p)}();
|
|
1
|
+
"use strict";function _getRequireWildcardCache(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,s=new WeakMap;return(_getRequireWildcardCache=function(e){return e?s:t})(e)}function _interopRequireWildcard(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var s=_getRequireWildcardCache(t);if(s&&s.has(e))return s.get(e);var a={__proto__:null},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&{}.hasOwnProperty.call(e,i)){var o=r?Object.getOwnPropertyDescriptor(e,i):null;o&&(o.get||o.set)?Object.defineProperty(a,i,o):a[i]=e[i]}return a.default=e,s&&s.set(e,a),a}function _classPrivateFieldLooseBase(e,t){if(!{}.hasOwnProperty.call(e,t))throw new TypeError("attempted to use private field on non-instance");return e}var id=0;function _classPrivateFieldLooseKey(e){return"__private_"+id+++"_"+e}!function(){let e;const t=function(){var e;return null!=(e=window)&&e.CAP_CUSTOM_FETCH?window.CAP_CUSTOM_FETCH(...arguments):fetch(...arguments)};var s=_classPrivateFieldLooseKey("workerUrl"),a=_classPrivateFieldLooseKey("resetTimer"),r=_classPrivateFieldLooseKey("workersCount"),i=_classPrivateFieldLooseKey("shadow"),o=_classPrivateFieldLooseKey("div"),n=_classPrivateFieldLooseKey("host"),c=_classPrivateFieldLooseKey("solving"),l=_classPrivateFieldLooseKey("eventHandlers");class d extends HTMLElement{static get observedAttributes(){return["onsolve","onprogress","onreset","onerror","workers"]}constructor(){super(),Object.defineProperty(this,s,{writable:!0,value:""}),Object.defineProperty(this,a,{writable:!0,value:null}),Object.defineProperty(this,r,{writable:!0,value:navigator.hardwareConcurrency||8}),this.token=null,Object.defineProperty(this,i,{writable:!0,value:void 0}),Object.defineProperty(this,o,{writable:!0,value:void 0}),Object.defineProperty(this,n,{writable:!0,value:void 0}),Object.defineProperty(this,c,{writable:!0,value:!1}),Object.defineProperty(this,l,{writable:!0,value:void 0}),_classPrivateFieldLooseBase(this,l)[l]&&_classPrivateFieldLooseBase(this,l)[l].forEach(((e,t)=>{this.removeEventListener(t.slice(2),e)})),_classPrivateFieldLooseBase(this,l)[l]=new Map,this.boundHandleProgress=this.handleProgress.bind(this),this.boundHandleSolve=this.handleSolve.bind(this),this.boundHandleError=this.handleError.bind(this),this.boundHandleReset=this.handleReset.bind(this)}initialize(){_classPrivateFieldLooseBase(this,s)[s]=URL.createObjectURL(new Blob([e],{type:"application/javascript"}))}attributeChangedCallback(e,t,s){if(e.startsWith("on")){const t=e.slice(2),a=_classPrivateFieldLooseBase(this,l)[l].get(e);if(a&&this.removeEventListener(t,a),s){const s=t=>{const s=this.getAttribute(e);"function"==typeof window[s]&&window[s].call(this,t)};_classPrivateFieldLooseBase(this,l)[l].set(e,s),this.addEventListener(t,s)}}}async connectedCallback(){_classPrivateFieldLooseBase(this,n)[n]=this,_classPrivateFieldLooseBase(this,i)[i]=this.attachShadow({mode:"open"}),_classPrivateFieldLooseBase(this,o)[o]=document.createElement("div"),this.createUI(),this.addEventListeners(),await this.initialize(),_classPrivateFieldLooseBase(this,o)[o].removeAttribute("disabled");const e=this.getAttribute("data-cap-worker-count");this.setWorkersCount(parseInt(e)?parseInt(e,10):navigator.hardwareConcurrency||8),_classPrivateFieldLooseBase(this,n)[n].innerHTML='<input type="hidden" name="cap-token">'}async solve(){if(!_classPrivateFieldLooseBase(this,c)[c])try{_classPrivateFieldLooseBase(this,c)[c]=!0,this.updateUI("verifying","Verifying...",!0),this.dispatchEvent("progress",{progress:0});try{const e=this.getAttribute("data-cap-api-endpoint");if(!e)throw new Error("Missing API endpoint");const{challenge:s,token:r}=await(await t(`${e}challenge`,{method:"POST"})).json(),i=await this.solveChallenges(s),o=await(await t(`${e}redeem`,{method:"POST",body:JSON.stringify({token:r,solutions:i}),headers:{"Content-Type":"application/json"}})).json();if(this.dispatchEvent("progress",{progress:100}),!o.success)throw new Error("Invalid solution");this.querySelector("input[name='cap-token']")&&(this.querySelector("input[name='cap-token']").value=o.token),this.dispatchEvent("solve",{token:o.token}),this.token=o.token,_classPrivateFieldLooseBase(this,a)[a]&&clearTimeout(_classPrivateFieldLooseBase(this,a)[a]);const n=new Date(o.expires).getTime()-Date.now();return n>0&&n<864e5?_classPrivateFieldLooseBase(this,a)[a]=setTimeout((()=>this.reset()),n):this.error("Invalid expiration time"),{success:!0,token:this.token}}catch(e){throw this.error(e.message),e}}finally{_classPrivateFieldLooseBase(this,c)[c]=!1}}async solveChallenges(e){const t=e.length;let a=0;const i=Array(_classPrivateFieldLooseBase(this,r)[r]).fill(null).map((()=>new Worker(_classPrivateFieldLooseBase(this,s)[s]))),o=(e,r)=>{let[o,n]=e;return new Promise(((e,c)=>{const l=i[r],d=setTimeout((()=>{l.terminate(),i[r]=new Worker(_classPrivateFieldLooseBase(this,s)[s]),c(new Error("Worker timeout"))}),3e4);l.onmessage=s=>{let{data:r}=s;r.found&&(clearTimeout(d),a++,this.dispatchEvent("progress",{progress:Math.round(a/t*100)}),e([o,n,r.nonce]))},l.onerror=e=>{clearTimeout(d),this.error(`Error in worker: ${e}`),c(e)},l.postMessage({salt:o,target:n})}))},n=[];try{for(let t=0;t<e.length;t+=_classPrivateFieldLooseBase(this,r)[r]){const s=e.slice(t,Math.min(t+_classPrivateFieldLooseBase(this,r)[r],e.length)),a=await Promise.all(s.map(((e,t)=>o(e,t))));n.push(...a)}}finally{i.forEach((e=>e.terminate()))}return n}setWorkersCount(e){const t=parseInt(e,10),s=Math.min(navigator.hardwareConcurrency||8,16);_classPrivateFieldLooseBase(this,r)[r]=!isNaN(t)&&t>0&&t<=s?t:navigator.hardwareConcurrency||8}createUI(){_classPrivateFieldLooseBase(this,o)[o].classList.add("captcha"),_classPrivateFieldLooseBase(this,o)[o].setAttribute("role","button"),_classPrivateFieldLooseBase(this,o)[o].setAttribute("tabindex","0"),_classPrivateFieldLooseBase(this,o)[o].setAttribute("disabled","true"),_classPrivateFieldLooseBase(this,o)[o].innerHTML='<div class="checkbox"></div><p>I\'m a human</p><a href="https://capjs.js.org/" class="credits" target="_blank" rel="follow noopener"><span>Secured by </span>Cap</a>',_classPrivateFieldLooseBase(this,i)[i].innerHTML='<style>.captcha{background-color:var(--cap-background);border:1px solid var(--cap-border-color);border-radius:var(--cap-border-radius);width:var(--cap-widget-width);display:flex;align-items:center;padding:var(--cap-widget-padding);gap:var(--cap-gap);cursor:pointer;transition:filter var(--cap-transition-duration),transform var(--cap-transition-duration);position:relative;-webkit-tap-highlight-color:rgba(255,255,255,0);overflow:hidden;color:var(--cap-color)}.captcha:hover{filter:var(--cap-hover-filter)}.captcha:not([disabled]):active{transform:scale(var(--cap-active-scale))}.checkbox{width:var(--cap-checkbox-size);height:var(--cap-checkbox-size);border:var(--cap-checkbox-border);border-radius:var(--cap-checkbox-border-radius);background-color:var(--cap-checkbox-background);transition:opacity var(--cap-transition-duration);margin-top:var(--cap-checkbox-margin);margin-bottom:var(--cap-checkbox-margin)}.captcha *{font-family:var(--cap-font)}.captcha p{margin:0;font-weight:500;font-size:15px;user-select:none;transition:opacity var(--cap-transition-duration)}.captcha[data-state=verifying] .checkbox{background: none;display:flex;align-items:center;justify-content:center;transform: scale(1.1);border: none;border-radius: 50%;background: conic-gradient(var(--cap-spinner-color) 0%, var(--cap-spinner-color) var(--progress, 0%), var(--cap-spinner-background-color) var(--progress, 0%), var(--cap-spinner-background-color) 100%);position: relative;}.captcha[data-state=verifying] .checkbox::after {content: "";background-color: var(--cap-background);width: calc(100% - var(--cap-spinner-thickness));height: calc(100% - var(--cap-spinner-thickness));border-radius: 50%;margin:calc(var(--cap-spinner-thickness) / 2)}.captcha[data-state=done] .checkbox{border:1px solid transparent;background-image:var(--cap-checkmark);background-size:cover}.captcha[data-state=error] .checkbox{border:1px solid transparent;background-image:var(--cap-error-cross);background-size:cover}.captcha[disabled]{\ncursor:not-allowed}.captcha[disabled][data-state=verifying]{cursor:progress}.captcha[disabled][data-state=done]{cursor:default}.captcha .credits{position:absolute;bottom:10px;right:10px;font-size:var(--cap-credits-font-size);color:var(--cap-color);opacity:var(--cap-opacity-hover)}.captcha .credits span{display:none;text-decoration:underline}.captcha .credits:hover span{display:inline-block}</style>',_classPrivateFieldLooseBase(this,i)[i].appendChild(_classPrivateFieldLooseBase(this,o)[o])}addEventListeners(){_classPrivateFieldLooseBase(this,o)[o].querySelector("a").addEventListener("click",(e=>{e.stopPropagation(),e.preventDefault(),window.open("https://capjs.js.org","_blank")})),_classPrivateFieldLooseBase(this,o)[o].addEventListener("click",(()=>{_classPrivateFieldLooseBase(this,o)[o].hasAttribute("disabled")||this.solve()})),_classPrivateFieldLooseBase(this,o)[o].addEventListener("keydown",(e=>{"Enter"!==e.key&&" "!==e.key||_classPrivateFieldLooseBase(this,o)[o].hasAttribute("disabled")||(e.preventDefault(),this.solve())})),this.addEventListener("progress",this.boundHandleProgress),this.addEventListener("solve",this.boundHandleSolve),this.addEventListener("error",this.boundHandleError),this.addEventListener("reset",this.boundHandleReset)}updateUI(e,t,s){void 0===s&&(s=!1),_classPrivateFieldLooseBase(this,o)[o].setAttribute("data-state",e),_classPrivateFieldLooseBase(this,o)[o].querySelector("p").innerText=t,s?_classPrivateFieldLooseBase(this,o)[o].setAttribute("disabled","true"):_classPrivateFieldLooseBase(this,o)[o].removeAttribute("disabled")}handleProgress(e){const t=_classPrivateFieldLooseBase(this,o)[o].querySelector("p");t&&(_classPrivateFieldLooseBase(this,o)[o].querySelector(".checkbox").style.setProperty("--progress",`${e.detail.progress}%`),t.innerText=`Verifying... ${e.detail.progress}%`),this.executeAttributeCode("onprogress",e)}handleSolve(e){this.updateUI("done","You're a human",!0),this.executeAttributeCode("onsolve",e)}handleError(e){this.updateUI("error","Error. Try again."),this.executeAttributeCode("onerror",e)}handleReset(e){this.updateUI("","I'm a human"),this.executeAttributeCode("onreset",e)}executeAttributeCode(e,t){const s=this.getAttribute(e);if(!s)return;new Function("event",s).call(this,t)}error(e){void 0===e&&(e="Unknown error"),console.error("[cap] Error:",e),this.dispatchEvent("error",{isCap:!0,message:e})}dispatchEvent(e,t){void 0===t&&(t={});const s=new CustomEvent(e,{bubbles:!0,composed:!0,detail:t});super.dispatchEvent(s)}reset(){_classPrivateFieldLooseBase(this,a)[a]&&(clearTimeout(_classPrivateFieldLooseBase(this,a)[a]),_classPrivateFieldLooseBase(this,a)[a]=null),this.dispatchEvent("reset"),this.token=null,this.querySelector("input[name='cap-token']")&&(this.querySelector("input[name='cap-token']").value="")}get token(){return this.token}disconnectedCallback(){this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),_classPrivateFieldLooseBase(this,l)[l].forEach(((e,t)=>{this.removeEventListener(t.slice(2),e)})),_classPrivateFieldLooseBase(this,l)[l].clear(),_classPrivateFieldLooseBase(this,i)[i]&&(_classPrivateFieldLooseBase(this,i)[i].innerHTML=""),this.reset(),this.cleanup()}cleanup(){_classPrivateFieldLooseBase(this,a)[a]&&(clearTimeout(_classPrivateFieldLooseBase(this,a)[a]),_classPrivateFieldLooseBase(this,a)[a]=null),_classPrivateFieldLooseBase(this,s)[s]&&(URL.revokeObjectURL(_classPrivateFieldLooseBase(this,s)[s]),_classPrivateFieldLooseBase(this,s)[s]="")}}class h{constructor(e,t){void 0===e&&(e={});let s=t||document.createElement("cap-widget");if(Object.entries(e).forEach((e=>{let[t,a]=e;s.setAttribute(t,a)})),!e.apiEndpoint)throw s.remove(),new Error("Missing API endpoint");s.setAttribute("data-cap-api-endpoint",e.apiEndpoint),this.widget=s,this.solve=this.widget.solve.bind(this.widget),this.reset=this.widget.reset.bind(this.widget),this.addEventListener=this.widget.addEventListener.bind(this.widget),Object.defineProperty(this,"token",{get:()=>s.getToken(),configurable:!0,enumerable:!0}),t||(s.style.display="none",document.documentElement.appendChild(s))}}const p=new CSSStyleSheet;p.replaceSync('html{--cap-font:system,-apple-system,"BlinkMacSystemFont",".SFNSText-Regular","San Francisco","Roboto","Segoe UI","Helvetica Neue","Lucida Grande","Ubuntu","arial",sans-serif;--cap-color:#212121;--cap-background:#fdfdfd;--cap-border-color:#dddddd8f;--cap-border-radius:14px;--cap-checkbox-border:1px solid #aaaaaad1;--cap-checkbox-border-radius:6px;--cap-checkbox-background:#fafafa91;--cap-widget-width:240px;--cap-widget-padding:14px;--cap-checkbox-size:24px;--cap-checkbox-margin:2px;--cap-transition-duration:0.2s;--cap-gap:15px;--cap-opacity-hover:0.8;--cap-hover-filter:brightness(97%);--cap-active-scale:0.98;--cap-credits-font-size:12px;--cap-spinner-color:black;--cap-spinner-background-color:#eee;--cap-error-cross:url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'96\' height=\'96\' viewBox=\'0 0 24 24\'%3E%3Cpath fill=\'%23f55b50\' d=\'M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8\'/%3E%3C/svg%3E");--cap-checkmark:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E");--cap-spinner-thickness:5px;}'),document.adoptedStyleSheets.push(p);e=`(() => {${function(){var e;let t,s;if("object"!=typeof WebAssembly||"function"!=typeof(null==(e=WebAssembly)?void 0:e.instantiate))return self.onmessage=async e=>{let{data:{salt:t,target:s}}=e,a=0;let r=0;const i=new TextEncoder,o=new Uint8Array(s.length/2);for(let e=0;e<o.length;e++)o[e]=parseInt(s.substring(2*e,2*e+2),16);const n=o.length;for(;;)try{for(let e=0;e<5e4;e++){const e=t+a,s=i.encode(e),r=await crypto.subtle.digest("SHA-256",s),c=new Uint8Array(r,0,n);let l=!0;for(let e=0;e<n;e++)if(c[e]!==o[e]){l=!1;break}if(l)return void self.postMessage({nonce:a,found:!0});a++}r+=5e4}catch(e){return console.error("[cap] fallback worker error",e),void self.postMessage({found:!1,error:e.message})}},console.warn("[cap] WebAssembly is not supported, falling back to alternative solver.");t=Promise.resolve().then((()=>_interopRequireWildcard(require("https://cdn.jsdelivr.net/npm/@cap.js/wasm@0.0.3/browser/cap_wasm.min.js")))).then((e=>e.default().then((t=>{s=(t&&t.exports?t.exports:e).solve_pow})))).catch((e=>{useFallback=!0,console.error("[cap] using fallback solver due to error:",e)})),self.onmessage=async e=>{let{data:{salt:a,target:r}}=e;try{await t;const e=performance.now(),i=s(a,r),o=performance.now();self.postMessage({nonce:Number(i),found:!0,durationMs:(o-e).toFixed(2)})}catch(e){initError||(console.error("[cap] solver error",e),self.postMessage({found:!1,error:e.message||String(e)}))}},self.onerror=e=>{self.postMessage({found:!1,error:`Worker error: ${e.message||e}`})}}.toString().replace(/^function\s*\([^\)]*\)\s*{|\}$/g,"").trim()}})()`,window.Cap=h,customElements.get("cap-widget")?console.warn("The cap-widget element has already been defined. Skipping re-defining it."):customElements.define("cap-widget",d),"object"==typeof exports&&"undefined"!=typeof module?module.exports=h:"function"==typeof define&&define.amd&&define([],(function(){return h})),"undefined"!=typeof exports&&(exports.default=h)}();
|
package/cap.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";!function(){let e;const t=(e,t=1e4)=>new Promise(((r,s)=>{const i=setTimeout((()=>{s(new Error("Initialize timeout"))}),t),a=()=>{e()?(clearTimeout(i),r()):setTimeout(a,500)};a()}));class r extends HTMLElement{#e="";#t=null;#r=navigator.hardwareConcurrency||8;#s=null;#i;#a;#n;#o=!1;#c;static get observedAttributes(){return["onsolve","onprogress","onreset","onerror","workers"]}constructor(){super(),this.#c&&this.#c.forEach(((e,t)=>{this.removeEventListener(t.slice(2),e)})),this.#c=new Map,this.boundHandleProgress=this.handleProgress.bind(this),this.boundHandleSolve=this.handleSolve.bind(this),this.boundHandleError=this.handleError.bind(this),this.boundHandleReset=this.handleReset.bind(this)}async initialize(){this.#e&&URL.revokeObjectURL(this.#e);try{await t((()=>!!e)),this.#e=URL.createObjectURL(new Blob([e],{type:"application/javascript"}))}catch(e){throw this.error("Failed to initialize worker"),e}}attributeChangedCallback(e,t,r){if(e.startsWith("on")){const t=e.slice(2),s=this.#c.get(e);if(s&&this.removeEventListener(t,s),r){const r=t=>{const r=this.getAttribute(e);"function"==typeof window[r]&&window[r].call(this,t)};this.#c.set(e,r),this.addEventListener(t,r)}}}async connectedCallback(){this.#n=this,this.#i=this.attachShadow({mode:"open"}),this.#a=document.createElement("div"),this.createUI(),this.addEventListeners(),await this.initialize(),this.#a.removeAttribute("disabled");const e=this.getAttribute("data-cap-worker-count");this.setWorkersCount(parseInt(e)?parseInt(e,10):navigator.hardwareConcurrency||8),this.#n.innerHTML='<input type="hidden" name="cap-token">'}async solve(){if(!this.#o)try{this.#o=!0,this.updateUI("verifying","Verifying...",!0),await t((()=>!!this.#e)),this.dispatchEvent("progress",{progress:0});try{const e=this.getAttribute("data-cap-api-endpoint");if(!e)throw new Error("Missing API endpoint");const{challenge:t,token:r}=await(await fetch(`${e}challenge`,{method:"POST"})).json(),s=await this.solveChallenges(t),i=await(await fetch(`${e}redeem`,{method:"POST",body:JSON.stringify({token:r,solutions:s}),headers:{"Content-Type":"application/json"}})).json();if(this.dispatchEvent("progress",{progress:100}),!i.success)throw new Error("Invalid solution");this.querySelector("input[name='cap-token']")&&(this.querySelector("input[name='cap-token']").value=i.token),this.dispatchEvent("solve",{token:i.token}),this.#s=i.token,this.#t&&clearTimeout(this.#t);const a=new Date(i.expires).getTime()-Date.now();return a>0&&a<864e5?this.#t=setTimeout((()=>this.reset()),a):this.error("Invalid expiration time"),{success:!0,token:this.#s}}catch(e){throw this.error(e.message),e}}finally{this.#o=!1}}async solveChallenges(e){const t=e.length;let r=0;const s=Array(this.#r).fill(null).map((()=>new Worker(this.#e))),i=([e,i],a)=>new Promise(((n,o)=>{const c=s[a],d=setTimeout((()=>{c.terminate(),s[a]=new Worker(this.#e),o(new Error("Worker timeout"))}),3e4);c.onmessage=({data:s})=>{s.found&&(clearTimeout(d),r++,this.dispatchEvent("progress",{progress:Math.round(r/t*100)}),n([e,i,s.nonce]))},c.onerror=e=>{clearTimeout(d),this.error(`Error in worker: ${e}`),o(e)},c.postMessage({salt:e,target:i})})),a=[];try{for(let t=0;t<e.length;t+=this.#r){const r=e.slice(t,Math.min(t+this.#r,e.length)),s=await Promise.all(r.map(((e,t)=>i(e,t))));a.push(...s)}}finally{s.forEach((e=>e.terminate()))}return a}setWorkersCount(e){const t=parseInt(e,10),r=Math.min(navigator.hardwareConcurrency||8,16);this.#r=!isNaN(t)&&t>0&&t<=r?t:navigator.hardwareConcurrency||8}createUI(){this.#a.classList.add("captcha"),this.#a.setAttribute("role","button"),this.#a.setAttribute("tabindex","0"),this.#a.setAttribute("disabled","true"),this.#a.innerHTML='<div class="checkbox"></div><p>I\'m a human</p><a href="https://capjs.js.org/" class="credits" target="_blank" rel="follow noopener"><span>Secured by </span>Cap</a>',this.#i.innerHTML='<style>.captcha{background-color:var(--cap-background);border:1px solid var(--cap-border-color);border-radius:var(--cap-border-radius);width:var(--cap-widget-width);display:flex;align-items:center;padding:var(--cap-widget-padding);gap:var(--cap-gap);cursor:pointer;transition:filter var(--cap-transition-duration),transform var(--cap-transition-duration);position:relative;-webkit-tap-highlight-color:rgba(255,255,255,0);overflow:hidden;color:var(--cap-color)}.captcha:hover{filter:var(--cap-hover-filter)}.captcha:not([disabled]):active{transform:scale(var(--cap-active-scale))}.checkbox{width:var(--cap-checkbox-size);height:var(--cap-checkbox-size);border:var(--cap-checkbox-border);border-radius:var(--cap-checkbox-border-radius);background-color:var(--cap-checkbox-background);transition:opacity var(--cap-transition-duration);margin-top:var(--cap-checkbox-margin);margin-bottom:var(--cap-checkbox-margin)}.captcha *{font-family:var(--cap-font)}.captcha p{margin:0;font-weight:500;font-size:15px;user-select:none;transition:opacity var(--cap-transition-duration)}.captcha[data-state=verifying] .checkbox{background: none;display:flex;align-items:center;justify-content:center;transform: scale(1.1);border: none;border-radius: 50%;background: conic-gradient(var(--cap-spinner-color) 0%, var(--cap-spinner-color) var(--progress, 0%), var(--cap-spinner-background-color) var(--progress, 0%), var(--cap-spinner-background-color) 100%);position: relative;}.captcha[data-state=verifying] .checkbox::after {content: "";background-color: var(--cap-background);width: calc(100% - var(--cap-spinner-thickness));height: calc(100% - var(--cap-spinner-thickness));border-radius: 50%;margin:calc(var(--cap-spinner-thickness) / 2)}.captcha[data-state=done] .checkbox{border:1px solid transparent;background-image:var(--cap-checkmark);background-size:cover}.captcha[data-state=error] .checkbox{border:1px solid transparent;background-image:var(--cap-error-cross);background-size:cover}.captcha[disabled]{\ncursor:not-allowed}.captcha[disabled][data-state=verifying]{cursor:progress}.captcha[disabled][data-state=done]{cursor:default}.captcha .credits{position:absolute;bottom:10px;right:10px;font-size:var(--cap-credits-font-size);color:var(--cap-color);opacity:var(--cap-opacity-hover)}.captcha .credits span{display:none;text-decoration:underline}.captcha .credits:hover span{display:inline-block}</style>',this.#i.appendChild(this.#a)}addEventListeners(){this.#a.querySelector("a").addEventListener("click",(e=>{e.stopPropagation(),e.preventDefault(),window.open("https://capjs.js.org","_blank")})),this.#a.addEventListener("click",(()=>{this.#a.hasAttribute("disabled")||this.solve()})),this.#a.addEventListener("keydown",(e=>{"Enter"!==e.key&&" "!==e.key||this.#a.hasAttribute("disabled")||(e.preventDefault(),this.solve())})),this.addEventListener("progress",this.boundHandleProgress),this.addEventListener("solve",this.boundHandleSolve),this.addEventListener("error",this.boundHandleError),this.addEventListener("reset",this.boundHandleReset)}updateUI(e,t,r=!1){this.#a.setAttribute("data-state",e),this.#a.querySelector("p").innerText=t,r?this.#a.setAttribute("disabled","true"):this.#a.removeAttribute("disabled")}handleProgress(e){const t=this.#a.querySelector("p");t&&(this.#a.querySelector(".checkbox").style.setProperty("--progress",`${e.detail.progress}%`),t.innerText=`Verifying... ${e.detail.progress}%`),this.executeAttributeCode("onprogress",e)}handleSolve(e){this.updateUI("done","You're a human",!0),this.executeAttributeCode("onsolve",e)}handleError(e){this.updateUI("error","Error. Try again."),this.executeAttributeCode("onerror",e)}handleReset(e){this.updateUI("","I'm a human"),this.executeAttributeCode("onreset",e)}executeAttributeCode(e,t){const r=this.getAttribute(e);if(!r)return;new Function("event",r).call(this,t)}error(e="Unknown error"){console.error("[Cap] Error:",e),this.dispatchEvent("error",{isCap:!0,message:e})}dispatchEvent(e,t={}){const r=new CustomEvent(e,{bubbles:!0,composed:!0,detail:t});super.dispatchEvent(r)}reset(){this.#t&&(clearTimeout(this.#t),this.#t=null),this.dispatchEvent("reset"),this.#s=null,this.querySelector("input[name='cap-token']")&&(this.querySelector("input[name='cap-token']").value="")}get token(){return this.#s}disconnectedCallback(){this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),this.#c.forEach(((e,t)=>{this.removeEventListener(t.slice(2),e)})),this.#c.clear(),this.#i&&(this.#i.innerHTML=""),this.reset(),this.cleanup()}cleanup(){this.#t&&(clearTimeout(this.#t),this.#t=null),this.#e&&(URL.revokeObjectURL(this.#e),this.#e="")}}class s{constructor(e={},t){let r=t||document.createElement("cap-widget");if(Object.entries(e).forEach((([e,t])=>{r.setAttribute(e,t)})),!e.apiEndpoint)throw r.remove(),new Error("Missing API endpoint");r.setAttribute("data-cap-api-endpoint",e.apiEndpoint),this.widget=r,this.solve=this.widget.solve.bind(this.widget),this.reset=this.widget.reset.bind(this.widget),this.addEventListener=this.widget.addEventListener.bind(this.widget),Object.defineProperty(this,"token",{get:()=>r.getToken(),configurable:!0,enumerable:!0}),t||(r.style.display="none",document.documentElement.appendChild(r))}}const i=new CSSStyleSheet;i.replaceSync('html{--cap-font:system,-apple-system,"BlinkMacSystemFont",".SFNSText-Regular","San Francisco","Roboto","Segoe UI","Helvetica Neue","Lucida Grande","Ubuntu","arial",sans-serif;--cap-color:#212121;--cap-background:#fdfdfd;--cap-border-color:#dddddd8f;--cap-border-radius:14px;--cap-checkbox-border:1px solid #aaaaaad1;--cap-checkbox-border-radius:6px;--cap-checkbox-background:#fafafa91;--cap-widget-width:240px;--cap-widget-padding:14px;--cap-checkbox-size:24px;--cap-checkbox-margin:2px;--cap-transition-duration:0.2s;--cap-gap:15px;--cap-opacity-hover:0.8;--cap-hover-filter:brightness(97%);--cap-active-scale:0.98;--cap-credits-font-size:12px;--cap-spinner-color:black;--cap-spinner-background-color:#eee;--cap-error-cross:url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'96\' height=\'96\' viewBox=\'0 0 24 24\'%3E%3Cpath fill=\'%23f55b50\' d=\'M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8\'/%3E%3C/svg%3E");--cap-checkmark:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E");--cap-spinner-thickness:5px;}'),document.adoptedStyleSheets.push(i);const a=function(){let e;self.onmessage=async({data:{salt:t,target:r}})=>{let s=0;const i=5e4;let a=0;const n=new TextEncoder;if("object"!=typeof WebAssembly||"function"!=typeof WebAssembly.instantiate){console.log("[cap] WASM not enabled, falling back to crypto.subtle\nThis is significanty slower than the WASM implementation");const e=new Uint8Array(r.length/2);for(let t=0;t<e.length;t++)e[t]=parseInt(r.substring(2*t,2*t+2),16);const o=e.length;for(;;)try{for(let r=0;r<i;r++){const r=t+s,i=n.encode(r),a=await crypto.subtle.digest("SHA-256",i),c=new Uint8Array(a,0,o);let d=!0;for(let t=0;t<o;t++)if(c[t]!==e[t]){d=!1;break}if(d)return void self.postMessage({nonce:s,found:!0});s++}a+=i}catch(e){return console.error("[cap] fallback worker error",e),void self.postMessage({found:!1,error:e.message})}}e||(e=await hashwasm.createSHA256());const o=new Uint8Array(128);for(;;)try{for(let a=0;a<i;a++){const i=t+s.toString(),a=n.encode(i);o.set(a),e.init(),e.update(o.subarray(0,a.length));if(e.digest("hex").startsWith(r))return void self.postMessage({nonce:s,found:!0});s++}a+=i}catch(e){return void self.postMessage({found:!1,error:e.message})}}};setTimeout((async function(){e=await(await fetch("https://cdn.jsdelivr.net/npm/@cap.js/widget/wasm-hashes.min.js")).text()+a.toString().replace(/^function\s*\([^\)]*\)\s*{|\}$/g,"").trim()}),1),window.Cap=s,customElements.get("cap-widget")?console.warn("The cap-widget element has already been defined. Skipping re-defining it."):customElements.define("cap-widget",r),"object"==typeof exports&&"undefined"!=typeof module?module.exports=s:"function"==typeof define&&define.amd&&define([],(function(){return s})),"undefined"!=typeof exports&&(exports.default=s)}();
|
|
1
|
+
"use strict";function _getRequireWildcardCache(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,r=new WeakMap;return(_getRequireWildcardCache=function(e){return e?r:t})(e)}function _interopRequireWildcard(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var r=_getRequireWildcardCache(t);if(r&&r.has(e))return r.get(e);var s={__proto__:null},a=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&{}.hasOwnProperty.call(e,i)){var n=a?Object.getOwnPropertyDescriptor(e,i):null;n&&(n.get||n.set)?Object.defineProperty(s,i,n):s[i]=e[i]}return s.default=e,r&&r.set(e,s),s}!function(){let e;const t=function(){return window?.CAP_CUSTOM_FETCH?window.CAP_CUSTOM_FETCH(...arguments):fetch(...arguments)};class r extends HTMLElement{#e="";#t=null;#r=navigator.hardwareConcurrency||8;token=null;#s;#a;#i;#n=!1;#o;static get observedAttributes(){return["onsolve","onprogress","onreset","onerror","workers"]}constructor(){super(),this.#o&&this.#o.forEach(((e,t)=>{this.removeEventListener(t.slice(2),e)})),this.#o=new Map,this.boundHandleProgress=this.handleProgress.bind(this),this.boundHandleSolve=this.handleSolve.bind(this),this.boundHandleError=this.handleError.bind(this),this.boundHandleReset=this.handleReset.bind(this)}initialize(){this.#e=URL.createObjectURL(new Blob([e],{type:"application/javascript"}))}attributeChangedCallback(e,t,r){if(e.startsWith("on")){const t=e.slice(2),s=this.#o.get(e);if(s&&this.removeEventListener(t,s),r){const r=t=>{const r=this.getAttribute(e);"function"==typeof window[r]&&window[r].call(this,t)};this.#o.set(e,r),this.addEventListener(t,r)}}}async connectedCallback(){this.#i=this,this.#s=this.attachShadow({mode:"open"}),this.#a=document.createElement("div"),this.createUI(),this.addEventListeners(),await this.initialize(),this.#a.removeAttribute("disabled");const e=this.getAttribute("data-cap-worker-count");this.setWorkersCount(parseInt(e)?parseInt(e,10):navigator.hardwareConcurrency||8),this.#i.innerHTML='<input type="hidden" name="cap-token">'}async solve(){if(!this.#n)try{this.#n=!0,this.updateUI("verifying","Verifying...",!0),this.dispatchEvent("progress",{progress:0});try{const e=this.getAttribute("data-cap-api-endpoint");if(!e)throw new Error("Missing API endpoint");const{challenge:r,token:s}=await(await t(`${e}challenge`,{method:"POST"})).json(),a=await this.solveChallenges(r),i=await(await t(`${e}redeem`,{method:"POST",body:JSON.stringify({token:s,solutions:a}),headers:{"Content-Type":"application/json"}})).json();if(this.dispatchEvent("progress",{progress:100}),!i.success)throw new Error("Invalid solution");this.querySelector("input[name='cap-token']")&&(this.querySelector("input[name='cap-token']").value=i.token),this.dispatchEvent("solve",{token:i.token}),this.token=i.token,this.#t&&clearTimeout(this.#t);const n=new Date(i.expires).getTime()-Date.now();return n>0&&n<864e5?this.#t=setTimeout((()=>this.reset()),n):this.error("Invalid expiration time"),{success:!0,token:this.token}}catch(e){throw this.error(e.message),e}}finally{this.#n=!1}}async solveChallenges(e){const t=e.length;let r=0;const s=Array(this.#r).fill(null).map((()=>new Worker(this.#e))),a=([e,a],i)=>new Promise(((n,o)=>{const c=s[i],d=setTimeout((()=>{c.terminate(),s[i]=new Worker(this.#e),o(new Error("Worker timeout"))}),3e4);c.onmessage=({data:s})=>{s.found&&(clearTimeout(d),r++,this.dispatchEvent("progress",{progress:Math.round(r/t*100)}),n([e,a,s.nonce]))},c.onerror=e=>{clearTimeout(d),this.error(`Error in worker: ${e}`),o(e)},c.postMessage({salt:e,target:a})})),i=[];try{for(let t=0;t<e.length;t+=this.#r){const r=e.slice(t,Math.min(t+this.#r,e.length)),s=await Promise.all(r.map(((e,t)=>a(e,t))));i.push(...s)}}finally{s.forEach((e=>e.terminate()))}return i}setWorkersCount(e){const t=parseInt(e,10),r=Math.min(navigator.hardwareConcurrency||8,16);this.#r=!isNaN(t)&&t>0&&t<=r?t:navigator.hardwareConcurrency||8}createUI(){this.#a.classList.add("captcha"),this.#a.setAttribute("role","button"),this.#a.setAttribute("tabindex","0"),this.#a.setAttribute("disabled","true"),this.#a.innerHTML='<div class="checkbox"></div><p>I\'m a human</p><a href="https://capjs.js.org/" class="credits" target="_blank" rel="follow noopener"><span>Secured by </span>Cap</a>',this.#s.innerHTML='<style>.captcha{background-color:var(--cap-background);border:1px solid var(--cap-border-color);border-radius:var(--cap-border-radius);width:var(--cap-widget-width);display:flex;align-items:center;padding:var(--cap-widget-padding);gap:var(--cap-gap);cursor:pointer;transition:filter var(--cap-transition-duration),transform var(--cap-transition-duration);position:relative;-webkit-tap-highlight-color:rgba(255,255,255,0);overflow:hidden;color:var(--cap-color)}.captcha:hover{filter:var(--cap-hover-filter)}.captcha:not([disabled]):active{transform:scale(var(--cap-active-scale))}.checkbox{width:var(--cap-checkbox-size);height:var(--cap-checkbox-size);border:var(--cap-checkbox-border);border-radius:var(--cap-checkbox-border-radius);background-color:var(--cap-checkbox-background);transition:opacity var(--cap-transition-duration);margin-top:var(--cap-checkbox-margin);margin-bottom:var(--cap-checkbox-margin)}.captcha *{font-family:var(--cap-font)}.captcha p{margin:0;font-weight:500;font-size:15px;user-select:none;transition:opacity var(--cap-transition-duration)}.captcha[data-state=verifying] .checkbox{background: none;display:flex;align-items:center;justify-content:center;transform: scale(1.1);border: none;border-radius: 50%;background: conic-gradient(var(--cap-spinner-color) 0%, var(--cap-spinner-color) var(--progress, 0%), var(--cap-spinner-background-color) var(--progress, 0%), var(--cap-spinner-background-color) 100%);position: relative;}.captcha[data-state=verifying] .checkbox::after {content: "";background-color: var(--cap-background);width: calc(100% - var(--cap-spinner-thickness));height: calc(100% - var(--cap-spinner-thickness));border-radius: 50%;margin:calc(var(--cap-spinner-thickness) / 2)}.captcha[data-state=done] .checkbox{border:1px solid transparent;background-image:var(--cap-checkmark);background-size:cover}.captcha[data-state=error] .checkbox{border:1px solid transparent;background-image:var(--cap-error-cross);background-size:cover}.captcha[disabled]{\ncursor:not-allowed}.captcha[disabled][data-state=verifying]{cursor:progress}.captcha[disabled][data-state=done]{cursor:default}.captcha .credits{position:absolute;bottom:10px;right:10px;font-size:var(--cap-credits-font-size);color:var(--cap-color);opacity:var(--cap-opacity-hover)}.captcha .credits span{display:none;text-decoration:underline}.captcha .credits:hover span{display:inline-block}</style>',this.#s.appendChild(this.#a)}addEventListeners(){this.#a.querySelector("a").addEventListener("click",(e=>{e.stopPropagation(),e.preventDefault(),window.open("https://capjs.js.org","_blank")})),this.#a.addEventListener("click",(()=>{this.#a.hasAttribute("disabled")||this.solve()})),this.#a.addEventListener("keydown",(e=>{"Enter"!==e.key&&" "!==e.key||this.#a.hasAttribute("disabled")||(e.preventDefault(),this.solve())})),this.addEventListener("progress",this.boundHandleProgress),this.addEventListener("solve",this.boundHandleSolve),this.addEventListener("error",this.boundHandleError),this.addEventListener("reset",this.boundHandleReset)}updateUI(e,t,r=!1){this.#a.setAttribute("data-state",e),this.#a.querySelector("p").innerText=t,r?this.#a.setAttribute("disabled","true"):this.#a.removeAttribute("disabled")}handleProgress(e){const t=this.#a.querySelector("p");t&&(this.#a.querySelector(".checkbox").style.setProperty("--progress",`${e.detail.progress}%`),t.innerText=`Verifying... ${e.detail.progress}%`),this.executeAttributeCode("onprogress",e)}handleSolve(e){this.updateUI("done","You're a human",!0),this.executeAttributeCode("onsolve",e)}handleError(e){this.updateUI("error","Error. Try again."),this.executeAttributeCode("onerror",e)}handleReset(e){this.updateUI("","I'm a human"),this.executeAttributeCode("onreset",e)}executeAttributeCode(e,t){const r=this.getAttribute(e);if(!r)return;new Function("event",r).call(this,t)}error(e="Unknown error"){console.error("[cap] Error:",e),this.dispatchEvent("error",{isCap:!0,message:e})}dispatchEvent(e,t={}){const r=new CustomEvent(e,{bubbles:!0,composed:!0,detail:t});super.dispatchEvent(r)}reset(){this.#t&&(clearTimeout(this.#t),this.#t=null),this.dispatchEvent("reset"),this.token=null,this.querySelector("input[name='cap-token']")&&(this.querySelector("input[name='cap-token']").value="")}get token(){return this.token}disconnectedCallback(){this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),this.#o.forEach(((e,t)=>{this.removeEventListener(t.slice(2),e)})),this.#o.clear(),this.#s&&(this.#s.innerHTML=""),this.reset(),this.cleanup()}cleanup(){this.#t&&(clearTimeout(this.#t),this.#t=null),this.#e&&(URL.revokeObjectURL(this.#e),this.#e="")}}class s{constructor(e={},t){let r=t||document.createElement("cap-widget");if(Object.entries(e).forEach((([e,t])=>{r.setAttribute(e,t)})),!e.apiEndpoint)throw r.remove(),new Error("Missing API endpoint");r.setAttribute("data-cap-api-endpoint",e.apiEndpoint),this.widget=r,this.solve=this.widget.solve.bind(this.widget),this.reset=this.widget.reset.bind(this.widget),this.addEventListener=this.widget.addEventListener.bind(this.widget),Object.defineProperty(this,"token",{get:()=>r.getToken(),configurable:!0,enumerable:!0}),t||(r.style.display="none",document.documentElement.appendChild(r))}}const a=new CSSStyleSheet;a.replaceSync('html{--cap-font:system,-apple-system,"BlinkMacSystemFont",".SFNSText-Regular","San Francisco","Roboto","Segoe UI","Helvetica Neue","Lucida Grande","Ubuntu","arial",sans-serif;--cap-color:#212121;--cap-background:#fdfdfd;--cap-border-color:#dddddd8f;--cap-border-radius:14px;--cap-checkbox-border:1px solid #aaaaaad1;--cap-checkbox-border-radius:6px;--cap-checkbox-background:#fafafa91;--cap-widget-width:240px;--cap-widget-padding:14px;--cap-checkbox-size:24px;--cap-checkbox-margin:2px;--cap-transition-duration:0.2s;--cap-gap:15px;--cap-opacity-hover:0.8;--cap-hover-filter:brightness(97%);--cap-active-scale:0.98;--cap-credits-font-size:12px;--cap-spinner-color:black;--cap-spinner-background-color:#eee;--cap-error-cross:url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'96\' height=\'96\' viewBox=\'0 0 24 24\'%3E%3Cpath fill=\'%23f55b50\' d=\'M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8\'/%3E%3C/svg%3E");--cap-checkmark:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E");--cap-spinner-thickness:5px;}'),document.adoptedStyleSheets.push(a);e=`(() => {${function(){let e,t;if("object"!=typeof WebAssembly||"function"!=typeof WebAssembly?.instantiate)return self.onmessage=async({data:{salt:e,target:t}})=>{let r=0;let s=0;const a=new TextEncoder,i=new Uint8Array(t.length/2);for(let e=0;e<i.length;e++)i[e]=parseInt(t.substring(2*e,2*e+2),16);const n=i.length;for(;;)try{for(let t=0;t<5e4;t++){const t=e+r,s=a.encode(t),o=await crypto.subtle.digest("SHA-256",s),c=new Uint8Array(o,0,n);let d=!0;for(let e=0;e<n;e++)if(c[e]!==i[e]){d=!1;break}if(d)return void self.postMessage({nonce:r,found:!0});r++}s+=5e4}catch(e){return console.error("[cap] fallback worker error",e),void self.postMessage({found:!1,error:e.message})}},console.warn("[cap] WebAssembly is not supported, falling back to alternative solver.");e=Promise.resolve().then((()=>_interopRequireWildcard(require("https://cdn.jsdelivr.net/npm/@cap.js/wasm@0.0.3/browser/cap_wasm.min.js")))).then((e=>e.default().then((r=>{t=(r&&r.exports?r.exports:e).solve_pow})))).catch((e=>{useFallback=!0,console.error("[cap] using fallback solver due to error:",e)})),self.onmessage=async({data:{salt:r,target:s}})=>{try{await e;const a=performance.now(),i=t(r,s),n=performance.now();self.postMessage({nonce:Number(i),found:!0,durationMs:(n-a).toFixed(2)})}catch(e){initError||(console.error("[cap] solver error",e),self.postMessage({found:!1,error:e.message||String(e)}))}},self.onerror=e=>{self.postMessage({found:!1,error:`Worker error: ${e.message||e}`})}}.toString().replace(/^function\s*\([^\)]*\)\s*{|\}$/g,"").trim()}})()`,window.Cap=s,customElements.get("cap-widget")?console.warn("The cap-widget element has already been defined. Skipping re-defining it."):customElements.define("cap-widget",r),"object"==typeof exports&&"undefined"!=typeof module?module.exports=s:"function"==typeof define&&define.amd&&define([],(function(){return s})),"undefined"!=typeof exports&&(exports.default=s)}();
|
package/package.json
CHANGED
package/src/cap.js
CHANGED
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
let workerScript;
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const poll = () => {
|
|
11
|
-
if (predFn()) {
|
|
12
|
-
clearTimeout(timeoutId);
|
|
13
|
-
resolve();
|
|
14
|
-
} else {
|
|
15
|
-
setTimeout(poll, 500);
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
poll();
|
|
19
|
-
});
|
|
4
|
+
const capFetch = function () {
|
|
5
|
+
if (window?.CAP_CUSTOM_FETCH) {
|
|
6
|
+
return window.CAP_CUSTOM_FETCH(...arguments);
|
|
7
|
+
}
|
|
8
|
+
return fetch(...arguments);
|
|
20
9
|
};
|
|
21
10
|
|
|
22
11
|
// MARK: Widget
|
|
@@ -24,7 +13,7 @@
|
|
|
24
13
|
#workerUrl = "";
|
|
25
14
|
#resetTimer = null;
|
|
26
15
|
#workersCount = navigator.hardwareConcurrency || 8;
|
|
27
|
-
|
|
16
|
+
token = null;
|
|
28
17
|
#shadow;
|
|
29
18
|
#div;
|
|
30
19
|
#host;
|
|
@@ -50,25 +39,15 @@
|
|
|
50
39
|
this.boundHandleReset = this.handleReset.bind(this);
|
|
51
40
|
}
|
|
52
41
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
await until(() => !!workerScript);
|
|
60
|
-
this.#workerUrl = URL.createObjectURL(
|
|
61
|
-
new Blob([workerScript], {
|
|
62
|
-
type: "application/javascript",
|
|
63
|
-
})
|
|
64
|
-
);
|
|
65
|
-
} catch (err) {
|
|
66
|
-
this.error("Failed to initialize worker");
|
|
67
|
-
throw err;
|
|
68
|
-
}
|
|
42
|
+
initialize() {
|
|
43
|
+
this.#workerUrl = URL.createObjectURL(
|
|
44
|
+
new Blob([workerScript], {
|
|
45
|
+
type: "application/javascript",
|
|
46
|
+
})
|
|
47
|
+
);
|
|
69
48
|
}
|
|
70
49
|
|
|
71
|
-
attributeChangedCallback(name,
|
|
50
|
+
attributeChangedCallback(name, _, value) {
|
|
72
51
|
if (name.startsWith("on")) {
|
|
73
52
|
const eventName = name.slice(2);
|
|
74
53
|
const oldHandler = this.#eventHandlers.get(name);
|
|
@@ -76,7 +55,7 @@
|
|
|
76
55
|
this.removeEventListener(eventName, oldHandler);
|
|
77
56
|
}
|
|
78
57
|
|
|
79
|
-
if (
|
|
58
|
+
if (value) {
|
|
80
59
|
const handler = (event) => {
|
|
81
60
|
const callback = this.getAttribute(name);
|
|
82
61
|
if (typeof window[callback] === "function") {
|
|
@@ -116,7 +95,6 @@
|
|
|
116
95
|
this.#solving = true;
|
|
117
96
|
this.updateUI("verifying", "Verifying...", true);
|
|
118
97
|
|
|
119
|
-
await until(() => !!this.#workerUrl);
|
|
120
98
|
this.dispatchEvent("progress", { progress: 0 });
|
|
121
99
|
|
|
122
100
|
try {
|
|
@@ -124,14 +102,14 @@
|
|
|
124
102
|
if (!apiEndpoint) throw new Error("Missing API endpoint");
|
|
125
103
|
|
|
126
104
|
const { challenge, token } = await (
|
|
127
|
-
await
|
|
105
|
+
await capFetch(`${apiEndpoint}challenge`, {
|
|
128
106
|
method: "POST",
|
|
129
107
|
})
|
|
130
108
|
).json();
|
|
131
109
|
const solutions = await this.solveChallenges(challenge);
|
|
132
110
|
|
|
133
111
|
const resp = await (
|
|
134
|
-
await
|
|
112
|
+
await capFetch(`${apiEndpoint}redeem`, {
|
|
135
113
|
method: "POST",
|
|
136
114
|
body: JSON.stringify({ token, solutions }),
|
|
137
115
|
headers: { "Content-Type": "application/json" },
|
|
@@ -146,7 +124,7 @@
|
|
|
146
124
|
}
|
|
147
125
|
|
|
148
126
|
this.dispatchEvent("solve", { token: resp.token });
|
|
149
|
-
this
|
|
127
|
+
this.token = resp.token;
|
|
150
128
|
|
|
151
129
|
if (this.#resetTimer) clearTimeout(this.#resetTimer);
|
|
152
130
|
const expiresIn = new Date(resp.expires).getTime() - Date.now();
|
|
@@ -156,7 +134,7 @@
|
|
|
156
134
|
this.error("Invalid expiration time");
|
|
157
135
|
}
|
|
158
136
|
|
|
159
|
-
return { success: true, token: this
|
|
137
|
+
return { success: true, token: this.token };
|
|
160
138
|
} catch (err) {
|
|
161
139
|
this.error(err.message);
|
|
162
140
|
throw err;
|
|
@@ -317,7 +295,7 @@
|
|
|
317
295
|
}
|
|
318
296
|
|
|
319
297
|
error(message = "Unknown error") {
|
|
320
|
-
console.error("[
|
|
298
|
+
console.error("[cap] Error:", message);
|
|
321
299
|
this.dispatchEvent("error", { isCap: true, message });
|
|
322
300
|
}
|
|
323
301
|
|
|
@@ -336,14 +314,14 @@
|
|
|
336
314
|
this.#resetTimer = null;
|
|
337
315
|
}
|
|
338
316
|
this.dispatchEvent("reset");
|
|
339
|
-
this
|
|
317
|
+
this.token = null;
|
|
340
318
|
if (this.querySelector("input[name='cap-token']")) {
|
|
341
319
|
this.querySelector("input[name='cap-token']").value = "";
|
|
342
320
|
}
|
|
343
321
|
}
|
|
344
322
|
|
|
345
323
|
get token() {
|
|
346
|
-
return this
|
|
324
|
+
return this.token;
|
|
347
325
|
}
|
|
348
326
|
|
|
349
327
|
disconnectedCallback() {
|
|
@@ -418,26 +396,20 @@
|
|
|
418
396
|
);
|
|
419
397
|
document.adoptedStyleSheets.push(sheet);
|
|
420
398
|
|
|
421
|
-
// MARK: Solver worker
|
|
422
399
|
const workerFunct = function () {
|
|
423
|
-
let
|
|
400
|
+
let initPromise, solve_pow_function;
|
|
424
401
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
)
|
|
437
|
-
) {
|
|
438
|
-
console.log(
|
|
439
|
-
"[cap] WASM not enabled, falling back to crypto.subtle\nThis is significanty slower than the WASM implementation"
|
|
440
|
-
);
|
|
402
|
+
if (
|
|
403
|
+
typeof WebAssembly !== "object" ||
|
|
404
|
+
typeof WebAssembly?.instantiate !== "function"
|
|
405
|
+
) {
|
|
406
|
+
self.onmessage = async ({ data: { salt, target } }) => {
|
|
407
|
+
// Fallback solver in case WASM is not available
|
|
408
|
+
|
|
409
|
+
let nonce = 0;
|
|
410
|
+
const batchSize = 50000;
|
|
411
|
+
let processed = 0;
|
|
412
|
+
const encoder = new TextEncoder();
|
|
441
413
|
|
|
442
414
|
const targetBytes = new Uint8Array(target.length / 2);
|
|
443
415
|
for (let k = 0; k < targetBytes.length; k++) {
|
|
@@ -488,54 +460,64 @@
|
|
|
488
460
|
return;
|
|
489
461
|
}
|
|
490
462
|
}
|
|
491
|
-
}
|
|
463
|
+
};
|
|
492
464
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
465
|
+
return console.warn(
|
|
466
|
+
"[cap] WebAssembly is not supported, falling back to alternative solver."
|
|
467
|
+
);
|
|
468
|
+
}
|
|
496
469
|
|
|
497
|
-
|
|
470
|
+
initPromise = import(
|
|
471
|
+
"https://cdn.jsdelivr.net/npm/@cap.js/wasm@0.0.3/browser/cap_wasm.min.js"
|
|
472
|
+
)
|
|
473
|
+
.then((wasmModule) => {
|
|
474
|
+
return wasmModule.default().then((instance) => {
|
|
475
|
+
solve_pow_function = (
|
|
476
|
+
instance && instance.exports ? instance.exports : wasmModule
|
|
477
|
+
).solve_pow;
|
|
478
|
+
});
|
|
479
|
+
})
|
|
480
|
+
.catch((e) => {
|
|
481
|
+
useFallback = true;
|
|
482
|
+
console.error("[cap] using fallback solver due to error:", e);
|
|
483
|
+
});
|
|
498
484
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
const input = salt + nonce.toString();
|
|
503
|
-
const inputBytes = encoder.encode(input);
|
|
504
|
-
buffer.set(inputBytes);
|
|
505
|
-
|
|
506
|
-
hasher.init();
|
|
507
|
-
hasher.update(buffer.subarray(0, inputBytes.length));
|
|
508
|
-
const hash = hasher.digest("hex");
|
|
509
|
-
|
|
510
|
-
if (hash.startsWith(target)) {
|
|
511
|
-
self.postMessage({ nonce, found: true });
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
485
|
+
self.onmessage = async ({ data: { salt, target } }) => {
|
|
486
|
+
try {
|
|
487
|
+
await initPromise;
|
|
514
488
|
|
|
515
|
-
|
|
516
|
-
|
|
489
|
+
const startTime = performance.now();
|
|
490
|
+
const nonce = solve_pow_function(salt, target);
|
|
491
|
+
const endTime = performance.now();
|
|
517
492
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
493
|
+
self.postMessage({
|
|
494
|
+
nonce: Number(nonce),
|
|
495
|
+
found: true,
|
|
496
|
+
durationMs: (endTime - startTime).toFixed(2),
|
|
497
|
+
});
|
|
498
|
+
} catch (error) {
|
|
499
|
+
if (!initError) {
|
|
500
|
+
console.error("[cap] solver error", error);
|
|
501
|
+
self.postMessage({
|
|
502
|
+
found: false,
|
|
503
|
+
error: error.message || String(error),
|
|
504
|
+
});
|
|
522
505
|
}
|
|
523
506
|
}
|
|
524
507
|
};
|
|
508
|
+
|
|
509
|
+
self.onerror = (error) => {
|
|
510
|
+
self.postMessage({
|
|
511
|
+
found: false,
|
|
512
|
+
error: `Worker error: ${error.message || error}`,
|
|
513
|
+
});
|
|
514
|
+
};
|
|
525
515
|
};
|
|
526
516
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
"https://cdn.jsdelivr.net/npm/@cap.js/widget/wasm-hashes.min.js"
|
|
532
|
-
)
|
|
533
|
-
).text()) +
|
|
534
|
-
workerFunct
|
|
535
|
-
.toString()
|
|
536
|
-
.replace(/^function\s*\([^\)]*\)\s*{|\}$/g, "")
|
|
537
|
-
.trim();
|
|
538
|
-
}, 1);
|
|
517
|
+
workerScript = `(() => {${workerFunct
|
|
518
|
+
.toString()
|
|
519
|
+
.replace(/^function\s*\([^\)]*\)\s*{|\}$/g, "")
|
|
520
|
+
.trim()}})()`;
|
|
539
521
|
|
|
540
522
|
window.Cap = Cap;
|
|
541
523
|
|