@oxvo/browser 7.3.4 → 7.4.15
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/cjs/entry.js +523 -84
- package/dist/cjs/entry.js.map +1 -1
- package/dist/cjs/index.js +517 -84
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/main/app/debugRedaction.d.ts +11 -0
- package/dist/cjs/main/app/index.d.ts +17 -1
- package/dist/cjs/main/index.d.ts +5 -0
- package/dist/cjs/main/singleton.d.ts +5 -0
- package/dist/lib/entry.js +523 -84
- package/dist/lib/entry.js.map +1 -1
- package/dist/lib/index.js +517 -84
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/main/app/debugRedaction.d.ts +11 -0
- package/dist/lib/main/app/index.d.ts +17 -1
- package/dist/lib/main/index.d.ts +5 -0
- package/dist/lib/main/singleton.d.ts +5 -0
- package/dist/types/main/app/debugRedaction.d.ts +11 -0
- package/dist/types/main/app/index.d.ts +17 -1
- package/dist/types/main/index.d.ts +5 -0
- package/dist/types/main/singleton.d.ts +5 -0
- package/package.json +2 -2
package/dist/lib/entry.js
CHANGED
|
@@ -2588,6 +2588,220 @@ function parseCrossDomainIframeBatch(messages) {
|
|
|
2588
2588
|
return { messages: messages, bytes };
|
|
2589
2589
|
}
|
|
2590
2590
|
|
|
2591
|
+
const REDACTED_DEBUG_VALUE = '[REDACTED]';
|
|
2592
|
+
const TRUNCATED_DEBUG_VALUE = '[TRUNCATED]';
|
|
2593
|
+
const MAX_DEBUG_TEXT_LENGTH = 2048;
|
|
2594
|
+
const MAX_DEBUG_CREDENTIAL_LOOKAHEAD = 512;
|
|
2595
|
+
const MAX_DEBUG_REDACTION_DEPTH = 5;
|
|
2596
|
+
const MAX_DEBUG_REDACTION_ITEMS = 50;
|
|
2597
|
+
const DEBUG_FIELD_VALUE_PATTERN = /(["']?)([ \t]*[a-z0-9_-]{1,64}[ \t]*)\1(\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|[^\s,;&{}\[\]()\r\n]+)/gim;
|
|
2598
|
+
const DEBUG_AUTHORIZATION_FIELD_PATTERN = /(["']?)((?:proxy[-_]?authorization|authorization)(?:[-_]?header)?)\1(\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|\[(?:REDACTED|TRUNCATED)\]|[^,;&}\]\)\r\n]+)/gi;
|
|
2599
|
+
const DEBUG_COOKIE_FIELD_PATTERN = /(["']?)((?:set[-_]?cookie|cookies?)(?:[-_]?header)?)\1(\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|\[(?:REDACTED|TRUNCATED)\]|[^\r\n]+)/gi;
|
|
2600
|
+
const DEBUG_AUTH_SCHEME_VALUE_PATTERN = /(\b(?:ApiKey|Basic|Bearer|Digest|Negotiate)\s+)[a-z0-9._~+/=-]+/gi;
|
|
2601
|
+
const DEBUG_TOKEN_AUTH_SCHEME_VALUE_PATTERN = /(\bToken\s+)[a-z0-9._~+/=-]+/g;
|
|
2602
|
+
const DEBUG_JWT_VALUE_PATTERN = /\beyJ[a-z0-9_-]{5,}\.[a-z0-9_-]{5,}\.[a-z0-9_-]{5,}\b/gi;
|
|
2603
|
+
const DEBUG_URL_CREDENTIAL_PATTERN = /(\bhttps?:\/\/)([^\s/:@]+):([^\s/@]+)@/gi;
|
|
2604
|
+
const DEBUG_ENCODED_FIELD_VALUE_PATTERN = /([a-z0-9_-]{0,48}(?:token|secret|grant|credential|api[-_]?key|private[-_]?key|signing[-_]?key|authorization|cookie))(%3a|%3d)(?:%22|%27)?[a-z0-9._~+/%=-]+/gi;
|
|
2605
|
+
const DEBUG_PROVIDER_CREDENTIAL_PATTERNS = [
|
|
2606
|
+
/sk-(?:(?:proj|svcacct|ant)-)?[a-z0-9_-]{8,}/gi,
|
|
2607
|
+
/AIza[a-z0-9_-]{20,}/gi,
|
|
2608
|
+
/(?:AKIA|ASIA)[A-Z0-9]{16}/g,
|
|
2609
|
+
/gh[pousr]_[a-z0-9]{20,}/gi,
|
|
2610
|
+
/xox[a-z]-[a-z0-9-]{10,}/gi,
|
|
2611
|
+
];
|
|
2612
|
+
const DEBUG_PRIVATE_KEY_PATTERN = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z0-9 ]*PRIVATE KEY-----|$)/g;
|
|
2613
|
+
const PROVIDER_KEY_PREFIXES = [
|
|
2614
|
+
'anthropic',
|
|
2615
|
+
'azureopenai',
|
|
2616
|
+
'cohere',
|
|
2617
|
+
'deepseek',
|
|
2618
|
+
'elevenlabs',
|
|
2619
|
+
'gemini',
|
|
2620
|
+
'google',
|
|
2621
|
+
'groq',
|
|
2622
|
+
'mistral',
|
|
2623
|
+
'openai',
|
|
2624
|
+
'openrouter',
|
|
2625
|
+
'perplexity',
|
|
2626
|
+
];
|
|
2627
|
+
const isSensitiveDebugField = (key) => {
|
|
2628
|
+
const normalized = key.replace(/[^a-z0-9]/gi, '').toLowerCase();
|
|
2629
|
+
return (normalized === 'auth' ||
|
|
2630
|
+
normalized.includes('authorization') ||
|
|
2631
|
+
normalized.includes('bearer') ||
|
|
2632
|
+
normalized.includes('cookie') ||
|
|
2633
|
+
normalized === 'sessionhash' ||
|
|
2634
|
+
normalized === 'oxvolinkageassertion' ||
|
|
2635
|
+
normalized === 'xoxvosessionstrace' ||
|
|
2636
|
+
normalized.includes('password') ||
|
|
2637
|
+
normalized === 'privatekey' ||
|
|
2638
|
+
normalized === 'privatekeyid' ||
|
|
2639
|
+
normalized === 'signingkey' ||
|
|
2640
|
+
normalized === 'jwt' ||
|
|
2641
|
+
normalized.endsWith('jwt') ||
|
|
2642
|
+
normalized.endsWith('token') ||
|
|
2643
|
+
normalized.endsWith('grant') ||
|
|
2644
|
+
normalized.includes('secret') ||
|
|
2645
|
+
normalized.endsWith('apikey') ||
|
|
2646
|
+
normalized.endsWith('accesskey') ||
|
|
2647
|
+
normalized.endsWith('accesskeyid') ||
|
|
2648
|
+
normalized.endsWith('subscriptionkey') ||
|
|
2649
|
+
normalized.endsWith('credential') ||
|
|
2650
|
+
normalized.endsWith('credentials') ||
|
|
2651
|
+
(normalized.includes('provider') && normalized.endsWith('key')) ||
|
|
2652
|
+
(normalized.endsWith('key') &&
|
|
2653
|
+
PROVIDER_KEY_PREFIXES.some((provider) => normalized.startsWith(provider))));
|
|
2654
|
+
};
|
|
2655
|
+
const redactedFieldValue = (rawValue) => {
|
|
2656
|
+
const valueQuote = rawValue[0];
|
|
2657
|
+
return valueQuote === '"' || valueQuote === "'"
|
|
2658
|
+
? `${valueQuote}${REDACTED_DEBUG_VALUE}${valueQuote}`
|
|
2659
|
+
: REDACTED_DEBUG_VALUE;
|
|
2660
|
+
};
|
|
2661
|
+
const redactDebugTextToLength = (value, maxOutputLength) => {
|
|
2662
|
+
const truncated = value.length > maxOutputLength;
|
|
2663
|
+
let redacted = value
|
|
2664
|
+
.slice(0, maxOutputLength + MAX_DEBUG_CREDENTIAL_LOOKAHEAD)
|
|
2665
|
+
.replace(DEBUG_AUTHORIZATION_FIELD_PATTERN, (_match, keyQuote, key, separator, rawValue) => `${keyQuote}${key}${keyQuote}${separator}${redactedFieldValue(rawValue)}`)
|
|
2666
|
+
.replace(DEBUG_COOKIE_FIELD_PATTERN, (_match, keyQuote, key, separator, rawValue) => `${keyQuote}${key}${keyQuote}${separator}${redactedFieldValue(rawValue)}`)
|
|
2667
|
+
.replace(DEBUG_AUTH_SCHEME_VALUE_PATTERN, `$1${REDACTED_DEBUG_VALUE}`)
|
|
2668
|
+
.replace(DEBUG_TOKEN_AUTH_SCHEME_VALUE_PATTERN, `$1${REDACTED_DEBUG_VALUE}`)
|
|
2669
|
+
.replace(DEBUG_FIELD_VALUE_PATTERN, (match, keyQuote, key, separator, rawValue) => {
|
|
2670
|
+
if (!isSensitiveDebugField(key)) {
|
|
2671
|
+
return match;
|
|
2672
|
+
}
|
|
2673
|
+
return `${keyQuote}${key}${keyQuote}${separator}${redactedFieldValue(rawValue)}`;
|
|
2674
|
+
})
|
|
2675
|
+
.replace(DEBUG_ENCODED_FIELD_VALUE_PATTERN, (_match, key, separator) => `${key}${separator}${REDACTED_DEBUG_VALUE}`)
|
|
2676
|
+
.replace(DEBUG_URL_CREDENTIAL_PATTERN, `$1${REDACTED_DEBUG_VALUE}:${REDACTED_DEBUG_VALUE}@`)
|
|
2677
|
+
.replace(DEBUG_JWT_VALUE_PATTERN, REDACTED_DEBUG_VALUE)
|
|
2678
|
+
.replace(DEBUG_PRIVATE_KEY_PATTERN, REDACTED_DEBUG_VALUE);
|
|
2679
|
+
for (const credentialPattern of DEBUG_PROVIDER_CREDENTIAL_PATTERNS) {
|
|
2680
|
+
redacted = redacted.replace(credentialPattern, REDACTED_DEBUG_VALUE);
|
|
2681
|
+
}
|
|
2682
|
+
const bounded = redacted.slice(0, maxOutputLength);
|
|
2683
|
+
return truncated ? `${bounded} ${TRUNCATED_DEBUG_VALUE}` : bounded;
|
|
2684
|
+
};
|
|
2685
|
+
const redactDebugText = (value) => redactDebugTextToLength(value, MAX_DEBUG_TEXT_LENGTH);
|
|
2686
|
+
const createDebugRedactionState = () => ({
|
|
2687
|
+
seen: new WeakSet(),
|
|
2688
|
+
remainingItems: MAX_DEBUG_REDACTION_ITEMS,
|
|
2689
|
+
remainingText: MAX_DEBUG_TEXT_LENGTH,
|
|
2690
|
+
});
|
|
2691
|
+
const redactDebugTextWithBudget = (value, state) => {
|
|
2692
|
+
if (state.remainingText <= 0) {
|
|
2693
|
+
return TRUNCATED_DEBUG_VALUE;
|
|
2694
|
+
}
|
|
2695
|
+
const permittedLength = Math.min(value.length, state.remainingText);
|
|
2696
|
+
state.remainingText -= permittedLength;
|
|
2697
|
+
return redactDebugTextToLength(value, permittedLength);
|
|
2698
|
+
};
|
|
2699
|
+
const redactDebugValue = (value, state = createDebugRedactionState(), depth = 0) => {
|
|
2700
|
+
if (typeof value === 'string') {
|
|
2701
|
+
return redactDebugTextWithBudget(value, state);
|
|
2702
|
+
}
|
|
2703
|
+
if (value instanceof Error) {
|
|
2704
|
+
const redacted = new Error(redactDebugTextWithBudget(value.message, state));
|
|
2705
|
+
redacted.name = redactDebugTextWithBudget(value.name, state);
|
|
2706
|
+
if (value.stack) {
|
|
2707
|
+
redacted.stack = redactDebugTextWithBudget(value.stack, state);
|
|
2708
|
+
}
|
|
2709
|
+
return redacted;
|
|
2710
|
+
}
|
|
2711
|
+
if (value === null || typeof value === 'number' || typeof value === 'boolean') {
|
|
2712
|
+
return value;
|
|
2713
|
+
}
|
|
2714
|
+
if (typeof value === 'undefined') {
|
|
2715
|
+
return undefined;
|
|
2716
|
+
}
|
|
2717
|
+
if (typeof value === 'bigint' || typeof value === 'symbol') {
|
|
2718
|
+
return String(value);
|
|
2719
|
+
}
|
|
2720
|
+
if (typeof value === 'function') {
|
|
2721
|
+
return '[Function]';
|
|
2722
|
+
}
|
|
2723
|
+
const objectValue = value;
|
|
2724
|
+
if (depth >= MAX_DEBUG_REDACTION_DEPTH || state.remainingItems <= 0) {
|
|
2725
|
+
return TRUNCATED_DEBUG_VALUE;
|
|
2726
|
+
}
|
|
2727
|
+
if (state.seen.has(objectValue)) {
|
|
2728
|
+
return '[Circular]';
|
|
2729
|
+
}
|
|
2730
|
+
state.seen.add(objectValue);
|
|
2731
|
+
if (Array.isArray(value)) {
|
|
2732
|
+
const count = Math.min(value.length, state.remainingItems);
|
|
2733
|
+
state.remainingItems -= count;
|
|
2734
|
+
const redacted = value.slice(0, count).map((entry) => redactDebugValue(entry, state, depth + 1));
|
|
2735
|
+
if (count < value.length) {
|
|
2736
|
+
redacted.push(TRUNCATED_DEBUG_VALUE);
|
|
2737
|
+
}
|
|
2738
|
+
return redacted;
|
|
2739
|
+
}
|
|
2740
|
+
const redacted = {};
|
|
2741
|
+
let allKeys;
|
|
2742
|
+
try {
|
|
2743
|
+
allKeys = Object.keys(objectValue);
|
|
2744
|
+
}
|
|
2745
|
+
catch {
|
|
2746
|
+
return '[Unavailable]';
|
|
2747
|
+
}
|
|
2748
|
+
const keys = allKeys.slice(0, state.remainingItems);
|
|
2749
|
+
state.remainingItems -= keys.length;
|
|
2750
|
+
for (const key of keys) {
|
|
2751
|
+
if (isSensitiveDebugField(key)) {
|
|
2752
|
+
redacted[key] = REDACTED_DEBUG_VALUE;
|
|
2753
|
+
continue;
|
|
2754
|
+
}
|
|
2755
|
+
try {
|
|
2756
|
+
redacted[key] = redactDebugValue(value[key], state, depth + 1);
|
|
2757
|
+
}
|
|
2758
|
+
catch {
|
|
2759
|
+
redacted[key] = '[Unavailable]';
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
if (keys.length < allKeys.length) {
|
|
2763
|
+
redacted.__truncated__ = TRUNCATED_DEBUG_VALUE;
|
|
2764
|
+
}
|
|
2765
|
+
return redacted;
|
|
2766
|
+
};
|
|
2767
|
+
const redactDebugArgs = (values) => {
|
|
2768
|
+
const state = createDebugRedactionState();
|
|
2769
|
+
return values.map((value) => redactDebugValue(value, state));
|
|
2770
|
+
};
|
|
2771
|
+
const debugValueText = (value) => {
|
|
2772
|
+
if (value instanceof Error) {
|
|
2773
|
+
return `${value.name}: ${value.message}`;
|
|
2774
|
+
}
|
|
2775
|
+
if (typeof value === 'string') {
|
|
2776
|
+
return value;
|
|
2777
|
+
}
|
|
2778
|
+
let serialized;
|
|
2779
|
+
try {
|
|
2780
|
+
serialized = JSON.stringify(value);
|
|
2781
|
+
}
|
|
2782
|
+
catch {
|
|
2783
|
+
return '[Unavailable]';
|
|
2784
|
+
}
|
|
2785
|
+
if (serialized === undefined) {
|
|
2786
|
+
return String(value);
|
|
2787
|
+
}
|
|
2788
|
+
return serialized.length > MAX_DEBUG_TEXT_LENGTH
|
|
2789
|
+
? `${serialized.slice(0, MAX_DEBUG_TEXT_LENGTH)} ${TRUNCATED_DEBUG_VALUE}`
|
|
2790
|
+
: serialized;
|
|
2791
|
+
};
|
|
2792
|
+
const redactedErrorFrom = (value, fallback, knownSecrets = []) => {
|
|
2793
|
+
const uniqueKnownSecrets = [
|
|
2794
|
+
...new Set(knownSecrets.filter((secret) => !!secret)),
|
|
2795
|
+
].sort((left, right) => right.length - left.length);
|
|
2796
|
+
const redacted = value instanceof Error || typeof value === 'string' ? value : redactDebugValue(value);
|
|
2797
|
+
let message = redacted instanceof Error ? redacted.message.trim() : debugValueText(redacted).trim();
|
|
2798
|
+
for (const secret of uniqueKnownSecrets) {
|
|
2799
|
+
message = message.split(secret).join(REDACTED_DEBUG_VALUE);
|
|
2800
|
+
}
|
|
2801
|
+
message = redactDebugText(message);
|
|
2802
|
+
return new Error(message.length > 0 ? message : fallback);
|
|
2803
|
+
};
|
|
2804
|
+
|
|
2591
2805
|
const LogLevel = {
|
|
2592
2806
|
Verbose: 5,
|
|
2593
2807
|
Log: 4,
|
|
@@ -2602,26 +2816,22 @@ class Logger {
|
|
|
2602
2816
|
};
|
|
2603
2817
|
this.info = (...args) => {
|
|
2604
2818
|
if (this.shouldLog(LogLevel.Verbose)) {
|
|
2605
|
-
|
|
2606
|
-
console.info(...args);
|
|
2819
|
+
console.info(...redactDebugArgs(args));
|
|
2607
2820
|
}
|
|
2608
2821
|
};
|
|
2609
2822
|
this.log = (...args) => {
|
|
2610
2823
|
if (this.shouldLog(LogLevel.Log)) {
|
|
2611
|
-
|
|
2612
|
-
console.log(...args);
|
|
2824
|
+
console.log(...redactDebugArgs(args));
|
|
2613
2825
|
}
|
|
2614
2826
|
};
|
|
2615
2827
|
this.warn = (...args) => {
|
|
2616
2828
|
if (this.shouldLog(LogLevel.Warnings)) {
|
|
2617
|
-
|
|
2618
|
-
console.warn(...args);
|
|
2829
|
+
console.warn(...redactDebugArgs(args));
|
|
2619
2830
|
}
|
|
2620
2831
|
};
|
|
2621
2832
|
this.error = (...args) => {
|
|
2622
2833
|
if (this.shouldLog(LogLevel.Errors)) {
|
|
2623
|
-
|
|
2624
|
-
console.error(...args);
|
|
2834
|
+
console.error(...redactDebugArgs(args));
|
|
2625
2835
|
}
|
|
2626
2836
|
};
|
|
2627
2837
|
this.level = debugLevel;
|
|
@@ -4555,6 +4765,61 @@ const bufferStorageKey = 'or_buffer_1';
|
|
|
4555
4765
|
const PROTO_VERSION = '2';
|
|
4556
4766
|
const BOOTSTRAP_ATTEMPT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
4557
4767
|
const MAX_BOOTSTRAP_ATTEMPT_STORAGE_LENGTH = 1024 * 1024;
|
|
4768
|
+
const MAX_SESSION_TOKEN_LENGTH = 4096;
|
|
4769
|
+
const MAX_ASSIST_SESSION_GRANT_LENGTH = 4096;
|
|
4770
|
+
const LINKAGE_ASSERTION_METADATA_KEY = 'oxvo_linkage_assertion';
|
|
4771
|
+
const MESSENGER_LINKAGE_CHALLENGE_PATTERN = /^[a-f0-9]{64}$/;
|
|
4772
|
+
const MIN_MESSENGER_LINKAGE_CHALLENGE_TTL_SECONDS = 5;
|
|
4773
|
+
const MAX_MESSENGER_LINKAGE_CHALLENGE_TTL_SECONDS = 120;
|
|
4774
|
+
const asRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
4775
|
+
? value
|
|
4776
|
+
: {};
|
|
4777
|
+
const isValidBootstrapCredential = (value, maxLength) => typeof value === 'string' &&
|
|
4778
|
+
value.length > 0 &&
|
|
4779
|
+
value.length <= maxLength &&
|
|
4780
|
+
value.trim() === value;
|
|
4781
|
+
const parseMessengerLinkageChallenge = (value, expectedSessionId) => {
|
|
4782
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
4783
|
+
return null;
|
|
4784
|
+
}
|
|
4785
|
+
const record = value;
|
|
4786
|
+
const keys = Object.keys(record).sort();
|
|
4787
|
+
if (keys.length !== 3 ||
|
|
4788
|
+
keys[0] !== 'challenge' ||
|
|
4789
|
+
keys[1] !== 'expiresIn' ||
|
|
4790
|
+
keys[2] !== 'sessionId' ||
|
|
4791
|
+
typeof record.challenge !== 'string' ||
|
|
4792
|
+
!MESSENGER_LINKAGE_CHALLENGE_PATTERN.test(record.challenge) ||
|
|
4793
|
+
record.sessionId !== expectedSessionId ||
|
|
4794
|
+
!Number.isInteger(record.expiresIn) ||
|
|
4795
|
+
record.expiresIn < MIN_MESSENGER_LINKAGE_CHALLENGE_TTL_SECONDS ||
|
|
4796
|
+
record.expiresIn > MAX_MESSENGER_LINKAGE_CHALLENGE_TTL_SECONDS) {
|
|
4797
|
+
return null;
|
|
4798
|
+
}
|
|
4799
|
+
return {
|
|
4800
|
+
challenge: record.challenge,
|
|
4801
|
+
sessionId: expectedSessionId,
|
|
4802
|
+
expiresIn: record.expiresIn,
|
|
4803
|
+
};
|
|
4804
|
+
};
|
|
4805
|
+
const bootstrapHttpError = async (response, responseText, knownSecrets = []) => {
|
|
4806
|
+
let body;
|
|
4807
|
+
try {
|
|
4808
|
+
body = responseText ?? (await response.text());
|
|
4809
|
+
}
|
|
4810
|
+
catch (error) {
|
|
4811
|
+
return redactedErrorFrom(error, `Server error: ${response.status}.`, knownSecrets);
|
|
4812
|
+
}
|
|
4813
|
+
return redactedErrorFrom(`Server error: ${response.status}. ${body}`, `Server error: ${response.status}.`, knownSecrets);
|
|
4814
|
+
};
|
|
4815
|
+
const bootstrapJson = async (response, knownSecrets = []) => {
|
|
4816
|
+
try {
|
|
4817
|
+
return asRecord(await response.json());
|
|
4818
|
+
}
|
|
4819
|
+
catch (error) {
|
|
4820
|
+
throw redactedErrorFrom(error, 'Incorrect server response (invalid JSON)', knownSecrets);
|
|
4821
|
+
}
|
|
4822
|
+
};
|
|
4558
4823
|
const UnsuccessfulStart = (reason) => ({ reason, success: false });
|
|
4559
4824
|
const SuccessfulStart = (body) => ({ ...body, success: true });
|
|
4560
4825
|
var ActivityState;
|
|
@@ -4624,13 +4889,14 @@ class App {
|
|
|
4624
4889
|
this.stopCallbacks = [];
|
|
4625
4890
|
this.commitCallbacks = [];
|
|
4626
4891
|
this.activityState = ActivityState.NotActive;
|
|
4627
|
-
this.version = '7.
|
|
4892
|
+
this.version = '7.4.15'; // TODO: version compatability check inside each plugin.
|
|
4628
4893
|
this.socketMode = false;
|
|
4629
4894
|
this.compressionThreshold = 24 * 1000;
|
|
4630
4895
|
this.bc = null;
|
|
4631
4896
|
this.canvasRecorder = null;
|
|
4632
4897
|
this.conditionsManager = null;
|
|
4633
4898
|
this.bootstrapAttempts = {};
|
|
4899
|
+
this.assistSessionGrant = null;
|
|
4634
4900
|
this.canStart = false;
|
|
4635
4901
|
this.rootId = null;
|
|
4636
4902
|
this.pageFrames = [];
|
|
@@ -4730,7 +4996,7 @@ class App {
|
|
|
4730
4996
|
this.startCrossDomainFrame(this.prevOpts);
|
|
4731
4997
|
}
|
|
4732
4998
|
catch (e) {
|
|
4733
|
-
console.error('children frame restart failed:', e);
|
|
4999
|
+
console.error('children frame restart failed:', redactDebugValue(e));
|
|
4734
5000
|
}
|
|
4735
5001
|
return;
|
|
4736
5002
|
}
|
|
@@ -4889,10 +5155,10 @@ class App {
|
|
|
4889
5155
|
this.allowAppStart();
|
|
4890
5156
|
this.start(this.prevOpts, true)
|
|
4891
5157
|
.then((r) => {
|
|
4892
|
-
this.debug.info('Session restart', r);
|
|
5158
|
+
this.debug.info('Session restart', redactDebugValue(r));
|
|
4893
5159
|
})
|
|
4894
5160
|
.catch((e) => {
|
|
4895
|
-
this.debug.error('Session restart failed', e);
|
|
5161
|
+
this.debug.error('Session restart failed', redactDebugValue(e));
|
|
4896
5162
|
});
|
|
4897
5163
|
});
|
|
4898
5164
|
};
|
|
@@ -5074,7 +5340,7 @@ class App {
|
|
|
5074
5340
|
});
|
|
5075
5341
|
this.markerWatcher = new MarkerWatcher({
|
|
5076
5342
|
sessionStorage: this.sessionStorage,
|
|
5077
|
-
errLog: this.debug.error,
|
|
5343
|
+
errLog: (...args) => this.debug.error(...args.map((arg) => redactDebugValue(arg))),
|
|
5078
5344
|
onMarkerHit: (markerId) => this.send(TagTrigger(markerId)),
|
|
5079
5345
|
});
|
|
5080
5346
|
this.session.attachUpdateCallback(({ userID, metadata }) => {
|
|
@@ -5140,10 +5406,10 @@ class App {
|
|
|
5140
5406
|
}, 250);
|
|
5141
5407
|
this.bc.onmessage = (ev) => {
|
|
5142
5408
|
if (ev.data.context === this.contextId || this.projectKey !== ev.data.projectKey) {
|
|
5143
|
-
this.debug.log('same ctx event', ev);
|
|
5409
|
+
this.debug.log('same ctx event', redactDebugValue(ev.data));
|
|
5144
5410
|
return;
|
|
5145
5411
|
}
|
|
5146
|
-
this.debug.log(ev);
|
|
5412
|
+
this.debug.log('broadcast event', redactDebugValue(ev.data));
|
|
5147
5413
|
if (ev.data.line === proto.resp) {
|
|
5148
5414
|
const sessionToken = ev.data.token;
|
|
5149
5415
|
this.session.setSessionSecret(sessionToken, this.projectKey);
|
|
@@ -5572,10 +5838,10 @@ class App {
|
|
|
5572
5838
|
this.allowAppStart();
|
|
5573
5839
|
this.start(this.prevOpts, true)
|
|
5574
5840
|
.then((r) => {
|
|
5575
|
-
this.debug.info('Worker restart, session too long', r);
|
|
5841
|
+
this.debug.info('Worker restart, session too long', redactDebugValue(r));
|
|
5576
5842
|
})
|
|
5577
5843
|
.catch((e) => {
|
|
5578
|
-
this.debug.error('Worker restart failed', e);
|
|
5844
|
+
this.debug.error('Worker restart failed', redactDebugValue(e));
|
|
5579
5845
|
});
|
|
5580
5846
|
});
|
|
5581
5847
|
}
|
|
@@ -5584,7 +5850,7 @@ class App {
|
|
|
5584
5850
|
}
|
|
5585
5851
|
else if (data.type === 'failure') {
|
|
5586
5852
|
this.stop(false);
|
|
5587
|
-
this.debug.error('worker_failed', data.reason);
|
|
5853
|
+
this.debug.error('worker_failed', redactDebugValue(data.reason));
|
|
5588
5854
|
this._debug('worker_failed', data.reason);
|
|
5589
5855
|
}
|
|
5590
5856
|
else if (data.type === 'compress') {
|
|
@@ -5605,7 +5871,7 @@ class App {
|
|
|
5605
5871
|
});
|
|
5606
5872
|
})
|
|
5607
5873
|
.catch((err) => {
|
|
5608
|
-
this.debug.error('OxvoSessions compression error:', err);
|
|
5874
|
+
this.debug.error('OxvoSessions compression error:', redactDebugValue(err));
|
|
5609
5875
|
this.worker?.postMessage({ type: 'uncompressed', batch: batch, dataType });
|
|
5610
5876
|
});
|
|
5611
5877
|
}
|
|
@@ -5627,18 +5893,18 @@ class App {
|
|
|
5627
5893
|
}
|
|
5628
5894
|
}
|
|
5629
5895
|
_debug(context, e) {
|
|
5896
|
+
const redactedError = redactDebugValue(e);
|
|
5630
5897
|
if (this.options.__debug_report_edp !== null) {
|
|
5631
5898
|
void fetch(this.options.__debug_report_edp, {
|
|
5632
5899
|
method: 'POST',
|
|
5633
5900
|
headers: { 'Content-Type': 'application/json' },
|
|
5634
5901
|
body: JSON.stringify({
|
|
5635
5902
|
context,
|
|
5636
|
-
|
|
5637
|
-
error: `${e}`,
|
|
5903
|
+
error: debugValueText(redactedError),
|
|
5638
5904
|
}),
|
|
5639
5905
|
});
|
|
5640
5906
|
}
|
|
5641
|
-
this.debug.error('OxvoSessions error: ', context,
|
|
5907
|
+
this.debug.error('OxvoSessions error: ', context, redactedError);
|
|
5642
5908
|
}
|
|
5643
5909
|
/**
|
|
5644
5910
|
* Normal workflow: add timestamp and tab data to batch, then commit it
|
|
@@ -5962,11 +6228,76 @@ class App {
|
|
|
5962
6228
|
(current.userUUID === '' || existing.userUUID === current.userUUID));
|
|
5963
6229
|
}
|
|
5964
6230
|
getSessionMeta() {
|
|
6231
|
+
const sessionInfo = this.session.getInfo();
|
|
6232
|
+
const metadata = { ...sessionInfo.metadata };
|
|
6233
|
+
Object.keys(metadata).forEach((key) => {
|
|
6234
|
+
if (key.trim().toLowerCase() === LINKAGE_ASSERTION_METADATA_KEY) {
|
|
6235
|
+
delete metadata[key];
|
|
6236
|
+
}
|
|
6237
|
+
});
|
|
5965
6238
|
return {
|
|
5966
|
-
...
|
|
6239
|
+
...sessionInfo,
|
|
6240
|
+
metadata,
|
|
5967
6241
|
...this.getTrackerInfo(),
|
|
5968
6242
|
};
|
|
5969
6243
|
}
|
|
6244
|
+
async requestMessengerLinkageChallenge() {
|
|
6245
|
+
const sessionId = this.session.getInfo().sessionID;
|
|
6246
|
+
const grantLineage = this.assistSessionGrant;
|
|
6247
|
+
const grant = this.getAssistSessionGrant();
|
|
6248
|
+
if (!sessionId || !grantLineage || !grant || grant.sessionId !== sessionId) {
|
|
6249
|
+
return null;
|
|
6250
|
+
}
|
|
6251
|
+
const tabId = this.session.getTabId();
|
|
6252
|
+
try {
|
|
6253
|
+
const response = await fetch(`${normalizeEndpoint(this.options.endpoint)}/v1/linkage-challenge`, {
|
|
6254
|
+
method: 'POST',
|
|
6255
|
+
headers: {
|
|
6256
|
+
Authorization: `Bearer ${grant.token}`,
|
|
6257
|
+
'Content-Type': 'application/json',
|
|
6258
|
+
},
|
|
6259
|
+
body: JSON.stringify({ tabId }),
|
|
6260
|
+
cache: 'no-store',
|
|
6261
|
+
credentials: 'omit',
|
|
6262
|
+
referrerPolicy: 'no-referrer',
|
|
6263
|
+
});
|
|
6264
|
+
if (response.status !== 200) {
|
|
6265
|
+
return null;
|
|
6266
|
+
}
|
|
6267
|
+
const challenge = parseMessengerLinkageChallenge(await response.json(), sessionId);
|
|
6268
|
+
if (!challenge) {
|
|
6269
|
+
return null;
|
|
6270
|
+
}
|
|
6271
|
+
const currentGrant = this.getAssistSessionGrant();
|
|
6272
|
+
if (!currentGrant ||
|
|
6273
|
+
this.assistSessionGrant !== grantLineage ||
|
|
6274
|
+
currentGrant.sessionId !== grant.sessionId ||
|
|
6275
|
+
currentGrant.token !== grant.token ||
|
|
6276
|
+
this.session.getInfo().sessionID !== sessionId ||
|
|
6277
|
+
this.session.getTabId() !== tabId) {
|
|
6278
|
+
return null;
|
|
6279
|
+
}
|
|
6280
|
+
return challenge;
|
|
6281
|
+
}
|
|
6282
|
+
catch {
|
|
6283
|
+
return null;
|
|
6284
|
+
}
|
|
6285
|
+
}
|
|
6286
|
+
getAssistSessionGrant() {
|
|
6287
|
+
return this.assistSessionGrant ? { ...this.assistSessionGrant } : null;
|
|
6288
|
+
}
|
|
6289
|
+
setAssistSessionGrant(sessionId, token) {
|
|
6290
|
+
this.assistSessionGrant =
|
|
6291
|
+
typeof token === 'string' &&
|
|
6292
|
+
token.length > 0 &&
|
|
6293
|
+
token.length <= MAX_ASSIST_SESSION_GRANT_LENGTH &&
|
|
6294
|
+
token.trim() === token
|
|
6295
|
+
? { sessionId, token }
|
|
6296
|
+
: null;
|
|
6297
|
+
}
|
|
6298
|
+
clearAssistSessionGrant() {
|
|
6299
|
+
this.assistSessionGrant = null;
|
|
6300
|
+
}
|
|
5970
6301
|
getSessionSecret() {
|
|
5971
6302
|
return this.session.getSessionSecret(this.projectKey);
|
|
5972
6303
|
}
|
|
@@ -6099,23 +6430,48 @@ class App {
|
|
|
6099
6430
|
async setupConditionalStart(startOpts) {
|
|
6100
6431
|
this.conditionsManager = new ConditionsManager(this, startOpts);
|
|
6101
6432
|
const ingestPoint = normalizeEndpoint(this.options.endpoint);
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6433
|
+
let r;
|
|
6434
|
+
try {
|
|
6435
|
+
r = await fetch(ingestPoint + '/v1/bootstrap', {
|
|
6436
|
+
method: 'POST',
|
|
6437
|
+
headers: {
|
|
6438
|
+
'Content-Type': 'application/json',
|
|
6439
|
+
},
|
|
6440
|
+
body: JSON.stringify(this.buildStartPayload({
|
|
6441
|
+
timestamp: now(),
|
|
6442
|
+
dry: true,
|
|
6443
|
+
bufferMs: 0,
|
|
6444
|
+
token: '',
|
|
6445
|
+
width: window.screen.width,
|
|
6446
|
+
height: window.screen.height,
|
|
6447
|
+
referrer: document.referrer,
|
|
6448
|
+
})),
|
|
6449
|
+
});
|
|
6450
|
+
}
|
|
6451
|
+
catch (error) {
|
|
6452
|
+
throw redactedErrorFrom(error, 'Conditional bootstrap request failed.');
|
|
6453
|
+
}
|
|
6454
|
+
if (r.status !== 200) {
|
|
6455
|
+
throw await bootstrapHttpError(r);
|
|
6456
|
+
}
|
|
6457
|
+
const response = await bootstrapJson(r);
|
|
6458
|
+
const session = asRecord(response.session);
|
|
6459
|
+
const client = asRecord(response.client);
|
|
6460
|
+
const device = asRecord(response.device);
|
|
6118
6461
|
const { token, projectId, assistToken } = session;
|
|
6462
|
+
const invalidResponseFields = [
|
|
6463
|
+
!isValidBootstrapCredential(token, MAX_SESSION_TOKEN_LENGTH) ? 'session.token' : null,
|
|
6464
|
+
typeof assistToken !== 'undefined' &&
|
|
6465
|
+
!isValidBootstrapCredential(assistToken, MAX_ASSIST_SESSION_GRANT_LENGTH)
|
|
6466
|
+
? 'session.assistToken'
|
|
6467
|
+
: null,
|
|
6468
|
+
typeof session.id !== 'string' ? 'session.id' : null,
|
|
6469
|
+
typeof projectId !== 'string' ? 'session.projectId' : null,
|
|
6470
|
+
typeof device.id !== 'string' ? 'device.id' : null,
|
|
6471
|
+
].filter((field) => field !== null);
|
|
6472
|
+
if (invalidResponseFields.length > 0) {
|
|
6473
|
+
throw new Error(`Incorrect server response (status ${r.status}; invalid fields: ${invalidResponseFields.join(', ')})`);
|
|
6474
|
+
}
|
|
6119
6475
|
const { browser: userBrowser, city: userCity, country: userCountry, device: userDevice, os: userOS, state: userState, } = client;
|
|
6120
6476
|
this.session.assign({ projectID: projectId });
|
|
6121
6477
|
this.session.setUserInfo({
|
|
@@ -6128,13 +6484,18 @@ class App {
|
|
|
6128
6484
|
});
|
|
6129
6485
|
const onStartInfo = {
|
|
6130
6486
|
sessionToken: token,
|
|
6131
|
-
assistToken
|
|
6132
|
-
userUUID: device
|
|
6133
|
-
sessionID: session
|
|
6487
|
+
assistToken,
|
|
6488
|
+
userUUID: device.id,
|
|
6489
|
+
sessionID: session.id,
|
|
6134
6490
|
};
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6491
|
+
try {
|
|
6492
|
+
this.startCallbacks.forEach((cb) => cb(onStartInfo));
|
|
6493
|
+
await this.conditionsManager?.fetchConditions(projectId, token);
|
|
6494
|
+
await this.markerWatcher.fetchTags(normalizeEndpoint(this.options.endpoint), token);
|
|
6495
|
+
}
|
|
6496
|
+
catch (error) {
|
|
6497
|
+
throw redactedErrorFrom(error, 'Conditional bootstrap failed.', [token, assistToken]);
|
|
6498
|
+
}
|
|
6138
6499
|
}
|
|
6139
6500
|
/**
|
|
6140
6501
|
* Starts offline session recording
|
|
@@ -6142,6 +6503,7 @@ class App {
|
|
|
6142
6503
|
* @param {Function} onSessionSent - callback that will be called once session is fully sent
|
|
6143
6504
|
* */
|
|
6144
6505
|
offlineRecording(startOpts = {}, onSessionSent) {
|
|
6506
|
+
this.clearAssistSessionGrant();
|
|
6145
6507
|
this.onSessionSent = onSessionSent;
|
|
6146
6508
|
this.singleBuffer = true;
|
|
6147
6509
|
adjustTimeOrigin();
|
|
@@ -6248,22 +6610,37 @@ class App {
|
|
|
6248
6610
|
'Content-Type': 'application/json',
|
|
6249
6611
|
'Idempotency-Key': bootstrapAttempt.idempotencyKey,
|
|
6250
6612
|
};
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6613
|
+
let r;
|
|
6614
|
+
try {
|
|
6615
|
+
r = await fetch(ingestPoint + '/v1/bootstrap', {
|
|
6616
|
+
method: 'POST',
|
|
6617
|
+
headers,
|
|
6618
|
+
body: bootstrapAttempt.requestBody,
|
|
6619
|
+
});
|
|
6620
|
+
}
|
|
6621
|
+
catch (error) {
|
|
6622
|
+
throw redactedErrorFrom(error, 'Offline bootstrap request failed.', [bootstrapToken]);
|
|
6623
|
+
}
|
|
6256
6624
|
if (r.status !== 200) {
|
|
6257
|
-
throw
|
|
6625
|
+
throw await bootstrapHttpError(r, undefined, [bootstrapToken]);
|
|
6258
6626
|
}
|
|
6259
|
-
const
|
|
6627
|
+
const response = await bootstrapJson(r, [bootstrapToken]);
|
|
6628
|
+
const session = asRecord(response.session);
|
|
6629
|
+
const client = asRecord(response.client);
|
|
6630
|
+
const limits = asRecord(response.limits);
|
|
6631
|
+
const offlineProtocolVersion = response.protocolVersion;
|
|
6260
6632
|
const { token, projectId } = session;
|
|
6261
6633
|
const { browser: userBrowser, city: userCity, country: userCountry, device: userDevice, os: userOS, state: userState, } = client;
|
|
6262
6634
|
const { beacon: beaconSizeLimit } = limits;
|
|
6263
|
-
|
|
6264
|
-
token.
|
|
6265
|
-
|
|
6266
|
-
|
|
6635
|
+
const invalidResponseFields = [
|
|
6636
|
+
!isValidBootstrapCredential(token, MAX_SESSION_TOKEN_LENGTH) ? 'session.token' : null,
|
|
6637
|
+
typeof projectId !== 'string' ? 'session.projectId' : null,
|
|
6638
|
+
typeof beaconSizeLimit !== 'number' && typeof beaconSizeLimit !== 'undefined'
|
|
6639
|
+
? 'limits.beacon'
|
|
6640
|
+
: null,
|
|
6641
|
+
].filter((field) => field !== null);
|
|
6642
|
+
if (invalidResponseFields.length > 0) {
|
|
6643
|
+
throw new Error(`Incorrect server response (status ${r.status}; invalid fields: ${invalidResponseFields.join(', ')})`);
|
|
6267
6644
|
}
|
|
6268
6645
|
this.session.setSessionSecret(token, this.projectKey);
|
|
6269
6646
|
this.clearBootstrapAttempt('offline');
|
|
@@ -6283,8 +6660,13 @@ class App {
|
|
|
6283
6660
|
beaconSizeLimit,
|
|
6284
6661
|
protocolVersion: offlineProtocolVersion,
|
|
6285
6662
|
});
|
|
6286
|
-
|
|
6287
|
-
|
|
6663
|
+
try {
|
|
6664
|
+
while (this.bufferedMessages1.length > 0) {
|
|
6665
|
+
await this.flushBuffer(this.bufferedMessages1);
|
|
6666
|
+
}
|
|
6667
|
+
}
|
|
6668
|
+
catch (error) {
|
|
6669
|
+
throw redactedErrorFrom(error, 'Offline recording upload failed.', [token, bootstrapToken]);
|
|
6288
6670
|
}
|
|
6289
6671
|
this.postToWorker([[-1]]);
|
|
6290
6672
|
this.clearBuffers();
|
|
@@ -6300,6 +6682,7 @@ class App {
|
|
|
6300
6682
|
this.rootId === null) {
|
|
6301
6683
|
return UnsuccessfulStart('Cross-domain iframe handshake was not established.');
|
|
6302
6684
|
}
|
|
6685
|
+
this.clearAssistSessionGrant();
|
|
6303
6686
|
if (Object.keys(startOpts).length !== 0) {
|
|
6304
6687
|
this.prevOpts = startOpts;
|
|
6305
6688
|
}
|
|
@@ -6369,6 +6752,7 @@ class App {
|
|
|
6369
6752
|
const reason = 'OxvoSessions: trying to call `start()` on the instance that has been started already.';
|
|
6370
6753
|
return Promise.resolve(UnsuccessfulStart(reason));
|
|
6371
6754
|
}
|
|
6755
|
+
this.clearAssistSessionGrant();
|
|
6372
6756
|
this.activityState = ActivityState.Starting;
|
|
6373
6757
|
if (!isColdStart) {
|
|
6374
6758
|
adjustTimeOrigin();
|
|
@@ -6422,7 +6806,8 @@ class App {
|
|
|
6422
6806
|
tabId: this.session.getTabId(),
|
|
6423
6807
|
localDebug: this.options.__local_debug,
|
|
6424
6808
|
});
|
|
6425
|
-
this.debug.log('OxvoSessions: starting session; need new session id?', isNewSession, 'session token:
|
|
6809
|
+
this.debug.log('OxvoSessions: starting session; need new session id?', isNewSession, 'has existing session token:', Boolean(sessionToken));
|
|
6810
|
+
const bootstrapSecrets = [sessionToken, bootstrapToken];
|
|
6426
6811
|
try {
|
|
6427
6812
|
const ingestPoint = normalizeEndpoint(this.options.endpoint);
|
|
6428
6813
|
const headers = {
|
|
@@ -6436,30 +6821,52 @@ class App {
|
|
|
6436
6821
|
});
|
|
6437
6822
|
if (r.status !== 200) {
|
|
6438
6823
|
const error = await r.text();
|
|
6439
|
-
|
|
6440
|
-
|
|
6824
|
+
if (error === CANCELED) {
|
|
6825
|
+
this.stop();
|
|
6826
|
+
this.signalError(CANCELED, []);
|
|
6827
|
+
return UnsuccessfulStart(CANCELED);
|
|
6828
|
+
}
|
|
6829
|
+
throw await bootstrapHttpError(r, error, bootstrapSecrets);
|
|
6441
6830
|
}
|
|
6442
6831
|
if (!this.worker && !this.insideIframe) {
|
|
6443
6832
|
const reason = 'no worker found after start request (this should not happen in real world)';
|
|
6444
6833
|
throw new Error(reason);
|
|
6445
6834
|
}
|
|
6446
|
-
const
|
|
6835
|
+
const response = await bootstrapJson(r, bootstrapSecrets);
|
|
6836
|
+
const session = asRecord(response.session);
|
|
6837
|
+
const device = asRecord(response.device);
|
|
6838
|
+
const client = asRecord(response.client);
|
|
6839
|
+
const limits = asRecord(response.limits);
|
|
6840
|
+
const canvas = asRecord(response.canvas);
|
|
6841
|
+
const flags = asRecord(response.flags);
|
|
6842
|
+
const protocolVersion = response.protocolVersion;
|
|
6447
6843
|
const { token, assistToken, id: sessionID, projectId: projectID, delayMs: delay, startedAt: startTimestamp, } = session;
|
|
6448
6844
|
const { id: userUUID } = device;
|
|
6449
6845
|
const { browser: userBrowser, city: userCity, country: userCountry, device: userDevice, os: userOS, state: userState, } = client;
|
|
6450
6846
|
const { beacon: beaconSizeLimit, compressAt: compressionThreshold } = limits;
|
|
6451
6847
|
const { enabled: canvasEnabled, quality: canvasQuality, fps: canvasFPS, framesSupport, } = canvas;
|
|
6452
6848
|
const socketOnly = flags?.socketOnly;
|
|
6453
|
-
|
|
6454
|
-
(
|
|
6455
|
-
typeof
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6849
|
+
const invalidResponseFields = [
|
|
6850
|
+
!isValidBootstrapCredential(token, MAX_SESSION_TOKEN_LENGTH) ? 'session.token' : null,
|
|
6851
|
+
typeof assistToken !== 'undefined' &&
|
|
6852
|
+
!isValidBootstrapCredential(assistToken, MAX_ASSIST_SESSION_GRANT_LENGTH)
|
|
6853
|
+
? 'session.assistToken'
|
|
6854
|
+
: null,
|
|
6855
|
+
typeof userUUID !== 'string' ? 'device.id' : null,
|
|
6856
|
+
typeof startTimestamp !== 'number' && typeof startTimestamp !== 'undefined'
|
|
6857
|
+
? 'session.startedAt'
|
|
6858
|
+
: null,
|
|
6859
|
+
typeof sessionID !== 'string' ? 'session.id' : null,
|
|
6860
|
+
typeof projectID !== 'string' ? 'session.projectId' : null,
|
|
6861
|
+
typeof delay !== 'number' ? 'session.delayMs' : null,
|
|
6862
|
+
typeof beaconSizeLimit !== 'number' && typeof beaconSizeLimit !== 'undefined'
|
|
6863
|
+
? 'limits.beacon'
|
|
6864
|
+
: null,
|
|
6865
|
+
].filter((field) => field !== null);
|
|
6866
|
+
if (invalidResponseFields.length > 0) {
|
|
6867
|
+
throw new Error(`Incorrect server response (status ${r.status}; invalid fields: ${invalidResponseFields.join(', ')})`);
|
|
6868
|
+
}
|
|
6869
|
+
bootstrapSecrets.push(token, assistToken);
|
|
6463
6870
|
this.crossDomainCanvasConfig = {
|
|
6464
6871
|
enabled: canvasEnabled === true,
|
|
6465
6872
|
...(['low', 'medium', 'high'].includes(canvasQuality) ? { quality: canvasQuality } : {}),
|
|
@@ -6488,6 +6895,7 @@ class App {
|
|
|
6488
6895
|
timestamp: startTimestamp || timestamp,
|
|
6489
6896
|
projectID,
|
|
6490
6897
|
});
|
|
6898
|
+
this.setAssistSessionGrant(sessionID, assistToken);
|
|
6491
6899
|
if (socketOnly) {
|
|
6492
6900
|
this.socketMode = true;
|
|
6493
6901
|
this.worker?.postMessage('stop');
|
|
@@ -6566,8 +6974,9 @@ class App {
|
|
|
6566
6974
|
this.signalError(CANCELED, []);
|
|
6567
6975
|
return UnsuccessfulStart(CANCELED);
|
|
6568
6976
|
}
|
|
6569
|
-
|
|
6570
|
-
|
|
6977
|
+
const redactedError = redactedErrorFrom(reason, 'Session start failed.', bootstrapSecrets);
|
|
6978
|
+
this._debug('session_start', redactedError);
|
|
6979
|
+
const errorMessage = redactedError.message;
|
|
6571
6980
|
this.signalError(errorMessage, []);
|
|
6572
6981
|
return UnsuccessfulStart(errorMessage);
|
|
6573
6982
|
}
|
|
@@ -6690,6 +7099,7 @@ class App {
|
|
|
6690
7099
|
};
|
|
6691
7100
|
}
|
|
6692
7101
|
stop(stopWorker = true) {
|
|
7102
|
+
this.clearAssistSessionGrant();
|
|
6693
7103
|
if (this.activityState !== ActivityState.NotActive) {
|
|
6694
7104
|
try {
|
|
6695
7105
|
if (this.options.crossdomain?.enabled) {
|
|
@@ -8370,10 +8780,14 @@ function Fonts (app) {
|
|
|
8370
8780
|
}
|
|
8371
8781
|
|
|
8372
8782
|
function axiosSpy (app, instance, opts, sanitize, stringify) {
|
|
8373
|
-
app.debug.log('OxvoSessions: attaching axios spy to instance'
|
|
8783
|
+
app.debug.log('OxvoSessions: attaching axios spy to configured instance');
|
|
8374
8784
|
function captureResponseData(axiosResponseObj) {
|
|
8375
|
-
app.debug.log('OxvoSessions: capturing axios response data',
|
|
8376
|
-
|
|
8785
|
+
app.debug.log('OxvoSessions: capturing axios response data', {
|
|
8786
|
+
method: axiosResponseObj.config.method,
|
|
8787
|
+
status: axiosResponseObj.status,
|
|
8788
|
+
url: axiosResponseObj.config.url,
|
|
8789
|
+
});
|
|
8790
|
+
const { headers: reqHs, data: reqData, method, url } = axiosResponseObj.config;
|
|
8377
8791
|
const { data: rData, headers: rHs, status: globStatus, response } = axiosResponseObj;
|
|
8378
8792
|
const { data: resData, headers: resHs, status: resStatus } = response || {};
|
|
8379
8793
|
const ihOpt = opts.ignoreHeaders;
|
|
@@ -8432,11 +8846,18 @@ function axiosSpy (app, instance, opts, sanitize, stringify) {
|
|
|
8432
8846
|
}
|
|
8433
8847
|
const requestStart = axiosResponseObj.config.__oxvosessions_timing;
|
|
8434
8848
|
const duration = performance.now() - requestStart;
|
|
8435
|
-
app.debug.log('OxvoSessions:
|
|
8849
|
+
app.debug.log('OxvoSessions: sanitized axios request is ready', {
|
|
8850
|
+
method: reqResInfo.method,
|
|
8851
|
+
status: reqResInfo.status,
|
|
8852
|
+
url: reqResInfo.url,
|
|
8853
|
+
});
|
|
8436
8854
|
app.send(NetworkRequest('xhr', String(method), String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), reqResInfo.status, requestStart + getTimeOrigin(), duration, 0));
|
|
8437
8855
|
}
|
|
8438
8856
|
function getStartTime(config) {
|
|
8439
|
-
app.debug.log('OxvoSessions: capturing
|
|
8857
|
+
app.debug.log('OxvoSessions: capturing axios request', {
|
|
8858
|
+
method: config.method,
|
|
8859
|
+
url: config.url,
|
|
8860
|
+
});
|
|
8440
8861
|
config.__oxvosessions_timing = performance.now();
|
|
8441
8862
|
if (opts.sessionTokenHeader) {
|
|
8442
8863
|
const header = typeof opts.sessionTokenHeader === 'string'
|
|
@@ -8456,17 +8877,23 @@ function axiosSpy (app, instance, opts, sanitize, stringify) {
|
|
|
8456
8877
|
return response;
|
|
8457
8878
|
}
|
|
8458
8879
|
function captureNetworkError(error) {
|
|
8459
|
-
app.debug.log('OxvoSessions: capturing
|
|
8880
|
+
app.debug.log('OxvoSessions: capturing axios request error', {
|
|
8881
|
+
hasResponse: Boolean(error.response),
|
|
8882
|
+
isAxiosError: isAxiosError(error),
|
|
8883
|
+
message: typeof error.message === 'string' ? error.message : undefined,
|
|
8884
|
+
});
|
|
8460
8885
|
if (isAxiosError(error) && Boolean(error.response)) {
|
|
8461
8886
|
captureResponseData(error.response);
|
|
8462
8887
|
}
|
|
8463
8888
|
else if (error instanceof Error) {
|
|
8464
8889
|
app.send(getExceptionMessage(error, []));
|
|
8465
8890
|
}
|
|
8891
|
+
// Axios rejection handlers must preserve the original Axios error object for downstream code.
|
|
8892
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
|
8466
8893
|
return Promise.reject(error);
|
|
8467
8894
|
}
|
|
8468
|
-
function logRequestError(
|
|
8469
|
-
app.debug.log('OxvoSessions: failed
|
|
8895
|
+
function logRequestError() {
|
|
8896
|
+
app.debug.log('OxvoSessions: failed axios request, skipping');
|
|
8470
8897
|
}
|
|
8471
8898
|
const reqInt = instance.interceptors.request.use(getStartTime, logRequestError, {
|
|
8472
8899
|
synchronous: true,
|
|
@@ -10279,7 +10706,7 @@ class ConstantProperties {
|
|
|
10279
10706
|
user_id: this.user_id,
|
|
10280
10707
|
distinct_id: this.deviceId,
|
|
10281
10708
|
sdk_edition: 'web',
|
|
10282
|
-
sdk_version: '7.
|
|
10709
|
+
sdk_version: '7.4.15',
|
|
10283
10710
|
timezone: getUTCOffsetString(),
|
|
10284
10711
|
search_engine: this.searchEngine,
|
|
10285
10712
|
};
|
|
@@ -11144,7 +11571,7 @@ class API {
|
|
|
11144
11571
|
this.signalStartIssue = (reason, missingApi) => {
|
|
11145
11572
|
const doNotTrack = this.checkDoNotTrack();
|
|
11146
11573
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
11147
|
-
trackerVersion: '7.
|
|
11574
|
+
trackerVersion: '7.4.15',
|
|
11148
11575
|
siteKey: this.options.siteKey,
|
|
11149
11576
|
doNotTrack,
|
|
11150
11577
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|
|
@@ -11510,6 +11937,12 @@ class API {
|
|
|
11510
11937
|
}
|
|
11511
11938
|
return this.app.getSessionSecret();
|
|
11512
11939
|
}
|
|
11940
|
+
requestMessengerLinkageChallenge() {
|
|
11941
|
+
if (this.app === null) {
|
|
11942
|
+
return Promise.resolve(null);
|
|
11943
|
+
}
|
|
11944
|
+
return this.app.requestMessengerLinkageChallenge();
|
|
11945
|
+
}
|
|
11513
11946
|
getSessionMeta() {
|
|
11514
11947
|
if (this.app === null) {
|
|
11515
11948
|
return null;
|
|
@@ -11668,6 +12101,12 @@ class BrowserSingleton {
|
|
|
11668
12101
|
}
|
|
11669
12102
|
return this.instance.getSessionSecret();
|
|
11670
12103
|
}
|
|
12104
|
+
requestMessengerLinkageChallenge() {
|
|
12105
|
+
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
12106
|
+
return Promise.resolve(null);
|
|
12107
|
+
}
|
|
12108
|
+
return this.instance.requestMessengerLinkageChallenge();
|
|
12109
|
+
}
|
|
11671
12110
|
track(key, payload = null, issue = false) {
|
|
11672
12111
|
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
11673
12112
|
return;
|