altcha 3.1.0 → 3.2.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.
Files changed (172) hide show
  1. package/dist/external/altcha.css +1 -1
  2. package/dist/external/altcha.js +2 -4
  3. package/dist/external/altcha.min.js +1 -1
  4. package/dist/external/altcha.umd.cjs +3 -5
  5. package/dist/external/altcha.umd.min.cjs +1 -1
  6. package/dist/i18n/af.js +109 -3
  7. package/dist/i18n/af.umd.cjs +109 -3
  8. package/dist/i18n/africa.js +115 -21
  9. package/dist/i18n/africa.umd.cjs +115 -21
  10. package/dist/i18n/all.js +169 -183
  11. package/dist/i18n/all.umd.cjs +169 -183
  12. package/dist/i18n/am.js +109 -3
  13. package/dist/i18n/am.umd.cjs +109 -3
  14. package/dist/i18n/americas.js +111 -9
  15. package/dist/i18n/americas.umd.cjs +111 -9
  16. package/dist/i18n/ar.js +109 -3
  17. package/dist/i18n/ar.umd.cjs +109 -3
  18. package/dist/i18n/asia.js +132 -72
  19. package/dist/i18n/asia.umd.cjs +132 -72
  20. package/dist/i18n/az.js +109 -3
  21. package/dist/i18n/az.umd.cjs +109 -3
  22. package/dist/i18n/be.js +109 -3
  23. package/dist/i18n/be.umd.cjs +109 -3
  24. package/dist/i18n/bg.js +109 -3
  25. package/dist/i18n/bg.umd.cjs +109 -3
  26. package/dist/i18n/bn.js +109 -3
  27. package/dist/i18n/bn.umd.cjs +109 -3
  28. package/dist/i18n/bs.js +109 -3
  29. package/dist/i18n/bs.umd.cjs +109 -3
  30. package/dist/i18n/ca.js +109 -3
  31. package/dist/i18n/ca.umd.cjs +109 -3
  32. package/dist/i18n/cs.js +109 -3
  33. package/dist/i18n/cs.umd.cjs +109 -3
  34. package/dist/i18n/da.js +109 -3
  35. package/dist/i18n/da.umd.cjs +109 -3
  36. package/dist/i18n/de.js +109 -3
  37. package/dist/i18n/de.umd.cjs +109 -3
  38. package/dist/i18n/el.js +109 -3
  39. package/dist/i18n/el.umd.cjs +109 -3
  40. package/dist/i18n/en.js +109 -3
  41. package/dist/i18n/en.umd.cjs +109 -3
  42. package/dist/i18n/es-419.js +109 -3
  43. package/dist/i18n/es-419.umd.cjs +109 -3
  44. package/dist/i18n/es-es.js +109 -3
  45. package/dist/i18n/es-es.umd.cjs +109 -3
  46. package/dist/i18n/et.js +109 -3
  47. package/dist/i18n/et.umd.cjs +109 -3
  48. package/dist/i18n/eu.js +109 -3
  49. package/dist/i18n/eu.umd.cjs +109 -3
  50. package/dist/i18n/europe.js +145 -111
  51. package/dist/i18n/europe.umd.cjs +145 -111
  52. package/dist/i18n/fa.js +109 -3
  53. package/dist/i18n/fa.umd.cjs +109 -3
  54. package/dist/i18n/fi.js +109 -3
  55. package/dist/i18n/fi.umd.cjs +109 -3
  56. package/dist/i18n/fr-ca.js +109 -3
  57. package/dist/i18n/fr-ca.umd.cjs +109 -3
  58. package/dist/i18n/fr-fr.js +109 -3
  59. package/dist/i18n/fr-fr.umd.cjs +109 -3
  60. package/dist/i18n/ga.js +109 -3
  61. package/dist/i18n/ga.umd.cjs +109 -3
  62. package/dist/i18n/he.js +109 -3
  63. package/dist/i18n/he.umd.cjs +109 -3
  64. package/dist/i18n/hi.js +109 -3
  65. package/dist/i18n/hi.umd.cjs +109 -3
  66. package/dist/i18n/hr.js +109 -3
  67. package/dist/i18n/hr.umd.cjs +109 -3
  68. package/dist/i18n/hu.js +109 -3
  69. package/dist/i18n/hu.umd.cjs +109 -3
  70. package/dist/i18n/hy.js +109 -3
  71. package/dist/i18n/hy.umd.cjs +109 -3
  72. package/dist/i18n/id.js +109 -3
  73. package/dist/i18n/id.umd.cjs +109 -3
  74. package/dist/i18n/is.js +109 -3
  75. package/dist/i18n/is.umd.cjs +109 -3
  76. package/dist/i18n/it.js +109 -3
  77. package/dist/i18n/it.umd.cjs +109 -3
  78. package/dist/i18n/ja.js +109 -3
  79. package/dist/i18n/ja.umd.cjs +109 -3
  80. package/dist/i18n/ka.js +109 -3
  81. package/dist/i18n/ka.umd.cjs +109 -3
  82. package/dist/i18n/kk.js +109 -3
  83. package/dist/i18n/kk.umd.cjs +109 -3
  84. package/dist/i18n/ko.js +109 -3
  85. package/dist/i18n/ko.umd.cjs +109 -3
  86. package/dist/i18n/lb.js +109 -3
  87. package/dist/i18n/lb.umd.cjs +109 -3
  88. package/dist/i18n/lt.js +109 -3
  89. package/dist/i18n/lt.umd.cjs +109 -3
  90. package/dist/i18n/lv.js +109 -3
  91. package/dist/i18n/lv.umd.cjs +109 -3
  92. package/dist/i18n/me.js +109 -3
  93. package/dist/i18n/me.umd.cjs +109 -3
  94. package/dist/i18n/mk.js +109 -3
  95. package/dist/i18n/mk.umd.cjs +109 -3
  96. package/dist/i18n/mr.js +109 -3
  97. package/dist/i18n/mr.umd.cjs +109 -3
  98. package/dist/i18n/mt.js +109 -3
  99. package/dist/i18n/mt.umd.cjs +109 -3
  100. package/dist/i18n/nb.js +109 -3
  101. package/dist/i18n/nb.umd.cjs +109 -3
  102. package/dist/i18n/nl.js +109 -3
  103. package/dist/i18n/nl.umd.cjs +109 -3
  104. package/dist/i18n/pl.js +109 -3
  105. package/dist/i18n/pl.umd.cjs +109 -3
  106. package/dist/i18n/pt-br.js +109 -3
  107. package/dist/i18n/pt-br.umd.cjs +109 -3
  108. package/dist/i18n/pt-pt.js +109 -3
  109. package/dist/i18n/pt-pt.umd.cjs +109 -3
  110. package/dist/i18n/ro.js +109 -3
  111. package/dist/i18n/ro.umd.cjs +109 -3
  112. package/dist/i18n/ru.js +109 -3
  113. package/dist/i18n/ru.umd.cjs +109 -3
  114. package/dist/i18n/sk.js +109 -3
  115. package/dist/i18n/sk.umd.cjs +109 -3
  116. package/dist/i18n/sl.js +109 -3
  117. package/dist/i18n/sl.umd.cjs +109 -3
  118. package/dist/i18n/sq.js +109 -3
  119. package/dist/i18n/sq.umd.cjs +109 -3
  120. package/dist/i18n/sr.js +109 -3
  121. package/dist/i18n/sr.umd.cjs +109 -3
  122. package/dist/i18n/sv.js +109 -3
  123. package/dist/i18n/sv.umd.cjs +109 -3
  124. package/dist/i18n/sw.js +109 -3
  125. package/dist/i18n/sw.umd.cjs +109 -3
  126. package/dist/i18n/ta.js +109 -3
  127. package/dist/i18n/ta.umd.cjs +109 -3
  128. package/dist/i18n/te.js +109 -3
  129. package/dist/i18n/te.umd.cjs +109 -3
  130. package/dist/i18n/th.js +109 -3
  131. package/dist/i18n/th.umd.cjs +109 -3
  132. package/dist/i18n/tk.js +109 -3
  133. package/dist/i18n/tk.umd.cjs +109 -3
  134. package/dist/i18n/tr.js +109 -3
  135. package/dist/i18n/tr.umd.cjs +109 -3
  136. package/dist/i18n/uk.js +109 -3
  137. package/dist/i18n/uk.umd.cjs +109 -3
  138. package/dist/i18n/ur.js +109 -3
  139. package/dist/i18n/ur.umd.cjs +109 -3
  140. package/dist/i18n/uz.js +109 -3
  141. package/dist/i18n/uz.umd.cjs +109 -3
  142. package/dist/i18n/vi.js +109 -3
  143. package/dist/i18n/vi.umd.cjs +109 -3
  144. package/dist/i18n/yo.js +109 -3
  145. package/dist/i18n/yo.umd.cjs +109 -3
  146. package/dist/i18n/zh-cn.js +109 -3
  147. package/dist/i18n/zh-cn.umd.cjs +109 -3
  148. package/dist/i18n/zh-hk.js +109 -3
  149. package/dist/i18n/zh-hk.umd.cjs +109 -3
  150. package/dist/i18n/zh-tw.js +109 -3
  151. package/dist/i18n/zh-tw.umd.cjs +109 -3
  152. package/dist/lib/index.js +2 -0
  153. package/dist/lib/index.min.js +1 -1
  154. package/dist/lib/index.umd.cjs +2 -0
  155. package/dist/lib/index.umd.min.cjs +1 -1
  156. package/dist/main/altcha.i18n.js +68 -188
  157. package/dist/main/altcha.i18n.min.js +1 -1
  158. package/dist/main/altcha.i18n.umd.cjs +68 -188
  159. package/dist/main/altcha.i18n.umd.min.cjs +1 -1
  160. package/dist/main/altcha.js +7 -5
  161. package/dist/main/altcha.min.js +1 -1
  162. package/dist/main/altcha.umd.cjs +7 -5
  163. package/dist/main/altcha.umd.min.cjs +1 -1
  164. package/dist/plugins/obfuscation.plugin.js +3 -0
  165. package/dist/plugins/obfuscation.plugin.min.js +1 -1
  166. package/dist/plugins/obfuscation.plugin.umd.cjs +3 -0
  167. package/dist/plugins/obfuscation.plugin.umd.min.cjs +1 -1
  168. package/dist/workers/argon2id.js +2 -0
  169. package/dist/workers/pbkdf2.js +2 -0
  170. package/dist/workers/scrypt.js +2 -0
  171. package/dist/workers/sha.js +2 -0
  172. package/package.json +4 -2
@@ -110,6 +110,7 @@ class BasePlugin {
110
110
  constructor(host) {
111
111
  this.host = host;
112
112
  }
113
+ host;
113
114
  static register(pluginClass) {
114
115
  if ("$altcha" in globalThis && !globalThis.$altcha.plugins.has(pluginClass)) {
115
116
  globalThis.$altcha.plugins.add(pluginClass);
@@ -250,6 +251,8 @@ class PasswordBuffer {
250
251
  this.buffer.set(this.nonce, 0);
251
252
  this.dataView = new DataView(this.buffer.buffer);
252
253
  }
254
+ nonce;
255
+ mode;
253
256
  COUNTER_BYTES = 4;
254
257
  buffer;
255
258
  dataView;
@@ -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=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))}});
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}host;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)}nonce;mode;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))}});
@@ -114,6 +114,7 @@
114
114
  constructor(host) {
115
115
  this.host = host;
116
116
  }
117
+ host;
117
118
  static register(pluginClass) {
118
119
  if ("$altcha" in globalThis && !globalThis.$altcha.plugins.has(pluginClass)) {
119
120
  globalThis.$altcha.plugins.add(pluginClass);
@@ -254,6 +255,8 @@
254
255
  this.buffer.set(this.nonce, 0);
255
256
  this.dataView = new DataView(this.buffer.buffer);
256
257
  }
258
+ nonce;
259
+ mode;
257
260
  COUNTER_BYTES = 4;
258
261
  buffer;
259
262
  dataView;
@@ -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=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))}})});
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=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}host;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)}nonce;mode;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))}})});
@@ -47,6 +47,8 @@
47
47
  this.buffer.set(this.nonce, 0);
48
48
  this.dataView = new DataView(this.buffer.buffer);
49
49
  }
50
+ nonce;
51
+ mode;
50
52
  COUNTER_BYTES = 4;
51
53
  buffer;
52
54
  dataView;
@@ -47,6 +47,8 @@
47
47
  this.buffer.set(this.nonce, 0);
48
48
  this.dataView = new DataView(this.buffer.buffer);
49
49
  }
50
+ nonce;
51
+ mode;
50
52
  COUNTER_BYTES = 4;
51
53
  buffer;
52
54
  dataView;
@@ -47,6 +47,8 @@
47
47
  this.buffer.set(this.nonce, 0);
48
48
  this.dataView = new DataView(this.buffer.buffer);
49
49
  }
50
+ nonce;
51
+ mode;
50
52
  COUNTER_BYTES = 4;
51
53
  buffer;
52
54
  dataView;
@@ -47,6 +47,8 @@
47
47
  this.buffer.set(this.nonce, 0);
48
48
  this.dataView = new DataView(this.buffer.buffer);
49
49
  }
50
+ nonce;
51
+ mode;
50
52
  COUNTER_BYTES = 4;
51
53
  buffer;
52
54
  dataView;
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.1.0",
4
+ "version": "3.2.1",
5
5
  "license": "MIT",
6
6
  "author": {
7
7
  "name": "Daniel Regeci",
@@ -136,7 +136,7 @@
136
136
  "tailwindcss": "^4.1.18",
137
137
  "terser": "^5.44.1",
138
138
  "typescript": "~5.9.3",
139
- "vite": "^7.3.1",
139
+ "vite": "^7.3.5",
140
140
  "vite-plugin-markdown": "^2.2.0",
141
141
  "vitest": "^4.1.8"
142
142
  },
@@ -144,6 +144,8 @@
144
144
  "hash-wasm": "^4.12.0"
145
145
  },
146
146
  "overrides": {
147
+ "esbuild": "^0.28.1",
148
+ "markdown-it": "^14.2.0",
147
149
  "tmp": "^0.2.7",
148
150
  "underscore": "^1.13.8"
149
151
  }