@cap.js/widget 0.0.22 → 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 +74 -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(){var e;return null!=(e=window)&&e.CAP_CUSTOM_FETCH?window.CAP_CUSTOM_FETCH(...arguments):fetch(...arguments)},s=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 a=_classPrivateFieldLooseKey("workerUrl"),i=_classPrivateFieldLooseKey("resetTimer"),r=_classPrivateFieldLooseKey("workersCount"),o=_classPrivateFieldLooseKey("token"),n=_classPrivateFieldLooseKey("shadow"),c=_classPrivateFieldLooseKey("div"),l=_classPrivateFieldLooseKey("host"),d=_classPrivateFieldLooseKey("solving"),h=_classPrivateFieldLooseKey("eventHandlers");class p extends HTMLElement{static get observedAttributes(){return["onsolve","onprogress","onreset","onerror","workers"]}constructor(){super(),Object.defineProperty(this,a,{writable:!0,value:""}),Object.defineProperty(this,i,{writable:!0,value:null}),Object.defineProperty(this,r,{writable:!0,value:navigator.hardwareConcurrency||8}),Object.defineProperty(this,o,{writable:!0,value:null}),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:void 0}),Object.defineProperty(this,d,{writable:!0,value:!1}),Object.defineProperty(this,h,{writable:!0,value:void 0}),_classPrivateFieldLooseBase(this,h)[h]&&_classPrivateFieldLooseBase(this,h)[h].forEach(((e,t)=>{this.removeEventListener(t.slice(2),e)})),_classPrivateFieldLooseBase(this,h)[h]=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,a)[a]&&URL.revokeObjectURL(_classPrivateFieldLooseBase(this,a)[a]);try{await s((()=>!!e)),_classPrivateFieldLooseBase(this,a)[a]=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,h)[h].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,h)[h].set(e,s),this.addEventListener(t,s)}}}async connectedCallback(){_classPrivateFieldLooseBase(this,l)[l]=this,_classPrivateFieldLooseBase(this,n)[n]=this.attachShadow({mode:"open"}),_classPrivateFieldLooseBase(this,c)[c]=document.createElement("div"),this.createUI(),this.addEventListeners(),await this.initialize(),_classPrivateFieldLooseBase(this,c)[c].removeAttribute("disabled");const e=this.getAttribute("data-cap-worker-count");this.setWorkersCount(parseInt(e)?parseInt(e,10):navigator.hardwareConcurrency||8),_classPrivateFieldLooseBase(this,l)[l].innerHTML='<input type="hidden" name="cap-token">'}async solve(){if(!_classPrivateFieldLooseBase(this,d)[d])try{_classPrivateFieldLooseBase(this,d)[d]=!0,this.updateUI("verifying","Verifying...",!0),await s((()=>!!_classPrivateFieldLooseBase(this,a)[a])),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:a}=await(await t(`${e}challenge`,{method:"POST"})).json(),r=await this.solveChallenges(s),n=await(await t(`${e}redeem`,{method:"POST",body:JSON.stringify({token:a,solutions:r}),headers:{"Content-Type":"application/json"}})).json();if(this.dispatchEvent("progress",{progress:100}),!n.success)throw new Error("Invalid solution");this.querySelector("input[name='cap-token']")&&(this.querySelector("input[name='cap-token']").value=n.token),this.dispatchEvent("solve",{token:n.token}),_classPrivateFieldLooseBase(this,o)[o]=n.token,_classPrivateFieldLooseBase(this,i)[i]&&clearTimeout(_classPrivateFieldLooseBase(this,i)[i]);const c=new Date(n.expires).getTime()-Date.now();return c>0&&c<864e5?_classPrivateFieldLooseBase(this,i)[i]=setTimeout((()=>this.reset()),c):this.error("Invalid expiration time"),{success:!0,token:_classPrivateFieldLooseBase(this,o)[o]}}catch(e){throw this.error(e.message),e}}finally{_classPrivateFieldLooseBase(this,d)[d]=!1}}async solveChallenges(e){const t=e.length;let s=0;const i=Array(_classPrivateFieldLooseBase(this,r)[r]).fill(null).map((()=>new Worker(_classPrivateFieldLooseBase(this,a)[a]))),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,a)[a]),c(new Error("Worker timeout"))}),3e4);l.onmessage=a=>{let{data:i}=a;i.found&&(clearTimeout(d),s++,this.dispatchEvent("progress",{progress:Math.round(s/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,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,c)[c].classList.add("captcha"),_classPrivateFieldLooseBase(this,c)[c].setAttribute("role","button"),_classPrivateFieldLooseBase(this,c)[c].setAttribute("tabindex","0"),_classPrivateFieldLooseBase(this,c)[c].setAttribute("disabled","true"),_classPrivateFieldLooseBase(this,c)[c].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,n)[n].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,n)[n].appendChild(_classPrivateFieldLooseBase(this,c)[c])}addEventListeners(){_classPrivateFieldLooseBase(this,c)[c].querySelector("a").addEventListener("click",(e=>{e.stopPropagation(),e.preventDefault(),window.open("https://capjs.js.org","_blank")})),_classPrivateFieldLooseBase(this,c)[c].addEventListener("click",(()=>{_classPrivateFieldLooseBase(this,c)[c].hasAttribute("disabled")||this.solve()})),_classPrivateFieldLooseBase(this,c)[c].addEventListener("keydown",(e=>{"Enter"!==e.key&&" "!==e.key||_classPrivateFieldLooseBase(this,c)[c].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,c)[c].setAttribute("data-state",e),_classPrivateFieldLooseBase(this,c)[c].querySelector("p").innerText=t,s?_classPrivateFieldLooseBase(this,c)[c].setAttribute("disabled","true"):_classPrivateFieldLooseBase(this,c)[c].removeAttribute("disabled")}handleProgress(e){const t=_classPrivateFieldLooseBase(this,c)[c].querySelector("p");t&&(_classPrivateFieldLooseBase(this,c)[c].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,i)[i]&&(clearTimeout(_classPrivateFieldLooseBase(this,i)[i]),_classPrivateFieldLooseBase(this,i)[i]=null),this.dispatchEvent("reset"),_classPrivateFieldLooseBase(this,o)[o]=null,this.querySelector("input[name='cap-token']")&&(this.querySelector("input[name='cap-token']").value="")}get token(){return _classPrivateFieldLooseBase(this,o)[o]}disconnectedCallback(){this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),_classPrivateFieldLooseBase(this,h)[h].forEach(((e,t)=>{this.removeEventListener(t.slice(2),e)})),_classPrivateFieldLooseBase(this,h)[h].clear(),_classPrivateFieldLooseBase(this,n)[n]&&(_classPrivateFieldLooseBase(this,n)[n].innerHTML=""),this.reset(),this.cleanup()}cleanup(){_classPrivateFieldLooseBase(this,i)[i]&&(clearTimeout(_classPrivateFieldLooseBase(this,i)[i]),_classPrivateFieldLooseBase(this,i)[i]=null),_classPrivateFieldLooseBase(this,a)[a]&&(URL.revokeObjectURL(_classPrivateFieldLooseBase(this,a)[a]),_classPrivateFieldLooseBase(this,a)[a]="")}}class v{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 u=new CSSStyleSheet;u.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(u);const b=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 t("https://cdn.jsdelivr.net/npm/@cap.js/widget/wasm-hashes.min.js")).text()+b.toString().replace(/^function\s*\([^\)]*\)\s*{|\}$/g,"").trim()}),1),window.Cap=v,customElements.get("cap-widget")?console.warn("The cap-widget element has already been defined. Skipping re-defining it."):customElements.define("cap-widget",p),"object"==typeof exports&&"undefined"!=typeof module?module.exports=v:"function"==typeof define&&define.amd&&define([],(function(){return v})),"undefined"!=typeof exports&&(exports.default=v)}();
|
|
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=function(){return window?.CAP_CUSTOM_FETCH?window.CAP_CUSTOM_FETCH(...arguments):fetch(...arguments)},r=(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 s 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 r((()=>!!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 r((()=>!!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:r,token:s}=await(await t(`${e}challenge`,{method:"POST"})).json(),i=await this.solveChallenges(r),a=await(await t(`${e}redeem`,{method:"POST",body:JSON.stringify({token:s,solutions:i}),headers:{"Content-Type":"application/json"}})).json();if(this.dispatchEvent("progress",{progress:100}),!a.success)throw new Error("Invalid solution");this.querySelector("input[name='cap-token']")&&(this.querySelector("input[name='cap-token']").value=a.token),this.dispatchEvent("solve",{token:a.token}),this.#s=a.token,this.#t&&clearTimeout(this.#t);const n=new Date(a.expires).getTime()-Date.now();return n>0&&n<864e5?this.#t=setTimeout((()=>this.reset()),n):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 i{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);const n=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 t("https://cdn.jsdelivr.net/npm/@cap.js/widget/wasm-hashes.min.js")).text()+n.toString().replace(/^function\s*\([^\)]*\)\s*{|\}$/g,"").trim()}),1),window.Cap=i,customElements.get("cap-widget")?console.warn("The cap-widget element has already been defined. Skipping re-defining it."):customElements.define("cap-widget",s),"object"==typeof exports&&"undefined"!=typeof module?module.exports=i:"function"==typeof define&&define.amd&&define([],(function(){return i})),"undefined"!=typeof exports&&(exports.default=i)}();
|
|
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
|
@@ -8,30 +8,12 @@
|
|
|
8
8
|
return fetch(...arguments);
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
const until = (predFn, timeout = 10000) => {
|
|
12
|
-
return new Promise((resolve, reject) => {
|
|
13
|
-
const timeoutId = setTimeout(() => {
|
|
14
|
-
reject(new Error("Initialize timeout"));
|
|
15
|
-
}, timeout);
|
|
16
|
-
|
|
17
|
-
const poll = () => {
|
|
18
|
-
if (predFn()) {
|
|
19
|
-
clearTimeout(timeoutId);
|
|
20
|
-
resolve();
|
|
21
|
-
} else {
|
|
22
|
-
setTimeout(poll, 500);
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
poll();
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
|
|
29
11
|
// MARK: Widget
|
|
30
12
|
class CapWidget extends HTMLElement {
|
|
31
13
|
#workerUrl = "";
|
|
32
14
|
#resetTimer = null;
|
|
33
15
|
#workersCount = navigator.hardwareConcurrency || 8;
|
|
34
|
-
|
|
16
|
+
token = null;
|
|
35
17
|
#shadow;
|
|
36
18
|
#div;
|
|
37
19
|
#host;
|
|
@@ -57,25 +39,15 @@
|
|
|
57
39
|
this.boundHandleReset = this.handleReset.bind(this);
|
|
58
40
|
}
|
|
59
41
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
await until(() => !!workerScript);
|
|
67
|
-
this.#workerUrl = URL.createObjectURL(
|
|
68
|
-
new Blob([workerScript], {
|
|
69
|
-
type: "application/javascript",
|
|
70
|
-
})
|
|
71
|
-
);
|
|
72
|
-
} catch (err) {
|
|
73
|
-
this.error("Failed to initialize worker");
|
|
74
|
-
throw err;
|
|
75
|
-
}
|
|
42
|
+
initialize() {
|
|
43
|
+
this.#workerUrl = URL.createObjectURL(
|
|
44
|
+
new Blob([workerScript], {
|
|
45
|
+
type: "application/javascript",
|
|
46
|
+
})
|
|
47
|
+
);
|
|
76
48
|
}
|
|
77
49
|
|
|
78
|
-
attributeChangedCallback(name,
|
|
50
|
+
attributeChangedCallback(name, _, value) {
|
|
79
51
|
if (name.startsWith("on")) {
|
|
80
52
|
const eventName = name.slice(2);
|
|
81
53
|
const oldHandler = this.#eventHandlers.get(name);
|
|
@@ -83,7 +55,7 @@
|
|
|
83
55
|
this.removeEventListener(eventName, oldHandler);
|
|
84
56
|
}
|
|
85
57
|
|
|
86
|
-
if (
|
|
58
|
+
if (value) {
|
|
87
59
|
const handler = (event) => {
|
|
88
60
|
const callback = this.getAttribute(name);
|
|
89
61
|
if (typeof window[callback] === "function") {
|
|
@@ -123,7 +95,6 @@
|
|
|
123
95
|
this.#solving = true;
|
|
124
96
|
this.updateUI("verifying", "Verifying...", true);
|
|
125
97
|
|
|
126
|
-
await until(() => !!this.#workerUrl);
|
|
127
98
|
this.dispatchEvent("progress", { progress: 0 });
|
|
128
99
|
|
|
129
100
|
try {
|
|
@@ -153,7 +124,7 @@
|
|
|
153
124
|
}
|
|
154
125
|
|
|
155
126
|
this.dispatchEvent("solve", { token: resp.token });
|
|
156
|
-
this
|
|
127
|
+
this.token = resp.token;
|
|
157
128
|
|
|
158
129
|
if (this.#resetTimer) clearTimeout(this.#resetTimer);
|
|
159
130
|
const expiresIn = new Date(resp.expires).getTime() - Date.now();
|
|
@@ -163,7 +134,7 @@
|
|
|
163
134
|
this.error("Invalid expiration time");
|
|
164
135
|
}
|
|
165
136
|
|
|
166
|
-
return { success: true, token: this
|
|
137
|
+
return { success: true, token: this.token };
|
|
167
138
|
} catch (err) {
|
|
168
139
|
this.error(err.message);
|
|
169
140
|
throw err;
|
|
@@ -324,7 +295,7 @@
|
|
|
324
295
|
}
|
|
325
296
|
|
|
326
297
|
error(message = "Unknown error") {
|
|
327
|
-
console.error("[
|
|
298
|
+
console.error("[cap] Error:", message);
|
|
328
299
|
this.dispatchEvent("error", { isCap: true, message });
|
|
329
300
|
}
|
|
330
301
|
|
|
@@ -343,14 +314,14 @@
|
|
|
343
314
|
this.#resetTimer = null;
|
|
344
315
|
}
|
|
345
316
|
this.dispatchEvent("reset");
|
|
346
|
-
this
|
|
317
|
+
this.token = null;
|
|
347
318
|
if (this.querySelector("input[name='cap-token']")) {
|
|
348
319
|
this.querySelector("input[name='cap-token']").value = "";
|
|
349
320
|
}
|
|
350
321
|
}
|
|
351
322
|
|
|
352
323
|
get token() {
|
|
353
|
-
return this
|
|
324
|
+
return this.token;
|
|
354
325
|
}
|
|
355
326
|
|
|
356
327
|
disconnectedCallback() {
|
|
@@ -425,26 +396,20 @@
|
|
|
425
396
|
);
|
|
426
397
|
document.adoptedStyleSheets.push(sheet);
|
|
427
398
|
|
|
428
|
-
// MARK: Solver worker
|
|
429
399
|
const workerFunct = function () {
|
|
430
|
-
let
|
|
400
|
+
let initPromise, solve_pow_function;
|
|
431
401
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
)
|
|
444
|
-
) {
|
|
445
|
-
console.log(
|
|
446
|
-
"[cap] WASM not enabled, falling back to crypto.subtle\nThis is significanty slower than the WASM implementation"
|
|
447
|
-
);
|
|
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();
|
|
448
413
|
|
|
449
414
|
const targetBytes = new Uint8Array(target.length / 2);
|
|
450
415
|
for (let k = 0; k < targetBytes.length; k++) {
|
|
@@ -495,54 +460,64 @@
|
|
|
495
460
|
return;
|
|
496
461
|
}
|
|
497
462
|
}
|
|
498
|
-
}
|
|
463
|
+
};
|
|
499
464
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
465
|
+
return console.warn(
|
|
466
|
+
"[cap] WebAssembly is not supported, falling back to alternative solver."
|
|
467
|
+
);
|
|
468
|
+
}
|
|
503
469
|
|
|
504
|
-
|
|
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
|
+
});
|
|
505
484
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
const input = salt + nonce.toString();
|
|
510
|
-
const inputBytes = encoder.encode(input);
|
|
511
|
-
buffer.set(inputBytes);
|
|
512
|
-
|
|
513
|
-
hasher.init();
|
|
514
|
-
hasher.update(buffer.subarray(0, inputBytes.length));
|
|
515
|
-
const hash = hasher.digest("hex");
|
|
516
|
-
|
|
517
|
-
if (hash.startsWith(target)) {
|
|
518
|
-
self.postMessage({ nonce, found: true });
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
485
|
+
self.onmessage = async ({ data: { salt, target } }) => {
|
|
486
|
+
try {
|
|
487
|
+
await initPromise;
|
|
521
488
|
|
|
522
|
-
|
|
523
|
-
|
|
489
|
+
const startTime = performance.now();
|
|
490
|
+
const nonce = solve_pow_function(salt, target);
|
|
491
|
+
const endTime = performance.now();
|
|
524
492
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
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
|
+
});
|
|
529
505
|
}
|
|
530
506
|
}
|
|
531
507
|
};
|
|
508
|
+
|
|
509
|
+
self.onerror = (error) => {
|
|
510
|
+
self.postMessage({
|
|
511
|
+
found: false,
|
|
512
|
+
error: `Worker error: ${error.message || error}`,
|
|
513
|
+
});
|
|
514
|
+
};
|
|
532
515
|
};
|
|
533
516
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
"https://cdn.jsdelivr.net/npm/@cap.js/widget/wasm-hashes.min.js"
|
|
539
|
-
)
|
|
540
|
-
).text()) +
|
|
541
|
-
workerFunct
|
|
542
|
-
.toString()
|
|
543
|
-
.replace(/^function\s*\([^\)]*\)\s*{|\}$/g, "")
|
|
544
|
-
.trim();
|
|
545
|
-
}, 1);
|
|
517
|
+
workerScript = `(() => {${workerFunct
|
|
518
|
+
.toString()
|
|
519
|
+
.replace(/^function\s*\([^\)]*\)\s*{|\}$/g, "")
|
|
520
|
+
.trim()}})()`;
|
|
546
521
|
|
|
547
522
|
window.Cap = Cap;
|
|
548
523
|
|