altcha 3.0.0 → 3.0.2
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/README.md +4 -4
- package/dist/external/altcha.js +1 -1
- package/dist/external/altcha.min.js +1 -1
- package/dist/external/altcha.umd.cjs +1 -1
- package/dist/external/altcha.umd.min.cjs +1 -1
- package/dist/lib/index.js +4 -2
- package/dist/lib/index.min.js +1 -1
- package/dist/lib/index.umd.cjs +4 -2
- package/dist/lib/index.umd.min.cjs +1 -1
- package/dist/main/altcha.i18n.js +9 -5
- package/dist/main/altcha.i18n.min.js +1 -1
- package/dist/main/altcha.i18n.umd.cjs +9 -5
- package/dist/main/altcha.i18n.umd.min.cjs +1 -1
- package/dist/main/altcha.js +9 -5
- package/dist/main/altcha.min.js +1 -1
- package/dist/main/altcha.umd.cjs +9 -5
- package/dist/main/altcha.umd.min.cjs +1 -1
- package/dist/plugins/obfuscation.plugin.js +4 -2
- package/dist/plugins/obfuscation.plugin.min.js +1 -1
- package/dist/plugins/obfuscation.plugin.umd.cjs +4 -2
- package/dist/plugins/obfuscation.plugin.umd.min.cjs +1 -1
- package/dist/workers/argon2id.js +4 -2
- package/dist/workers/pbkdf2.js +4 -2
- package/dist/workers/scrypt.js +4 -2
- package/dist/workers/sha.js +4 -2
- package/package.json +1 -1
|
@@ -340,10 +340,11 @@ async function solveChallenge(options) {
|
|
|
340
340
|
const password = new PasswordBuffer(nonceBuf, counterMode);
|
|
341
341
|
const start = performance.now();
|
|
342
342
|
let counter = counterStart;
|
|
343
|
+
let iterations = 0;
|
|
343
344
|
let derivedKeyHex = "";
|
|
344
345
|
let lastYield = start;
|
|
345
346
|
while (true) {
|
|
346
|
-
if (controller?.signal.aborted || timeout &&
|
|
347
|
+
if (controller?.signal.aborted || timeout && iterations % 10 === 0 && performance.now() - start > timeout) {
|
|
347
348
|
return null;
|
|
348
349
|
}
|
|
349
350
|
const { derivedKey } = await deriveKey2(
|
|
@@ -351,7 +352,7 @@ async function solveChallenge(options) {
|
|
|
351
352
|
saltBuf,
|
|
352
353
|
password.setCounter(counter)
|
|
353
354
|
);
|
|
354
|
-
if (
|
|
355
|
+
if (iterations % 10 === 0 && performance.now() - lastYield > 200) {
|
|
355
356
|
await delay(0);
|
|
356
357
|
lastYield = performance.now();
|
|
357
358
|
}
|
|
@@ -360,6 +361,7 @@ async function solveChallenge(options) {
|
|
|
360
361
|
break;
|
|
361
362
|
}
|
|
362
363
|
counter = counter + counterStep;
|
|
364
|
+
iterations = iterations + 1;
|
|
363
365
|
}
|
|
364
366
|
return {
|
|
365
367
|
counter,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=()=>{};function t(t,r,n){if(null==t)return r(void 0),e;const a=function(e){var t=o;try{return o=!0,e()}finally{o=t}}(()=>t.subscribe(r,n));return a.unsubscribe?()=>a.unsubscribe():a}const r=[];function n(t,n=e){let a=null;const o=new Set;function i(e){if(i=e,((n=t)!=n?i==i:n!==i||null!==n&&"object"==typeof n||"function"==typeof n)&&(t=e,a)){const e=!r.length;for(const e of o)e[1](),r.push(e,t);if(e){for(let e=0;e<r.length;e+=2)r[e][0](r[e+1]);r.length=0}}var n,i}function s(e){i(e(t))}return{set:i,update:s,subscribe:function(r,c=e){const l=[r,c];return o.add(l),1===o.size&&(a=n(i,s)||e),r(t),()=>{o.delete(l),0===o.size&&a&&(a(),a=null)}}}}function a(e){let r;return t(e,e=>r=e)(),r}let o=!1;function i(e){const t={get:e=>a(t.store)[e],set:(e,r)=>{"string"==typeof e?Object.assign(a(t.store),{[e]:r}):Object.assign(a(t.store),e),t.store.set(a(t.store))},store:n(e)};return t}globalThis.$altcha=globalThis.$altcha||{algorithms:new Map,defaults:i({}),i18n:i({}),instances:new Set,plugins:new Set};class s{constructor(e){this.host=e}static register(e){"$altcha"in globalThis&&!globalThis.$altcha.plugins.has(e)&&globalThis.$altcha.plugins.add(e)}async onFetchChallenge(e){}async onRequestServerVerification(e,t){}async onVerify(e){}}function c(e){switch(e){case"PBKDF2/SHA-512":return"SHA-512";case"PBKDF2/SHA-384":return"SHA-384";default:return"SHA-256"}}async function l(e,t,r){const{algorithm:n,cost:a,keyLength:o=32}=e,i=await crypto.subtle.importKey("raw",r,{name:"PBKDF2"},!1,["deriveKey"]),s=await crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:a,hash:c(n)},i,{name:"AES-GCM",length:8*o},!0,["encrypt"]);return{derivedKey:new Uint8Array(await crypto.subtle.exportKey("raw",s))}}function u(e,t){if(t.length>e.length)return!1;for(let r=0;r<t.length;r++)if(e[r]!==t[r])return!1;return!0}function h(e){return Array.from(new Uint8Array(e)).map(e=>e.toString(16).padStart(2,"0")).join("")}function f(e){if(e.length%2!=0)throw new Error(`Hex string must have an even length. Got: ${e}`);const t=new ArrayBuffer(e.length/2),r=new DataView(t);for(let t=0;t<e.length;t+=2){const n=e.substring(t,t+2),a=parseInt(n,16);r.setUint8(t/2,a)}return new Uint8Array(t)}async function y(e){await new Promise(t=>setTimeout(t,e))}async function g(e,t,r){const n=await crypto.subtle.importKey("raw",(new TextEncoder).encode(r),{name:"HMAC",hash:{name:e}},!1,["sign","verify"]),a=await crypto.subtle.sign("HMAC",n,"string"==typeof t?(new TextEncoder).encode(t):t);return new Uint8Array(a)}function d(e){return"object"!=typeof e||null===e||Array.isArray(e)?e:Object.keys(e).sort().reduce((t,r)=>{const n=e[r];return void 0!==n&&(t[r]=d(n)),t},{})}function m(e){return Math.floor(10*(performance.now()-e))/10}var w=(e=>(e.SHA_256="SHA-256",e.SHA_384="SHA-384",e.SHA_512="SHA-512",e))(w||{}),p=(e=>(e.CODE="code",e.ERROR="error",e.VERIFIED="verified",e.VERIFYING="verifying",e.UNVERIFIED="unverified",e.EXPIRED="expired",e))(p||{});class b{constructor(e,t="uint32"){this.nonce=e,this.mode=t,this.buffer=new Uint8Array(this.nonce.length+this.COUNTER_BYTES),this.buffer.set(this.nonce,0),this.dataView=new DataView(this.buffer.buffer)}COUNTER_BYTES=4;buffer;dataView;encoder=new TextEncoder;setCounter(e){return"string"===this.mode?function(e,t){const r=new Uint8Array(e.length+t.length);return r.set(e,0),r.set(t,e.length),r}(this.nonce,this.encoder.encode(e.toString())):(this.dataView.setUint32(this.nonce.length,e,!1),this.buffer)}}async function S(e){const{algorithm:t,counter:r,counterMode:n="uint32",cost:a,deriveKey:o,data:i,expiresAt:s,hmacAlgorithm:c=w.SHA_256,hmacKeySignatureSecret:l,hmacSignatureSecret:u,keyLength:y=32,keyPrefix:m="00",keyPrefixLength:p=y/2,memoryCost:S,parallelism:v}=e,A={algorithm:t,nonce:h(crypto.getRandomValues(new Uint8Array(16))),salt:h(crypto.getRandomValues(new Uint8Array(16))),cost:a,keyLength:y,memoryCost:S,parallelism:v,keyPrefix:m,expiresAt:s instanceof Date?Math.floor(s.getTime()/1e3):s,data:i};let E=null;if(void 0!==r){const e=f(A.nonce);E=await o(A,f(A.salt),new b(e,n).setCounter(r)),E.parameters&&Object.assign(A,E.parameters),A.keyPrefix=h(E.derivedKey.slice(0,p))}return u?async function(e,t,r,n,a){r&&a&&(t.keySignature=h(await g(e,r,a)));return t=d(t),{parameters:t,signature:h(await g(e,JSON.stringify(t),n))}}(c,A,E?.derivedKey,u,l):{parameters:d(A)}}async function v(e){const{challenge:t,concurrency:r=navigator.hardwareConcurrency,controller:n=new AbortController,createWorker:a,onOutOfMemory:o=e=>e>1?Math.floor(e/2):0,counterMode:i,timeout:s=9e4}=e,c=Math.min(16,Math.max(1,r)),l=[],u=()=>{for(const e of l)e.terminate()};for(let e=0;e<c;e++)l.push(await a(t.parameters.algorithm));let h=null;try{h=await Promise.race(l.map((e,r)=>(n.signal.addEventListener("abort",()=>{e.postMessage({type:"abort"})}),new Promise((n,a)=>{e.addEventListener("error",e=>{a(e)}),e.addEventListener("message",t=>{if(t.data){for(const t of l)t!==e&&t.postMessage({type:"abort"});if(t.data.error)return a(new Error(t.data.error))}n(t.data)}),e.postMessage({challenge:t,counterMode:i,counterStart:r,counterStep:c,timeout:s,type:"work"})}))))}catch(r){if(r instanceof Error&&!!r?.message?.includes("Out of memory")&&o){u();const r=o(c);if(r)return v({...e,challenge:t,controller:n,concurrency:r,createWorker:a})}throw r}finally{u()}return n.signal.aborted?null:h||null}async function A(e,t={}){let{concurrency:r=Math.max(1,Math.min(4,navigator.hardwareConcurrency)),createWorker:n,deriveKey:a=l}=t,o=null;try{o=JSON.parse(atob(e))}catch{throw new Error("Unable to parse obfuscated data.")}if(!o||"object"!=typeof o||!("parameters"in o)||!("cipher"in o))throw new Error("Invalid obfuscated data format.");const i=o.cipher;let s=null;if(!n&&"$altcha"in globalThis&&(n=globalThis.$altcha.algorithms.get(o.parameters.algorithm)),s=n?await v({challenge:o,concurrency:r,createWorker:n}):await async function(e){const{challenge:t,controller:r,counterMode:n="uint32",counterStart:a=0,counterStep:o=1,deriveKey:i,timeout:s=9e4}=e,{nonce:c,keyPrefix:l,salt:g}=t.parameters,d=f(c),w=f(g),p=l.length%2==0?f(l):null,S=new b(d,n),v=performance.now();let A=a,E="",
|
|
1
|
+
const e=()=>{};function t(t,r,n){if(null==t)return r(void 0),e;const a=function(e){var t=o;try{return o=!0,e()}finally{o=t}}(()=>t.subscribe(r,n));return a.unsubscribe?()=>a.unsubscribe():a}const r=[];function n(t,n=e){let a=null;const o=new Set;function i(e){if(i=e,((n=t)!=n?i==i:n!==i||null!==n&&"object"==typeof n||"function"==typeof n)&&(t=e,a)){const e=!r.length;for(const e of o)e[1](),r.push(e,t);if(e){for(let e=0;e<r.length;e+=2)r[e][0](r[e+1]);r.length=0}}var n,i}function s(e){i(e(t))}return{set:i,update:s,subscribe:function(r,c=e){const l=[r,c];return o.add(l),1===o.size&&(a=n(i,s)||e),r(t),()=>{o.delete(l),0===o.size&&a&&(a(),a=null)}}}}function a(e){let r;return t(e,e=>r=e)(),r}let o=!1;function i(e){const t={get:e=>a(t.store)[e],set:(e,r)=>{"string"==typeof e?Object.assign(a(t.store),{[e]:r}):Object.assign(a(t.store),e),t.store.set(a(t.store))},store:n(e)};return t}globalThis.$altcha=globalThis.$altcha||{algorithms:new Map,defaults:i({}),i18n:i({}),instances:new Set,plugins:new Set};class s{constructor(e){this.host=e}static register(e){"$altcha"in globalThis&&!globalThis.$altcha.plugins.has(e)&&globalThis.$altcha.plugins.add(e)}async onFetchChallenge(e){}async onRequestServerVerification(e,t){}async onVerify(e){}}function c(e){switch(e){case"PBKDF2/SHA-512":return"SHA-512";case"PBKDF2/SHA-384":return"SHA-384";default:return"SHA-256"}}async function l(e,t,r){const{algorithm:n,cost:a,keyLength:o=32}=e,i=await crypto.subtle.importKey("raw",r,{name:"PBKDF2"},!1,["deriveKey"]),s=await crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:a,hash:c(n)},i,{name:"AES-GCM",length:8*o},!0,["encrypt"]);return{derivedKey:new Uint8Array(await crypto.subtle.exportKey("raw",s))}}function u(e,t){if(t.length>e.length)return!1;for(let r=0;r<t.length;r++)if(e[r]!==t[r])return!1;return!0}function h(e){return Array.from(new Uint8Array(e)).map(e=>e.toString(16).padStart(2,"0")).join("")}function f(e){if(e.length%2!=0)throw new Error(`Hex string must have an even length. Got: ${e}`);const t=new ArrayBuffer(e.length/2),r=new DataView(t);for(let t=0;t<e.length;t+=2){const n=e.substring(t,t+2),a=parseInt(n,16);r.setUint8(t/2,a)}return new Uint8Array(t)}async function y(e){await new Promise(t=>setTimeout(t,e))}async function g(e,t,r){const n=await crypto.subtle.importKey("raw",(new TextEncoder).encode(r),{name:"HMAC",hash:{name:e}},!1,["sign","verify"]),a=await crypto.subtle.sign("HMAC",n,"string"==typeof t?(new TextEncoder).encode(t):t);return new Uint8Array(a)}function d(e){return"object"!=typeof e||null===e||Array.isArray(e)?e:Object.keys(e).sort().reduce((t,r)=>{const n=e[r];return void 0!==n&&(t[r]=d(n)),t},{})}function m(e){return Math.floor(10*(performance.now()-e))/10}var w=(e=>(e.SHA_256="SHA-256",e.SHA_384="SHA-384",e.SHA_512="SHA-512",e))(w||{}),p=(e=>(e.CODE="code",e.ERROR="error",e.VERIFIED="verified",e.VERIFYING="verifying",e.UNVERIFIED="unverified",e.EXPIRED="expired",e))(p||{});class b{constructor(e,t="uint32"){this.nonce=e,this.mode=t,this.buffer=new Uint8Array(this.nonce.length+this.COUNTER_BYTES),this.buffer.set(this.nonce,0),this.dataView=new DataView(this.buffer.buffer)}COUNTER_BYTES=4;buffer;dataView;encoder=new TextEncoder;setCounter(e){return"string"===this.mode?function(e,t){const r=new Uint8Array(e.length+t.length);return r.set(e,0),r.set(t,e.length),r}(this.nonce,this.encoder.encode(e.toString())):(this.dataView.setUint32(this.nonce.length,e,!1),this.buffer)}}async function S(e){const{algorithm:t,counter:r,counterMode:n="uint32",cost:a,deriveKey:o,data:i,expiresAt:s,hmacAlgorithm:c=w.SHA_256,hmacKeySignatureSecret:l,hmacSignatureSecret:u,keyLength:y=32,keyPrefix:m="00",keyPrefixLength:p=y/2,memoryCost:S,parallelism:v}=e,A={algorithm:t,nonce:h(crypto.getRandomValues(new Uint8Array(16))),salt:h(crypto.getRandomValues(new Uint8Array(16))),cost:a,keyLength:y,memoryCost:S,parallelism:v,keyPrefix:m,expiresAt:s instanceof Date?Math.floor(s.getTime()/1e3):s,data:i};let E=null;if(void 0!==r){const e=f(A.nonce);E=await o(A,f(A.salt),new b(e,n).setCounter(r)),E.parameters&&Object.assign(A,E.parameters),A.keyPrefix=h(E.derivedKey.slice(0,p))}return u?async function(e,t,r,n,a){r&&a&&(t.keySignature=h(await g(e,r,a)));return t=d(t),{parameters:t,signature:h(await g(e,JSON.stringify(t),n))}}(c,A,E?.derivedKey,u,l):{parameters:d(A)}}async function v(e){const{challenge:t,concurrency:r=navigator.hardwareConcurrency,controller:n=new AbortController,createWorker:a,onOutOfMemory:o=e=>e>1?Math.floor(e/2):0,counterMode:i,timeout:s=9e4}=e,c=Math.min(16,Math.max(1,r)),l=[],u=()=>{for(const e of l)e.terminate()};for(let e=0;e<c;e++)l.push(await a(t.parameters.algorithm));let h=null;try{h=await Promise.race(l.map((e,r)=>(n.signal.addEventListener("abort",()=>{e.postMessage({type:"abort"})}),new Promise((n,a)=>{e.addEventListener("error",e=>{a(e)}),e.addEventListener("message",t=>{if(t.data){for(const t of l)t!==e&&t.postMessage({type:"abort"});if(t.data.error)return a(new Error(t.data.error))}n(t.data)}),e.postMessage({challenge:t,counterMode:i,counterStart:r,counterStep:c,timeout:s,type:"work"})}))))}catch(r){if(r instanceof Error&&!!r?.message?.includes("Out of memory")&&o){u();const r=o(c);if(r)return v({...e,challenge:t,controller:n,concurrency:r,createWorker:a})}throw r}finally{u()}return n.signal.aborted?null:h||null}async function A(e,t={}){let{concurrency:r=Math.max(1,Math.min(4,navigator.hardwareConcurrency)),createWorker:n,deriveKey:a=l}=t,o=null;try{o=JSON.parse(atob(e))}catch{throw new Error("Unable to parse obfuscated data.")}if(!o||"object"!=typeof o||!("parameters"in o)||!("cipher"in o))throw new Error("Invalid obfuscated data format.");const i=o.cipher;let s=null;if(!n&&"$altcha"in globalThis&&(n=globalThis.$altcha.algorithms.get(o.parameters.algorithm)),s=n?await v({challenge:o,concurrency:r,createWorker:n}):await async function(e){const{challenge:t,controller:r,counterMode:n="uint32",counterStart:a=0,counterStep:o=1,deriveKey:i,timeout:s=9e4}=e,{nonce:c,keyPrefix:l,salt:g}=t.parameters,d=f(c),w=f(g),p=l.length%2==0?f(l):null,S=new b(d,n),v=performance.now();let A=a,E=0,T="",x=v;for(;;){if(r?.signal.aborted||s&&E%10==0&&performance.now()-v>s)return null;const{derivedKey:e}=await i(t.parameters,w,S.setCounter(A));if(E%10==0&&performance.now()-x>200&&(await y(0),x=performance.now()),p?u(e,p):h(e).startsWith(l)){T=h(e);break}A+=o,E+=1}return{counter:A,derivedKey:T,time:m(v)}}({challenge:o,deriveKey:a}),!s)throw new Error("Unable to find solution.");const c=await crypto.subtle.importKey("raw",f(s.derivedKey),{name:"AES-GCM"},!1,["decrypt"]),g=await crypto.subtle.decrypt({name:"AES-GCM",iv:f(i.iv)},c,f(i.data));return(new TextDecoder).decode(g)}async function E(e,t={}){const{deriveKey:r=l}=t,n=t?.counterMin||20,a=t?.counterMax||200,{parameters:o}=await S({algorithm:"PBKDF2/SHA-256",cost:5e3,deriveKey:r,counter:Math.floor(Math.random()*(a-n+1))+n,keyPrefixLength:32,...t}),i=await crypto.subtle.importKey("raw",f(o.keyPrefix),{name:"AES-GCM"},!1,["encrypt"]),s=crypto.getRandomValues(new Uint8Array(12)),c=await crypto.subtle.encrypt({name:"AES-GCM",iv:s},i,(new TextEncoder).encode(e));return btoa(JSON.stringify({parameters:{...o,keyPrefix:o.keyPrefix.slice(0,o.keyLength||32)},cipher:{iv:h(s),data:h(c)}}))}s.register(class extends s{static deobfuscate=A;static obfuscate=E;elTrigger=null;activate(){this.elTrigger=this.host.querySelector("button"),this.elTrigger&&(this.elTrigger.addEventListener("click",this.onTriggerClick.bind(this)),this.host.configure({floatingAnchor:this.elTrigger}))}destroy(){}async onVerify(e){const{minDuration:t=500}=e,r=performance.now(),n=this.host.getAttribute("data-obfuscated");if(n){this.host.reset(p.VERIFYING);try{const e=await A(n);await this.#e(Math.max(0,t-(performance.now()-r))),this.#t(e)}catch(e){this.host.setState(p.ERROR,String(e))}finally{this.host.setState(p.VERIFIED)}return null}}onTriggerClick(e){e.preventDefault(),this.host.show(),this.host.verify().then(()=>{this.host.hide()})}#t(e){let t;if(e.match(/^(mailto|tel|sms|https?):/)){const[r]=e.slice(e.indexOf(":")+1).replace(/^\/\//,"").split("?");t=document.createElement("a"),t.href=e,t.innerText=r}else t=document.createTextNode(e);this.elTrigger&&t&&(this.elTrigger.after(t),this.elTrigger.parentElement?.removeChild(this.elTrigger))}async#e(e){await new Promise(t=>setTimeout(t,e))}});
|
|
@@ -344,10 +344,11 @@
|
|
|
344
344
|
const password = new PasswordBuffer(nonceBuf, counterMode);
|
|
345
345
|
const start = performance.now();
|
|
346
346
|
let counter = counterStart;
|
|
347
|
+
let iterations = 0;
|
|
347
348
|
let derivedKeyHex = "";
|
|
348
349
|
let lastYield = start;
|
|
349
350
|
while (true) {
|
|
350
|
-
if (controller?.signal.aborted || timeout &&
|
|
351
|
+
if (controller?.signal.aborted || timeout && iterations % 10 === 0 && performance.now() - start > timeout) {
|
|
351
352
|
return null;
|
|
352
353
|
}
|
|
353
354
|
const { derivedKey } = await deriveKey2(
|
|
@@ -355,7 +356,7 @@
|
|
|
355
356
|
saltBuf,
|
|
356
357
|
password.setCounter(counter)
|
|
357
358
|
);
|
|
358
|
-
if (
|
|
359
|
+
if (iterations % 10 === 0 && performance.now() - lastYield > 200) {
|
|
359
360
|
await delay(0);
|
|
360
361
|
lastYield = performance.now();
|
|
361
362
|
}
|
|
@@ -364,6 +365,7 @@
|
|
|
364
365
|
break;
|
|
365
366
|
}
|
|
366
367
|
counter = counter + counterStep;
|
|
368
|
+
iterations = iterations + 1;
|
|
367
369
|
}
|
|
368
370
|
return {
|
|
369
371
|
counter,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e){"function"==typeof define&&define.amd?define(e):e()}(function(){"use strict";const e=()=>{};function t(t,r,n){if(null==t)return r(void 0),e;const a=function(e){var t=i;try{return i=!0,e()}finally{i=t}}(()=>t.subscribe(r,n));return a.unsubscribe?()=>a.unsubscribe():a}const r=[];function n(t,n=e){let a=null;const i=new Set;function o(e){if(o=e,((n=t)!=n?o==o:n!==o||null!==n&&"object"==typeof n||"function"==typeof n)&&(t=e,a)){const e=!r.length;for(const e of i)e[1](),r.push(e,t);if(e){for(let e=0;e<r.length;e+=2)r[e][0](r[e+1]);r.length=0}}var n,o}function s(e){o(e(t))}return{set:o,update:s,subscribe:function(r,c=e){const l=[r,c];return i.add(l),1===i.size&&(a=n(o,s)||e),r(t),()=>{i.delete(l),0===i.size&&a&&(a(),a=null)}}}}function a(e){let r;return t(e,e=>r=e)(),r}let i=!1;function o(e){const t={get:e=>a(t.store)[e],set:(e,r)=>{"string"==typeof e?Object.assign(a(t.store),{[e]:r}):Object.assign(a(t.store),e),t.store.set(a(t.store))},store:n(e)};return t}globalThis.$altcha=globalThis.$altcha||{algorithms:new Map,defaults:o({}),i18n:o({}),instances:new Set,plugins:new Set};class s{constructor(e){this.host=e}static register(e){"$altcha"in globalThis&&!globalThis.$altcha.plugins.has(e)&&globalThis.$altcha.plugins.add(e)}async onFetchChallenge(e){}async onRequestServerVerification(e,t){}async onVerify(e){}}function c(e){switch(e){case"PBKDF2/SHA-512":return"SHA-512";case"PBKDF2/SHA-384":return"SHA-384";default:return"SHA-256"}}async function l(e,t,r){const{algorithm:n,cost:a,keyLength:i=32}=e,o=await crypto.subtle.importKey("raw",r,{name:"PBKDF2"},!1,["deriveKey"]),s=await crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:a,hash:c(n)},o,{name:"AES-GCM",length:8*i},!0,["encrypt"]);return{derivedKey:new Uint8Array(await crypto.subtle.exportKey("raw",s))}}function u(e,t){if(t.length>e.length)return!1;for(let r=0;r<t.length;r++)if(e[r]!==t[r])return!1;return!0}function h(e){return Array.from(new Uint8Array(e)).map(e=>e.toString(16).padStart(2,"0")).join("")}function f(e){if(e.length%2!=0)throw new Error(`Hex string must have an even length. Got: ${e}`);const t=new ArrayBuffer(e.length/2),r=new DataView(t);for(let t=0;t<e.length;t+=2){const n=e.substring(t,t+2),a=parseInt(n,16);r.setUint8(t/2,a)}return new Uint8Array(t)}async function y(e){await new Promise(t=>setTimeout(t,e))}async function g(e,t,r){const n=await crypto.subtle.importKey("raw",(new TextEncoder).encode(r),{name:"HMAC",hash:{name:e}},!1,["sign","verify"]),a=await crypto.subtle.sign("HMAC",n,"string"==typeof t?(new TextEncoder).encode(t):t);return new Uint8Array(a)}function d(e){return"object"!=typeof e||null===e||Array.isArray(e)?e:Object.keys(e).sort().reduce((t,r)=>{const n=e[r];return void 0!==n&&(t[r]=d(n)),t},{})}function m(e){return Math.floor(10*(performance.now()-e))/10}var w=(e=>(e.SHA_256="SHA-256",e.SHA_384="SHA-384",e.SHA_512="SHA-512",e))(w||{}),p=(e=>(e.CODE="code",e.ERROR="error",e.VERIFIED="verified",e.VERIFYING="verifying",e.UNVERIFIED="unverified",e.EXPIRED="expired",e))(p||{});class b{constructor(e,t="uint32"){this.nonce=e,this.mode=t,this.buffer=new Uint8Array(this.nonce.length+this.COUNTER_BYTES),this.buffer.set(this.nonce,0),this.dataView=new DataView(this.buffer.buffer)}COUNTER_BYTES=4;buffer;dataView;encoder=new TextEncoder;setCounter(e){return"string"===this.mode?function(e,t){const r=new Uint8Array(e.length+t.length);return r.set(e,0),r.set(t,e.length),r}(this.nonce,this.encoder.encode(e.toString())):(this.dataView.setUint32(this.nonce.length,e,!1),this.buffer)}}async function S(e){const{algorithm:t,counter:r,counterMode:n="uint32",cost:a,deriveKey:i,data:o,expiresAt:s,hmacAlgorithm:c=w.SHA_256,hmacKeySignatureSecret:l,hmacSignatureSecret:u,keyLength:y=32,keyPrefix:m="00",keyPrefixLength:p=y/2,memoryCost:S,parallelism:v}=e,A={algorithm:t,nonce:h(crypto.getRandomValues(new Uint8Array(16))),salt:h(crypto.getRandomValues(new Uint8Array(16))),cost:a,keyLength:y,memoryCost:S,parallelism:v,keyPrefix:m,expiresAt:s instanceof Date?Math.floor(s.getTime()/1e3):s,data:o};let E=null;if(void 0!==r){const e=f(A.nonce);E=await i(A,f(A.salt),new b(e,n).setCounter(r)),E.parameters&&Object.assign(A,E.parameters),A.keyPrefix=h(E.derivedKey.slice(0,p))}return u?async function(e,t,r,n,a){r&&a&&(t.keySignature=h(await g(e,r,a)));return t=d(t),{parameters:t,signature:h(await g(e,JSON.stringify(t),n))}}(c,A,E?.derivedKey,u,l):{parameters:d(A)}}async function v(e){const{challenge:t,concurrency:r=navigator.hardwareConcurrency,controller:n=new AbortController,createWorker:a,onOutOfMemory:i=e=>e>1?Math.floor(e/2):0,counterMode:o,timeout:s=9e4}=e,c=Math.min(16,Math.max(1,r)),l=[],u=()=>{for(const e of l)e.terminate()};for(let e=0;e<c;e++)l.push(await a(t.parameters.algorithm));let h=null;try{h=await Promise.race(l.map((e,r)=>(n.signal.addEventListener("abort",()=>{e.postMessage({type:"abort"})}),new Promise((n,a)=>{e.addEventListener("error",e=>{a(e)}),e.addEventListener("message",t=>{if(t.data){for(const t of l)t!==e&&t.postMessage({type:"abort"});if(t.data.error)return a(new Error(t.data.error))}n(t.data)}),e.postMessage({challenge:t,counterMode:o,counterStart:r,counterStep:c,timeout:s,type:"work"})}))))}catch(r){if(r instanceof Error&&!!r?.message?.includes("Out of memory")&&i){u();const r=i(c);if(r)return v({...e,challenge:t,controller:n,concurrency:r,createWorker:a})}throw r}finally{u()}return n.signal.aborted?null:h||null}async function A(e,t={}){let{concurrency:r=Math.max(1,Math.min(4,navigator.hardwareConcurrency)),createWorker:n,deriveKey:a=l}=t,i=null;try{i=JSON.parse(atob(e))}catch{throw new Error("Unable to parse obfuscated data.")}if(!i||"object"!=typeof i||!("parameters"in i)||!("cipher"in i))throw new Error("Invalid obfuscated data format.");const o=i.cipher;let s=null;if(!n&&"$altcha"in globalThis&&(n=globalThis.$altcha.algorithms.get(i.parameters.algorithm)),s=n?await v({challenge:i,concurrency:r,createWorker:n}):await async function(e){const{challenge:t,controller:r,counterMode:n="uint32",counterStart:a=0,counterStep:i=1,deriveKey:o,timeout:s=9e4}=e,{nonce:c,keyPrefix:l,salt:g}=t.parameters,d=f(c),w=f(g),p=l.length%2==0?f(l):null,S=new b(d,n),v=performance.now();let A=a,E="",
|
|
1
|
+
!function(e){"function"==typeof define&&define.amd?define(e):e()}(function(){"use strict";const e=()=>{};function t(t,r,n){if(null==t)return r(void 0),e;const a=function(e){var t=i;try{return i=!0,e()}finally{i=t}}(()=>t.subscribe(r,n));return a.unsubscribe?()=>a.unsubscribe():a}const r=[];function n(t,n=e){let a=null;const i=new Set;function o(e){if(o=e,((n=t)!=n?o==o:n!==o||null!==n&&"object"==typeof n||"function"==typeof n)&&(t=e,a)){const e=!r.length;for(const e of i)e[1](),r.push(e,t);if(e){for(let e=0;e<r.length;e+=2)r[e][0](r[e+1]);r.length=0}}var n,o}function s(e){o(e(t))}return{set:o,update:s,subscribe:function(r,c=e){const l=[r,c];return i.add(l),1===i.size&&(a=n(o,s)||e),r(t),()=>{i.delete(l),0===i.size&&a&&(a(),a=null)}}}}function a(e){let r;return t(e,e=>r=e)(),r}let i=!1;function o(e){const t={get:e=>a(t.store)[e],set:(e,r)=>{"string"==typeof e?Object.assign(a(t.store),{[e]:r}):Object.assign(a(t.store),e),t.store.set(a(t.store))},store:n(e)};return t}globalThis.$altcha=globalThis.$altcha||{algorithms:new Map,defaults:o({}),i18n:o({}),instances:new Set,plugins:new Set};class s{constructor(e){this.host=e}static register(e){"$altcha"in globalThis&&!globalThis.$altcha.plugins.has(e)&&globalThis.$altcha.plugins.add(e)}async onFetchChallenge(e){}async onRequestServerVerification(e,t){}async onVerify(e){}}function c(e){switch(e){case"PBKDF2/SHA-512":return"SHA-512";case"PBKDF2/SHA-384":return"SHA-384";default:return"SHA-256"}}async function l(e,t,r){const{algorithm:n,cost:a,keyLength:i=32}=e,o=await crypto.subtle.importKey("raw",r,{name:"PBKDF2"},!1,["deriveKey"]),s=await crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:a,hash:c(n)},o,{name:"AES-GCM",length:8*i},!0,["encrypt"]);return{derivedKey:new Uint8Array(await crypto.subtle.exportKey("raw",s))}}function u(e,t){if(t.length>e.length)return!1;for(let r=0;r<t.length;r++)if(e[r]!==t[r])return!1;return!0}function h(e){return Array.from(new Uint8Array(e)).map(e=>e.toString(16).padStart(2,"0")).join("")}function f(e){if(e.length%2!=0)throw new Error(`Hex string must have an even length. Got: ${e}`);const t=new ArrayBuffer(e.length/2),r=new DataView(t);for(let t=0;t<e.length;t+=2){const n=e.substring(t,t+2),a=parseInt(n,16);r.setUint8(t/2,a)}return new Uint8Array(t)}async function y(e){await new Promise(t=>setTimeout(t,e))}async function g(e,t,r){const n=await crypto.subtle.importKey("raw",(new TextEncoder).encode(r),{name:"HMAC",hash:{name:e}},!1,["sign","verify"]),a=await crypto.subtle.sign("HMAC",n,"string"==typeof t?(new TextEncoder).encode(t):t);return new Uint8Array(a)}function d(e){return"object"!=typeof e||null===e||Array.isArray(e)?e:Object.keys(e).sort().reduce((t,r)=>{const n=e[r];return void 0!==n&&(t[r]=d(n)),t},{})}function m(e){return Math.floor(10*(performance.now()-e))/10}var w=(e=>(e.SHA_256="SHA-256",e.SHA_384="SHA-384",e.SHA_512="SHA-512",e))(w||{}),p=(e=>(e.CODE="code",e.ERROR="error",e.VERIFIED="verified",e.VERIFYING="verifying",e.UNVERIFIED="unverified",e.EXPIRED="expired",e))(p||{});class b{constructor(e,t="uint32"){this.nonce=e,this.mode=t,this.buffer=new Uint8Array(this.nonce.length+this.COUNTER_BYTES),this.buffer.set(this.nonce,0),this.dataView=new DataView(this.buffer.buffer)}COUNTER_BYTES=4;buffer;dataView;encoder=new TextEncoder;setCounter(e){return"string"===this.mode?function(e,t){const r=new Uint8Array(e.length+t.length);return r.set(e,0),r.set(t,e.length),r}(this.nonce,this.encoder.encode(e.toString())):(this.dataView.setUint32(this.nonce.length,e,!1),this.buffer)}}async function S(e){const{algorithm:t,counter:r,counterMode:n="uint32",cost:a,deriveKey:i,data:o,expiresAt:s,hmacAlgorithm:c=w.SHA_256,hmacKeySignatureSecret:l,hmacSignatureSecret:u,keyLength:y=32,keyPrefix:m="00",keyPrefixLength:p=y/2,memoryCost:S,parallelism:v}=e,A={algorithm:t,nonce:h(crypto.getRandomValues(new Uint8Array(16))),salt:h(crypto.getRandomValues(new Uint8Array(16))),cost:a,keyLength:y,memoryCost:S,parallelism:v,keyPrefix:m,expiresAt:s instanceof Date?Math.floor(s.getTime()/1e3):s,data:o};let E=null;if(void 0!==r){const e=f(A.nonce);E=await i(A,f(A.salt),new b(e,n).setCounter(r)),E.parameters&&Object.assign(A,E.parameters),A.keyPrefix=h(E.derivedKey.slice(0,p))}return u?async function(e,t,r,n,a){r&&a&&(t.keySignature=h(await g(e,r,a)));return t=d(t),{parameters:t,signature:h(await g(e,JSON.stringify(t),n))}}(c,A,E?.derivedKey,u,l):{parameters:d(A)}}async function v(e){const{challenge:t,concurrency:r=navigator.hardwareConcurrency,controller:n=new AbortController,createWorker:a,onOutOfMemory:i=e=>e>1?Math.floor(e/2):0,counterMode:o,timeout:s=9e4}=e,c=Math.min(16,Math.max(1,r)),l=[],u=()=>{for(const e of l)e.terminate()};for(let e=0;e<c;e++)l.push(await a(t.parameters.algorithm));let h=null;try{h=await Promise.race(l.map((e,r)=>(n.signal.addEventListener("abort",()=>{e.postMessage({type:"abort"})}),new Promise((n,a)=>{e.addEventListener("error",e=>{a(e)}),e.addEventListener("message",t=>{if(t.data){for(const t of l)t!==e&&t.postMessage({type:"abort"});if(t.data.error)return a(new Error(t.data.error))}n(t.data)}),e.postMessage({challenge:t,counterMode:o,counterStart:r,counterStep:c,timeout:s,type:"work"})}))))}catch(r){if(r instanceof Error&&!!r?.message?.includes("Out of memory")&&i){u();const r=i(c);if(r)return v({...e,challenge:t,controller:n,concurrency:r,createWorker:a})}throw r}finally{u()}return n.signal.aborted?null:h||null}async function A(e,t={}){let{concurrency:r=Math.max(1,Math.min(4,navigator.hardwareConcurrency)),createWorker:n,deriveKey:a=l}=t,i=null;try{i=JSON.parse(atob(e))}catch{throw new Error("Unable to parse obfuscated data.")}if(!i||"object"!=typeof i||!("parameters"in i)||!("cipher"in i))throw new Error("Invalid obfuscated data format.");const o=i.cipher;let s=null;if(!n&&"$altcha"in globalThis&&(n=globalThis.$altcha.algorithms.get(i.parameters.algorithm)),s=n?await v({challenge:i,concurrency:r,createWorker:n}):await async function(e){const{challenge:t,controller:r,counterMode:n="uint32",counterStart:a=0,counterStep:i=1,deriveKey:o,timeout:s=9e4}=e,{nonce:c,keyPrefix:l,salt:g}=t.parameters,d=f(c),w=f(g),p=l.length%2==0?f(l):null,S=new b(d,n),v=performance.now();let A=a,E=0,T="",x=v;for(;;){if(r?.signal.aborted||s&&E%10==0&&performance.now()-v>s)return null;const{derivedKey:e}=await o(t.parameters,w,S.setCounter(A));if(E%10==0&&performance.now()-x>200&&(await y(0),x=performance.now()),p?u(e,p):h(e).startsWith(l)){T=h(e);break}A+=i,E+=1}return{counter:A,derivedKey:T,time:m(v)}}({challenge:i,deriveKey:a}),!s)throw new Error("Unable to find solution.");const c=await crypto.subtle.importKey("raw",f(s.derivedKey),{name:"AES-GCM"},!1,["decrypt"]),g=await crypto.subtle.decrypt({name:"AES-GCM",iv:f(o.iv)},c,f(o.data));return(new TextDecoder).decode(g)}async function E(e,t={}){const{deriveKey:r=l}=t,n=t?.counterMin||20,a=t?.counterMax||200,{parameters:i}=await S({algorithm:"PBKDF2/SHA-256",cost:5e3,deriveKey:r,counter:Math.floor(Math.random()*(a-n+1))+n,keyPrefixLength:32,...t}),o=await crypto.subtle.importKey("raw",f(i.keyPrefix),{name:"AES-GCM"},!1,["encrypt"]),s=crypto.getRandomValues(new Uint8Array(12)),c=await crypto.subtle.encrypt({name:"AES-GCM",iv:s},o,(new TextEncoder).encode(e));return btoa(JSON.stringify({parameters:{...i,keyPrefix:i.keyPrefix.slice(0,i.keyLength||32)},cipher:{iv:h(s),data:h(c)}}))}s.register(class extends s{static deobfuscate=A;static obfuscate=E;elTrigger=null;activate(){this.elTrigger=this.host.querySelector("button"),this.elTrigger&&(this.elTrigger.addEventListener("click",this.onTriggerClick.bind(this)),this.host.configure({floatingAnchor:this.elTrigger}))}destroy(){}async onVerify(e){const{minDuration:t=500}=e,r=performance.now(),n=this.host.getAttribute("data-obfuscated");if(n){this.host.reset(p.VERIFYING);try{const e=await A(n);await this.#e(Math.max(0,t-(performance.now()-r))),this.#t(e)}catch(e){this.host.setState(p.ERROR,String(e))}finally{this.host.setState(p.VERIFIED)}return null}}onTriggerClick(e){e.preventDefault(),this.host.show(),this.host.verify().then(()=>{this.host.hide()})}#t(e){let t;if(e.match(/^(mailto|tel|sms|https?):/)){const[r]=e.slice(e.indexOf(":")+1).replace(/^\/\//,"").split("?");t=document.createElement("a"),t.href=e,t.innerText=r}else t=document.createTextNode(e);this.elTrigger&&t&&(this.elTrigger.after(t),this.elTrigger.parentElement?.removeChild(this.elTrigger))}async#e(e){await new Promise(t=>setTimeout(t,e))}})});
|
package/dist/workers/argon2id.js
CHANGED
|
@@ -81,10 +81,11 @@
|
|
|
81
81
|
const password = new PasswordBuffer(nonceBuf, counterMode);
|
|
82
82
|
const start = performance.now();
|
|
83
83
|
let counter = counterStart;
|
|
84
|
+
let iterations = 0;
|
|
84
85
|
let derivedKeyHex = "";
|
|
85
86
|
let lastYield = start;
|
|
86
87
|
while (true) {
|
|
87
|
-
if (controller?.signal.aborted || timeout &&
|
|
88
|
+
if (controller?.signal.aborted || timeout && iterations % 10 === 0 && performance.now() - start > timeout) {
|
|
88
89
|
return null;
|
|
89
90
|
}
|
|
90
91
|
const { derivedKey } = await deriveKey2(
|
|
@@ -92,7 +93,7 @@
|
|
|
92
93
|
saltBuf,
|
|
93
94
|
password.setCounter(counter)
|
|
94
95
|
);
|
|
95
|
-
if (
|
|
96
|
+
if (iterations % 10 === 0 && performance.now() - lastYield > 200) {
|
|
96
97
|
await delay(0);
|
|
97
98
|
lastYield = performance.now();
|
|
98
99
|
}
|
|
@@ -101,6 +102,7 @@
|
|
|
101
102
|
break;
|
|
102
103
|
}
|
|
103
104
|
counter = counter + counterStep;
|
|
105
|
+
iterations = iterations + 1;
|
|
104
106
|
}
|
|
105
107
|
return {
|
|
106
108
|
counter,
|
package/dist/workers/pbkdf2.js
CHANGED
|
@@ -81,10 +81,11 @@
|
|
|
81
81
|
const password = new PasswordBuffer(nonceBuf, counterMode);
|
|
82
82
|
const start = performance.now();
|
|
83
83
|
let counter = counterStart;
|
|
84
|
+
let iterations = 0;
|
|
84
85
|
let derivedKeyHex = "";
|
|
85
86
|
let lastYield = start;
|
|
86
87
|
while (true) {
|
|
87
|
-
if (controller?.signal.aborted || timeout &&
|
|
88
|
+
if (controller?.signal.aborted || timeout && iterations % 10 === 0 && performance.now() - start > timeout) {
|
|
88
89
|
return null;
|
|
89
90
|
}
|
|
90
91
|
const { derivedKey } = await deriveKey2(
|
|
@@ -92,7 +93,7 @@
|
|
|
92
93
|
saltBuf,
|
|
93
94
|
password.setCounter(counter)
|
|
94
95
|
);
|
|
95
|
-
if (
|
|
96
|
+
if (iterations % 10 === 0 && performance.now() - lastYield > 200) {
|
|
96
97
|
await delay(0);
|
|
97
98
|
lastYield = performance.now();
|
|
98
99
|
}
|
|
@@ -101,6 +102,7 @@
|
|
|
101
102
|
break;
|
|
102
103
|
}
|
|
103
104
|
counter = counter + counterStep;
|
|
105
|
+
iterations = iterations + 1;
|
|
104
106
|
}
|
|
105
107
|
return {
|
|
106
108
|
counter,
|
package/dist/workers/scrypt.js
CHANGED
|
@@ -81,10 +81,11 @@
|
|
|
81
81
|
const password = new PasswordBuffer(nonceBuf, counterMode);
|
|
82
82
|
const start = performance.now();
|
|
83
83
|
let counter = counterStart;
|
|
84
|
+
let iterations = 0;
|
|
84
85
|
let derivedKeyHex = "";
|
|
85
86
|
let lastYield = start;
|
|
86
87
|
while (true) {
|
|
87
|
-
if (controller?.signal.aborted || timeout &&
|
|
88
|
+
if (controller?.signal.aborted || timeout && iterations % 10 === 0 && performance.now() - start > timeout) {
|
|
88
89
|
return null;
|
|
89
90
|
}
|
|
90
91
|
const { derivedKey } = await deriveKey2(
|
|
@@ -92,7 +93,7 @@
|
|
|
92
93
|
saltBuf,
|
|
93
94
|
password.setCounter(counter)
|
|
94
95
|
);
|
|
95
|
-
if (
|
|
96
|
+
if (iterations % 10 === 0 && performance.now() - lastYield > 200) {
|
|
96
97
|
await delay(0);
|
|
97
98
|
lastYield = performance.now();
|
|
98
99
|
}
|
|
@@ -101,6 +102,7 @@
|
|
|
101
102
|
break;
|
|
102
103
|
}
|
|
103
104
|
counter = counter + counterStep;
|
|
105
|
+
iterations = iterations + 1;
|
|
104
106
|
}
|
|
105
107
|
return {
|
|
106
108
|
counter,
|
package/dist/workers/sha.js
CHANGED
|
@@ -81,10 +81,11 @@
|
|
|
81
81
|
const password = new PasswordBuffer(nonceBuf, counterMode);
|
|
82
82
|
const start = performance.now();
|
|
83
83
|
let counter = counterStart;
|
|
84
|
+
let iterations = 0;
|
|
84
85
|
let derivedKeyHex = "";
|
|
85
86
|
let lastYield = start;
|
|
86
87
|
while (true) {
|
|
87
|
-
if (controller?.signal.aborted || timeout &&
|
|
88
|
+
if (controller?.signal.aborted || timeout && iterations % 10 === 0 && performance.now() - start > timeout) {
|
|
88
89
|
return null;
|
|
89
90
|
}
|
|
90
91
|
const { derivedKey } = await deriveKey2(
|
|
@@ -92,7 +93,7 @@
|
|
|
92
93
|
saltBuf,
|
|
93
94
|
password.setCounter(counter)
|
|
94
95
|
);
|
|
95
|
-
if (
|
|
96
|
+
if (iterations % 10 === 0 && performance.now() - lastYield > 200) {
|
|
96
97
|
await delay(0);
|
|
97
98
|
lastYield = performance.now();
|
|
98
99
|
}
|
|
@@ -101,6 +102,7 @@
|
|
|
101
102
|
break;
|
|
102
103
|
}
|
|
103
104
|
counter = counter + counterStep;
|
|
105
|
+
iterations = iterations + 1;
|
|
104
106
|
}
|
|
105
107
|
return {
|
|
106
108
|
counter,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "altcha",
|
|
3
3
|
"description": "Privacy-first CAPTCHA widget, compliant with global regulations (GDPR/HIPAA/CCPA/LGDP/DPDPA/PIPL) and WCAG accessible. No tracking, self-verifying.",
|
|
4
|
-
"version": "3.0.
|
|
4
|
+
"version": "3.0.2",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Daniel Regeci",
|