altcha 3.0.0-beta.2 → 3.0.0-beta.3
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 +5 -2
- package/dist/external/altcha.js +247 -36
- package/dist/external/altcha.min.js +1 -1
- package/dist/external/altcha.umd.cjs +247 -36
- package/dist/external/altcha.umd.min.cjs +1 -1
- package/dist/lib/index.d.ts +18 -6
- package/dist/lib/index.js +3 -1
- package/dist/lib/index.min.js +1 -1
- package/dist/lib/index.umd.cjs +3 -1
- package/dist/lib/index.umd.min.cjs +1 -1
- package/dist/main/altcha.i18n.js +253 -40
- package/dist/main/altcha.i18n.min.js +1 -1
- package/dist/main/altcha.i18n.umd.cjs +253 -40
- package/dist/main/altcha.i18n.umd.min.cjs +1 -1
- package/dist/main/altcha.js +253 -40
- package/dist/main/altcha.min.js +1 -1
- package/dist/main/altcha.umd.cjs +253 -40
- package/dist/main/altcha.umd.min.cjs +1 -1
- package/dist/plugins/obfuscation.plugin.js +55 -14
- package/dist/plugins/obfuscation.plugin.min.js +1 -1
- package/dist/plugins/obfuscation.plugin.umd.cjs +55 -14
- package/dist/plugins/obfuscation.plugin.umd.min.cjs +1 -1
- package/dist/types/generic.d.ts +4 -1
- package/dist/types/index.d.ts +18 -6
- package/dist/workers/argon2id.js +3 -2
- package/dist/workers/pbkdf2.js +3 -2
- package/dist/workers/scrypt.js +3 -2
- package/dist/workers/sha.js +3 -2
- package/package.json +2 -2
- package/dist/external/index.d.ts +0 -1
package/README.md
CHANGED
|
@@ -119,13 +119,13 @@ ALTCHA is optimized for performance:
|
|
|
119
119
|
|
|
120
120
|
| Distribution | Size (GZIPped) |
|
|
121
121
|
| ---------------------------- | -------------- |
|
|
122
|
-
| ALTCHA |
|
|
122
|
+
| ALTCHA | 34 kB |
|
|
123
123
|
| ALTCHA with all translations | 49 kB |
|
|
124
124
|
| Cloudflare Turnstile | 85+ kB |
|
|
125
125
|
| hCaptcha | 250+ kB |
|
|
126
126
|
| reCAPTCHA | 300+ kB |
|
|
127
127
|
|
|
128
|
-
When GZIPped, it totals about
|
|
128
|
+
When GZIPped, it totals about 34 kB, making ALTCHA’s widget about ~90% smaller than reCAPTCHA.
|
|
129
129
|
|
|
130
130
|
## Content Security Policy (CSP)
|
|
131
131
|
|
|
@@ -205,6 +205,7 @@ For simple implementations, the widget supports a subset of configuration option
|
|
|
205
205
|
- **`floatingPlacement`**: Preferred position relative to the anchor (`'auto'`, `'bottom'`, or `'top'`).
|
|
206
206
|
- **`floatingOffset`**: Vertical offset in pixels between the UI and its anchor. (Default: `12`)
|
|
207
207
|
- **`floatingPersist`**: Whether the floating widget remains visible after successful verification.
|
|
208
|
+
- **`popoverPlacement`**: Preferred position of popovers relative to the widget (`'auto'`, `'bottom'`, or `'top'`).
|
|
208
209
|
|
|
209
210
|
### Modal & Challenge Settings
|
|
210
211
|
|
|
@@ -219,7 +220,9 @@ For simple implementations, the widget supports a subset of configuration option
|
|
|
219
220
|
- **`test`**: Mocks a successful verification for testing environments.
|
|
220
221
|
- **`mockError`**: Forces the widget into a failed state for UI testing.
|
|
221
222
|
- **`fetch`**: A custom `fetch` implementation for network requests.
|
|
223
|
+
- **`humanInteractionSignature`**: Whether the collector for HIS is enabled (Default: `true`).
|
|
222
224
|
- **`setCookie`**: When configured, sends the payload as a cookie.
|
|
225
|
+
- **`timeout`**: Verification timeout in milliseconds (Default: `90_000`).
|
|
223
226
|
- **`verifyFunction`**: A custom verification handler that overrides default network verification.
|
|
224
227
|
|
|
225
228
|
## Cookies
|
package/dist/external/altcha.js
CHANGED
|
@@ -5431,7 +5431,7 @@ var root_3$1 = /* @__PURE__ */ from_html(`<div role="button" class="altcha-popov
|
|
|
5431
5431
|
var root$1 = /* @__PURE__ */ from_html(`<!> <div><!> <!> <div class="altcha-popover-content"><!></div></div>`, 1);
|
|
5432
5432
|
function Popover($$anchor, $$props) {
|
|
5433
5433
|
push($$props, true);
|
|
5434
|
-
let anchor = prop($$props, "anchor"), children = prop($$props, "children"), display = prop($$props, "display", 7, "standard"), backdrop = prop($$props, "backdrop", 7, false), onClickOutside = prop($$props, "onClickOutside"), onClickOutsideDelay = prop($$props, "onClickOutsideDelay", 7, 600), onClose = prop($$props, "onClose"), variant = prop($$props, "variant", 7, "neutral"), rest = /* @__PURE__ */ rest_props($$props, [
|
|
5434
|
+
let anchor = prop($$props, "anchor"), children = prop($$props, "children"), display = prop($$props, "display", 7, "standard"), backdrop = prop($$props, "backdrop", 7, false), onClickOutside = prop($$props, "onClickOutside"), onClickOutsideDelay = prop($$props, "onClickOutsideDelay", 7, 600), onClose = prop($$props, "onClose"), placement = prop($$props, "placement", 7, "auto"), variant = prop($$props, "variant", 7, "neutral"), rest = /* @__PURE__ */ rest_props($$props, [
|
|
5435
5435
|
"$$slots",
|
|
5436
5436
|
"$$events",
|
|
5437
5437
|
"$$legacy",
|
|
@@ -5443,12 +5443,18 @@ function Popover($$anchor, $$props) {
|
|
|
5443
5443
|
"onClickOutside",
|
|
5444
5444
|
"onClickOutsideDelay",
|
|
5445
5445
|
"onClose",
|
|
5446
|
+
"placement",
|
|
5446
5447
|
"variant"
|
|
5447
5448
|
]);
|
|
5448
5449
|
let el = /* @__PURE__ */ state(void 0);
|
|
5449
5450
|
let elBackdrop = /* @__PURE__ */ state(void 0);
|
|
5450
5451
|
let top = /* @__PURE__ */ state(false);
|
|
5451
5452
|
let mountedAt = /* @__PURE__ */ state(0);
|
|
5453
|
+
user_effect(() => {
|
|
5454
|
+
if (placement() !== "auto") {
|
|
5455
|
+
set(top, placement() === "top");
|
|
5456
|
+
}
|
|
5457
|
+
});
|
|
5452
5458
|
onMount(() => {
|
|
5453
5459
|
const moveToBody = display() === "bottomsheet" || display() === "overlay";
|
|
5454
5460
|
if (moveToBody) {
|
|
@@ -5482,7 +5488,7 @@ function Popover($$anchor, $$props) {
|
|
|
5482
5488
|
reposition();
|
|
5483
5489
|
}
|
|
5484
5490
|
function reposition() {
|
|
5485
|
-
if (anchor() && get(el)) {
|
|
5491
|
+
if (anchor() && placement() === "auto" && get(el)) {
|
|
5486
5492
|
const boundary2 = anchor().getBoundingClientRect();
|
|
5487
5493
|
const bottomGap = document.documentElement.clientHeight - (boundary2.top + boundary2.height);
|
|
5488
5494
|
const newTop = bottomGap < get(el).clientHeight;
|
|
@@ -5541,6 +5547,13 @@ function Popover($$anchor, $$props) {
|
|
|
5541
5547
|
onClose($$value);
|
|
5542
5548
|
flushSync();
|
|
5543
5549
|
},
|
|
5550
|
+
get placement() {
|
|
5551
|
+
return placement();
|
|
5552
|
+
},
|
|
5553
|
+
set placement($$value = "auto") {
|
|
5554
|
+
placement($$value);
|
|
5555
|
+
flushSync();
|
|
5556
|
+
},
|
|
5544
5557
|
get variant() {
|
|
5545
5558
|
return variant();
|
|
5546
5559
|
},
|
|
@@ -5614,6 +5627,7 @@ create_custom_element(
|
|
|
5614
5627
|
onClickOutside: {},
|
|
5615
5628
|
onClickOutsideDelay: {},
|
|
5616
5629
|
onClose: {},
|
|
5630
|
+
placement: {},
|
|
5617
5631
|
variant: {}
|
|
5618
5632
|
},
|
|
5619
5633
|
[],
|
|
@@ -5630,7 +5644,8 @@ async function solveChallengeWorkers(options) {
|
|
|
5630
5644
|
controller = new AbortController(),
|
|
5631
5645
|
createWorker,
|
|
5632
5646
|
onOutOfMemory = (c) => c > 1 ? Math.floor(c / 2) : 0,
|
|
5633
|
-
counterMode
|
|
5647
|
+
counterMode,
|
|
5648
|
+
timeout = 9e4
|
|
5634
5649
|
} = options;
|
|
5635
5650
|
const workersConcurrency = Math.min(16, Math.max(1, concurrency));
|
|
5636
5651
|
const workersInstances = [];
|
|
@@ -5671,6 +5686,7 @@ async function solveChallengeWorkers(options) {
|
|
|
5671
5686
|
counterMode,
|
|
5672
5687
|
counterStart: i,
|
|
5673
5688
|
counterStep: workersConcurrency,
|
|
5689
|
+
timeout,
|
|
5674
5690
|
type: "work"
|
|
5675
5691
|
});
|
|
5676
5692
|
});
|
|
@@ -5702,6 +5718,147 @@ async function solveChallengeWorkers(options) {
|
|
|
5702
5718
|
}
|
|
5703
5719
|
return solution || null;
|
|
5704
5720
|
}
|
|
5721
|
+
class Collector {
|
|
5722
|
+
TAG_CODES = {
|
|
5723
|
+
INPUT: 1,
|
|
5724
|
+
TEXTAREA: 2,
|
|
5725
|
+
SELECT: 3,
|
|
5726
|
+
BUTTON: 4,
|
|
5727
|
+
A: 5,
|
|
5728
|
+
DETAILS: 6,
|
|
5729
|
+
SUMMARY: 7,
|
|
5730
|
+
IFRAME: 8,
|
|
5731
|
+
VIDEO: 9,
|
|
5732
|
+
AUDIO: 10
|
|
5733
|
+
};
|
|
5734
|
+
maxSamples;
|
|
5735
|
+
sampleInterval;
|
|
5736
|
+
target;
|
|
5737
|
+
focusStartTime = 0;
|
|
5738
|
+
focusInteraction = 0;
|
|
5739
|
+
focusInteractionTimer = null;
|
|
5740
|
+
lastPointerSample = 0;
|
|
5741
|
+
lastTouchSample = 0;
|
|
5742
|
+
lastScrollSample = 0;
|
|
5743
|
+
pendingPointer = null;
|
|
5744
|
+
pendingTouch = null;
|
|
5745
|
+
focus = [];
|
|
5746
|
+
pointer = [];
|
|
5747
|
+
scroll = [];
|
|
5748
|
+
touch = [];
|
|
5749
|
+
constructor(options = {}) {
|
|
5750
|
+
const { maxSamples = 60, sampleInterval = 50, target = window } = options;
|
|
5751
|
+
this.maxSamples = maxSamples;
|
|
5752
|
+
this.sampleInterval = sampleInterval;
|
|
5753
|
+
this.target = target;
|
|
5754
|
+
this.attach();
|
|
5755
|
+
}
|
|
5756
|
+
destroy() {
|
|
5757
|
+
const o = { capture: true };
|
|
5758
|
+
this.target.removeEventListener("focusin", this.onFocus, o);
|
|
5759
|
+
this.target.removeEventListener("keydown", this.onInteraction, o);
|
|
5760
|
+
this.target.removeEventListener("pointerdown", this.onInteraction, o);
|
|
5761
|
+
this.target.removeEventListener("pointermove", this.onPointer, o);
|
|
5762
|
+
this.target.removeEventListener("scroll", this.onScroll, o);
|
|
5763
|
+
this.target.removeEventListener("touchmove", this.onTouchMove, o);
|
|
5764
|
+
}
|
|
5765
|
+
export() {
|
|
5766
|
+
return {
|
|
5767
|
+
focus: this.focus,
|
|
5768
|
+
maxTouchPoints: navigator.maxTouchPoints || 0,
|
|
5769
|
+
pointer: this.pointer,
|
|
5770
|
+
scroll: this.scroll,
|
|
5771
|
+
time: Date.now(),
|
|
5772
|
+
touch: this.touch
|
|
5773
|
+
};
|
|
5774
|
+
}
|
|
5775
|
+
attach() {
|
|
5776
|
+
const o = { passive: true, capture: true };
|
|
5777
|
+
this.target.addEventListener("focusin", this.onFocus, o);
|
|
5778
|
+
this.target.addEventListener("keydown", this.onInteraction, o);
|
|
5779
|
+
this.target.addEventListener("pointerdown", this.onInteraction, o);
|
|
5780
|
+
this.target.addEventListener("pointermove", this.onPointer, o);
|
|
5781
|
+
this.target.addEventListener("scroll", this.onScroll, o);
|
|
5782
|
+
this.target.addEventListener("touchmove", this.onTouchMove, o);
|
|
5783
|
+
}
|
|
5784
|
+
evict(buffer) {
|
|
5785
|
+
if (buffer.length > this.maxSamples) {
|
|
5786
|
+
buffer.splice(0, buffer.length - this.maxSamples);
|
|
5787
|
+
}
|
|
5788
|
+
}
|
|
5789
|
+
onFocus = (e) => {
|
|
5790
|
+
if (this.focusInteraction === 2) {
|
|
5791
|
+
return;
|
|
5792
|
+
}
|
|
5793
|
+
const el = e.target;
|
|
5794
|
+
if (!(el instanceof Element)) {
|
|
5795
|
+
return;
|
|
5796
|
+
}
|
|
5797
|
+
const now = performance.now();
|
|
5798
|
+
if (this.focusStartTime === 0) {
|
|
5799
|
+
this.focusStartTime = now;
|
|
5800
|
+
}
|
|
5801
|
+
this.focus.push([
|
|
5802
|
+
Math.round(now - this.focusStartTime),
|
|
5803
|
+
el.tabIndex,
|
|
5804
|
+
this.TAG_CODES[el.tagName] ?? 0,
|
|
5805
|
+
this.focusInteraction ? 1 : 0
|
|
5806
|
+
]);
|
|
5807
|
+
this.evict(this.focus);
|
|
5808
|
+
};
|
|
5809
|
+
onInteraction = (e) => {
|
|
5810
|
+
this.focusInteraction = "keyCode" in e ? 1 : 2;
|
|
5811
|
+
if (this.focusInteractionTimer) {
|
|
5812
|
+
clearTimeout(this.focusInteractionTimer);
|
|
5813
|
+
}
|
|
5814
|
+
this.focusInteractionTimer = setTimeout(() => {
|
|
5815
|
+
this.focusInteraction = 0;
|
|
5816
|
+
}, 100);
|
|
5817
|
+
};
|
|
5818
|
+
onPointer = (e) => {
|
|
5819
|
+
if (e.pointerType === "touch") {
|
|
5820
|
+
return;
|
|
5821
|
+
}
|
|
5822
|
+
const now = e.timeStamp || performance.now();
|
|
5823
|
+
this.pendingPointer = [Math.round(e.clientX), Math.round(e.clientY), Math.round(now)];
|
|
5824
|
+
if (now - this.lastPointerSample >= this.sampleInterval) {
|
|
5825
|
+
this.pointer.push(this.pendingPointer);
|
|
5826
|
+
this.lastPointerSample = now;
|
|
5827
|
+
this.pendingPointer = null;
|
|
5828
|
+
this.evict(this.pointer);
|
|
5829
|
+
}
|
|
5830
|
+
};
|
|
5831
|
+
onScroll = () => {
|
|
5832
|
+
const now = performance.now();
|
|
5833
|
+
if (now - this.lastScrollSample < this.sampleInterval) {
|
|
5834
|
+
return;
|
|
5835
|
+
}
|
|
5836
|
+
this.scroll.push([Math.round(window.scrollY), Math.round(now)]);
|
|
5837
|
+
this.lastScrollSample = now;
|
|
5838
|
+
this.evict(this.scroll);
|
|
5839
|
+
};
|
|
5840
|
+
onTouchMove = (e) => {
|
|
5841
|
+
const now = e.timeStamp || performance.now();
|
|
5842
|
+
const t = e.touches[0];
|
|
5843
|
+
if (!t) {
|
|
5844
|
+
return;
|
|
5845
|
+
}
|
|
5846
|
+
this.pendingTouch = [
|
|
5847
|
+
Math.round(t.clientX),
|
|
5848
|
+
Math.round(t.clientY),
|
|
5849
|
+
Math.round(now),
|
|
5850
|
+
Math.round(t.force * 1e3) / 1e3,
|
|
5851
|
+
Math.round(t.radiusX || 0),
|
|
5852
|
+
Math.round(t.radiusY || 0)
|
|
5853
|
+
];
|
|
5854
|
+
if (now - this.lastTouchSample >= this.sampleInterval) {
|
|
5855
|
+
this.touch.push(this.pendingTouch);
|
|
5856
|
+
this.lastTouchSample = now;
|
|
5857
|
+
this.pendingTouch = null;
|
|
5858
|
+
this.evict(this.touch);
|
|
5859
|
+
}
|
|
5860
|
+
};
|
|
5861
|
+
}
|
|
5705
5862
|
var root_1 = /* @__PURE__ */ from_html(`<div class="altcha-overlay-backdrop" data-backdrop=""></div>`);
|
|
5706
5863
|
var root_3 = /* @__PURE__ */ from_html(`<div class="altcha-overlay-content"></div>`);
|
|
5707
5864
|
var root_2 = /* @__PURE__ */ from_html(`<div role="button" class="altcha-overlay-close">×</div> <!>`, 1);
|
|
@@ -5732,6 +5889,7 @@ function Widget($$anchor, $$props) {
|
|
|
5732
5889
|
instance?.dispatchEvent(new CustomEvent(event2, { detail }));
|
|
5733
5890
|
});
|
|
5734
5891
|
};
|
|
5892
|
+
let hisCollector = null;
|
|
5735
5893
|
let baseUrl = /* @__PURE__ */ state(proxy(new URL(location.origin)));
|
|
5736
5894
|
let checked = /* @__PURE__ */ state(false);
|
|
5737
5895
|
let codeChallenge = /* @__PURE__ */ state(null);
|
|
@@ -5766,16 +5924,19 @@ function Widget($$anchor, $$props) {
|
|
|
5766
5924
|
floatingPlacement: "auto",
|
|
5767
5925
|
hideFooter: false,
|
|
5768
5926
|
hideLogo: false,
|
|
5927
|
+
humanInteractionSignature: true,
|
|
5769
5928
|
language: "",
|
|
5770
5929
|
mockError: false,
|
|
5771
5930
|
minDuration: 500,
|
|
5772
5931
|
overlayContent: "",
|
|
5773
5932
|
name: "altcha",
|
|
5933
|
+
popoverPlacement: "auto",
|
|
5774
5934
|
retryOnOutOfMemoryError: true,
|
|
5775
5935
|
setCookie: null,
|
|
5776
5936
|
serverVerificationFields: false,
|
|
5777
5937
|
serverVerificationTimeZone: false,
|
|
5778
5938
|
test: false,
|
|
5939
|
+
timeout: 9e4,
|
|
5779
5940
|
type: "checkbox",
|
|
5780
5941
|
validationMessage: "",
|
|
5781
5942
|
verifyFunction: null,
|
|
@@ -5786,6 +5947,7 @@ function Widget($$anchor, $$props) {
|
|
|
5786
5947
|
}));
|
|
5787
5948
|
const checkboxId = /* @__PURE__ */ user_derived(() => `altcha-checkbox-${$$props.id || Math.floor(Math.random() * 1e12).toString(16)}`);
|
|
5788
5949
|
const CheckboxComponent = /* @__PURE__ */ user_derived(() => getCheckboxComponent(get(config).type));
|
|
5950
|
+
const auto = /* @__PURE__ */ user_derived(() => get(config).auto);
|
|
5789
5951
|
const loading = /* @__PURE__ */ user_derived(() => get(currentState) === State.VERIFYING);
|
|
5790
5952
|
const showFooter = /* @__PURE__ */ user_derived(() => !get(config).hideFooter);
|
|
5791
5953
|
const showLogo = /* @__PURE__ */ user_derived(() => !get(config).hideLogo && get(config).display !== "bar");
|
|
@@ -5847,7 +6009,7 @@ function Widget($$anchor, $$props) {
|
|
|
5847
6009
|
}
|
|
5848
6010
|
});
|
|
5849
6011
|
user_effect(() => {
|
|
5850
|
-
if (get(
|
|
6012
|
+
if (get(auto) === "onload") {
|
|
5851
6013
|
const tm = setTimeout(
|
|
5852
6014
|
() => {
|
|
5853
6015
|
verify();
|
|
@@ -5872,15 +6034,19 @@ function Widget($$anchor, $$props) {
|
|
|
5872
6034
|
}
|
|
5873
6035
|
});
|
|
5874
6036
|
onMount(() => {
|
|
5875
|
-
log("mounted", "3.0.0-beta.
|
|
6037
|
+
log("mounted", "3.0.0-beta.3");
|
|
5876
6038
|
if (instance) {
|
|
5877
6039
|
globalThis.$altcha.instances.add(instance);
|
|
5878
6040
|
}
|
|
5879
6041
|
set(elForm, get(elRoot)?.closest("form"), true);
|
|
5880
6042
|
get(elForm)?.addEventListener("reset", onFormReset);
|
|
5881
|
-
get(elForm)?.addEventListener("submit", onFormSubmit);
|
|
6043
|
+
get(elForm)?.addEventListener("submit", onFormSubmit, { capture: true });
|
|
5882
6044
|
get(elForm)?.addEventListener("focusin", onFormFocusIn);
|
|
5883
6045
|
activatePlugins();
|
|
6046
|
+
if (get(config).humanInteractionSignature) {
|
|
6047
|
+
log("human interaction signature enabled");
|
|
6048
|
+
hisCollector = new Collector();
|
|
6049
|
+
}
|
|
5884
6050
|
dispatch("load");
|
|
5885
6051
|
if (!isSecureContext) {
|
|
5886
6052
|
log("secure context (HTTPS) required");
|
|
@@ -5894,8 +6060,9 @@ function Widget($$anchor, $$props) {
|
|
|
5894
6060
|
clearTimeout(get(expirationTimeout));
|
|
5895
6061
|
}
|
|
5896
6062
|
get(elForm)?.removeEventListener("reset", onFormReset);
|
|
5897
|
-
get(elForm)?.removeEventListener("submit", onFormSubmit);
|
|
6063
|
+
get(elForm)?.removeEventListener("submit", onFormSubmit, { capture: true });
|
|
5898
6064
|
get(elForm)?.removeEventListener("focusin", onFormFocusIn);
|
|
6065
|
+
hisCollector?.destroy();
|
|
5899
6066
|
};
|
|
5900
6067
|
});
|
|
5901
6068
|
function activatePlugins() {
|
|
@@ -5959,23 +6126,41 @@ function Widget($$anchor, $$props) {
|
|
|
5959
6126
|
async function delay(ms) {
|
|
5960
6127
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
5961
6128
|
}
|
|
5962
|
-
async function fetchChallenge(source2 = get(config).challenge) {
|
|
6129
|
+
async function fetchChallenge(source2 = get(config).challenge, requestOptions) {
|
|
5963
6130
|
const hook = await callHook("onFetchChallenge", source2);
|
|
6131
|
+
let challenge = null;
|
|
5964
6132
|
if (hook !== void 0) {
|
|
5965
6133
|
return hook;
|
|
5966
6134
|
}
|
|
5967
6135
|
if (typeof source2 === "string") {
|
|
5968
|
-
let challenge = null;
|
|
5969
6136
|
if (source2.match(/^(https?:)?\//)) {
|
|
5970
|
-
log("fetching challenge from", source2);
|
|
6137
|
+
log("fetching challenge from", requestOptions?.method || "GET", source2);
|
|
5971
6138
|
set(baseUrl, new URL(source2, location.origin), true);
|
|
5972
|
-
const resp = await get(config).fetch(source2, {
|
|
5973
|
-
|
|
6139
|
+
const resp = await get(config).fetch(source2, {
|
|
6140
|
+
credentials: get(config).credentials || void 0,
|
|
6141
|
+
...requestOptions
|
|
6142
|
+
});
|
|
6143
|
+
await validateResponse(resp);
|
|
5974
6144
|
const configHeader = resp.headers.get("x-altcha-config");
|
|
5975
6145
|
if (configHeader) {
|
|
5976
6146
|
processConfigHeader(configHeader);
|
|
5977
6147
|
}
|
|
5978
|
-
|
|
6148
|
+
const json = await resp.json();
|
|
6149
|
+
if (json && "his" in json && json.his) {
|
|
6150
|
+
log("requested HIS");
|
|
6151
|
+
if (!hisCollector) {
|
|
6152
|
+
throw new Error("Server requested HIS data but collector is disabled.");
|
|
6153
|
+
}
|
|
6154
|
+
return fetchChallenge(getUrl(json.his.url, get(baseUrl)), {
|
|
6155
|
+
body: JSON.stringify({ his: hisCollector.export() }),
|
|
6156
|
+
headers: { "content-type": "application/json" },
|
|
6157
|
+
method: "POST"
|
|
6158
|
+
});
|
|
6159
|
+
}
|
|
6160
|
+
if (json && "hisResult" in json && json.hisResult) {
|
|
6161
|
+
log("HIS result", json.hisResult);
|
|
6162
|
+
}
|
|
6163
|
+
challenge = json;
|
|
5979
6164
|
} else {
|
|
5980
6165
|
log("parsing JSON challenge");
|
|
5981
6166
|
try {
|
|
@@ -5984,20 +6169,26 @@ function Widget($$anchor, $$props) {
|
|
|
5984
6169
|
throw new Error(`Unable to parse JSON challenge.`);
|
|
5985
6170
|
}
|
|
5986
6171
|
}
|
|
5987
|
-
if (typeof challenge === "object" && "challenge" in challenge) {
|
|
5988
|
-
challenge = createChallengeFromV1(challenge);
|
|
5989
|
-
}
|
|
5990
|
-
if (!isChallengeValid(challenge)) {
|
|
5991
|
-
throw new Error(`Challenge validation failed.`);
|
|
5992
|
-
}
|
|
5993
|
-
return challenge;
|
|
5994
6172
|
} else if (source2 && typeof source2 === "object") {
|
|
5995
|
-
|
|
6173
|
+
try {
|
|
6174
|
+
challenge = JSON.parse(JSON.stringify(source2));
|
|
6175
|
+
} catch {
|
|
6176
|
+
throw new Error(`Unable to parse JSON challenge.`);
|
|
6177
|
+
}
|
|
5996
6178
|
}
|
|
5997
|
-
|
|
6179
|
+
if (isChallengeV1(challenge)) {
|
|
6180
|
+
challenge = createChallengeFromV1(challenge);
|
|
6181
|
+
}
|
|
6182
|
+
if (!isChallengeValid(challenge)) {
|
|
6183
|
+
throw new Error(`Challenge validation failed.`);
|
|
6184
|
+
}
|
|
6185
|
+
return challenge;
|
|
6186
|
+
}
|
|
6187
|
+
function isChallengeV1(challenge) {
|
|
6188
|
+
return typeof challenge === "object" && "challenge" in challenge;
|
|
5998
6189
|
}
|
|
5999
6190
|
function isChallengeValid(challenge) {
|
|
6000
|
-
return !!challenge && typeof challenge === "object" && "parameters" in challenge &&
|
|
6191
|
+
return !!challenge && typeof challenge === "object" && "parameters" in challenge && !!challenge.parameters && typeof challenge.parameters === "object" && "algorithm" in challenge.parameters && "nonce" in challenge.parameters && "salt" in challenge.parameters && "keyPrefix" in challenge.parameters;
|
|
6001
6192
|
}
|
|
6002
6193
|
function getCheckboxElement() {
|
|
6003
6194
|
return document.getElementById(get(checkboxId));
|
|
@@ -6110,7 +6301,7 @@ function Widget($$anchor, $$props) {
|
|
|
6110
6301
|
}
|
|
6111
6302
|
}
|
|
6112
6303
|
function onFormFocusIn(ev) {
|
|
6113
|
-
if (get(
|
|
6304
|
+
if (get(auto) === "onfocus" && get(currentState) === State.UNVERIFIED) {
|
|
6114
6305
|
verify();
|
|
6115
6306
|
}
|
|
6116
6307
|
}
|
|
@@ -6123,7 +6314,7 @@ function Widget($$anchor, $$props) {
|
|
|
6123
6314
|
}
|
|
6124
6315
|
function onFormSubmit(ev) {
|
|
6125
6316
|
set(elSubmitter, ev.submitter, true);
|
|
6126
|
-
if (get(
|
|
6317
|
+
if (get(auto) === "onsubmit" && get(currentState) === State.UNVERIFIED) {
|
|
6127
6318
|
ev.preventDefault();
|
|
6128
6319
|
ev.stopPropagation();
|
|
6129
6320
|
show();
|
|
@@ -6209,7 +6400,7 @@ function Widget($$anchor, $$props) {
|
|
|
6209
6400
|
headers: { "Content-Type": "application/json" },
|
|
6210
6401
|
method: "POST"
|
|
6211
6402
|
});
|
|
6212
|
-
validateResponse(resp);
|
|
6403
|
+
await validateResponse(resp);
|
|
6213
6404
|
const json = await resp.json();
|
|
6214
6405
|
if (json && typeof json === "object" && "payload" in json && !!json.payload) {
|
|
6215
6406
|
dispatch("serververification", json);
|
|
@@ -6250,7 +6441,7 @@ function Widget($$anchor, $$props) {
|
|
|
6250
6441
|
case "floating":
|
|
6251
6442
|
case "overlay":
|
|
6252
6443
|
hide();
|
|
6253
|
-
if (!get(
|
|
6444
|
+
if (!get(auto) || get(auto) === "off") {
|
|
6254
6445
|
get(userConfig).auto = "onsubmit";
|
|
6255
6446
|
}
|
|
6256
6447
|
break;
|
|
@@ -6278,8 +6469,18 @@ function Widget($$anchor, $$props) {
|
|
|
6278
6469
|
onExpired();
|
|
6279
6470
|
}
|
|
6280
6471
|
}
|
|
6281
|
-
function validateResponse(resp) {
|
|
6472
|
+
async function validateResponse(resp) {
|
|
6282
6473
|
if (resp.status >= 400) {
|
|
6474
|
+
if (resp.headers.get("content-type")?.includes("/json")) {
|
|
6475
|
+
let json;
|
|
6476
|
+
try {
|
|
6477
|
+
json = await resp.json();
|
|
6478
|
+
} catch {
|
|
6479
|
+
}
|
|
6480
|
+
if (json && "error" in json) {
|
|
6481
|
+
throw new Error(`Server responded with ${resp.status} - ${json.error}`);
|
|
6482
|
+
}
|
|
6483
|
+
}
|
|
6283
6484
|
throw new Error(`Server responded with ${resp.status}.`);
|
|
6284
6485
|
}
|
|
6285
6486
|
const contentType = resp.headers.get("content-type");
|
|
@@ -6310,7 +6511,7 @@ function Widget($$anchor, $$props) {
|
|
|
6310
6511
|
log("verified");
|
|
6311
6512
|
setState(State.VERIFIED);
|
|
6312
6513
|
dispatch("verified", { payload: get(payload) });
|
|
6313
|
-
if (get(
|
|
6514
|
+
if (get(auto) === "onsubmit") {
|
|
6314
6515
|
tick().then(() => {
|
|
6315
6516
|
requestSubmit(get(elSubmitter));
|
|
6316
6517
|
});
|
|
@@ -6377,7 +6578,7 @@ function Widget($$anchor, $$props) {
|
|
|
6377
6578
|
const start = performance.now();
|
|
6378
6579
|
let challenge = null;
|
|
6379
6580
|
let solution = null;
|
|
6380
|
-
let
|
|
6581
|
+
let isChallengeV12 = false;
|
|
6381
6582
|
const hook = await callHook("onVerify", options);
|
|
6382
6583
|
if (hook !== void 0) {
|
|
6383
6584
|
return hook;
|
|
@@ -6412,7 +6613,7 @@ function Widget($$anchor, $$props) {
|
|
|
6412
6613
|
if (challenge.parameters.expiresAt) {
|
|
6413
6614
|
setChallengeExpiration(challenge.parameters.expiresAt);
|
|
6414
6615
|
}
|
|
6415
|
-
|
|
6616
|
+
isChallengeV12 = "_version" in challenge && challenge._version === 1;
|
|
6416
6617
|
const createWorker = globalThis.$altcha.algorithms.get(challenge.parameters.algorithm);
|
|
6417
6618
|
if (!createWorker) {
|
|
6418
6619
|
throw new Error(`Unsupported algorithm ${challenge.parameters.algorithm}.`);
|
|
@@ -6422,7 +6623,7 @@ function Widget($$anchor, $$props) {
|
|
|
6422
6623
|
concurrency,
|
|
6423
6624
|
controller,
|
|
6424
6625
|
createWorker,
|
|
6425
|
-
counterMode:
|
|
6626
|
+
counterMode: isChallengeV12 ? "string" : "uint32",
|
|
6426
6627
|
onOutOfMemory: (c) => {
|
|
6427
6628
|
log("out of memory error received");
|
|
6428
6629
|
dispatch("outofmemory");
|
|
@@ -6431,7 +6632,8 @@ function Widget($$anchor, $$props) {
|
|
|
6431
6632
|
log(`retrying with ${retryConcurrency} workers...`);
|
|
6432
6633
|
return retryConcurrency;
|
|
6433
6634
|
}
|
|
6434
|
-
}
|
|
6635
|
+
},
|
|
6636
|
+
timeout: get(config).timeout
|
|
6435
6637
|
});
|
|
6436
6638
|
if (get(currentController)?.signal.aborted) {
|
|
6437
6639
|
reset$1();
|
|
@@ -6443,13 +6645,16 @@ function Widget($$anchor, $$props) {
|
|
|
6443
6645
|
log("solution", solution);
|
|
6444
6646
|
await delay(Math.max(0, minDuration - (performance.now() - start)));
|
|
6445
6647
|
set(codeChallenge, challenge.codeChallenge || get(config).codeChallenge || null, true);
|
|
6446
|
-
if (
|
|
6648
|
+
if (isChallengeV12) {
|
|
6447
6649
|
set(payload, btoa(JSON.stringify(createPayloadV1(challenge, solution))), true);
|
|
6448
6650
|
} else {
|
|
6449
6651
|
set(
|
|
6450
6652
|
payload,
|
|
6451
6653
|
btoa(JSON.stringify({
|
|
6452
|
-
challenge: {
|
|
6654
|
+
challenge: {
|
|
6655
|
+
parameters: challenge.parameters,
|
|
6656
|
+
signature: challenge.signature
|
|
6657
|
+
},
|
|
6453
6658
|
solution
|
|
6454
6659
|
})),
|
|
6455
6660
|
true
|
|
@@ -6532,7 +6737,7 @@ function Widget($$anchor, $$props) {
|
|
|
6532
6737
|
var div_6 = child(div_5);
|
|
6533
6738
|
var node_3 = child(div_6);
|
|
6534
6739
|
{
|
|
6535
|
-
let $0 = /* @__PURE__ */ user_derived(() => get(config).display === "standard" && get(
|
|
6740
|
+
let $0 = /* @__PURE__ */ user_derived(() => get(config).display === "standard" && get(auto) !== "onsubmit" || get(currentState) === State.VERIFYING);
|
|
6536
6741
|
component(node_3, () => get(CheckboxComponent), ($$anchor2, CheckboxComponent_1) => {
|
|
6537
6742
|
CheckboxComponent_1($$anchor2, {
|
|
6538
6743
|
get id() {
|
|
@@ -6657,6 +6862,9 @@ function Widget($$anchor, $$props) {
|
|
|
6657
6862
|
reset$1();
|
|
6658
6863
|
}
|
|
6659
6864
|
},
|
|
6865
|
+
get placement() {
|
|
6866
|
+
return get(config).popoverPlacement;
|
|
6867
|
+
},
|
|
6660
6868
|
role: "alert",
|
|
6661
6869
|
variant: "error",
|
|
6662
6870
|
get dir() {
|
|
@@ -6717,6 +6925,9 @@ function Widget($$anchor, $$props) {
|
|
|
6717
6925
|
onClose: () => {
|
|
6718
6926
|
reset$1();
|
|
6719
6927
|
},
|
|
6928
|
+
get placement() {
|
|
6929
|
+
return get(config).popoverPlacement;
|
|
6930
|
+
},
|
|
6720
6931
|
role: "dialog",
|
|
6721
6932
|
get "aria-label"() {
|
|
6722
6933
|
return get(strings).verificationRequired;
|