415gotit
This commit is contained in:
@@ -1,150 +1,170 @@
|
||||
'use strict';
|
||||
/**
|
||||
* Performance Mock
|
||||
*
|
||||
* Timing and performance metrics for fingerprinting.
|
||||
* P0: Performance mock
|
||||
* hsw 检测:timing / timeOrigin / getEntriesByType('resource') / getEntriesByType('navigation')
|
||||
*/
|
||||
|
||||
export function createPerformance(fingerprint = {}) {
|
||||
const timeOrigin = Date.now() - (fingerprint.uptime || 10000);
|
||||
const entries = [];
|
||||
const { createNative } = require('./native');
|
||||
|
||||
return {
|
||||
timeOrigin,
|
||||
const NAV_START = Date.now() - 1200;
|
||||
|
||||
now() {
|
||||
return Date.now() - timeOrigin;
|
||||
},
|
||||
const timingData = {
|
||||
navigationStart: NAV_START,
|
||||
fetchStart: NAV_START + 11,
|
||||
domainLookupStart: NAV_START + 11,
|
||||
domainLookupEnd: NAV_START + 11,
|
||||
connectStart: NAV_START + 11,
|
||||
secureConnectionStart: NAV_START + 11,
|
||||
connectEnd: NAV_START + 11,
|
||||
requestStart: NAV_START + 37,
|
||||
responseStart: NAV_START + 47,
|
||||
responseEnd: NAV_START + 114,
|
||||
domLoading: NAV_START + 203,
|
||||
domInteractive: NAV_START + 399,
|
||||
domContentLoadedEventStart: NAV_START + 399,
|
||||
domContentLoadedEventEnd: NAV_START + 399,
|
||||
domComplete: NAV_START + 399,
|
||||
loadEventStart: NAV_START + 399,
|
||||
loadEventEnd: NAV_START + 399,
|
||||
redirectStart: 0,
|
||||
redirectEnd: 0,
|
||||
unloadEventStart: 0,
|
||||
unloadEventEnd: 0,
|
||||
};
|
||||
|
||||
// Timing (deprecated but still used)
|
||||
timing: {
|
||||
navigationStart: timeOrigin,
|
||||
unloadEventStart: 0,
|
||||
unloadEventEnd: 0,
|
||||
redirectStart: 0,
|
||||
redirectEnd: 0,
|
||||
fetchStart: timeOrigin + 1,
|
||||
domainLookupStart: timeOrigin + 2,
|
||||
domainLookupEnd: timeOrigin + 10,
|
||||
connectStart: timeOrigin + 10,
|
||||
connectEnd: timeOrigin + 50,
|
||||
secureConnectionStart: timeOrigin + 20,
|
||||
requestStart: timeOrigin + 50,
|
||||
responseStart: timeOrigin + 100,
|
||||
responseEnd: timeOrigin + 200,
|
||||
domLoading: timeOrigin + 200,
|
||||
domInteractive: timeOrigin + 500,
|
||||
domContentLoadedEventStart: timeOrigin + 500,
|
||||
domContentLoadedEventEnd: timeOrigin + 510,
|
||||
domComplete: timeOrigin + 1000,
|
||||
loadEventStart: timeOrigin + 1000,
|
||||
loadEventEnd: timeOrigin + 1010,
|
||||
},
|
||||
// 模拟 resource 条目(hsw 会查 checksiteconfig 请求痕迹)
|
||||
const resourceEntries = [
|
||||
{
|
||||
name: 'https://api.hcaptcha.com/checksiteconfig?v=xxx&host=b.stripecdn.com&sitekey=xxx&sc=1&swa=1&spst=1',
|
||||
entryType: 'resource',
|
||||
initiatorType: 'xmlhttprequest',
|
||||
startTime: 399.2,
|
||||
duration: 643.1,
|
||||
fetchStart: 399.2,
|
||||
responseEnd: 1042.3,
|
||||
transferSize: 0,
|
||||
encodedBodySize: 0,
|
||||
decodedBodySize: 0,
|
||||
responseStatus: 200,
|
||||
deliveryType: '',
|
||||
nextHopProtocol: '',
|
||||
contentEncoding: 'br',
|
||||
workerStart: 0,
|
||||
redirectStart: 0,
|
||||
redirectEnd: 0,
|
||||
domainLookupStart: 0,
|
||||
domainLookupEnd: 0,
|
||||
connectStart: 0,
|
||||
secureConnectionStart: 0,
|
||||
connectEnd: 0,
|
||||
requestStart: 0,
|
||||
responseStart: 0,
|
||||
firstInterimResponseStart: 0,
|
||||
finalResponseHeadersStart: 0, // P2 要求的字段
|
||||
serverTiming: [],
|
||||
renderBlockingStatus: 'non-blocking',
|
||||
},
|
||||
{
|
||||
name: 'https://newassets.hcaptcha.com/c/xxx/hsw.js',
|
||||
entryType: 'resource',
|
||||
initiatorType: 'script',
|
||||
deliveryType: 'cache',
|
||||
nextHopProtocol: 'h2',
|
||||
startTime: 1043.8,
|
||||
duration: 5.7,
|
||||
fetchStart: 1043.8,
|
||||
domainLookupStart: 1043.8,
|
||||
domainLookupEnd: 1043.8,
|
||||
connectStart: 1043.8,
|
||||
secureConnectionStart: 1043.8,
|
||||
connectEnd: 1043.8,
|
||||
requestStart: 1044.6,
|
||||
responseStart: 1044.6,
|
||||
firstInterimResponseStart: 1044.6,
|
||||
finalResponseHeadersStart: 0,
|
||||
responseEnd: 1049.5,
|
||||
transferSize: 0,
|
||||
encodedBodySize: 359059,
|
||||
decodedBodySize: 829689,
|
||||
responseStatus: 200,
|
||||
contentEncoding: 'gzip',
|
||||
workerStart: 0,
|
||||
redirectStart: 0,
|
||||
redirectEnd: 0,
|
||||
serverTiming: [],
|
||||
renderBlockingStatus: 'non-blocking',
|
||||
},
|
||||
];
|
||||
|
||||
// Navigation (deprecated)
|
||||
navigation: {
|
||||
type: 0, // TYPE_NAVIGATE
|
||||
redirectCount: 0,
|
||||
},
|
||||
// 模拟 navigation 条目
|
||||
const navigationEntry = {
|
||||
name: 'https://newassets.hcaptcha.com/captcha/v1/xxx/static/hcaptcha.html',
|
||||
entryType: 'navigation',
|
||||
initiatorType: 'navigation',
|
||||
deliveryType: 'cache',
|
||||
nextHopProtocol: 'h2',
|
||||
startTime: 0,
|
||||
duration: 399.9,
|
||||
fetchStart: 11.6,
|
||||
domainLookupStart: 11.6,
|
||||
domainLookupEnd: 11.6,
|
||||
connectStart: 11.6,
|
||||
secureConnectionStart: 11.6,
|
||||
connectEnd: 11.6,
|
||||
requestStart: 37.6,
|
||||
responseStart: 47.4,
|
||||
firstInterimResponseStart: 47.4,
|
||||
finalResponseHeadersStart: 0,
|
||||
responseEnd: 114.2,
|
||||
transferSize: 0,
|
||||
encodedBodySize: 167487,
|
||||
decodedBodySize: 567885,
|
||||
responseStatus: 200,
|
||||
redirectStart: 0,
|
||||
redirectEnd: 0,
|
||||
unloadEventStart: 0,
|
||||
unloadEventEnd: 0,
|
||||
domInteractive: 399.4,
|
||||
domContentLoadedEventStart: 399.5,
|
||||
domContentLoadedEventEnd: 399.5,
|
||||
domComplete: 399.8,
|
||||
loadEventStart: 399.9,
|
||||
loadEventEnd: 399.9,
|
||||
type: 'navigate',
|
||||
redirectCount: 0,
|
||||
activationStart: 0,
|
||||
criticalCHRestart: 0,
|
||||
notRestoredReasons: null,
|
||||
confidence: null,
|
||||
serverTiming: [],
|
||||
workerStart: 0,
|
||||
contentEncoding: 'br',
|
||||
renderBlockingStatus: 'non-blocking',
|
||||
};
|
||||
|
||||
// Memory (Chrome-specific)
|
||||
memory: {
|
||||
jsHeapSizeLimit: 4294705152,
|
||||
totalJSHeapSize: 35000000,
|
||||
usedJSHeapSize: 25000000,
|
||||
},
|
||||
const performanceMock = {
|
||||
timeOrigin: NAV_START,
|
||||
timing: timingData,
|
||||
navigation: { type: 0, redirectCount: 0 },
|
||||
|
||||
// Event counts (Chrome)
|
||||
eventCounts: {
|
||||
size: 0,
|
||||
get: () => 0,
|
||||
has: () => false,
|
||||
keys: () => [][Symbol.iterator](),
|
||||
values: () => [][Symbol.iterator](),
|
||||
entries: () => [][Symbol.iterator](),
|
||||
forEach: () => {},
|
||||
[Symbol.iterator]: () => [][Symbol.iterator](),
|
||||
},
|
||||
getEntriesByType: createNative('getEntriesByType', function (type) {
|
||||
if (type === 'resource') return resourceEntries;
|
||||
if (type === 'navigation') return [navigationEntry];
|
||||
return [];
|
||||
}),
|
||||
|
||||
// Entry methods
|
||||
getEntries() {
|
||||
return [...entries];
|
||||
},
|
||||
getEntriesByName: createNative('getEntriesByName', function (name) {
|
||||
return resourceEntries.filter(e => e.name === name);
|
||||
}),
|
||||
|
||||
getEntriesByType(type) {
|
||||
return entries.filter(e => e.entryType === type);
|
||||
},
|
||||
now: createNative('now', function () {
|
||||
return Date.now() - NAV_START;
|
||||
}),
|
||||
|
||||
getEntriesByName(name, type) {
|
||||
return entries.filter(e =>
|
||||
e.name === name && (!type || e.entryType === type)
|
||||
);
|
||||
},
|
||||
mark: createNative('mark', function () {}),
|
||||
measure: createNative('measure', function () {}),
|
||||
clearMarks: createNative('clearMarks', function () {}),
|
||||
clearMeasures: createNative('clearMeasures', function () {}),
|
||||
};
|
||||
|
||||
// Marks and measures
|
||||
mark(name, options) {
|
||||
const entry = {
|
||||
name,
|
||||
entryType: 'mark',
|
||||
startTime: this.now(),
|
||||
duration: 0,
|
||||
detail: options?.detail || null,
|
||||
};
|
||||
entries.push(entry);
|
||||
return entry;
|
||||
},
|
||||
|
||||
measure(name, startMark, endMark) {
|
||||
const startTime = typeof startMark === 'string'
|
||||
? (entries.find(e => e.name === startMark)?.startTime || 0)
|
||||
: (startMark?.start || 0);
|
||||
const endTime = typeof endMark === 'string'
|
||||
? (entries.find(e => e.name === endMark)?.startTime || this.now())
|
||||
: (endMark?.end || this.now());
|
||||
|
||||
const entry = {
|
||||
name,
|
||||
entryType: 'measure',
|
||||
startTime,
|
||||
duration: endTime - startTime,
|
||||
};
|
||||
entries.push(entry);
|
||||
return entry;
|
||||
},
|
||||
|
||||
clearMarks(name) {
|
||||
if (name) {
|
||||
const idx = entries.findIndex(e => e.name === name && e.entryType === 'mark');
|
||||
if (idx > -1) entries.splice(idx, 1);
|
||||
} else {
|
||||
entries.splice(0, entries.length, ...entries.filter(e => e.entryType !== 'mark'));
|
||||
}
|
||||
},
|
||||
|
||||
clearMeasures(name) {
|
||||
if (name) {
|
||||
const idx = entries.findIndex(e => e.name === name && e.entryType === 'measure');
|
||||
if (idx > -1) entries.splice(idx, 1);
|
||||
} else {
|
||||
entries.splice(0, entries.length, ...entries.filter(e => e.entryType !== 'measure'));
|
||||
}
|
||||
},
|
||||
|
||||
clearResourceTimings() {
|
||||
entries.splice(0, entries.length, ...entries.filter(e => e.entryType !== 'resource'));
|
||||
},
|
||||
|
||||
setResourceTimingBufferSize() {},
|
||||
|
||||
// Observer
|
||||
observe() {},
|
||||
|
||||
// JSON
|
||||
toJSON() {
|
||||
return {
|
||||
timeOrigin: this.timeOrigin,
|
||||
timing: this.timing,
|
||||
navigation: this.navigation,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
module.exports = performanceMock;
|
||||
|
||||
Reference in New Issue
Block a user