@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/cjs/entry.js
CHANGED
|
@@ -2592,6 +2592,220 @@ function parseCrossDomainIframeBatch(messages) {
|
|
|
2592
2592
|
return { messages: messages, bytes };
|
|
2593
2593
|
}
|
|
2594
2594
|
|
|
2595
|
+
const REDACTED_DEBUG_VALUE = '[REDACTED]';
|
|
2596
|
+
const TRUNCATED_DEBUG_VALUE = '[TRUNCATED]';
|
|
2597
|
+
const MAX_DEBUG_TEXT_LENGTH = 2048;
|
|
2598
|
+
const MAX_DEBUG_CREDENTIAL_LOOKAHEAD = 512;
|
|
2599
|
+
const MAX_DEBUG_REDACTION_DEPTH = 5;
|
|
2600
|
+
const MAX_DEBUG_REDACTION_ITEMS = 50;
|
|
2601
|
+
const DEBUG_FIELD_VALUE_PATTERN = /(["']?)([ \t]*[a-z0-9_-]{1,64}[ \t]*)\1(\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|[^\s,;&{}\[\]()\r\n]+)/gim;
|
|
2602
|
+
const DEBUG_AUTHORIZATION_FIELD_PATTERN = /(["']?)((?:proxy[-_]?authorization|authorization)(?:[-_]?header)?)\1(\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|\[(?:REDACTED|TRUNCATED)\]|[^,;&}\]\)\r\n]+)/gi;
|
|
2603
|
+
const DEBUG_COOKIE_FIELD_PATTERN = /(["']?)((?:set[-_]?cookie|cookies?)(?:[-_]?header)?)\1(\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|\[(?:REDACTED|TRUNCATED)\]|[^\r\n]+)/gi;
|
|
2604
|
+
const DEBUG_AUTH_SCHEME_VALUE_PATTERN = /(\b(?:ApiKey|Basic|Bearer|Digest|Negotiate)\s+)[a-z0-9._~+/=-]+/gi;
|
|
2605
|
+
const DEBUG_TOKEN_AUTH_SCHEME_VALUE_PATTERN = /(\bToken\s+)[a-z0-9._~+/=-]+/g;
|
|
2606
|
+
const DEBUG_JWT_VALUE_PATTERN = /\beyJ[a-z0-9_-]{5,}\.[a-z0-9_-]{5,}\.[a-z0-9_-]{5,}\b/gi;
|
|
2607
|
+
const DEBUG_URL_CREDENTIAL_PATTERN = /(\bhttps?:\/\/)([^\s/:@]+):([^\s/@]+)@/gi;
|
|
2608
|
+
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;
|
|
2609
|
+
const DEBUG_PROVIDER_CREDENTIAL_PATTERNS = [
|
|
2610
|
+
/sk-(?:(?:proj|svcacct|ant)-)?[a-z0-9_-]{8,}/gi,
|
|
2611
|
+
/AIza[a-z0-9_-]{20,}/gi,
|
|
2612
|
+
/(?:AKIA|ASIA)[A-Z0-9]{16}/g,
|
|
2613
|
+
/gh[pousr]_[a-z0-9]{20,}/gi,
|
|
2614
|
+
/xox[a-z]-[a-z0-9-]{10,}/gi,
|
|
2615
|
+
];
|
|
2616
|
+
const DEBUG_PRIVATE_KEY_PATTERN = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z0-9 ]*PRIVATE KEY-----|$)/g;
|
|
2617
|
+
const PROVIDER_KEY_PREFIXES = [
|
|
2618
|
+
'anthropic',
|
|
2619
|
+
'azureopenai',
|
|
2620
|
+
'cohere',
|
|
2621
|
+
'deepseek',
|
|
2622
|
+
'elevenlabs',
|
|
2623
|
+
'gemini',
|
|
2624
|
+
'google',
|
|
2625
|
+
'groq',
|
|
2626
|
+
'mistral',
|
|
2627
|
+
'openai',
|
|
2628
|
+
'openrouter',
|
|
2629
|
+
'perplexity',
|
|
2630
|
+
];
|
|
2631
|
+
const isSensitiveDebugField = (key) => {
|
|
2632
|
+
const normalized = key.replace(/[^a-z0-9]/gi, '').toLowerCase();
|
|
2633
|
+
return (normalized === 'auth' ||
|
|
2634
|
+
normalized.includes('authorization') ||
|
|
2635
|
+
normalized.includes('bearer') ||
|
|
2636
|
+
normalized.includes('cookie') ||
|
|
2637
|
+
normalized === 'sessionhash' ||
|
|
2638
|
+
normalized === 'oxvolinkageassertion' ||
|
|
2639
|
+
normalized === 'xoxvosessionstrace' ||
|
|
2640
|
+
normalized.includes('password') ||
|
|
2641
|
+
normalized === 'privatekey' ||
|
|
2642
|
+
normalized === 'privatekeyid' ||
|
|
2643
|
+
normalized === 'signingkey' ||
|
|
2644
|
+
normalized === 'jwt' ||
|
|
2645
|
+
normalized.endsWith('jwt') ||
|
|
2646
|
+
normalized.endsWith('token') ||
|
|
2647
|
+
normalized.endsWith('grant') ||
|
|
2648
|
+
normalized.includes('secret') ||
|
|
2649
|
+
normalized.endsWith('apikey') ||
|
|
2650
|
+
normalized.endsWith('accesskey') ||
|
|
2651
|
+
normalized.endsWith('accesskeyid') ||
|
|
2652
|
+
normalized.endsWith('subscriptionkey') ||
|
|
2653
|
+
normalized.endsWith('credential') ||
|
|
2654
|
+
normalized.endsWith('credentials') ||
|
|
2655
|
+
(normalized.includes('provider') && normalized.endsWith('key')) ||
|
|
2656
|
+
(normalized.endsWith('key') &&
|
|
2657
|
+
PROVIDER_KEY_PREFIXES.some((provider) => normalized.startsWith(provider))));
|
|
2658
|
+
};
|
|
2659
|
+
const redactedFieldValue = (rawValue) => {
|
|
2660
|
+
const valueQuote = rawValue[0];
|
|
2661
|
+
return valueQuote === '"' || valueQuote === "'"
|
|
2662
|
+
? `${valueQuote}${REDACTED_DEBUG_VALUE}${valueQuote}`
|
|
2663
|
+
: REDACTED_DEBUG_VALUE;
|
|
2664
|
+
};
|
|
2665
|
+
const redactDebugTextToLength = (value, maxOutputLength) => {
|
|
2666
|
+
const truncated = value.length > maxOutputLength;
|
|
2667
|
+
let redacted = value
|
|
2668
|
+
.slice(0, maxOutputLength + MAX_DEBUG_CREDENTIAL_LOOKAHEAD)
|
|
2669
|
+
.replace(DEBUG_AUTHORIZATION_FIELD_PATTERN, (_match, keyQuote, key, separator, rawValue) => `${keyQuote}${key}${keyQuote}${separator}${redactedFieldValue(rawValue)}`)
|
|
2670
|
+
.replace(DEBUG_COOKIE_FIELD_PATTERN, (_match, keyQuote, key, separator, rawValue) => `${keyQuote}${key}${keyQuote}${separator}${redactedFieldValue(rawValue)}`)
|
|
2671
|
+
.replace(DEBUG_AUTH_SCHEME_VALUE_PATTERN, `$1${REDACTED_DEBUG_VALUE}`)
|
|
2672
|
+
.replace(DEBUG_TOKEN_AUTH_SCHEME_VALUE_PATTERN, `$1${REDACTED_DEBUG_VALUE}`)
|
|
2673
|
+
.replace(DEBUG_FIELD_VALUE_PATTERN, (match, keyQuote, key, separator, rawValue) => {
|
|
2674
|
+
if (!isSensitiveDebugField(key)) {
|
|
2675
|
+
return match;
|
|
2676
|
+
}
|
|
2677
|
+
return `${keyQuote}${key}${keyQuote}${separator}${redactedFieldValue(rawValue)}`;
|
|
2678
|
+
})
|
|
2679
|
+
.replace(DEBUG_ENCODED_FIELD_VALUE_PATTERN, (_match, key, separator) => `${key}${separator}${REDACTED_DEBUG_VALUE}`)
|
|
2680
|
+
.replace(DEBUG_URL_CREDENTIAL_PATTERN, `$1${REDACTED_DEBUG_VALUE}:${REDACTED_DEBUG_VALUE}@`)
|
|
2681
|
+
.replace(DEBUG_JWT_VALUE_PATTERN, REDACTED_DEBUG_VALUE)
|
|
2682
|
+
.replace(DEBUG_PRIVATE_KEY_PATTERN, REDACTED_DEBUG_VALUE);
|
|
2683
|
+
for (const credentialPattern of DEBUG_PROVIDER_CREDENTIAL_PATTERNS) {
|
|
2684
|
+
redacted = redacted.replace(credentialPattern, REDACTED_DEBUG_VALUE);
|
|
2685
|
+
}
|
|
2686
|
+
const bounded = redacted.slice(0, maxOutputLength);
|
|
2687
|
+
return truncated ? `${bounded} ${TRUNCATED_DEBUG_VALUE}` : bounded;
|
|
2688
|
+
};
|
|
2689
|
+
const redactDebugText = (value) => redactDebugTextToLength(value, MAX_DEBUG_TEXT_LENGTH);
|
|
2690
|
+
const createDebugRedactionState = () => ({
|
|
2691
|
+
seen: new WeakSet(),
|
|
2692
|
+
remainingItems: MAX_DEBUG_REDACTION_ITEMS,
|
|
2693
|
+
remainingText: MAX_DEBUG_TEXT_LENGTH,
|
|
2694
|
+
});
|
|
2695
|
+
const redactDebugTextWithBudget = (value, state) => {
|
|
2696
|
+
if (state.remainingText <= 0) {
|
|
2697
|
+
return TRUNCATED_DEBUG_VALUE;
|
|
2698
|
+
}
|
|
2699
|
+
const permittedLength = Math.min(value.length, state.remainingText);
|
|
2700
|
+
state.remainingText -= permittedLength;
|
|
2701
|
+
return redactDebugTextToLength(value, permittedLength);
|
|
2702
|
+
};
|
|
2703
|
+
const redactDebugValue = (value, state = createDebugRedactionState(), depth = 0) => {
|
|
2704
|
+
if (typeof value === 'string') {
|
|
2705
|
+
return redactDebugTextWithBudget(value, state);
|
|
2706
|
+
}
|
|
2707
|
+
if (value instanceof Error) {
|
|
2708
|
+
const redacted = new Error(redactDebugTextWithBudget(value.message, state));
|
|
2709
|
+
redacted.name = redactDebugTextWithBudget(value.name, state);
|
|
2710
|
+
if (value.stack) {
|
|
2711
|
+
redacted.stack = redactDebugTextWithBudget(value.stack, state);
|
|
2712
|
+
}
|
|
2713
|
+
return redacted;
|
|
2714
|
+
}
|
|
2715
|
+
if (value === null || typeof value === 'number' || typeof value === 'boolean') {
|
|
2716
|
+
return value;
|
|
2717
|
+
}
|
|
2718
|
+
if (typeof value === 'undefined') {
|
|
2719
|
+
return undefined;
|
|
2720
|
+
}
|
|
2721
|
+
if (typeof value === 'bigint' || typeof value === 'symbol') {
|
|
2722
|
+
return String(value);
|
|
2723
|
+
}
|
|
2724
|
+
if (typeof value === 'function') {
|
|
2725
|
+
return '[Function]';
|
|
2726
|
+
}
|
|
2727
|
+
const objectValue = value;
|
|
2728
|
+
if (depth >= MAX_DEBUG_REDACTION_DEPTH || state.remainingItems <= 0) {
|
|
2729
|
+
return TRUNCATED_DEBUG_VALUE;
|
|
2730
|
+
}
|
|
2731
|
+
if (state.seen.has(objectValue)) {
|
|
2732
|
+
return '[Circular]';
|
|
2733
|
+
}
|
|
2734
|
+
state.seen.add(objectValue);
|
|
2735
|
+
if (Array.isArray(value)) {
|
|
2736
|
+
const count = Math.min(value.length, state.remainingItems);
|
|
2737
|
+
state.remainingItems -= count;
|
|
2738
|
+
const redacted = value.slice(0, count).map((entry) => redactDebugValue(entry, state, depth + 1));
|
|
2739
|
+
if (count < value.length) {
|
|
2740
|
+
redacted.push(TRUNCATED_DEBUG_VALUE);
|
|
2741
|
+
}
|
|
2742
|
+
return redacted;
|
|
2743
|
+
}
|
|
2744
|
+
const redacted = {};
|
|
2745
|
+
let allKeys;
|
|
2746
|
+
try {
|
|
2747
|
+
allKeys = Object.keys(objectValue);
|
|
2748
|
+
}
|
|
2749
|
+
catch {
|
|
2750
|
+
return '[Unavailable]';
|
|
2751
|
+
}
|
|
2752
|
+
const keys = allKeys.slice(0, state.remainingItems);
|
|
2753
|
+
state.remainingItems -= keys.length;
|
|
2754
|
+
for (const key of keys) {
|
|
2755
|
+
if (isSensitiveDebugField(key)) {
|
|
2756
|
+
redacted[key] = REDACTED_DEBUG_VALUE;
|
|
2757
|
+
continue;
|
|
2758
|
+
}
|
|
2759
|
+
try {
|
|
2760
|
+
redacted[key] = redactDebugValue(value[key], state, depth + 1);
|
|
2761
|
+
}
|
|
2762
|
+
catch {
|
|
2763
|
+
redacted[key] = '[Unavailable]';
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
if (keys.length < allKeys.length) {
|
|
2767
|
+
redacted.__truncated__ = TRUNCATED_DEBUG_VALUE;
|
|
2768
|
+
}
|
|
2769
|
+
return redacted;
|
|
2770
|
+
};
|
|
2771
|
+
const redactDebugArgs = (values) => {
|
|
2772
|
+
const state = createDebugRedactionState();
|
|
2773
|
+
return values.map((value) => redactDebugValue(value, state));
|
|
2774
|
+
};
|
|
2775
|
+
const debugValueText = (value) => {
|
|
2776
|
+
if (value instanceof Error) {
|
|
2777
|
+
return `${value.name}: ${value.message}`;
|
|
2778
|
+
}
|
|
2779
|
+
if (typeof value === 'string') {
|
|
2780
|
+
return value;
|
|
2781
|
+
}
|
|
2782
|
+
let serialized;
|
|
2783
|
+
try {
|
|
2784
|
+
serialized = JSON.stringify(value);
|
|
2785
|
+
}
|
|
2786
|
+
catch {
|
|
2787
|
+
return '[Unavailable]';
|
|
2788
|
+
}
|
|
2789
|
+
if (serialized === undefined) {
|
|
2790
|
+
return String(value);
|
|
2791
|
+
}
|
|
2792
|
+
return serialized.length > MAX_DEBUG_TEXT_LENGTH
|
|
2793
|
+
? `${serialized.slice(0, MAX_DEBUG_TEXT_LENGTH)} ${TRUNCATED_DEBUG_VALUE}`
|
|
2794
|
+
: serialized;
|
|
2795
|
+
};
|
|
2796
|
+
const redactedErrorFrom = (value, fallback, knownSecrets = []) => {
|
|
2797
|
+
const uniqueKnownSecrets = [
|
|
2798
|
+
...new Set(knownSecrets.filter((secret) => !!secret)),
|
|
2799
|
+
].sort((left, right) => right.length - left.length);
|
|
2800
|
+
const redacted = value instanceof Error || typeof value === 'string' ? value : redactDebugValue(value);
|
|
2801
|
+
let message = redacted instanceof Error ? redacted.message.trim() : debugValueText(redacted).trim();
|
|
2802
|
+
for (const secret of uniqueKnownSecrets) {
|
|
2803
|
+
message = message.split(secret).join(REDACTED_DEBUG_VALUE);
|
|
2804
|
+
}
|
|
2805
|
+
message = redactDebugText(message);
|
|
2806
|
+
return new Error(message.length > 0 ? message : fallback);
|
|
2807
|
+
};
|
|
2808
|
+
|
|
2595
2809
|
const LogLevel = {
|
|
2596
2810
|
Verbose: 5,
|
|
2597
2811
|
Log: 4,
|
|
@@ -2606,26 +2820,22 @@ class Logger {
|
|
|
2606
2820
|
};
|
|
2607
2821
|
this.info = (...args) => {
|
|
2608
2822
|
if (this.shouldLog(LogLevel.Verbose)) {
|
|
2609
|
-
|
|
2610
|
-
console.info(...args);
|
|
2823
|
+
console.info(...redactDebugArgs(args));
|
|
2611
2824
|
}
|
|
2612
2825
|
};
|
|
2613
2826
|
this.log = (...args) => {
|
|
2614
2827
|
if (this.shouldLog(LogLevel.Log)) {
|
|
2615
|
-
|
|
2616
|
-
console.log(...args);
|
|
2828
|
+
console.log(...redactDebugArgs(args));
|
|
2617
2829
|
}
|
|
2618
2830
|
};
|
|
2619
2831
|
this.warn = (...args) => {
|
|
2620
2832
|
if (this.shouldLog(LogLevel.Warnings)) {
|
|
2621
|
-
|
|
2622
|
-
console.warn(...args);
|
|
2833
|
+
console.warn(...redactDebugArgs(args));
|
|
2623
2834
|
}
|
|
2624
2835
|
};
|
|
2625
2836
|
this.error = (...args) => {
|
|
2626
2837
|
if (this.shouldLog(LogLevel.Errors)) {
|
|
2627
|
-
|
|
2628
|
-
console.error(...args);
|
|
2838
|
+
console.error(...redactDebugArgs(args));
|
|
2629
2839
|
}
|
|
2630
2840
|
};
|
|
2631
2841
|
this.level = debugLevel;
|
|
@@ -4559,6 +4769,61 @@ const bufferStorageKey = 'or_buffer_1';
|
|
|
4559
4769
|
const PROTO_VERSION = '2';
|
|
4560
4770
|
const BOOTSTRAP_ATTEMPT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
4561
4771
|
const MAX_BOOTSTRAP_ATTEMPT_STORAGE_LENGTH = 1024 * 1024;
|
|
4772
|
+
const MAX_SESSION_TOKEN_LENGTH = 4096;
|
|
4773
|
+
const MAX_ASSIST_SESSION_GRANT_LENGTH = 4096;
|
|
4774
|
+
const LINKAGE_ASSERTION_METADATA_KEY = 'oxvo_linkage_assertion';
|
|
4775
|
+
const MESSENGER_LINKAGE_CHALLENGE_PATTERN = /^[a-f0-9]{64}$/;
|
|
4776
|
+
const MIN_MESSENGER_LINKAGE_CHALLENGE_TTL_SECONDS = 5;
|
|
4777
|
+
const MAX_MESSENGER_LINKAGE_CHALLENGE_TTL_SECONDS = 120;
|
|
4778
|
+
const asRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
4779
|
+
? value
|
|
4780
|
+
: {};
|
|
4781
|
+
const isValidBootstrapCredential = (value, maxLength) => typeof value === 'string' &&
|
|
4782
|
+
value.length > 0 &&
|
|
4783
|
+
value.length <= maxLength &&
|
|
4784
|
+
value.trim() === value;
|
|
4785
|
+
const parseMessengerLinkageChallenge = (value, expectedSessionId) => {
|
|
4786
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
4787
|
+
return null;
|
|
4788
|
+
}
|
|
4789
|
+
const record = value;
|
|
4790
|
+
const keys = Object.keys(record).sort();
|
|
4791
|
+
if (keys.length !== 3 ||
|
|
4792
|
+
keys[0] !== 'challenge' ||
|
|
4793
|
+
keys[1] !== 'expiresIn' ||
|
|
4794
|
+
keys[2] !== 'sessionId' ||
|
|
4795
|
+
typeof record.challenge !== 'string' ||
|
|
4796
|
+
!MESSENGER_LINKAGE_CHALLENGE_PATTERN.test(record.challenge) ||
|
|
4797
|
+
record.sessionId !== expectedSessionId ||
|
|
4798
|
+
!Number.isInteger(record.expiresIn) ||
|
|
4799
|
+
record.expiresIn < MIN_MESSENGER_LINKAGE_CHALLENGE_TTL_SECONDS ||
|
|
4800
|
+
record.expiresIn > MAX_MESSENGER_LINKAGE_CHALLENGE_TTL_SECONDS) {
|
|
4801
|
+
return null;
|
|
4802
|
+
}
|
|
4803
|
+
return {
|
|
4804
|
+
challenge: record.challenge,
|
|
4805
|
+
sessionId: expectedSessionId,
|
|
4806
|
+
expiresIn: record.expiresIn,
|
|
4807
|
+
};
|
|
4808
|
+
};
|
|
4809
|
+
const bootstrapHttpError = async (response, responseText, knownSecrets = []) => {
|
|
4810
|
+
let body;
|
|
4811
|
+
try {
|
|
4812
|
+
body = responseText ?? (await response.text());
|
|
4813
|
+
}
|
|
4814
|
+
catch (error) {
|
|
4815
|
+
return redactedErrorFrom(error, `Server error: ${response.status}.`, knownSecrets);
|
|
4816
|
+
}
|
|
4817
|
+
return redactedErrorFrom(`Server error: ${response.status}. ${body}`, `Server error: ${response.status}.`, knownSecrets);
|
|
4818
|
+
};
|
|
4819
|
+
const bootstrapJson = async (response, knownSecrets = []) => {
|
|
4820
|
+
try {
|
|
4821
|
+
return asRecord(await response.json());
|
|
4822
|
+
}
|
|
4823
|
+
catch (error) {
|
|
4824
|
+
throw redactedErrorFrom(error, 'Incorrect server response (invalid JSON)', knownSecrets);
|
|
4825
|
+
}
|
|
4826
|
+
};
|
|
4562
4827
|
const UnsuccessfulStart = (reason) => ({ reason, success: false });
|
|
4563
4828
|
const SuccessfulStart = (body) => ({ ...body, success: true });
|
|
4564
4829
|
var ActivityState;
|
|
@@ -4628,13 +4893,14 @@ class App {
|
|
|
4628
4893
|
this.stopCallbacks = [];
|
|
4629
4894
|
this.commitCallbacks = [];
|
|
4630
4895
|
this.activityState = ActivityState.NotActive;
|
|
4631
|
-
this.version = '7.
|
|
4896
|
+
this.version = '7.4.15'; // TODO: version compatability check inside each plugin.
|
|
4632
4897
|
this.socketMode = false;
|
|
4633
4898
|
this.compressionThreshold = 24 * 1000;
|
|
4634
4899
|
this.bc = null;
|
|
4635
4900
|
this.canvasRecorder = null;
|
|
4636
4901
|
this.conditionsManager = null;
|
|
4637
4902
|
this.bootstrapAttempts = {};
|
|
4903
|
+
this.assistSessionGrant = null;
|
|
4638
4904
|
this.canStart = false;
|
|
4639
4905
|
this.rootId = null;
|
|
4640
4906
|
this.pageFrames = [];
|
|
@@ -4734,7 +5000,7 @@ class App {
|
|
|
4734
5000
|
this.startCrossDomainFrame(this.prevOpts);
|
|
4735
5001
|
}
|
|
4736
5002
|
catch (e) {
|
|
4737
|
-
console.error('children frame restart failed:', e);
|
|
5003
|
+
console.error('children frame restart failed:', redactDebugValue(e));
|
|
4738
5004
|
}
|
|
4739
5005
|
return;
|
|
4740
5006
|
}
|
|
@@ -4893,10 +5159,10 @@ class App {
|
|
|
4893
5159
|
this.allowAppStart();
|
|
4894
5160
|
this.start(this.prevOpts, true)
|
|
4895
5161
|
.then((r) => {
|
|
4896
|
-
this.debug.info('Session restart', r);
|
|
5162
|
+
this.debug.info('Session restart', redactDebugValue(r));
|
|
4897
5163
|
})
|
|
4898
5164
|
.catch((e) => {
|
|
4899
|
-
this.debug.error('Session restart failed', e);
|
|
5165
|
+
this.debug.error('Session restart failed', redactDebugValue(e));
|
|
4900
5166
|
});
|
|
4901
5167
|
});
|
|
4902
5168
|
};
|
|
@@ -5078,7 +5344,7 @@ class App {
|
|
|
5078
5344
|
});
|
|
5079
5345
|
this.markerWatcher = new MarkerWatcher({
|
|
5080
5346
|
sessionStorage: this.sessionStorage,
|
|
5081
|
-
errLog: this.debug.error,
|
|
5347
|
+
errLog: (...args) => this.debug.error(...args.map((arg) => redactDebugValue(arg))),
|
|
5082
5348
|
onMarkerHit: (markerId) => this.send(TagTrigger(markerId)),
|
|
5083
5349
|
});
|
|
5084
5350
|
this.session.attachUpdateCallback(({ userID, metadata }) => {
|
|
@@ -5144,10 +5410,10 @@ class App {
|
|
|
5144
5410
|
}, 250);
|
|
5145
5411
|
this.bc.onmessage = (ev) => {
|
|
5146
5412
|
if (ev.data.context === this.contextId || this.projectKey !== ev.data.projectKey) {
|
|
5147
|
-
this.debug.log('same ctx event', ev);
|
|
5413
|
+
this.debug.log('same ctx event', redactDebugValue(ev.data));
|
|
5148
5414
|
return;
|
|
5149
5415
|
}
|
|
5150
|
-
this.debug.log(ev);
|
|
5416
|
+
this.debug.log('broadcast event', redactDebugValue(ev.data));
|
|
5151
5417
|
if (ev.data.line === proto.resp) {
|
|
5152
5418
|
const sessionToken = ev.data.token;
|
|
5153
5419
|
this.session.setSessionSecret(sessionToken, this.projectKey);
|
|
@@ -5576,10 +5842,10 @@ class App {
|
|
|
5576
5842
|
this.allowAppStart();
|
|
5577
5843
|
this.start(this.prevOpts, true)
|
|
5578
5844
|
.then((r) => {
|
|
5579
|
-
this.debug.info('Worker restart, session too long', r);
|
|
5845
|
+
this.debug.info('Worker restart, session too long', redactDebugValue(r));
|
|
5580
5846
|
})
|
|
5581
5847
|
.catch((e) => {
|
|
5582
|
-
this.debug.error('Worker restart failed', e);
|
|
5848
|
+
this.debug.error('Worker restart failed', redactDebugValue(e));
|
|
5583
5849
|
});
|
|
5584
5850
|
});
|
|
5585
5851
|
}
|
|
@@ -5588,7 +5854,7 @@ class App {
|
|
|
5588
5854
|
}
|
|
5589
5855
|
else if (data.type === 'failure') {
|
|
5590
5856
|
this.stop(false);
|
|
5591
|
-
this.debug.error('worker_failed', data.reason);
|
|
5857
|
+
this.debug.error('worker_failed', redactDebugValue(data.reason));
|
|
5592
5858
|
this._debug('worker_failed', data.reason);
|
|
5593
5859
|
}
|
|
5594
5860
|
else if (data.type === 'compress') {
|
|
@@ -5609,7 +5875,7 @@ class App {
|
|
|
5609
5875
|
});
|
|
5610
5876
|
})
|
|
5611
5877
|
.catch((err) => {
|
|
5612
|
-
this.debug.error('OxvoSessions compression error:', err);
|
|
5878
|
+
this.debug.error('OxvoSessions compression error:', redactDebugValue(err));
|
|
5613
5879
|
this.worker?.postMessage({ type: 'uncompressed', batch: batch, dataType });
|
|
5614
5880
|
});
|
|
5615
5881
|
}
|
|
@@ -5631,18 +5897,18 @@ class App {
|
|
|
5631
5897
|
}
|
|
5632
5898
|
}
|
|
5633
5899
|
_debug(context, e) {
|
|
5900
|
+
const redactedError = redactDebugValue(e);
|
|
5634
5901
|
if (this.options.__debug_report_edp !== null) {
|
|
5635
5902
|
void fetch(this.options.__debug_report_edp, {
|
|
5636
5903
|
method: 'POST',
|
|
5637
5904
|
headers: { 'Content-Type': 'application/json' },
|
|
5638
5905
|
body: JSON.stringify({
|
|
5639
5906
|
context,
|
|
5640
|
-
|
|
5641
|
-
error: `${e}`,
|
|
5907
|
+
error: debugValueText(redactedError),
|
|
5642
5908
|
}),
|
|
5643
5909
|
});
|
|
5644
5910
|
}
|
|
5645
|
-
this.debug.error('OxvoSessions error: ', context,
|
|
5911
|
+
this.debug.error('OxvoSessions error: ', context, redactedError);
|
|
5646
5912
|
}
|
|
5647
5913
|
/**
|
|
5648
5914
|
* Normal workflow: add timestamp and tab data to batch, then commit it
|
|
@@ -5966,11 +6232,76 @@ class App {
|
|
|
5966
6232
|
(current.userUUID === '' || existing.userUUID === current.userUUID));
|
|
5967
6233
|
}
|
|
5968
6234
|
getSessionMeta() {
|
|
6235
|
+
const sessionInfo = this.session.getInfo();
|
|
6236
|
+
const metadata = { ...sessionInfo.metadata };
|
|
6237
|
+
Object.keys(metadata).forEach((key) => {
|
|
6238
|
+
if (key.trim().toLowerCase() === LINKAGE_ASSERTION_METADATA_KEY) {
|
|
6239
|
+
delete metadata[key];
|
|
6240
|
+
}
|
|
6241
|
+
});
|
|
5969
6242
|
return {
|
|
5970
|
-
...
|
|
6243
|
+
...sessionInfo,
|
|
6244
|
+
metadata,
|
|
5971
6245
|
...this.getTrackerInfo(),
|
|
5972
6246
|
};
|
|
5973
6247
|
}
|
|
6248
|
+
async requestMessengerLinkageChallenge() {
|
|
6249
|
+
const sessionId = this.session.getInfo().sessionID;
|
|
6250
|
+
const grantLineage = this.assistSessionGrant;
|
|
6251
|
+
const grant = this.getAssistSessionGrant();
|
|
6252
|
+
if (!sessionId || !grantLineage || !grant || grant.sessionId !== sessionId) {
|
|
6253
|
+
return null;
|
|
6254
|
+
}
|
|
6255
|
+
const tabId = this.session.getTabId();
|
|
6256
|
+
try {
|
|
6257
|
+
const response = await fetch(`${normalizeEndpoint(this.options.endpoint)}/v1/linkage-challenge`, {
|
|
6258
|
+
method: 'POST',
|
|
6259
|
+
headers: {
|
|
6260
|
+
Authorization: `Bearer ${grant.token}`,
|
|
6261
|
+
'Content-Type': 'application/json',
|
|
6262
|
+
},
|
|
6263
|
+
body: JSON.stringify({ tabId }),
|
|
6264
|
+
cache: 'no-store',
|
|
6265
|
+
credentials: 'omit',
|
|
6266
|
+
referrerPolicy: 'no-referrer',
|
|
6267
|
+
});
|
|
6268
|
+
if (response.status !== 200) {
|
|
6269
|
+
return null;
|
|
6270
|
+
}
|
|
6271
|
+
const challenge = parseMessengerLinkageChallenge(await response.json(), sessionId);
|
|
6272
|
+
if (!challenge) {
|
|
6273
|
+
return null;
|
|
6274
|
+
}
|
|
6275
|
+
const currentGrant = this.getAssistSessionGrant();
|
|
6276
|
+
if (!currentGrant ||
|
|
6277
|
+
this.assistSessionGrant !== grantLineage ||
|
|
6278
|
+
currentGrant.sessionId !== grant.sessionId ||
|
|
6279
|
+
currentGrant.token !== grant.token ||
|
|
6280
|
+
this.session.getInfo().sessionID !== sessionId ||
|
|
6281
|
+
this.session.getTabId() !== tabId) {
|
|
6282
|
+
return null;
|
|
6283
|
+
}
|
|
6284
|
+
return challenge;
|
|
6285
|
+
}
|
|
6286
|
+
catch {
|
|
6287
|
+
return null;
|
|
6288
|
+
}
|
|
6289
|
+
}
|
|
6290
|
+
getAssistSessionGrant() {
|
|
6291
|
+
return this.assistSessionGrant ? { ...this.assistSessionGrant } : null;
|
|
6292
|
+
}
|
|
6293
|
+
setAssistSessionGrant(sessionId, token) {
|
|
6294
|
+
this.assistSessionGrant =
|
|
6295
|
+
typeof token === 'string' &&
|
|
6296
|
+
token.length > 0 &&
|
|
6297
|
+
token.length <= MAX_ASSIST_SESSION_GRANT_LENGTH &&
|
|
6298
|
+
token.trim() === token
|
|
6299
|
+
? { sessionId, token }
|
|
6300
|
+
: null;
|
|
6301
|
+
}
|
|
6302
|
+
clearAssistSessionGrant() {
|
|
6303
|
+
this.assistSessionGrant = null;
|
|
6304
|
+
}
|
|
5974
6305
|
getSessionSecret() {
|
|
5975
6306
|
return this.session.getSessionSecret(this.projectKey);
|
|
5976
6307
|
}
|
|
@@ -6103,23 +6434,48 @@ class App {
|
|
|
6103
6434
|
async setupConditionalStart(startOpts) {
|
|
6104
6435
|
this.conditionsManager = new ConditionsManager(this, startOpts);
|
|
6105
6436
|
const ingestPoint = normalizeEndpoint(this.options.endpoint);
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6437
|
+
let r;
|
|
6438
|
+
try {
|
|
6439
|
+
r = await fetch(ingestPoint + '/v1/bootstrap', {
|
|
6440
|
+
method: 'POST',
|
|
6441
|
+
headers: {
|
|
6442
|
+
'Content-Type': 'application/json',
|
|
6443
|
+
},
|
|
6444
|
+
body: JSON.stringify(this.buildStartPayload({
|
|
6445
|
+
timestamp: now(),
|
|
6446
|
+
dry: true,
|
|
6447
|
+
bufferMs: 0,
|
|
6448
|
+
token: '',
|
|
6449
|
+
width: window.screen.width,
|
|
6450
|
+
height: window.screen.height,
|
|
6451
|
+
referrer: document.referrer,
|
|
6452
|
+
})),
|
|
6453
|
+
});
|
|
6454
|
+
}
|
|
6455
|
+
catch (error) {
|
|
6456
|
+
throw redactedErrorFrom(error, 'Conditional bootstrap request failed.');
|
|
6457
|
+
}
|
|
6458
|
+
if (r.status !== 200) {
|
|
6459
|
+
throw await bootstrapHttpError(r);
|
|
6460
|
+
}
|
|
6461
|
+
const response = await bootstrapJson(r);
|
|
6462
|
+
const session = asRecord(response.session);
|
|
6463
|
+
const client = asRecord(response.client);
|
|
6464
|
+
const device = asRecord(response.device);
|
|
6122
6465
|
const { token, projectId, assistToken } = session;
|
|
6466
|
+
const invalidResponseFields = [
|
|
6467
|
+
!isValidBootstrapCredential(token, MAX_SESSION_TOKEN_LENGTH) ? 'session.token' : null,
|
|
6468
|
+
typeof assistToken !== 'undefined' &&
|
|
6469
|
+
!isValidBootstrapCredential(assistToken, MAX_ASSIST_SESSION_GRANT_LENGTH)
|
|
6470
|
+
? 'session.assistToken'
|
|
6471
|
+
: null,
|
|
6472
|
+
typeof session.id !== 'string' ? 'session.id' : null,
|
|
6473
|
+
typeof projectId !== 'string' ? 'session.projectId' : null,
|
|
6474
|
+
typeof device.id !== 'string' ? 'device.id' : null,
|
|
6475
|
+
].filter((field) => field !== null);
|
|
6476
|
+
if (invalidResponseFields.length > 0) {
|
|
6477
|
+
throw new Error(`Incorrect server response (status ${r.status}; invalid fields: ${invalidResponseFields.join(', ')})`);
|
|
6478
|
+
}
|
|
6123
6479
|
const { browser: userBrowser, city: userCity, country: userCountry, device: userDevice, os: userOS, state: userState, } = client;
|
|
6124
6480
|
this.session.assign({ projectID: projectId });
|
|
6125
6481
|
this.session.setUserInfo({
|
|
@@ -6132,13 +6488,18 @@ class App {
|
|
|
6132
6488
|
});
|
|
6133
6489
|
const onStartInfo = {
|
|
6134
6490
|
sessionToken: token,
|
|
6135
|
-
assistToken
|
|
6136
|
-
userUUID: device
|
|
6137
|
-
sessionID: session
|
|
6491
|
+
assistToken,
|
|
6492
|
+
userUUID: device.id,
|
|
6493
|
+
sessionID: session.id,
|
|
6138
6494
|
};
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6495
|
+
try {
|
|
6496
|
+
this.startCallbacks.forEach((cb) => cb(onStartInfo));
|
|
6497
|
+
await this.conditionsManager?.fetchConditions(projectId, token);
|
|
6498
|
+
await this.markerWatcher.fetchTags(normalizeEndpoint(this.options.endpoint), token);
|
|
6499
|
+
}
|
|
6500
|
+
catch (error) {
|
|
6501
|
+
throw redactedErrorFrom(error, 'Conditional bootstrap failed.', [token, assistToken]);
|
|
6502
|
+
}
|
|
6142
6503
|
}
|
|
6143
6504
|
/**
|
|
6144
6505
|
* Starts offline session recording
|
|
@@ -6146,6 +6507,7 @@ class App {
|
|
|
6146
6507
|
* @param {Function} onSessionSent - callback that will be called once session is fully sent
|
|
6147
6508
|
* */
|
|
6148
6509
|
offlineRecording(startOpts = {}, onSessionSent) {
|
|
6510
|
+
this.clearAssistSessionGrant();
|
|
6149
6511
|
this.onSessionSent = onSessionSent;
|
|
6150
6512
|
this.singleBuffer = true;
|
|
6151
6513
|
adjustTimeOrigin();
|
|
@@ -6252,22 +6614,37 @@ class App {
|
|
|
6252
6614
|
'Content-Type': 'application/json',
|
|
6253
6615
|
'Idempotency-Key': bootstrapAttempt.idempotencyKey,
|
|
6254
6616
|
};
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6617
|
+
let r;
|
|
6618
|
+
try {
|
|
6619
|
+
r = await fetch(ingestPoint + '/v1/bootstrap', {
|
|
6620
|
+
method: 'POST',
|
|
6621
|
+
headers,
|
|
6622
|
+
body: bootstrapAttempt.requestBody,
|
|
6623
|
+
});
|
|
6624
|
+
}
|
|
6625
|
+
catch (error) {
|
|
6626
|
+
throw redactedErrorFrom(error, 'Offline bootstrap request failed.', [bootstrapToken]);
|
|
6627
|
+
}
|
|
6260
6628
|
if (r.status !== 200) {
|
|
6261
|
-
throw
|
|
6629
|
+
throw await bootstrapHttpError(r, undefined, [bootstrapToken]);
|
|
6262
6630
|
}
|
|
6263
|
-
const
|
|
6631
|
+
const response = await bootstrapJson(r, [bootstrapToken]);
|
|
6632
|
+
const session = asRecord(response.session);
|
|
6633
|
+
const client = asRecord(response.client);
|
|
6634
|
+
const limits = asRecord(response.limits);
|
|
6635
|
+
const offlineProtocolVersion = response.protocolVersion;
|
|
6264
6636
|
const { token, projectId } = session;
|
|
6265
6637
|
const { browser: userBrowser, city: userCity, country: userCountry, device: userDevice, os: userOS, state: userState, } = client;
|
|
6266
6638
|
const { beacon: beaconSizeLimit } = limits;
|
|
6267
|
-
|
|
6268
|
-
token.
|
|
6269
|
-
|
|
6270
|
-
|
|
6639
|
+
const invalidResponseFields = [
|
|
6640
|
+
!isValidBootstrapCredential(token, MAX_SESSION_TOKEN_LENGTH) ? 'session.token' : null,
|
|
6641
|
+
typeof projectId !== 'string' ? 'session.projectId' : null,
|
|
6642
|
+
typeof beaconSizeLimit !== 'number' && typeof beaconSizeLimit !== 'undefined'
|
|
6643
|
+
? 'limits.beacon'
|
|
6644
|
+
: null,
|
|
6645
|
+
].filter((field) => field !== null);
|
|
6646
|
+
if (invalidResponseFields.length > 0) {
|
|
6647
|
+
throw new Error(`Incorrect server response (status ${r.status}; invalid fields: ${invalidResponseFields.join(', ')})`);
|
|
6271
6648
|
}
|
|
6272
6649
|
this.session.setSessionSecret(token, this.projectKey);
|
|
6273
6650
|
this.clearBootstrapAttempt('offline');
|
|
@@ -6287,8 +6664,13 @@ class App {
|
|
|
6287
6664
|
beaconSizeLimit,
|
|
6288
6665
|
protocolVersion: offlineProtocolVersion,
|
|
6289
6666
|
});
|
|
6290
|
-
|
|
6291
|
-
|
|
6667
|
+
try {
|
|
6668
|
+
while (this.bufferedMessages1.length > 0) {
|
|
6669
|
+
await this.flushBuffer(this.bufferedMessages1);
|
|
6670
|
+
}
|
|
6671
|
+
}
|
|
6672
|
+
catch (error) {
|
|
6673
|
+
throw redactedErrorFrom(error, 'Offline recording upload failed.', [token, bootstrapToken]);
|
|
6292
6674
|
}
|
|
6293
6675
|
this.postToWorker([[-1]]);
|
|
6294
6676
|
this.clearBuffers();
|
|
@@ -6304,6 +6686,7 @@ class App {
|
|
|
6304
6686
|
this.rootId === null) {
|
|
6305
6687
|
return UnsuccessfulStart('Cross-domain iframe handshake was not established.');
|
|
6306
6688
|
}
|
|
6689
|
+
this.clearAssistSessionGrant();
|
|
6307
6690
|
if (Object.keys(startOpts).length !== 0) {
|
|
6308
6691
|
this.prevOpts = startOpts;
|
|
6309
6692
|
}
|
|
@@ -6373,6 +6756,7 @@ class App {
|
|
|
6373
6756
|
const reason = 'OxvoSessions: trying to call `start()` on the instance that has been started already.';
|
|
6374
6757
|
return Promise.resolve(UnsuccessfulStart(reason));
|
|
6375
6758
|
}
|
|
6759
|
+
this.clearAssistSessionGrant();
|
|
6376
6760
|
this.activityState = ActivityState.Starting;
|
|
6377
6761
|
if (!isColdStart) {
|
|
6378
6762
|
adjustTimeOrigin();
|
|
@@ -6426,7 +6810,8 @@ class App {
|
|
|
6426
6810
|
tabId: this.session.getTabId(),
|
|
6427
6811
|
localDebug: this.options.__local_debug,
|
|
6428
6812
|
});
|
|
6429
|
-
this.debug.log('OxvoSessions: starting session; need new session id?', isNewSession, 'session token:
|
|
6813
|
+
this.debug.log('OxvoSessions: starting session; need new session id?', isNewSession, 'has existing session token:', Boolean(sessionToken));
|
|
6814
|
+
const bootstrapSecrets = [sessionToken, bootstrapToken];
|
|
6430
6815
|
try {
|
|
6431
6816
|
const ingestPoint = normalizeEndpoint(this.options.endpoint);
|
|
6432
6817
|
const headers = {
|
|
@@ -6440,30 +6825,52 @@ class App {
|
|
|
6440
6825
|
});
|
|
6441
6826
|
if (r.status !== 200) {
|
|
6442
6827
|
const error = await r.text();
|
|
6443
|
-
|
|
6444
|
-
|
|
6828
|
+
if (error === CANCELED) {
|
|
6829
|
+
this.stop();
|
|
6830
|
+
this.signalError(CANCELED, []);
|
|
6831
|
+
return UnsuccessfulStart(CANCELED);
|
|
6832
|
+
}
|
|
6833
|
+
throw await bootstrapHttpError(r, error, bootstrapSecrets);
|
|
6445
6834
|
}
|
|
6446
6835
|
if (!this.worker && !this.insideIframe) {
|
|
6447
6836
|
const reason = 'no worker found after start request (this should not happen in real world)';
|
|
6448
6837
|
throw new Error(reason);
|
|
6449
6838
|
}
|
|
6450
|
-
const
|
|
6839
|
+
const response = await bootstrapJson(r, bootstrapSecrets);
|
|
6840
|
+
const session = asRecord(response.session);
|
|
6841
|
+
const device = asRecord(response.device);
|
|
6842
|
+
const client = asRecord(response.client);
|
|
6843
|
+
const limits = asRecord(response.limits);
|
|
6844
|
+
const canvas = asRecord(response.canvas);
|
|
6845
|
+
const flags = asRecord(response.flags);
|
|
6846
|
+
const protocolVersion = response.protocolVersion;
|
|
6451
6847
|
const { token, assistToken, id: sessionID, projectId: projectID, delayMs: delay, startedAt: startTimestamp, } = session;
|
|
6452
6848
|
const { id: userUUID } = device;
|
|
6453
6849
|
const { browser: userBrowser, city: userCity, country: userCountry, device: userDevice, os: userOS, state: userState, } = client;
|
|
6454
6850
|
const { beacon: beaconSizeLimit, compressAt: compressionThreshold } = limits;
|
|
6455
6851
|
const { enabled: canvasEnabled, quality: canvasQuality, fps: canvasFPS, framesSupport, } = canvas;
|
|
6456
6852
|
const socketOnly = flags?.socketOnly;
|
|
6457
|
-
|
|
6458
|
-
(
|
|
6459
|
-
typeof
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6853
|
+
const invalidResponseFields = [
|
|
6854
|
+
!isValidBootstrapCredential(token, MAX_SESSION_TOKEN_LENGTH) ? 'session.token' : null,
|
|
6855
|
+
typeof assistToken !== 'undefined' &&
|
|
6856
|
+
!isValidBootstrapCredential(assistToken, MAX_ASSIST_SESSION_GRANT_LENGTH)
|
|
6857
|
+
? 'session.assistToken'
|
|
6858
|
+
: null,
|
|
6859
|
+
typeof userUUID !== 'string' ? 'device.id' : null,
|
|
6860
|
+
typeof startTimestamp !== 'number' && typeof startTimestamp !== 'undefined'
|
|
6861
|
+
? 'session.startedAt'
|
|
6862
|
+
: null,
|
|
6863
|
+
typeof sessionID !== 'string' ? 'session.id' : null,
|
|
6864
|
+
typeof projectID !== 'string' ? 'session.projectId' : null,
|
|
6865
|
+
typeof delay !== 'number' ? 'session.delayMs' : null,
|
|
6866
|
+
typeof beaconSizeLimit !== 'number' && typeof beaconSizeLimit !== 'undefined'
|
|
6867
|
+
? 'limits.beacon'
|
|
6868
|
+
: null,
|
|
6869
|
+
].filter((field) => field !== null);
|
|
6870
|
+
if (invalidResponseFields.length > 0) {
|
|
6871
|
+
throw new Error(`Incorrect server response (status ${r.status}; invalid fields: ${invalidResponseFields.join(', ')})`);
|
|
6872
|
+
}
|
|
6873
|
+
bootstrapSecrets.push(token, assistToken);
|
|
6467
6874
|
this.crossDomainCanvasConfig = {
|
|
6468
6875
|
enabled: canvasEnabled === true,
|
|
6469
6876
|
...(['low', 'medium', 'high'].includes(canvasQuality) ? { quality: canvasQuality } : {}),
|
|
@@ -6492,6 +6899,7 @@ class App {
|
|
|
6492
6899
|
timestamp: startTimestamp || timestamp,
|
|
6493
6900
|
projectID,
|
|
6494
6901
|
});
|
|
6902
|
+
this.setAssistSessionGrant(sessionID, assistToken);
|
|
6495
6903
|
if (socketOnly) {
|
|
6496
6904
|
this.socketMode = true;
|
|
6497
6905
|
this.worker?.postMessage('stop');
|
|
@@ -6570,8 +6978,9 @@ class App {
|
|
|
6570
6978
|
this.signalError(CANCELED, []);
|
|
6571
6979
|
return UnsuccessfulStart(CANCELED);
|
|
6572
6980
|
}
|
|
6573
|
-
|
|
6574
|
-
|
|
6981
|
+
const redactedError = redactedErrorFrom(reason, 'Session start failed.', bootstrapSecrets);
|
|
6982
|
+
this._debug('session_start', redactedError);
|
|
6983
|
+
const errorMessage = redactedError.message;
|
|
6575
6984
|
this.signalError(errorMessage, []);
|
|
6576
6985
|
return UnsuccessfulStart(errorMessage);
|
|
6577
6986
|
}
|
|
@@ -6694,6 +7103,7 @@ class App {
|
|
|
6694
7103
|
};
|
|
6695
7104
|
}
|
|
6696
7105
|
stop(stopWorker = true) {
|
|
7106
|
+
this.clearAssistSessionGrant();
|
|
6697
7107
|
if (this.activityState !== ActivityState.NotActive) {
|
|
6698
7108
|
try {
|
|
6699
7109
|
if (this.options.crossdomain?.enabled) {
|
|
@@ -8374,10 +8784,14 @@ function Fonts (app) {
|
|
|
8374
8784
|
}
|
|
8375
8785
|
|
|
8376
8786
|
function axiosSpy (app, instance, opts, sanitize, stringify) {
|
|
8377
|
-
app.debug.log('OxvoSessions: attaching axios spy to instance'
|
|
8787
|
+
app.debug.log('OxvoSessions: attaching axios spy to configured instance');
|
|
8378
8788
|
function captureResponseData(axiosResponseObj) {
|
|
8379
|
-
app.debug.log('OxvoSessions: capturing axios response data',
|
|
8380
|
-
|
|
8789
|
+
app.debug.log('OxvoSessions: capturing axios response data', {
|
|
8790
|
+
method: axiosResponseObj.config.method,
|
|
8791
|
+
status: axiosResponseObj.status,
|
|
8792
|
+
url: axiosResponseObj.config.url,
|
|
8793
|
+
});
|
|
8794
|
+
const { headers: reqHs, data: reqData, method, url } = axiosResponseObj.config;
|
|
8381
8795
|
const { data: rData, headers: rHs, status: globStatus, response } = axiosResponseObj;
|
|
8382
8796
|
const { data: resData, headers: resHs, status: resStatus } = response || {};
|
|
8383
8797
|
const ihOpt = opts.ignoreHeaders;
|
|
@@ -8436,11 +8850,18 @@ function axiosSpy (app, instance, opts, sanitize, stringify) {
|
|
|
8436
8850
|
}
|
|
8437
8851
|
const requestStart = axiosResponseObj.config.__oxvosessions_timing;
|
|
8438
8852
|
const duration = performance.now() - requestStart;
|
|
8439
|
-
app.debug.log('OxvoSessions:
|
|
8853
|
+
app.debug.log('OxvoSessions: sanitized axios request is ready', {
|
|
8854
|
+
method: reqResInfo.method,
|
|
8855
|
+
status: reqResInfo.status,
|
|
8856
|
+
url: reqResInfo.url,
|
|
8857
|
+
});
|
|
8440
8858
|
app.send(NetworkRequest('xhr', String(method), String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), reqResInfo.status, requestStart + getTimeOrigin(), duration, 0));
|
|
8441
8859
|
}
|
|
8442
8860
|
function getStartTime(config) {
|
|
8443
|
-
app.debug.log('OxvoSessions: capturing
|
|
8861
|
+
app.debug.log('OxvoSessions: capturing axios request', {
|
|
8862
|
+
method: config.method,
|
|
8863
|
+
url: config.url,
|
|
8864
|
+
});
|
|
8444
8865
|
config.__oxvosessions_timing = performance.now();
|
|
8445
8866
|
if (opts.sessionTokenHeader) {
|
|
8446
8867
|
const header = typeof opts.sessionTokenHeader === 'string'
|
|
@@ -8460,17 +8881,23 @@ function axiosSpy (app, instance, opts, sanitize, stringify) {
|
|
|
8460
8881
|
return response;
|
|
8461
8882
|
}
|
|
8462
8883
|
function captureNetworkError(error) {
|
|
8463
|
-
app.debug.log('OxvoSessions: capturing
|
|
8884
|
+
app.debug.log('OxvoSessions: capturing axios request error', {
|
|
8885
|
+
hasResponse: Boolean(error.response),
|
|
8886
|
+
isAxiosError: isAxiosError(error),
|
|
8887
|
+
message: typeof error.message === 'string' ? error.message : undefined,
|
|
8888
|
+
});
|
|
8464
8889
|
if (isAxiosError(error) && Boolean(error.response)) {
|
|
8465
8890
|
captureResponseData(error.response);
|
|
8466
8891
|
}
|
|
8467
8892
|
else if (error instanceof Error) {
|
|
8468
8893
|
app.send(getExceptionMessage(error, []));
|
|
8469
8894
|
}
|
|
8895
|
+
// Axios rejection handlers must preserve the original Axios error object for downstream code.
|
|
8896
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
|
8470
8897
|
return Promise.reject(error);
|
|
8471
8898
|
}
|
|
8472
|
-
function logRequestError(
|
|
8473
|
-
app.debug.log('OxvoSessions: failed
|
|
8899
|
+
function logRequestError() {
|
|
8900
|
+
app.debug.log('OxvoSessions: failed axios request, skipping');
|
|
8474
8901
|
}
|
|
8475
8902
|
const reqInt = instance.interceptors.request.use(getStartTime, logRequestError, {
|
|
8476
8903
|
synchronous: true,
|
|
@@ -10283,7 +10710,7 @@ class ConstantProperties {
|
|
|
10283
10710
|
user_id: this.user_id,
|
|
10284
10711
|
distinct_id: this.deviceId,
|
|
10285
10712
|
sdk_edition: 'web',
|
|
10286
|
-
sdk_version: '7.
|
|
10713
|
+
sdk_version: '7.4.15',
|
|
10287
10714
|
timezone: getUTCOffsetString(),
|
|
10288
10715
|
search_engine: this.searchEngine,
|
|
10289
10716
|
};
|
|
@@ -11148,7 +11575,7 @@ class API {
|
|
|
11148
11575
|
this.signalStartIssue = (reason, missingApi) => {
|
|
11149
11576
|
const doNotTrack = this.checkDoNotTrack();
|
|
11150
11577
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
11151
|
-
trackerVersion: '7.
|
|
11578
|
+
trackerVersion: '7.4.15',
|
|
11152
11579
|
siteKey: this.options.siteKey,
|
|
11153
11580
|
doNotTrack,
|
|
11154
11581
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|
|
@@ -11514,6 +11941,12 @@ class API {
|
|
|
11514
11941
|
}
|
|
11515
11942
|
return this.app.getSessionSecret();
|
|
11516
11943
|
}
|
|
11944
|
+
requestMessengerLinkageChallenge() {
|
|
11945
|
+
if (this.app === null) {
|
|
11946
|
+
return Promise.resolve(null);
|
|
11947
|
+
}
|
|
11948
|
+
return this.app.requestMessengerLinkageChallenge();
|
|
11949
|
+
}
|
|
11517
11950
|
getSessionMeta() {
|
|
11518
11951
|
if (this.app === null) {
|
|
11519
11952
|
return null;
|
|
@@ -11672,6 +12105,12 @@ class BrowserSingleton {
|
|
|
11672
12105
|
}
|
|
11673
12106
|
return this.instance.getSessionSecret();
|
|
11674
12107
|
}
|
|
12108
|
+
requestMessengerLinkageChallenge() {
|
|
12109
|
+
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
12110
|
+
return Promise.resolve(null);
|
|
12111
|
+
}
|
|
12112
|
+
return this.instance.requestMessengerLinkageChallenge();
|
|
12113
|
+
}
|
|
11675
12114
|
track(key, payload = null, issue = false) {
|
|
11676
12115
|
if (!IN_BROWSER || !this.ensureConfigured() || !this.instance) {
|
|
11677
12116
|
return;
|