@cap.js/widget 0.0.22 → 0.1.1
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 +89 -106
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","[cap]"]}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);const t=this.getAttribute("data-cap-hidden-field-name")||"cap-token";_classPrivateFieldLooseBase(this,n)[n].innerHTML=`<input type="hidden" name="${t}">`}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");const n=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${n}']`)&&(this.querySelector(`input[name='${n}']`).value=o.token),this.dispatchEvent("solve",{token:o.token}),this.token=o.token,_classPrivateFieldLooseBase(this,a)[a]&&clearTimeout(_classPrivateFieldLooseBase(this,a)[a]);const c=new Date(o.expires).getTime()-Date.now();return c>0&&c<864e5?_classPrivateFieldLooseBase(this,a)[a]=setTimeout((()=>this.reset()),c):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;const e=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${e}']`)&&(this.querySelector(`input[name='${e}']`).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){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","[cap]"]}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);const t=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.#i.innerHTML=`<input type="hidden" name="${t}">`}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");const n=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${n}']`)&&(this.querySelector(`input[name='${n}']`).value=i.token),this.dispatchEvent("solve",{token:i.token}),this.token=i.token,this.#t&&clearTimeout(this.#t);const o=new Date(i.expires).getTime()-Date.now();return o>0&&o<864e5?this.#t=setTimeout((()=>this.reset()),o):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;const e=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${e}']`)&&(this.querySelector(`input[name='${e}']`).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){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;
|
|
@@ -39,7 +21,14 @@
|
|
|
39
21
|
#eventHandlers;
|
|
40
22
|
|
|
41
23
|
static get observedAttributes() {
|
|
42
|
-
return [
|
|
24
|
+
return [
|
|
25
|
+
"onsolve",
|
|
26
|
+
"onprogress",
|
|
27
|
+
"onreset",
|
|
28
|
+
"onerror",
|
|
29
|
+
"workers",
|
|
30
|
+
"[cap]",
|
|
31
|
+
];
|
|
43
32
|
}
|
|
44
33
|
|
|
45
34
|
constructor() {
|
|
@@ -57,25 +46,15 @@
|
|
|
57
46
|
this.boundHandleReset = this.handleReset.bind(this);
|
|
58
47
|
}
|
|
59
48
|
|
|
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
|
-
}
|
|
49
|
+
initialize() {
|
|
50
|
+
this.#workerUrl = URL.createObjectURL(
|
|
51
|
+
new Blob([workerScript], {
|
|
52
|
+
type: "application/javascript",
|
|
53
|
+
})
|
|
54
|
+
);
|
|
76
55
|
}
|
|
77
56
|
|
|
78
|
-
attributeChangedCallback(name,
|
|
57
|
+
attributeChangedCallback(name, _, value) {
|
|
79
58
|
if (name.startsWith("on")) {
|
|
80
59
|
const eventName = name.slice(2);
|
|
81
60
|
const oldHandler = this.#eventHandlers.get(name);
|
|
@@ -83,7 +62,7 @@
|
|
|
83
62
|
this.removeEventListener(eventName, oldHandler);
|
|
84
63
|
}
|
|
85
64
|
|
|
86
|
-
if (
|
|
65
|
+
if (value) {
|
|
87
66
|
const handler = (event) => {
|
|
88
67
|
const callback = this.getAttribute(name);
|
|
89
68
|
if (typeof window[callback] === "function") {
|
|
@@ -111,7 +90,8 @@
|
|
|
111
90
|
? parseInt(workers, 10)
|
|
112
91
|
: navigator.hardwareConcurrency || 8
|
|
113
92
|
);
|
|
114
|
-
|
|
93
|
+
const fieldName = this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
94
|
+
this.#host.innerHTML = `<input type="hidden" name="${fieldName}">`;
|
|
115
95
|
}
|
|
116
96
|
|
|
117
97
|
async solve() {
|
|
@@ -123,7 +103,6 @@
|
|
|
123
103
|
this.#solving = true;
|
|
124
104
|
this.updateUI("verifying", "Verifying...", true);
|
|
125
105
|
|
|
126
|
-
await until(() => !!this.#workerUrl);
|
|
127
106
|
this.dispatchEvent("progress", { progress: 0 });
|
|
128
107
|
|
|
129
108
|
try {
|
|
@@ -148,12 +127,13 @@
|
|
|
148
127
|
this.dispatchEvent("progress", { progress: 100 });
|
|
149
128
|
|
|
150
129
|
if (!resp.success) throw new Error("Invalid solution");
|
|
151
|
-
|
|
152
|
-
|
|
130
|
+
const fieldName = this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
131
|
+
if (this.querySelector(`input[name='${fieldName}']`)) {
|
|
132
|
+
this.querySelector(`input[name='${fieldName}']`).value = resp.token;
|
|
153
133
|
}
|
|
154
134
|
|
|
155
135
|
this.dispatchEvent("solve", { token: resp.token });
|
|
156
|
-
this
|
|
136
|
+
this.token = resp.token;
|
|
157
137
|
|
|
158
138
|
if (this.#resetTimer) clearTimeout(this.#resetTimer);
|
|
159
139
|
const expiresIn = new Date(resp.expires).getTime() - Date.now();
|
|
@@ -163,7 +143,7 @@
|
|
|
163
143
|
this.error("Invalid expiration time");
|
|
164
144
|
}
|
|
165
145
|
|
|
166
|
-
return { success: true, token: this
|
|
146
|
+
return { success: true, token: this.token };
|
|
167
147
|
} catch (err) {
|
|
168
148
|
this.error(err.message);
|
|
169
149
|
throw err;
|
|
@@ -324,7 +304,7 @@
|
|
|
324
304
|
}
|
|
325
305
|
|
|
326
306
|
error(message = "Unknown error") {
|
|
327
|
-
console.error("[
|
|
307
|
+
console.error("[cap] Error:", message);
|
|
328
308
|
this.dispatchEvent("error", { isCap: true, message });
|
|
329
309
|
}
|
|
330
310
|
|
|
@@ -343,14 +323,15 @@
|
|
|
343
323
|
this.#resetTimer = null;
|
|
344
324
|
}
|
|
345
325
|
this.dispatchEvent("reset");
|
|
346
|
-
this
|
|
347
|
-
|
|
348
|
-
|
|
326
|
+
this.token = null;
|
|
327
|
+
const fieldName = this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
328
|
+
if (this.querySelector(`input[name='${fieldName}']`)) {
|
|
329
|
+
this.querySelector(`input[name='${fieldName}']`).value = "";
|
|
349
330
|
}
|
|
350
331
|
}
|
|
351
332
|
|
|
352
333
|
get token() {
|
|
353
|
-
return this
|
|
334
|
+
return this.token;
|
|
354
335
|
}
|
|
355
336
|
|
|
356
337
|
disconnectedCallback() {
|
|
@@ -425,26 +406,20 @@
|
|
|
425
406
|
);
|
|
426
407
|
document.adoptedStyleSheets.push(sheet);
|
|
427
408
|
|
|
428
|
-
// MARK: Solver worker
|
|
429
409
|
const workerFunct = function () {
|
|
430
|
-
let
|
|
410
|
+
let initPromise, solve_pow_function;
|
|
431
411
|
|
|
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
|
-
);
|
|
412
|
+
if (
|
|
413
|
+
typeof WebAssembly !== "object" ||
|
|
414
|
+
typeof WebAssembly?.instantiate !== "function"
|
|
415
|
+
) {
|
|
416
|
+
self.onmessage = async ({ data: { salt, target } }) => {
|
|
417
|
+
// Fallback solver in case WASM is not available
|
|
418
|
+
|
|
419
|
+
let nonce = 0;
|
|
420
|
+
const batchSize = 50000;
|
|
421
|
+
let processed = 0;
|
|
422
|
+
const encoder = new TextEncoder();
|
|
448
423
|
|
|
449
424
|
const targetBytes = new Uint8Array(target.length / 2);
|
|
450
425
|
for (let k = 0; k < targetBytes.length; k++) {
|
|
@@ -495,54 +470,62 @@
|
|
|
495
470
|
return;
|
|
496
471
|
}
|
|
497
472
|
}
|
|
498
|
-
}
|
|
473
|
+
};
|
|
499
474
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
475
|
+
return console.warn(
|
|
476
|
+
"[cap] WebAssembly is not supported, falling back to alternative solver."
|
|
477
|
+
);
|
|
478
|
+
}
|
|
503
479
|
|
|
504
|
-
|
|
480
|
+
initPromise = import(
|
|
481
|
+
"https://cdn.jsdelivr.net/npm/@cap.js/wasm@0.0.3/browser/cap_wasm.min.js"
|
|
482
|
+
)
|
|
483
|
+
.then((wasmModule) => {
|
|
484
|
+
return wasmModule.default().then((instance) => {
|
|
485
|
+
solve_pow_function = (
|
|
486
|
+
instance && instance.exports ? instance.exports : wasmModule
|
|
487
|
+
).solve_pow;
|
|
488
|
+
});
|
|
489
|
+
})
|
|
490
|
+
.catch((e) => {
|
|
491
|
+
useFallback = true;
|
|
492
|
+
console.error("[cap] using fallback solver due to error:", e);
|
|
493
|
+
});
|
|
505
494
|
|
|
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
|
-
}
|
|
495
|
+
self.onmessage = async ({ data: { salt, target } }) => {
|
|
496
|
+
try {
|
|
497
|
+
await initPromise;
|
|
521
498
|
|
|
522
|
-
|
|
523
|
-
|
|
499
|
+
const startTime = performance.now();
|
|
500
|
+
const nonce = solve_pow_function(salt, target);
|
|
501
|
+
const endTime = performance.now();
|
|
524
502
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
}
|
|
503
|
+
self.postMessage({
|
|
504
|
+
nonce: Number(nonce),
|
|
505
|
+
found: true,
|
|
506
|
+
durationMs: (endTime - startTime).toFixed(2),
|
|
507
|
+
});
|
|
508
|
+
} catch (error) {
|
|
509
|
+
console.error("[cap] solver error", error);
|
|
510
|
+
self.postMessage({
|
|
511
|
+
found: false,
|
|
512
|
+
error: error.message || String(error),
|
|
513
|
+
});
|
|
530
514
|
}
|
|
531
515
|
};
|
|
516
|
+
|
|
517
|
+
self.onerror = (error) => {
|
|
518
|
+
self.postMessage({
|
|
519
|
+
found: false,
|
|
520
|
+
error: `Worker error: ${error.message || error}`,
|
|
521
|
+
});
|
|
522
|
+
};
|
|
532
523
|
};
|
|
533
524
|
|
|
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);
|
|
525
|
+
workerScript = `(() => {${workerFunct
|
|
526
|
+
.toString()
|
|
527
|
+
.replace(/^function\s*\([^\)]*\)\s*{|\}$/g, "")
|
|
528
|
+
.trim()}})()`;
|
|
546
529
|
|
|
547
530
|
window.Cap = Cap;
|
|
548
531
|
|