@ztimson/momentum 1.5.7 → 1.5.9
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/dist/analytics.d.ts +17 -3
- package/dist/analytics.d.ts.map +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/captcha.d.ts +2 -2
- package/dist/captcha.d.ts.map +1 -1
- package/dist/client.d.ts +0 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/index.js +331 -202
- package/dist/index.mjs +331 -202
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -239,30 +239,37 @@
|
|
|
239
239
|
if (type == "function") return target.toString() == values.toString();
|
|
240
240
|
return target == values;
|
|
241
241
|
}
|
|
242
|
-
function isEqual(a, b,
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
242
|
+
function isEqual(a, b, compare) {
|
|
243
|
+
const eq = (a2, b2, compare2, seen, path) => {
|
|
244
|
+
if (Array.isArray(compare2)) {
|
|
245
|
+
if (compare2.some((p) => new RegExp(`^${p.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^.]*")}(\\.|$)`).test(path))) return true;
|
|
246
|
+
} else if (typeof compare2 === "function") {
|
|
247
|
+
const r = compare2(path, a2, b2);
|
|
248
|
+
if (r !== void 0) return r;
|
|
249
|
+
}
|
|
250
|
+
if (a2 === b2) return true;
|
|
251
|
+
if (a2 instanceof Date && b2 instanceof Date) return a2.getTime() === b2.getTime();
|
|
252
|
+
if (a2 instanceof RegExp && b2 instanceof RegExp) return a2.source === b2.source && a2.flags === b2.flags;
|
|
253
|
+
if (typeof a2 !== "object" || a2 === null || typeof b2 !== "object" || b2 === null) {
|
|
254
|
+
if (Number.isNaN(a2) && Number.isNaN(b2)) return true;
|
|
255
|
+
if (typeof a2 === "function" && typeof b2 === "function") return a2.toString() === b2.toString();
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
if (seen.has(a2)) return seen.get(a2) === b2;
|
|
259
|
+
seen.set(a2, b2);
|
|
260
|
+
const isArrayA = Array.isArray(a2), isArrayB = Array.isArray(b2);
|
|
261
|
+
if (isArrayA && isArrayB) {
|
|
262
|
+
if (a2.length !== b2.length) return false;
|
|
263
|
+
for (let i = 0; i < a2.length; i++) if (!eq(a2[i], b2[i], compare2, seen, path ? `${path}.${i}` : `${i}`)) return false;
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
if (isArrayA !== isArrayB) return false;
|
|
267
|
+
const keysA = Object.keys(a2), keysB = Object.keys(b2);
|
|
268
|
+
if (keysA.length !== keysB.length) return false;
|
|
269
|
+
for (const key of keysA) if (!Object.prototype.hasOwnProperty.call(b2, key) || !eq(a2[key], b2[key], compare2, seen, path ? `${path}.${key}` : key)) return false;
|
|
258
270
|
return true;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const keysA = Object.keys(a);
|
|
262
|
-
const keysB = Object.keys(b);
|
|
263
|
-
if (keysA.length !== keysB.length) return false;
|
|
264
|
-
for (const key of keysA) if (!Object.prototype.hasOwnProperty.call(b, key) || !isEqual(a[key], b[key], seen)) return false;
|
|
265
|
-
return true;
|
|
271
|
+
};
|
|
272
|
+
return eq(a, b, compare, /* @__PURE__ */ new WeakMap(), "");
|
|
266
273
|
}
|
|
267
274
|
var ASet = class ASet extends Array {
|
|
268
275
|
/** Number of elements in set */
|
|
@@ -1137,34 +1144,88 @@
|
|
|
1137
1144
|
};
|
|
1138
1145
|
var PromiseProgress = class PromiseProgress extends Promise {
|
|
1139
1146
|
listeners = [];
|
|
1140
|
-
|
|
1147
|
+
_meta = {
|
|
1148
|
+
start: Date.now(),
|
|
1149
|
+
end: null,
|
|
1150
|
+
elapsed: 0,
|
|
1151
|
+
speed: 0,
|
|
1152
|
+
progress: 0,
|
|
1153
|
+
size: 0,
|
|
1154
|
+
total: 0,
|
|
1155
|
+
eta: null
|
|
1156
|
+
};
|
|
1157
|
+
get meta() {
|
|
1158
|
+
return this._meta;
|
|
1159
|
+
}
|
|
1160
|
+
get start() {
|
|
1161
|
+
return this._meta.start;
|
|
1162
|
+
}
|
|
1163
|
+
get end() {
|
|
1164
|
+
return this._meta.end;
|
|
1165
|
+
}
|
|
1166
|
+
get elapsed() {
|
|
1167
|
+
return this._meta.elapsed;
|
|
1168
|
+
}
|
|
1169
|
+
get speed() {
|
|
1170
|
+
return this._meta.speed;
|
|
1171
|
+
}
|
|
1141
1172
|
get progress() {
|
|
1142
|
-
return this.
|
|
1173
|
+
return this._meta.progress;
|
|
1143
1174
|
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1175
|
+
get size() {
|
|
1176
|
+
return this._meta.size;
|
|
1177
|
+
}
|
|
1178
|
+
get total() {
|
|
1179
|
+
return this._meta.total;
|
|
1180
|
+
}
|
|
1181
|
+
get eta() {
|
|
1182
|
+
return this._meta.eta;
|
|
1183
|
+
}
|
|
1184
|
+
update(size, total) {
|
|
1185
|
+
const elapsed = (Date.now() - this._meta.start) / 1e3;
|
|
1186
|
+
const speed = elapsed ? size / elapsed : 0;
|
|
1187
|
+
const progress = total ? size / total : this._meta.progress;
|
|
1188
|
+
this._meta = {
|
|
1189
|
+
...this._meta,
|
|
1190
|
+
size,
|
|
1191
|
+
total,
|
|
1192
|
+
progress,
|
|
1193
|
+
elapsed,
|
|
1194
|
+
speed,
|
|
1195
|
+
eta: speed && total ? (total - size) / speed : null
|
|
1196
|
+
};
|
|
1197
|
+
(this.listeners ||= []).forEach((l) => l(this._meta));
|
|
1148
1198
|
}
|
|
1149
1199
|
constructor(executor) {
|
|
1150
|
-
super((resolve, reject) => executor((value) =>
|
|
1200
|
+
super((resolve, reject) => executor((value) => {
|
|
1201
|
+
this._meta = {
|
|
1202
|
+
...this._meta,
|
|
1203
|
+
end: Date.now()
|
|
1204
|
+
};
|
|
1205
|
+
resolve(value);
|
|
1206
|
+
}, (reason) => {
|
|
1207
|
+
this._meta = {
|
|
1208
|
+
...this._meta,
|
|
1209
|
+
end: Date.now()
|
|
1210
|
+
};
|
|
1211
|
+
reject(reason);
|
|
1212
|
+
}, (size, total) => this.update(size, total ?? this._meta.total)));
|
|
1151
1213
|
}
|
|
1152
1214
|
static from(promise) {
|
|
1153
1215
|
if (promise instanceof PromiseProgress) return promise;
|
|
1154
|
-
return new PromiseProgress((res, rej) => promise.then(
|
|
1216
|
+
return new PromiseProgress((res, rej) => promise.then(res).catch(rej));
|
|
1155
1217
|
}
|
|
1156
1218
|
from(promise) {
|
|
1157
1219
|
const newPromise = PromiseProgress.from(promise);
|
|
1158
|
-
this.onProgress((
|
|
1220
|
+
this.onProgress((m) => newPromise.update(m.size, m.total));
|
|
1159
1221
|
return newPromise;
|
|
1160
1222
|
}
|
|
1161
1223
|
onProgress(callback) {
|
|
1162
|
-
this.listeners.push(callback);
|
|
1224
|
+
(this.listeners ||= []).push(callback);
|
|
1163
1225
|
return this;
|
|
1164
1226
|
}
|
|
1165
1227
|
then(res, rej) {
|
|
1166
|
-
|
|
1167
|
-
return this.from(resp);
|
|
1228
|
+
return this.from(super.then(res, rej));
|
|
1168
1229
|
}
|
|
1169
1230
|
catch(rej) {
|
|
1170
1231
|
return this.from(super.catch(rej));
|
|
@@ -1213,7 +1274,7 @@
|
|
|
1213
1274
|
const formData2 = new FormData();
|
|
1214
1275
|
options.files.forEach((f) => formData2.append("files", f));
|
|
1215
1276
|
xhr.withCredentials = !!options.withCredentials;
|
|
1216
|
-
xhr.upload.addEventListener("progress", (event) => event.lengthComputable ? prog(event.loaded
|
|
1277
|
+
xhr.upload.addEventListener("progress", (event) => event.lengthComputable ? prog(event.loaded, event.total) : null);
|
|
1217
1278
|
xhr.addEventListener("loadend", () => res(JSONAttemptParse(xhr.responseText)));
|
|
1218
1279
|
xhr.addEventListener("error", () => rej(JSONAttemptParse(xhr.responseText)));
|
|
1219
1280
|
xhr.addEventListener("timeout", () => rej({ error: "Request timed out" }));
|
|
@@ -2251,6 +2312,182 @@
|
|
|
2251
2312
|
}
|
|
2252
2313
|
};
|
|
2253
2314
|
//#endregion
|
|
2315
|
+
//#region src/captcha.ts
|
|
2316
|
+
var Captcha = class {
|
|
2317
|
+
start = Date.now();
|
|
2318
|
+
events = {
|
|
2319
|
+
mouse: [],
|
|
2320
|
+
keys: [],
|
|
2321
|
+
clicks: [],
|
|
2322
|
+
scroll: [],
|
|
2323
|
+
focus: []
|
|
2324
|
+
};
|
|
2325
|
+
lastMouse = null;
|
|
2326
|
+
velocities = [];
|
|
2327
|
+
_score = .5;
|
|
2328
|
+
onScoreChange;
|
|
2329
|
+
set score(v) {
|
|
2330
|
+
const next = +Math.max(0, Math.min(1, Number.isFinite(v) ? v : .5)).toFixed(2);
|
|
2331
|
+
if (next == this._score) return;
|
|
2332
|
+
this._score = next;
|
|
2333
|
+
this.onScoreChange?.(next);
|
|
2334
|
+
}
|
|
2335
|
+
get score() {
|
|
2336
|
+
return this._score;
|
|
2337
|
+
}
|
|
2338
|
+
get verdict() {
|
|
2339
|
+
if (this.score >= .45 && this.score <= .55) return "unknown";
|
|
2340
|
+
if (this.score > .5) return "human";
|
|
2341
|
+
return "bot";
|
|
2342
|
+
}
|
|
2343
|
+
constructor(onScoreChange) {
|
|
2344
|
+
this.onScoreChange = onScoreChange;
|
|
2345
|
+
if (typeof window === "undefined" || !document) {
|
|
2346
|
+
this._score = 0;
|
|
2347
|
+
return;
|
|
2348
|
+
}
|
|
2349
|
+
document.addEventListener("pointermove", (e) => {
|
|
2350
|
+
const now = Date.now();
|
|
2351
|
+
const curr = {
|
|
2352
|
+
x: e.clientX,
|
|
2353
|
+
y: e.clientY,
|
|
2354
|
+
t: now
|
|
2355
|
+
};
|
|
2356
|
+
this.events.mouse.push(curr);
|
|
2357
|
+
if (this.lastMouse) {
|
|
2358
|
+
const dt = now - this.lastMouse.t;
|
|
2359
|
+
const dx = curr.x - this.lastMouse.x;
|
|
2360
|
+
const dy = curr.y - this.lastMouse.y;
|
|
2361
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
2362
|
+
if (dt > 0 && dt < 1e3) this.velocities.push(dist / dt);
|
|
2363
|
+
}
|
|
2364
|
+
this.lastMouse = curr;
|
|
2365
|
+
if (this.events.mouse.length > 80) this.events.mouse.shift();
|
|
2366
|
+
if (this.velocities.length > 40) this.velocities.shift();
|
|
2367
|
+
}, { passive: true });
|
|
2368
|
+
document.addEventListener("keydown", () => {
|
|
2369
|
+
this.events.keys.push(Date.now());
|
|
2370
|
+
if (this.events.keys.length > 30) this.events.keys.shift();
|
|
2371
|
+
this.update();
|
|
2372
|
+
});
|
|
2373
|
+
document.addEventListener("pointerdown", (e) => {
|
|
2374
|
+
this.events.clicks.push({
|
|
2375
|
+
x: e.clientX,
|
|
2376
|
+
y: e.clientY,
|
|
2377
|
+
t: Date.now()
|
|
2378
|
+
});
|
|
2379
|
+
if (this.events.clicks.length > 20) this.events.clicks.shift();
|
|
2380
|
+
this.update();
|
|
2381
|
+
}, { passive: true });
|
|
2382
|
+
window.addEventListener("scroll", () => {
|
|
2383
|
+
this.events.scroll.push({
|
|
2384
|
+
x: window.scrollX,
|
|
2385
|
+
y: window.scrollY,
|
|
2386
|
+
t: Date.now()
|
|
2387
|
+
});
|
|
2388
|
+
if (this.events.scroll.length > 20) this.events.scroll.shift();
|
|
2389
|
+
}, { passive: true });
|
|
2390
|
+
document.addEventListener("visibilitychange", () => {
|
|
2391
|
+
this.events.focus.push({
|
|
2392
|
+
visible: document.visibilityState == "visible",
|
|
2393
|
+
t: Date.now()
|
|
2394
|
+
});
|
|
2395
|
+
if (this.events.focus.length > 20) this.events.focus.shift();
|
|
2396
|
+
this.update();
|
|
2397
|
+
});
|
|
2398
|
+
window.addEventListener("focus", () => {
|
|
2399
|
+
this.events.focus.push({
|
|
2400
|
+
visible: true,
|
|
2401
|
+
t: Date.now()
|
|
2402
|
+
});
|
|
2403
|
+
this.update();
|
|
2404
|
+
});
|
|
2405
|
+
window.addEventListener("blur", () => {
|
|
2406
|
+
this.events.focus.push({
|
|
2407
|
+
visible: false,
|
|
2408
|
+
t: Date.now()
|
|
2409
|
+
});
|
|
2410
|
+
this.update();
|
|
2411
|
+
});
|
|
2412
|
+
setInterval(() => this.update(), 2e3);
|
|
2413
|
+
}
|
|
2414
|
+
update() {
|
|
2415
|
+
if (navigator?.webdriver) {
|
|
2416
|
+
this._score = 0;
|
|
2417
|
+
this.onScoreChange?.(0);
|
|
2418
|
+
return;
|
|
2419
|
+
}
|
|
2420
|
+
let delta = 0;
|
|
2421
|
+
const elapsed = (Date.now() - this.start) / 1e3;
|
|
2422
|
+
delta += elapsed > 30 ? .08 : elapsed > 10 ? .04 : elapsed > 3 ? .01 : -.05;
|
|
2423
|
+
if (this.events.mouse.length >= 6) {
|
|
2424
|
+
const recent = this.events.mouse.slice(-30);
|
|
2425
|
+
const buckets = new Array(8).fill(0);
|
|
2426
|
+
for (let i = 1; i < recent.length; i++) {
|
|
2427
|
+
const dx = recent[i].x - recent[i - 1].x;
|
|
2428
|
+
const dy = recent[i].y - recent[i - 1].y;
|
|
2429
|
+
if (dx == 0 && dy == 0) continue;
|
|
2430
|
+
let angle = Math.atan2(dy, dx);
|
|
2431
|
+
if (angle < 0) angle += Math.PI * 2;
|
|
2432
|
+
buckets[Math.min(7, Math.floor(angle / (Math.PI * 2) * 8))]++;
|
|
2433
|
+
}
|
|
2434
|
+
const total = buckets.reduce((a, b) => a + b, 0);
|
|
2435
|
+
if (total >= 4) {
|
|
2436
|
+
let entropy = 0;
|
|
2437
|
+
for (const count of buckets) {
|
|
2438
|
+
if (!count) continue;
|
|
2439
|
+
const p = count / total;
|
|
2440
|
+
entropy -= p * Math.log2(p);
|
|
2441
|
+
}
|
|
2442
|
+
entropy /= Math.log2(8);
|
|
2443
|
+
if (entropy > .65) delta += .12;
|
|
2444
|
+
else if (entropy > .4) delta += .05;
|
|
2445
|
+
else delta -= .07;
|
|
2446
|
+
}
|
|
2447
|
+
} else if (this.events.mouse.length == 0) delta -= .01;
|
|
2448
|
+
if (this.velocities.length >= 5) {
|
|
2449
|
+
const avg = this.velocities.reduce((a, b) => a + b, 0) / this.velocities.length;
|
|
2450
|
+
const variance = this.velocities.reduce((a, b) => a + Math.pow(b - avg, 2), 0) / this.velocities.length;
|
|
2451
|
+
const cv = avg > 0 ? Math.sqrt(variance) / avg : 0;
|
|
2452
|
+
if (cv > .45) delta += .1;
|
|
2453
|
+
else if (cv > .18) delta += .04;
|
|
2454
|
+
else if (avg > 0) delta -= .08;
|
|
2455
|
+
}
|
|
2456
|
+
if (this.events.clicks.length > 0) {
|
|
2457
|
+
const lastClick = this.events.clicks.at(-1);
|
|
2458
|
+
const mouseBeforeClick = this.events.mouse.some((m) => m.t < lastClick.t && lastClick.t - m.t < 2e3);
|
|
2459
|
+
delta += mouseBeforeClick ? .06 : -.08;
|
|
2460
|
+
const suspiciousClicks = this.events.clicks.filter((c) => Number.isInteger(c.x) && Number.isInteger(c.y) && c.x % 10 == 0 && c.y % 10 == 0).length;
|
|
2461
|
+
if (this.events.clicks.length >= 4 && suspiciousClicks / this.events.clicks.length > .5) delta -= .06;
|
|
2462
|
+
}
|
|
2463
|
+
if (this.events.keys.length >= 4) {
|
|
2464
|
+
const intervals = [];
|
|
2465
|
+
for (let i = 1; i < this.events.keys.length; i++) intervals.push(this.events.keys[i] - this.events.keys[i - 1]);
|
|
2466
|
+
const avg = intervals.reduce((a, b) => a + b, 0) / intervals.length;
|
|
2467
|
+
const stdDev = Math.sqrt(intervals.reduce((a, b) => a + Math.pow(b - avg, 2), 0) / intervals.length);
|
|
2468
|
+
if (avg < 20) delta -= .15;
|
|
2469
|
+
else if (stdDev < 5) delta -= .1;
|
|
2470
|
+
else if (avg < 50) delta -= .04;
|
|
2471
|
+
else if (avg < 1e3 && stdDev > 20) delta += .08;
|
|
2472
|
+
}
|
|
2473
|
+
if (this.events.scroll.length >= 4) {
|
|
2474
|
+
let directionChanges = 0;
|
|
2475
|
+
let previousDirection = 0;
|
|
2476
|
+
for (let i = 1; i < this.events.scroll.length; i++) {
|
|
2477
|
+
const direction = Math.sign(this.events.scroll[i].y - this.events.scroll[i - 1].y);
|
|
2478
|
+
if (direction && previousDirection && direction != previousDirection) directionChanges++;
|
|
2479
|
+
if (direction) previousDirection = direction;
|
|
2480
|
+
}
|
|
2481
|
+
if (directionChanges >= 2) delta += .04;
|
|
2482
|
+
}
|
|
2483
|
+
if (this.events.focus.length >= 2) {
|
|
2484
|
+
const visible = this.events.focus.filter((x) => x.visible).length;
|
|
2485
|
+
delta += visible / this.events.focus.length > .4 ? .02 : -.02;
|
|
2486
|
+
}
|
|
2487
|
+
this.score = this.score + delta * .25;
|
|
2488
|
+
}
|
|
2489
|
+
};
|
|
2490
|
+
//#endregion
|
|
2254
2491
|
//#region src/dialog.ts
|
|
2255
2492
|
var dialogCount = 0;
|
|
2256
2493
|
var closed = 0;
|
|
@@ -2463,6 +2700,16 @@
|
|
|
2463
2700
|
var Analytics = class extends AssetController {
|
|
2464
2701
|
momentum;
|
|
2465
2702
|
lastPage;
|
|
2703
|
+
captcha = new Captcha((score) => this.updateCaptcha(score));
|
|
2704
|
+
captchaSecret;
|
|
2705
|
+
captchaSequence = 0;
|
|
2706
|
+
captchaUpdate;
|
|
2707
|
+
get captchaScore() {
|
|
2708
|
+
return this.captcha.score;
|
|
2709
|
+
}
|
|
2710
|
+
get actorType() {
|
|
2711
|
+
return this.captcha.verdict;
|
|
2712
|
+
}
|
|
2466
2713
|
_ready;
|
|
2467
2714
|
ready = new Promise((res) => this._ready = res);
|
|
2468
2715
|
_performance = {
|
|
@@ -2541,6 +2788,9 @@
|
|
|
2541
2788
|
this._id = "";
|
|
2542
2789
|
this._consent = void 0;
|
|
2543
2790
|
this._new = true;
|
|
2791
|
+
this.captchaSecret = void 0;
|
|
2792
|
+
this.captchaSequence = 0;
|
|
2793
|
+
delete this.momentum.api.headers["X-Captcha"];
|
|
2544
2794
|
});
|
|
2545
2795
|
this.momentum.auth.on("login:c", async () => {
|
|
2546
2796
|
if (this.consent) await this.init();
|
|
@@ -2617,7 +2867,7 @@
|
|
|
2617
2867
|
async init() {
|
|
2618
2868
|
if (!this.momentum.opts.analytics) return;
|
|
2619
2869
|
const performance = await this.performance;
|
|
2620
|
-
|
|
2870
|
+
const response = await this.momentum.api.request({
|
|
2621
2871
|
url: `api/analytics`,
|
|
2622
2872
|
body: [
|
|
2623
2873
|
navigator?.language,
|
|
@@ -2635,6 +2885,10 @@
|
|
|
2635
2885
|
performance.total
|
|
2636
2886
|
]
|
|
2637
2887
|
});
|
|
2888
|
+
this.id = response.id;
|
|
2889
|
+
this.captchaSecret = response.captchaSecret;
|
|
2890
|
+
this.captchaSequence = response.captchaSequence;
|
|
2891
|
+
await this.updateCaptcha(this.captcha.score, true);
|
|
2638
2892
|
if (this._ready) {
|
|
2639
2893
|
this._ready();
|
|
2640
2894
|
this._ready = null;
|
|
@@ -2644,6 +2898,25 @@
|
|
|
2644
2898
|
window.addEventListener("beforeunload", () => this.page("CLOSED"));
|
|
2645
2899
|
return this.id;
|
|
2646
2900
|
}
|
|
2901
|
+
updateCaptcha(score, initial = false) {
|
|
2902
|
+
if (!this.captchaSecret || !this.id || !globalThis.crypto?.subtle) return Promise.resolve();
|
|
2903
|
+
const update = this.captchaUpdate?.catch(() => {}) || Promise.resolve();
|
|
2904
|
+
this.captchaUpdate = update.then(() => this.attestCaptcha(score, initial)).catch(() => {});
|
|
2905
|
+
return this.captchaUpdate;
|
|
2906
|
+
}
|
|
2907
|
+
async attestCaptcha(score, initial) {
|
|
2908
|
+
if (!this.captchaSecret || !this.id) return;
|
|
2909
|
+
if (!initial) this.captchaSequence++;
|
|
2910
|
+
const canonical = Math.max(0, Math.min(1, Number.isFinite(score) ? score : .5)).toFixed(2);
|
|
2911
|
+
const payload = `${canonical}:${this.captchaSequence}`;
|
|
2912
|
+
const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(this.captchaSecret), {
|
|
2913
|
+
name: "HMAC",
|
|
2914
|
+
hash: "SHA-256"
|
|
2915
|
+
}, false, ["sign"]);
|
|
2916
|
+
const signature = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(payload));
|
|
2917
|
+
const proof = btoa(String.fromCharCode(...new Uint8Array(signature))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
2918
|
+
this.momentum.api.headers["X-Captcha"] = `${canonical},${this.captchaSequence},${proof}`;
|
|
2919
|
+
}
|
|
2647
2920
|
async consentPrompt(content) {
|
|
2648
2921
|
const settings = await this.momentum.settings.map();
|
|
2649
2922
|
const { close, dialog, result } = createDialog(`
|
|
@@ -3017,19 +3290,29 @@
|
|
|
3017
3290
|
loginRedirect(host = location.origin) {
|
|
3018
3291
|
return new Promise((res, rej) => {
|
|
3019
3292
|
let listener, win;
|
|
3293
|
+
const loginOrigin = new URL(this.momentum.opts.loginUrl, location.href).origin;
|
|
3294
|
+
const hostOrigin = new URL(host, location.href).origin;
|
|
3020
3295
|
window.addEventListener("message", listener = async (event) => {
|
|
3296
|
+
if (event.origin !== loginOrigin || event?.data?.sender !== loginOrigin) return;
|
|
3021
3297
|
const data = event?.data || {};
|
|
3022
|
-
if (
|
|
3023
|
-
|
|
3298
|
+
if (!data.token) {
|
|
3299
|
+
window.removeEventListener("message", listener);
|
|
3300
|
+
return rej(/* @__PURE__ */ new Error("Unknown response from login"));
|
|
3301
|
+
}
|
|
3024
3302
|
window.removeEventListener("message", listener);
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3303
|
+
try {
|
|
3304
|
+
await this.readSession(data.token, true);
|
|
3305
|
+
win?.close();
|
|
3306
|
+
res(data.token);
|
|
3307
|
+
} catch (err) {
|
|
3308
|
+
win?.close();
|
|
3309
|
+
rej(err);
|
|
3310
|
+
}
|
|
3028
3311
|
});
|
|
3029
|
-
win = window.open(`${this.momentum.opts.loginUrl}?redirect=postmessage&host=${
|
|
3312
|
+
win = window.open(`${this.momentum.opts.loginUrl}?redirect=postmessage&host=${encodeURIComponent(hostOrigin)}`, "_blank");
|
|
3030
3313
|
if (!win) {
|
|
3031
3314
|
window.removeEventListener("message", listener);
|
|
3032
|
-
return rej("Unable to open login");
|
|
3315
|
+
return rej(/* @__PURE__ */ new Error("Unable to open login"));
|
|
3033
3316
|
}
|
|
3034
3317
|
});
|
|
3035
3318
|
}
|
|
@@ -3155,174 +3438,20 @@
|
|
|
3155
3438
|
}
|
|
3156
3439
|
};
|
|
3157
3440
|
//#endregion
|
|
3158
|
-
//#region src/captcha.ts
|
|
3159
|
-
var Captcha = class {
|
|
3160
|
-
start = Date.now();
|
|
3161
|
-
events = {
|
|
3162
|
-
mouse: [],
|
|
3163
|
-
keys: [],
|
|
3164
|
-
clicks: []
|
|
3165
|
-
};
|
|
3166
|
-
lastMouse = null;
|
|
3167
|
-
velocities = [];
|
|
3168
|
-
_score = .5;
|
|
3169
|
-
set score(v) {
|
|
3170
|
-
this._score = v;
|
|
3171
|
-
}
|
|
3172
|
-
get score() {
|
|
3173
|
-
return this._score;
|
|
3174
|
-
}
|
|
3175
|
-
get verdict() {
|
|
3176
|
-
if (this.score == .5) return "unknown";
|
|
3177
|
-
if (this.score > .5) return "human";
|
|
3178
|
-
return "bot";
|
|
3179
|
-
}
|
|
3180
|
-
constructor() {
|
|
3181
|
-
if (typeof window === "undefined" || !window.innerWidth || !this.validUserAgent()) {
|
|
3182
|
-
this.score = 0;
|
|
3183
|
-
return;
|
|
3184
|
-
}
|
|
3185
|
-
document.addEventListener("mousemove", (e) => {
|
|
3186
|
-
const now = Date.now();
|
|
3187
|
-
const curr = {
|
|
3188
|
-
x: e.clientX,
|
|
3189
|
-
y: e.clientY,
|
|
3190
|
-
t: now
|
|
3191
|
-
};
|
|
3192
|
-
this.events.mouse.push(curr);
|
|
3193
|
-
if (this.lastMouse) {
|
|
3194
|
-
const dt = now - this.lastMouse.t;
|
|
3195
|
-
const dx = curr.x - this.lastMouse.x;
|
|
3196
|
-
const dy = curr.y - this.lastMouse.y;
|
|
3197
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
3198
|
-
if (dt > 0) this.velocities.push(dist / dt);
|
|
3199
|
-
}
|
|
3200
|
-
this.lastMouse = curr;
|
|
3201
|
-
if (this.events.mouse.length > 50) this.events.mouse.shift();
|
|
3202
|
-
if (this.velocities.length > 30) this.velocities.shift();
|
|
3203
|
-
});
|
|
3204
|
-
document.addEventListener("keydown", (e) => {
|
|
3205
|
-
this.events.keys.push(Date.now());
|
|
3206
|
-
if (this.events.keys.length > 20) this.events.keys.shift();
|
|
3207
|
-
});
|
|
3208
|
-
document.addEventListener("click", (e) => {
|
|
3209
|
-
this.events.clicks.push({
|
|
3210
|
-
x: e.clientX,
|
|
3211
|
-
y: e.clientY,
|
|
3212
|
-
t: Date.now()
|
|
3213
|
-
});
|
|
3214
|
-
if (this.events.clicks.length > 15) this.events.clicks.shift();
|
|
3215
|
-
});
|
|
3216
|
-
setInterval(() => this.update(), 1e3);
|
|
3217
|
-
}
|
|
3218
|
-
validUserAgent() {
|
|
3219
|
-
if (!navigator?.userAgent) return false;
|
|
3220
|
-
const ua = navigator.userAgent.toLowerCase();
|
|
3221
|
-
if ([
|
|
3222
|
-
"bot",
|
|
3223
|
-
"crawler",
|
|
3224
|
-
"spider",
|
|
3225
|
-
"scraper",
|
|
3226
|
-
"headless",
|
|
3227
|
-
"phantom",
|
|
3228
|
-
"selenium",
|
|
3229
|
-
"webdriver",
|
|
3230
|
-
"puppeteer",
|
|
3231
|
-
"playwright",
|
|
3232
|
-
"cypress",
|
|
3233
|
-
"automation"
|
|
3234
|
-
].some((pattern) => ua.includes(pattern))) return false;
|
|
3235
|
-
if (![
|
|
3236
|
-
"chrome",
|
|
3237
|
-
"firefox",
|
|
3238
|
-
"safari",
|
|
3239
|
-
"edge",
|
|
3240
|
-
"opera"
|
|
3241
|
-
].some((browser) => ua.includes(browser))) return false;
|
|
3242
|
-
if (![
|
|
3243
|
-
"windows",
|
|
3244
|
-
"mac",
|
|
3245
|
-
"linux",
|
|
3246
|
-
"android",
|
|
3247
|
-
"ios"
|
|
3248
|
-
].some((os) => ua.includes(os))) return false;
|
|
3249
|
-
return ua.length > 20 && ua.length < 1e3;
|
|
3250
|
-
}
|
|
3251
|
-
update() {
|
|
3252
|
-
if (navigator.webdriver) {
|
|
3253
|
-
this.score = 0;
|
|
3254
|
-
return;
|
|
3255
|
-
}
|
|
3256
|
-
let delta = 0;
|
|
3257
|
-
const elapsed = (Date.now() - this.start) / 1e3;
|
|
3258
|
-
delta += elapsed > 30 ? .08 : elapsed > 10 ? .04 : elapsed > 3 ? .01 : -.05;
|
|
3259
|
-
if (this.events.mouse.length >= 5) {
|
|
3260
|
-
const recent = this.events.mouse.slice(-20);
|
|
3261
|
-
let changes = 0;
|
|
3262
|
-
let maxStraightRun = 0;
|
|
3263
|
-
let currentRun = 0;
|
|
3264
|
-
for (let i = 2; i < recent.length; i++) {
|
|
3265
|
-
const a1 = Math.atan2(recent[i - 1].y - recent[i - 2].y, recent[i - 1].x - recent[i - 2].x);
|
|
3266
|
-
const a2 = Math.atan2(recent[i].y - recent[i - 1].y, recent[i].x - recent[i - 1].x);
|
|
3267
|
-
if (Math.abs(a1 - a2) > .3) {
|
|
3268
|
-
changes++;
|
|
3269
|
-
currentRun = 0;
|
|
3270
|
-
} else {
|
|
3271
|
-
currentRun++;
|
|
3272
|
-
maxStraightRun = Math.max(maxStraightRun, currentRun);
|
|
3273
|
-
}
|
|
3274
|
-
}
|
|
3275
|
-
const entropy = changes / (recent.length - 2);
|
|
3276
|
-
if (entropy > .4) delta += .12;
|
|
3277
|
-
else if (entropy > .2) delta += .05;
|
|
3278
|
-
else delta -= .08;
|
|
3279
|
-
if (maxStraightRun > 8) delta -= .1;
|
|
3280
|
-
} else if (this.events.mouse.length === 0) delta -= .03;
|
|
3281
|
-
if (this.velocities.length >= 5) {
|
|
3282
|
-
const avg = this.velocities.reduce((a, b) => a + b, 0) / this.velocities.length;
|
|
3283
|
-
const variance = this.velocities.reduce((a, b) => a + Math.pow(b - avg, 2), 0) / this.velocities.length;
|
|
3284
|
-
const cv = avg > 0 ? Math.sqrt(variance) / avg : 0;
|
|
3285
|
-
if (cv > .4) delta += .1;
|
|
3286
|
-
else if (cv > .15) delta += .04;
|
|
3287
|
-
else if (avg > 0) delta -= .1;
|
|
3288
|
-
}
|
|
3289
|
-
if (this.events.clicks.length > 0) {
|
|
3290
|
-
const lastClick = this.events.clicks[this.events.clicks.length - 1];
|
|
3291
|
-
const mouseBeforeClick = this.events.mouse.some((m) => m.t < lastClick.t && lastClick.t - m.t < 2e3);
|
|
3292
|
-
delta += mouseBeforeClick ? .08 : -.12;
|
|
3293
|
-
if (this.events.clicks.filter((c) => Number.isInteger(c.x) && Number.isInteger(c.y) && c.x % 10 === 0 && c.y % 10 === 0).length / this.events.clicks.length > .5) delta -= .08;
|
|
3294
|
-
}
|
|
3295
|
-
if (this.events.keys.length >= 3) {
|
|
3296
|
-
const intervals = [];
|
|
3297
|
-
for (let i = 1; i < this.events.keys.length; i++) intervals.push(this.events.keys[i] - this.events.keys[i - 1]);
|
|
3298
|
-
const avg = intervals.reduce((a, b) => a + b, 0) / intervals.length;
|
|
3299
|
-
const stdDev = Math.sqrt(intervals.reduce((a, b) => a + Math.pow(b - avg, 2), 0) / intervals.length);
|
|
3300
|
-
if (avg < 20) delta -= .15;
|
|
3301
|
-
else if (stdDev < 5) delta -= .12;
|
|
3302
|
-
else if (avg < 50) delta -= .05;
|
|
3303
|
-
else if (avg < 1e3 && stdDev > 20) delta += .1;
|
|
3304
|
-
}
|
|
3305
|
-
const raw = this.score + delta;
|
|
3306
|
-
this.score = this.score * .75 + raw * .25;
|
|
3307
|
-
this.score = Math.max(.05, Math.min(.95, this.score));
|
|
3308
|
-
}
|
|
3309
|
-
};
|
|
3310
|
-
//#endregion
|
|
3311
3441
|
//#region src/client.ts
|
|
3312
3442
|
/** Handle device settings */
|
|
3313
3443
|
var Client = class Client extends PathEventEmitter {
|
|
3314
3444
|
momentum;
|
|
3315
|
-
captcha = new Captcha();
|
|
3316
3445
|
installTimeout;
|
|
3317
3446
|
nativePwaPrompt;
|
|
3318
3447
|
pendingInstall = null;
|
|
3319
3448
|
speed;
|
|
3320
3449
|
updating = false;
|
|
3321
3450
|
get actorType() {
|
|
3322
|
-
return this.
|
|
3451
|
+
return this.momentum.analytics.actorType;
|
|
3323
3452
|
}
|
|
3324
3453
|
get captchaScore() {
|
|
3325
|
-
return this.
|
|
3454
|
+
return this.momentum.analytics.captchaScore;
|
|
3326
3455
|
}
|
|
3327
3456
|
/** Check for updates */
|
|
3328
3457
|
updateReady = new Promise((res) => {
|
|
@@ -4841,7 +4970,7 @@ ${Object.entries(t).map(([name, value]) => `--theme-${kebabCase(name)}: ${value}
|
|
|
4841
4970
|
headers: this.momentum.api.headers,
|
|
4842
4971
|
files: f
|
|
4843
4972
|
}).onProgress((p) => {
|
|
4844
|
-
prog(p);
|
|
4973
|
+
prog(p.progress);
|
|
4845
4974
|
}).then((resp) => {
|
|
4846
4975
|
this.emit(PES`${this.module}/${path}:c`, resp);
|
|
4847
4976
|
res(resp);
|
|
@@ -5019,7 +5148,7 @@ ${Object.entries(t).map(([name, value]) => `--theme-${kebabCase(name)}: ${value}
|
|
|
5019
5148
|
};
|
|
5020
5149
|
//#endregion
|
|
5021
5150
|
//#region package.json
|
|
5022
|
-
var version = "1.5.
|
|
5151
|
+
var version = "1.5.9";
|
|
5023
5152
|
//#endregion
|
|
5024
5153
|
//#region src/webRtc.ts
|
|
5025
5154
|
var WebRtc = class extends PathEventEmitter {
|