├── .gitignore ├── README.md ├── consts ├── script.go └── type.go ├── example └── main.go ├── go.mod ├── go.sum ├── utils ├── cookie.go ├── help.go └── utils.go └── xhs ├── api.go └── xhs.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xhs-go 2 | 3 | -------------------------------------------------------------------------------- /consts/script.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const StealthMinJs = "/*!\n * Note: Auto-generated, do not update manually.\n * Generated by: https://github.com/berstend/puppeteer-extra/tree/master/packages/extract-stealth-evasions\n * Generated on: Mon, 26 Jun 2023 06:21:46 GMT\n * License: MIT\n */\n(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:\"() => {\\n utils.preloadCache()\\n}\",stripProxyFromErrors:\"(handler = {}) => {\\n const newHandler = {\\n setPrototypeOf: function (target, proto) {\\n if (proto === null)\\n throw new TypeError('Cannot convert object to primitive value')\\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\\n throw new TypeError('Cyclic __proto__ value')\\n }\\n return Reflect.setPrototypeOf(target, proto)\\n }\\n }\\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\\n const traps = Object.getOwnPropertyNames(handler)\\n traps.forEach(trap => {\\n newHandler[trap] = function () {\\n try {\\n // Forward the call to the defined proxy handler\\n return handler[trap].apply(this, arguments || [])\\n } catch (err) {\\n // Stack traces differ per browser, we only support chromium based ones currently\\n if (!err || !err.stack || !err.stack.includes(`at `)) {\\n throw err\\n }\\n\\n // When something throws within one of our traps the Proxy will show up in error stacks\\n // An earlier implementation of this code would simply strip lines with a blacklist,\\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\\n // We try to use a known \\\"anchor\\\" line for that and strip it with everything above it.\\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\\n\\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\\n const blacklist = [\\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\\n `at Object.${trap} `, // e.g. Object.get or Object.apply\\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\\n ]\\n return (\\n err.stack\\n .split('\\\\n')\\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\\n .filter((line, index) => !(index === 1 && stripFirstLine))\\n // Check if the line starts with one of our blacklisted strings\\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\\n .join('\\\\n')\\n )\\n }\\n\\n const stripWithAnchor = (stack, anchor) => {\\n const stackArr = stack.split('\\\\n')\\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\\n const anchorIndex = stackArr.findIndex(line =>\\n line.trim().startsWith(anchor)\\n )\\n if (anchorIndex === -1) {\\n return false // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n return stackArr.join('\\\\n')\\n }\\n\\n // Special cases due to our nested toString proxies\\n err.stack = err.stack.replace(\\n 'at Object.toString (',\\n 'at Function.toString ('\\n )\\n if ((err.stack || '').includes('at Function.toString (')) {\\n err.stack = stripWithBlacklist(err.stack, false)\\n throw err\\n }\\n\\n // Try using the anchor method, fallback to blacklist if necessary\\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\\n\\n throw err // Re-throw our now sanitized error\\n }\\n }\\n })\\n return newHandler\\n}\",stripErrorWithAnchor:\"(err, anchor) => {\\n const stackArr = err.stack.split('\\\\n')\\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\\n if (anchorIndex === -1) {\\n return err // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n err.stack = stackArr.join('\\\\n')\\n return err\\n}\",replaceProperty:\"(obj, propName, descriptorOverrides = {}) => {\\n return Object.defineProperty(obj, propName, {\\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\\n // Add our overrides (e.g. value, get())\\n ...descriptorOverrides\\n })\\n}\",preloadCache:\"() => {\\n if (utils.cache) {\\n return\\n }\\n utils.cache = {\\n // Used in our proxies\\n Reflect: {\\n get: Reflect.get.bind(Reflect),\\n apply: Reflect.apply.bind(Reflect)\\n },\\n // Used in `makeNativeString`\\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\\n }\\n}\",makeNativeString:\"(name = '') => {\\n return utils.cache.nativeToStringStr.replace('toString', name || '')\\n}\",patchToString:\"(obj, str = '') => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n // `toString` targeted at our proxied Object detected\\n if (ctx === obj) {\\n // We either return the optional string verbatim or derive the most desired result automatically\\n return str || utils.makeNativeString(obj.name)\\n }\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",patchToStringNested:\"(obj = {}) => {\\n return utils.execRecursively(obj, ['function'], utils.patchToString)\\n}\",redirectToString:\"(proxyObj, originalObj) => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n\\n // `toString` targeted at our proxied Object detected\\n if (ctx === proxyObj) {\\n const fallback = () =>\\n originalObj && originalObj.name\\n ? utils.makeNativeString(originalObj.name)\\n : utils.makeNativeString(proxyObj.name)\\n\\n // Return the toString representation of our original object if possible\\n return originalObj + '' || fallback()\\n }\\n\\n if (typeof ctx === 'undefined' || ctx === null) {\\n return target.call(ctx)\\n }\\n\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",replaceWithProxy:\"(obj, propName, handler) => {\\n const originalObj = obj[propName]\\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.redirectToString(proxyObj, originalObj)\\n\\n return true\\n}\",replaceGetterWithProxy:\"(obj, propName, handler) => {\\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\\n const fnStr = fn.toString() // special getter function string\\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { get: proxyObj })\\n utils.patchToString(proxyObj, fnStr)\\n\\n return true\\n}\",replaceGetterSetter:\"(obj, propName, handlerGetterSetter) => {\\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\\n const handler = { ...ownPropertyDescriptor }\\n\\n if (handlerGetterSetter.get !== undefined) {\\n const nativeFn = ownPropertyDescriptor.get\\n handler.get = function() {\\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.get, nativeFn)\\n }\\n\\n if (handlerGetterSetter.set !== undefined) {\\n const nativeFn = ownPropertyDescriptor.set\\n handler.set = function(newValue) {\\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.set, nativeFn)\\n }\\n\\n Object.defineProperty(obj, propName, handler)\\n}\",mockWithProxy:\"(obj, propName, pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.patchToString(proxyObj)\\n\\n return true\\n}\",createProxy:\"(pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n utils.patchToString(proxyObj)\\n\\n return proxyObj\\n}\",splitObjPath:\"objPath => ({\\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\\n objName: objPath.split('.').slice(0, -1).join('.'),\\n // Extract last dot entry ==> `canPlayType`\\n propName: objPath.split('.').slice(-1)[0]\\n})\",replaceObjPathWithProxy:\"(objPath, handler) => {\\n const { objName, propName } = utils.splitObjPath(objPath)\\n const obj = eval(objName) // eslint-disable-line no-eval\\n return utils.replaceWithProxy(obj, propName, handler)\\n}\",execRecursively:\"(obj = {}, typeFilter = [], fn) => {\\n function recurse(obj) {\\n for (const key in obj) {\\n if (obj[key] === undefined) {\\n continue\\n }\\n if (obj[key] && typeof obj[key] === 'object') {\\n recurse(obj[key])\\n } else {\\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\\n fn.call(this, obj[key])\\n }\\n }\\n }\\n }\\n recurse(obj)\\n return obj\\n}\",stringifyFns:\"(fnObj = { hello: () => 'world' }) => {\\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\\n // https://github.com/feross/fromentries\\n function fromEntries(iterable) {\\n return [...iterable].reduce((obj, [key, val]) => {\\n obj[key] = val\\n return obj\\n }, {})\\n }\\n return (Object.fromEntries || fromEntries)(\\n Object.entries(fnObj)\\n .filter(([key, value]) => typeof value === 'function')\\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\\n )\\n}\",materializeFns:\"(fnStrObj = { hello: \\\"() => 'world'\\\" }) => {\\n return Object.fromEntries(\\n Object.entries(fnStrObj).map(([key, value]) => {\\n if (value.startsWith('function')) {\\n // some trickery is needed to make oldschool functions work :-)\\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\\n } else {\\n // arrow functions just work\\n return [key, eval(value)] // eslint-disable-line no-eval\\n }\\n })\\n )\\n}\",makeHandler:\"() => ({\\n // Used by simple `navigator` getter evasions\\n getterValue: value => ({\\n apply(target, ctx, args) {\\n // Let's fetch the value first, to trigger and escalate potential errors\\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\\n utils.cache.Reflect.apply(...arguments)\\n return value\\n }\\n })\\n})\",arrayEquals:\"(array1, array2) => {\\n if (array1.length !== array2.length) {\\n return false\\n }\\n for (let i = 0; i < array1.length; ++i) {\\n if (array1[i] !== array2[i]) {\\n return false\\n }\\n }\\n return true\\n}\",memoize:\"fn => {\\n const cache = []\\n return function(...args) {\\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\\n cache.push({ key: args, value: fn.apply(this, args) })\\n }\\n return cache.find(c => utils.arrayEquals(c.key, args)).value\\n }\\n}\"},_mainFunction:'utils => {\\n if (!window.chrome) {\\n // Use the exact property descriptor found in headful Chrome\\n // fetch it via `Object.getOwnPropertyDescriptor(window, \\'chrome\\')`\\n Object.defineProperty(window, \\'chrome\\', {\\n writable: true,\\n enumerable: true,\\n configurable: false, // note!\\n value: {} // We\\'ll extend that later\\n })\\n }\\n\\n // That means we\\'re running headful and don\\'t need to mock anything\\n if (\\'app\\' in window.chrome) {\\n return // Nothing to do here\\n }\\n\\n const makeError = {\\n ErrorInInvocation: fn => {\\n const err = new TypeError(`Error in invocation of app.${fn}()`)\\n return utils.stripErrorWithAnchor(\\n err,\\n `at ${fn} (eval at `\\n )\\n }\\n }\\n\\n // There\\'s a some static data in that property which doesn\\'t seem to change,\\n // we should periodically check for updates: `JSON.stringify(window.app, null, 2)`\\n const STATIC_DATA = JSON.parse(\\n `\\n{\\n \"isInstalled\": false,\\n \"InstallState\": {\\n \"DISABLED\": \"disabled\",\\n \"INSTALLED\": \"installed\",\\n \"NOT_INSTALLED\": \"not_installed\"\\n },\\n \"RunningState\": {\\n \"CANNOT_RUN\": \"cannot_run\",\\n \"READY_TO_RUN\": \"ready_to_run\",\\n \"RUNNING\": \"running\"\\n }\\n}\\n `.trim()\\n )\\n\\n window.chrome.app = {\\n ...STATIC_DATA,\\n\\n get isInstalled() {\\n return false\\n },\\n\\n getDetails: function getDetails() {\\n if (arguments.length) {\\n throw makeError.ErrorInInvocation(`getDetails`)\\n }\\n return null\\n },\\n getIsInstalled: function getDetails() {\\n if (arguments.length) {\\n throw makeError.ErrorInInvocation(`getIsInstalled`)\\n }\\n return false\\n },\\n runningState: function getDetails() {\\n if (arguments.length) {\\n throw makeError.ErrorInInvocation(`runningState`)\\n }\\n return \\'cannot_run\\'\\n }\\n }\\n utils.patchToStringNested(window.chrome.app)\\n }',_args:[]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:\"() => {\\n utils.preloadCache()\\n}\",stripProxyFromErrors:\"(handler = {}) => {\\n const newHandler = {\\n setPrototypeOf: function (target, proto) {\\n if (proto === null)\\n throw new TypeError('Cannot convert object to primitive value')\\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\\n throw new TypeError('Cyclic __proto__ value')\\n }\\n return Reflect.setPrototypeOf(target, proto)\\n }\\n }\\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\\n const traps = Object.getOwnPropertyNames(handler)\\n traps.forEach(trap => {\\n newHandler[trap] = function () {\\n try {\\n // Forward the call to the defined proxy handler\\n return handler[trap].apply(this, arguments || [])\\n } catch (err) {\\n // Stack traces differ per browser, we only support chromium based ones currently\\n if (!err || !err.stack || !err.stack.includes(`at `)) {\\n throw err\\n }\\n\\n // When something throws within one of our traps the Proxy will show up in error stacks\\n // An earlier implementation of this code would simply strip lines with a blacklist,\\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\\n // We try to use a known \\\"anchor\\\" line for that and strip it with everything above it.\\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\\n\\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\\n const blacklist = [\\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\\n `at Object.${trap} `, // e.g. Object.get or Object.apply\\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\\n ]\\n return (\\n err.stack\\n .split('\\\\n')\\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\\n .filter((line, index) => !(index === 1 && stripFirstLine))\\n // Check if the line starts with one of our blacklisted strings\\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\\n .join('\\\\n')\\n )\\n }\\n\\n const stripWithAnchor = (stack, anchor) => {\\n const stackArr = stack.split('\\\\n')\\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\\n const anchorIndex = stackArr.findIndex(line =>\\n line.trim().startsWith(anchor)\\n )\\n if (anchorIndex === -1) {\\n return false // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n return stackArr.join('\\\\n')\\n }\\n\\n // Special cases due to our nested toString proxies\\n err.stack = err.stack.replace(\\n 'at Object.toString (',\\n 'at Function.toString ('\\n )\\n if ((err.stack || '').includes('at Function.toString (')) {\\n err.stack = stripWithBlacklist(err.stack, false)\\n throw err\\n }\\n\\n // Try using the anchor method, fallback to blacklist if necessary\\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\\n\\n throw err // Re-throw our now sanitized error\\n }\\n }\\n })\\n return newHandler\\n}\",stripErrorWithAnchor:\"(err, anchor) => {\\n const stackArr = err.stack.split('\\\\n')\\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\\n if (anchorIndex === -1) {\\n return err // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n err.stack = stackArr.join('\\\\n')\\n return err\\n}\",replaceProperty:\"(obj, propName, descriptorOverrides = {}) => {\\n return Object.defineProperty(obj, propName, {\\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\\n // Add our overrides (e.g. value, get())\\n ...descriptorOverrides\\n })\\n}\",preloadCache:\"() => {\\n if (utils.cache) {\\n return\\n }\\n utils.cache = {\\n // Used in our proxies\\n Reflect: {\\n get: Reflect.get.bind(Reflect),\\n apply: Reflect.apply.bind(Reflect)\\n },\\n // Used in `makeNativeString`\\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\\n }\\n}\",makeNativeString:\"(name = '') => {\\n return utils.cache.nativeToStringStr.replace('toString', name || '')\\n}\",patchToString:\"(obj, str = '') => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n // `toString` targeted at our proxied Object detected\\n if (ctx === obj) {\\n // We either return the optional string verbatim or derive the most desired result automatically\\n return str || utils.makeNativeString(obj.name)\\n }\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",patchToStringNested:\"(obj = {}) => {\\n return utils.execRecursively(obj, ['function'], utils.patchToString)\\n}\",redirectToString:\"(proxyObj, originalObj) => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n\\n // `toString` targeted at our proxied Object detected\\n if (ctx === proxyObj) {\\n const fallback = () =>\\n originalObj && originalObj.name\\n ? utils.makeNativeString(originalObj.name)\\n : utils.makeNativeString(proxyObj.name)\\n\\n // Return the toString representation of our original object if possible\\n return originalObj + '' || fallback()\\n }\\n\\n if (typeof ctx === 'undefined' || ctx === null) {\\n return target.call(ctx)\\n }\\n\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",replaceWithProxy:\"(obj, propName, handler) => {\\n const originalObj = obj[propName]\\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.redirectToString(proxyObj, originalObj)\\n\\n return true\\n}\",replaceGetterWithProxy:\"(obj, propName, handler) => {\\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\\n const fnStr = fn.toString() // special getter function string\\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { get: proxyObj })\\n utils.patchToString(proxyObj, fnStr)\\n\\n return true\\n}\",replaceGetterSetter:\"(obj, propName, handlerGetterSetter) => {\\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\\n const handler = { ...ownPropertyDescriptor }\\n\\n if (handlerGetterSetter.get !== undefined) {\\n const nativeFn = ownPropertyDescriptor.get\\n handler.get = function() {\\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.get, nativeFn)\\n }\\n\\n if (handlerGetterSetter.set !== undefined) {\\n const nativeFn = ownPropertyDescriptor.set\\n handler.set = function(newValue) {\\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.set, nativeFn)\\n }\\n\\n Object.defineProperty(obj, propName, handler)\\n}\",mockWithProxy:\"(obj, propName, pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.patchToString(proxyObj)\\n\\n return true\\n}\",createProxy:\"(pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n utils.patchToString(proxyObj)\\n\\n return proxyObj\\n}\",splitObjPath:\"objPath => ({\\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\\n objName: objPath.split('.').slice(0, -1).join('.'),\\n // Extract last dot entry ==> `canPlayType`\\n propName: objPath.split('.').slice(-1)[0]\\n})\",replaceObjPathWithProxy:\"(objPath, handler) => {\\n const { objName, propName } = utils.splitObjPath(objPath)\\n const obj = eval(objName) // eslint-disable-line no-eval\\n return utils.replaceWithProxy(obj, propName, handler)\\n}\",execRecursively:\"(obj = {}, typeFilter = [], fn) => {\\n function recurse(obj) {\\n for (const key in obj) {\\n if (obj[key] === undefined) {\\n continue\\n }\\n if (obj[key] && typeof obj[key] === 'object') {\\n recurse(obj[key])\\n } else {\\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\\n fn.call(this, obj[key])\\n }\\n }\\n }\\n }\\n recurse(obj)\\n return obj\\n}\",stringifyFns:\"(fnObj = { hello: () => 'world' }) => {\\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\\n // https://github.com/feross/fromentries\\n function fromEntries(iterable) {\\n return [...iterable].reduce((obj, [key, val]) => {\\n obj[key] = val\\n return obj\\n }, {})\\n }\\n return (Object.fromEntries || fromEntries)(\\n Object.entries(fnObj)\\n .filter(([key, value]) => typeof value === 'function')\\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\\n )\\n}\",materializeFns:\"(fnStrObj = { hello: \\\"() => 'world'\\\" }) => {\\n return Object.fromEntries(\\n Object.entries(fnStrObj).map(([key, value]) => {\\n if (value.startsWith('function')) {\\n // some trickery is needed to make oldschool functions work :-)\\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\\n } else {\\n // arrow functions just work\\n return [key, eval(value)] // eslint-disable-line no-eval\\n }\\n })\\n )\\n}\",makeHandler:\"() => ({\\n // Used by simple `navigator` getter evasions\\n getterValue: value => ({\\n apply(target, ctx, args) {\\n // Let's fetch the value first, to trigger and escalate potential errors\\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\\n utils.cache.Reflect.apply(...arguments)\\n return value\\n }\\n })\\n})\",arrayEquals:\"(array1, array2) => {\\n if (array1.length !== array2.length) {\\n return false\\n }\\n for (let i = 0; i < array1.length; ++i) {\\n if (array1[i] !== array2[i]) {\\n return false\\n }\\n }\\n return true\\n}\",memoize:\"fn => {\\n const cache = []\\n return function(...args) {\\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\\n cache.push({ key: args, value: fn.apply(this, args) })\\n }\\n return cache.find(c => utils.arrayEquals(c.key, args)).value\\n }\\n}\"},_mainFunction:\"utils => {\\n if (!window.chrome) {\\n // Use the exact property descriptor found in headful Chrome\\n // fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')`\\n Object.defineProperty(window, 'chrome', {\\n writable: true,\\n enumerable: true,\\n configurable: false, // note!\\n value: {} // We'll extend that later\\n })\\n }\\n\\n // That means we're running headful and don't need to mock anything\\n if ('csi' in window.chrome) {\\n return // Nothing to do here\\n }\\n\\n // Check that the Navigation Timing API v1 is available, we need that\\n if (!window.performance || !window.performance.timing) {\\n return\\n }\\n\\n const { timing } = window.performance\\n\\n window.chrome.csi = function() {\\n return {\\n onloadT: timing.domContentLoadedEventEnd,\\n startE: timing.navigationStart,\\n pageT: Date.now() - timing.navigationStart,\\n tran: 15 // Transition type or something\\n }\\n }\\n utils.patchToString(window.chrome.csi)\\n }\",_args:[]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:\"() => {\\n utils.preloadCache()\\n}\",stripProxyFromErrors:\"(handler = {}) => {\\n const newHandler = {\\n setPrototypeOf: function (target, proto) {\\n if (proto === null)\\n throw new TypeError('Cannot convert object to primitive value')\\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\\n throw new TypeError('Cyclic __proto__ value')\\n }\\n return Reflect.setPrototypeOf(target, proto)\\n }\\n }\\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\\n const traps = Object.getOwnPropertyNames(handler)\\n traps.forEach(trap => {\\n newHandler[trap] = function () {\\n try {\\n // Forward the call to the defined proxy handler\\n return handler[trap].apply(this, arguments || [])\\n } catch (err) {\\n // Stack traces differ per browser, we only support chromium based ones currently\\n if (!err || !err.stack || !err.stack.includes(`at `)) {\\n throw err\\n }\\n\\n // When something throws within one of our traps the Proxy will show up in error stacks\\n // An earlier implementation of this code would simply strip lines with a blacklist,\\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\\n // We try to use a known \\\"anchor\\\" line for that and strip it with everything above it.\\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\\n\\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\\n const blacklist = [\\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\\n `at Object.${trap} `, // e.g. Object.get or Object.apply\\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\\n ]\\n return (\\n err.stack\\n .split('\\\\n')\\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\\n .filter((line, index) => !(index === 1 && stripFirstLine))\\n // Check if the line starts with one of our blacklisted strings\\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\\n .join('\\\\n')\\n )\\n }\\n\\n const stripWithAnchor = (stack, anchor) => {\\n const stackArr = stack.split('\\\\n')\\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\\n const anchorIndex = stackArr.findIndex(line =>\\n line.trim().startsWith(anchor)\\n )\\n if (anchorIndex === -1) {\\n return false // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n return stackArr.join('\\\\n')\\n }\\n\\n // Special cases due to our nested toString proxies\\n err.stack = err.stack.replace(\\n 'at Object.toString (',\\n 'at Function.toString ('\\n )\\n if ((err.stack || '').includes('at Function.toString (')) {\\n err.stack = stripWithBlacklist(err.stack, false)\\n throw err\\n }\\n\\n // Try using the anchor method, fallback to blacklist if necessary\\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\\n\\n throw err // Re-throw our now sanitized error\\n }\\n }\\n })\\n return newHandler\\n}\",stripErrorWithAnchor:\"(err, anchor) => {\\n const stackArr = err.stack.split('\\\\n')\\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\\n if (anchorIndex === -1) {\\n return err // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n err.stack = stackArr.join('\\\\n')\\n return err\\n}\",replaceProperty:\"(obj, propName, descriptorOverrides = {}) => {\\n return Object.defineProperty(obj, propName, {\\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\\n // Add our overrides (e.g. value, get())\\n ...descriptorOverrides\\n })\\n}\",preloadCache:\"() => {\\n if (utils.cache) {\\n return\\n }\\n utils.cache = {\\n // Used in our proxies\\n Reflect: {\\n get: Reflect.get.bind(Reflect),\\n apply: Reflect.apply.bind(Reflect)\\n },\\n // Used in `makeNativeString`\\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\\n }\\n}\",makeNativeString:\"(name = '') => {\\n return utils.cache.nativeToStringStr.replace('toString', name || '')\\n}\",patchToString:\"(obj, str = '') => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n // `toString` targeted at our proxied Object detected\\n if (ctx === obj) {\\n // We either return the optional string verbatim or derive the most desired result automatically\\n return str || utils.makeNativeString(obj.name)\\n }\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",patchToStringNested:\"(obj = {}) => {\\n return utils.execRecursively(obj, ['function'], utils.patchToString)\\n}\",redirectToString:\"(proxyObj, originalObj) => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n\\n // `toString` targeted at our proxied Object detected\\n if (ctx === proxyObj) {\\n const fallback = () =>\\n originalObj && originalObj.name\\n ? utils.makeNativeString(originalObj.name)\\n : utils.makeNativeString(proxyObj.name)\\n\\n // Return the toString representation of our original object if possible\\n return originalObj + '' || fallback()\\n }\\n\\n if (typeof ctx === 'undefined' || ctx === null) {\\n return target.call(ctx)\\n }\\n\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",replaceWithProxy:\"(obj, propName, handler) => {\\n const originalObj = obj[propName]\\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.redirectToString(proxyObj, originalObj)\\n\\n return true\\n}\",replaceGetterWithProxy:\"(obj, propName, handler) => {\\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\\n const fnStr = fn.toString() // special getter function string\\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { get: proxyObj })\\n utils.patchToString(proxyObj, fnStr)\\n\\n return true\\n}\",replaceGetterSetter:\"(obj, propName, handlerGetterSetter) => {\\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\\n const handler = { ...ownPropertyDescriptor }\\n\\n if (handlerGetterSetter.get !== undefined) {\\n const nativeFn = ownPropertyDescriptor.get\\n handler.get = function() {\\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.get, nativeFn)\\n }\\n\\n if (handlerGetterSetter.set !== undefined) {\\n const nativeFn = ownPropertyDescriptor.set\\n handler.set = function(newValue) {\\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.set, nativeFn)\\n }\\n\\n Object.defineProperty(obj, propName, handler)\\n}\",mockWithProxy:\"(obj, propName, pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.patchToString(proxyObj)\\n\\n return true\\n}\",createProxy:\"(pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n utils.patchToString(proxyObj)\\n\\n return proxyObj\\n}\",splitObjPath:\"objPath => ({\\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\\n objName: objPath.split('.').slice(0, -1).join('.'),\\n // Extract last dot entry ==> `canPlayType`\\n propName: objPath.split('.').slice(-1)[0]\\n})\",replaceObjPathWithProxy:\"(objPath, handler) => {\\n const { objName, propName } = utils.splitObjPath(objPath)\\n const obj = eval(objName) // eslint-disable-line no-eval\\n return utils.replaceWithProxy(obj, propName, handler)\\n}\",execRecursively:\"(obj = {}, typeFilter = [], fn) => {\\n function recurse(obj) {\\n for (const key in obj) {\\n if (obj[key] === undefined) {\\n continue\\n }\\n if (obj[key] && typeof obj[key] === 'object') {\\n recurse(obj[key])\\n } else {\\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\\n fn.call(this, obj[key])\\n }\\n }\\n }\\n }\\n recurse(obj)\\n return obj\\n}\",stringifyFns:\"(fnObj = { hello: () => 'world' }) => {\\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\\n // https://github.com/feross/fromentries\\n function fromEntries(iterable) {\\n return [...iterable].reduce((obj, [key, val]) => {\\n obj[key] = val\\n return obj\\n }, {})\\n }\\n return (Object.fromEntries || fromEntries)(\\n Object.entries(fnObj)\\n .filter(([key, value]) => typeof value === 'function')\\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\\n )\\n}\",materializeFns:\"(fnStrObj = { hello: \\\"() => 'world'\\\" }) => {\\n return Object.fromEntries(\\n Object.entries(fnStrObj).map(([key, value]) => {\\n if (value.startsWith('function')) {\\n // some trickery is needed to make oldschool functions work :-)\\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\\n } else {\\n // arrow functions just work\\n return [key, eval(value)] // eslint-disable-line no-eval\\n }\\n })\\n )\\n}\",makeHandler:\"() => ({\\n // Used by simple `navigator` getter evasions\\n getterValue: value => ({\\n apply(target, ctx, args) {\\n // Let's fetch the value first, to trigger and escalate potential errors\\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\\n utils.cache.Reflect.apply(...arguments)\\n return value\\n }\\n })\\n})\",arrayEquals:\"(array1, array2) => {\\n if (array1.length !== array2.length) {\\n return false\\n }\\n for (let i = 0; i < array1.length; ++i) {\\n if (array1[i] !== array2[i]) {\\n return false\\n }\\n }\\n return true\\n}\",memoize:\"fn => {\\n const cache = []\\n return function(...args) {\\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\\n cache.push({ key: args, value: fn.apply(this, args) })\\n }\\n return cache.find(c => utils.arrayEquals(c.key, args)).value\\n }\\n}\"},_mainFunction:\"(utils, { opts }) => {\\n if (!window.chrome) {\\n // Use the exact property descriptor found in headful Chrome\\n // fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')`\\n Object.defineProperty(window, 'chrome', {\\n writable: true,\\n enumerable: true,\\n configurable: false, // note!\\n value: {} // We'll extend that later\\n })\\n }\\n\\n // That means we're running headful and don't need to mock anything\\n if ('loadTimes' in window.chrome) {\\n return // Nothing to do here\\n }\\n\\n // Check that the Navigation Timing API v1 + v2 is available, we need that\\n if (\\n !window.performance ||\\n !window.performance.timing ||\\n !window.PerformancePaintTiming\\n ) {\\n return\\n }\\n\\n const { performance } = window\\n\\n // Some stuff is not available on about:blank as it requires a navigation to occur,\\n // let's harden the code to not fail then:\\n const ntEntryFallback = {\\n nextHopProtocol: 'h2',\\n type: 'other'\\n }\\n\\n // The API exposes some funky info regarding the connection\\n const protocolInfo = {\\n get connectionInfo() {\\n const ntEntry =\\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\\n return ntEntry.nextHopProtocol\\n },\\n get npnNegotiatedProtocol() {\\n // NPN is deprecated in favor of ALPN, but this implementation returns the\\n // HTTP/2 or HTTP2+QUIC/39 requests negotiated via ALPN.\\n const ntEntry =\\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\\n return ['h2', 'hq'].includes(ntEntry.nextHopProtocol)\\n ? ntEntry.nextHopProtocol\\n : 'unknown'\\n },\\n get navigationType() {\\n const ntEntry =\\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\\n return ntEntry.type\\n },\\n get wasAlternateProtocolAvailable() {\\n // The Alternate-Protocol header is deprecated in favor of Alt-Svc\\n // (https://www.mnot.net/blog/2016/03/09/alt-svc), so technically this\\n // should always return false.\\n return false\\n },\\n get wasFetchedViaSpdy() {\\n // SPDY is deprecated in favor of HTTP/2, but this implementation returns\\n // true for HTTP/2 or HTTP2+QUIC/39 as well.\\n const ntEntry =\\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\\n return ['h2', 'hq'].includes(ntEntry.nextHopProtocol)\\n },\\n get wasNpnNegotiated() {\\n // NPN is deprecated in favor of ALPN, but this implementation returns true\\n // for HTTP/2 or HTTP2+QUIC/39 requests negotiated via ALPN.\\n const ntEntry =\\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\\n return ['h2', 'hq'].includes(ntEntry.nextHopProtocol)\\n }\\n }\\n\\n const { timing } = window.performance\\n\\n // Truncate number to specific number of decimals, most of the `loadTimes` stuff has 3\\n function toFixed(num, fixed) {\\n var re = new RegExp('^-?\\\\\\\\d+(?:.\\\\\\\\d{0,' + (fixed || -1) + '})?')\\n return num.toString().match(re)[0]\\n }\\n\\n const timingInfo = {\\n get firstPaintAfterLoadTime() {\\n // This was never actually implemented and always returns 0.\\n return 0\\n },\\n get requestTime() {\\n return timing.navigationStart / 1000\\n },\\n get startLoadTime() {\\n return timing.navigationStart / 1000\\n },\\n get commitLoadTime() {\\n return timing.responseStart / 1000\\n },\\n get finishDocumentLoadTime() {\\n return timing.domContentLoadedEventEnd / 1000\\n },\\n get finishLoadTime() {\\n return timing.loadEventEnd / 1000\\n },\\n get firstPaintTime() {\\n const fpEntry = performance.getEntriesByType('paint')[0] || {\\n startTime: timing.loadEventEnd / 1000 // Fallback if no navigation occured (`about:blank`)\\n }\\n return toFixed(\\n (fpEntry.startTime + performance.timeOrigin) / 1000,\\n 3\\n )\\n }\\n }\\n\\n window.chrome.loadTimes = function() {\\n return {\\n ...protocolInfo,\\n ...timingInfo\\n }\\n }\\n utils.patchToString(window.chrome.loadTimes)\\n }\",_args:[{opts:{}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:\"() => {\\n utils.preloadCache()\\n}\",stripProxyFromErrors:\"(handler = {}) => {\\n const newHandler = {\\n setPrototypeOf: function (target, proto) {\\n if (proto === null)\\n throw new TypeError('Cannot convert object to primitive value')\\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\\n throw new TypeError('Cyclic __proto__ value')\\n }\\n return Reflect.setPrototypeOf(target, proto)\\n }\\n }\\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\\n const traps = Object.getOwnPropertyNames(handler)\\n traps.forEach(trap => {\\n newHandler[trap] = function () {\\n try {\\n // Forward the call to the defined proxy handler\\n return handler[trap].apply(this, arguments || [])\\n } catch (err) {\\n // Stack traces differ per browser, we only support chromium based ones currently\\n if (!err || !err.stack || !err.stack.includes(`at `)) {\\n throw err\\n }\\n\\n // When something throws within one of our traps the Proxy will show up in error stacks\\n // An earlier implementation of this code would simply strip lines with a blacklist,\\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\\n // We try to use a known \\\"anchor\\\" line for that and strip it with everything above it.\\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\\n\\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\\n const blacklist = [\\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\\n `at Object.${trap} `, // e.g. Object.get or Object.apply\\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\\n ]\\n return (\\n err.stack\\n .split('\\\\n')\\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\\n .filter((line, index) => !(index === 1 && stripFirstLine))\\n // Check if the line starts with one of our blacklisted strings\\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\\n .join('\\\\n')\\n )\\n }\\n\\n const stripWithAnchor = (stack, anchor) => {\\n const stackArr = stack.split('\\\\n')\\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\\n const anchorIndex = stackArr.findIndex(line =>\\n line.trim().startsWith(anchor)\\n )\\n if (anchorIndex === -1) {\\n return false // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n return stackArr.join('\\\\n')\\n }\\n\\n // Special cases due to our nested toString proxies\\n err.stack = err.stack.replace(\\n 'at Object.toString (',\\n 'at Function.toString ('\\n )\\n if ((err.stack || '').includes('at Function.toString (')) {\\n err.stack = stripWithBlacklist(err.stack, false)\\n throw err\\n }\\n\\n // Try using the anchor method, fallback to blacklist if necessary\\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\\n\\n throw err // Re-throw our now sanitized error\\n }\\n }\\n })\\n return newHandler\\n}\",stripErrorWithAnchor:\"(err, anchor) => {\\n const stackArr = err.stack.split('\\\\n')\\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\\n if (anchorIndex === -1) {\\n return err // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n err.stack = stackArr.join('\\\\n')\\n return err\\n}\",replaceProperty:\"(obj, propName, descriptorOverrides = {}) => {\\n return Object.defineProperty(obj, propName, {\\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\\n // Add our overrides (e.g. value, get())\\n ...descriptorOverrides\\n })\\n}\",preloadCache:\"() => {\\n if (utils.cache) {\\n return\\n }\\n utils.cache = {\\n // Used in our proxies\\n Reflect: {\\n get: Reflect.get.bind(Reflect),\\n apply: Reflect.apply.bind(Reflect)\\n },\\n // Used in `makeNativeString`\\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\\n }\\n}\",makeNativeString:\"(name = '') => {\\n return utils.cache.nativeToStringStr.replace('toString', name || '')\\n}\",patchToString:\"(obj, str = '') => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n // `toString` targeted at our proxied Object detected\\n if (ctx === obj) {\\n // We either return the optional string verbatim or derive the most desired result automatically\\n return str || utils.makeNativeString(obj.name)\\n }\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",patchToStringNested:\"(obj = {}) => {\\n return utils.execRecursively(obj, ['function'], utils.patchToString)\\n}\",redirectToString:\"(proxyObj, originalObj) => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n\\n // `toString` targeted at our proxied Object detected\\n if (ctx === proxyObj) {\\n const fallback = () =>\\n originalObj && originalObj.name\\n ? utils.makeNativeString(originalObj.name)\\n : utils.makeNativeString(proxyObj.name)\\n\\n // Return the toString representation of our original object if possible\\n return originalObj + '' || fallback()\\n }\\n\\n if (typeof ctx === 'undefined' || ctx === null) {\\n return target.call(ctx)\\n }\\n\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",replaceWithProxy:\"(obj, propName, handler) => {\\n const originalObj = obj[propName]\\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.redirectToString(proxyObj, originalObj)\\n\\n return true\\n}\",replaceGetterWithProxy:\"(obj, propName, handler) => {\\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\\n const fnStr = fn.toString() // special getter function string\\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { get: proxyObj })\\n utils.patchToString(proxyObj, fnStr)\\n\\n return true\\n}\",replaceGetterSetter:\"(obj, propName, handlerGetterSetter) => {\\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\\n const handler = { ...ownPropertyDescriptor }\\n\\n if (handlerGetterSetter.get !== undefined) {\\n const nativeFn = ownPropertyDescriptor.get\\n handler.get = function() {\\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.get, nativeFn)\\n }\\n\\n if (handlerGetterSetter.set !== undefined) {\\n const nativeFn = ownPropertyDescriptor.set\\n handler.set = function(newValue) {\\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.set, nativeFn)\\n }\\n\\n Object.defineProperty(obj, propName, handler)\\n}\",mockWithProxy:\"(obj, propName, pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.patchToString(proxyObj)\\n\\n return true\\n}\",createProxy:\"(pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n utils.patchToString(proxyObj)\\n\\n return proxyObj\\n}\",splitObjPath:\"objPath => ({\\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\\n objName: objPath.split('.').slice(0, -1).join('.'),\\n // Extract last dot entry ==> `canPlayType`\\n propName: objPath.split('.').slice(-1)[0]\\n})\",replaceObjPathWithProxy:\"(objPath, handler) => {\\n const { objName, propName } = utils.splitObjPath(objPath)\\n const obj = eval(objName) // eslint-disable-line no-eval\\n return utils.replaceWithProxy(obj, propName, handler)\\n}\",execRecursively:\"(obj = {}, typeFilter = [], fn) => {\\n function recurse(obj) {\\n for (const key in obj) {\\n if (obj[key] === undefined) {\\n continue\\n }\\n if (obj[key] && typeof obj[key] === 'object') {\\n recurse(obj[key])\\n } else {\\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\\n fn.call(this, obj[key])\\n }\\n }\\n }\\n }\\n recurse(obj)\\n return obj\\n}\",stringifyFns:\"(fnObj = { hello: () => 'world' }) => {\\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\\n // https://github.com/feross/fromentries\\n function fromEntries(iterable) {\\n return [...iterable].reduce((obj, [key, val]) => {\\n obj[key] = val\\n return obj\\n }, {})\\n }\\n return (Object.fromEntries || fromEntries)(\\n Object.entries(fnObj)\\n .filter(([key, value]) => typeof value === 'function')\\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\\n )\\n}\",materializeFns:\"(fnStrObj = { hello: \\\"() => 'world'\\\" }) => {\\n return Object.fromEntries(\\n Object.entries(fnStrObj).map(([key, value]) => {\\n if (value.startsWith('function')) {\\n // some trickery is needed to make oldschool functions work :-)\\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\\n } else {\\n // arrow functions just work\\n return [key, eval(value)] // eslint-disable-line no-eval\\n }\\n })\\n )\\n}\",makeHandler:\"() => ({\\n // Used by simple `navigator` getter evasions\\n getterValue: value => ({\\n apply(target, ctx, args) {\\n // Let's fetch the value first, to trigger and escalate potential errors\\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\\n utils.cache.Reflect.apply(...arguments)\\n return value\\n }\\n })\\n})\",arrayEquals:\"(array1, array2) => {\\n if (array1.length !== array2.length) {\\n return false\\n }\\n for (let i = 0; i < array1.length; ++i) {\\n if (array1[i] !== array2[i]) {\\n return false\\n }\\n }\\n return true\\n}\",memoize:\"fn => {\\n const cache = []\\n return function(...args) {\\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\\n cache.push({ key: args, value: fn.apply(this, args) })\\n }\\n return cache.find(c => utils.arrayEquals(c.key, args)).value\\n }\\n}\"},_mainFunction:\"(utils, { opts, STATIC_DATA }) => {\\n if (!window.chrome) {\\n // Use the exact property descriptor found in headful Chrome\\n // fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')`\\n Object.defineProperty(window, 'chrome', {\\n writable: true,\\n enumerable: true,\\n configurable: false, // note!\\n value: {} // We'll extend that later\\n })\\n }\\n\\n // That means we're running headful and don't need to mock anything\\n const existsAlready = 'runtime' in window.chrome\\n // `chrome.runtime` is only exposed on secure origins\\n const isNotSecure = !window.location.protocol.startsWith('https')\\n if (existsAlready || (isNotSecure && !opts.runOnInsecureOrigins)) {\\n return // Nothing to do here\\n }\\n\\n window.chrome.runtime = {\\n // There's a bunch of static data in that property which doesn't seem to change,\\n // we should periodically check for updates: `JSON.stringify(window.chrome.runtime, null, 2)`\\n ...STATIC_DATA,\\n // `chrome.runtime.id` is extension related and returns undefined in Chrome\\n get id() {\\n return undefined\\n },\\n // These two require more sophisticated mocks\\n connect: null,\\n sendMessage: null\\n }\\n\\n const makeCustomRuntimeErrors = (preamble, method, extensionId) => ({\\n NoMatchingSignature: new TypeError(\\n preamble + `No matching signature.`\\n ),\\n MustSpecifyExtensionID: new TypeError(\\n preamble +\\n `${method} called from a webpage must specify an Extension ID (string) for its first argument.`\\n ),\\n InvalidExtensionID: new TypeError(\\n preamble + `Invalid extension id: '${extensionId}'`\\n )\\n })\\n\\n // Valid Extension IDs are 32 characters in length and use the letter `a` to `p`:\\n // https://source.chromium.org/chromium/chromium/src/+/master:components/crx_file/id_util.cc;drc=14a055ccb17e8c8d5d437fe080faba4c6f07beac;l=90\\n const isValidExtensionID = str =>\\n str.length === 32 && str.toLowerCase().match(/^[a-p]+$/)\\n\\n /** Mock `chrome.runtime.sendMessage` */\\n const sendMessageHandler = {\\n apply: function(target, ctx, args) {\\n const [extensionId, options, responseCallback] = args || []\\n\\n // Define custom errors\\n const errorPreamble = `Error in invocation of runtime.sendMessage(optional string extensionId, any message, optional object options, optional function responseCallback): `\\n const Errors = makeCustomRuntimeErrors(\\n errorPreamble,\\n `chrome.runtime.sendMessage()`,\\n extensionId\\n )\\n\\n // Check if the call signature looks ok\\n const noArguments = args.length === 0\\n const tooManyArguments = args.length > 4\\n const incorrectOptions = options && typeof options !== 'object'\\n const incorrectResponseCallback =\\n responseCallback && typeof responseCallback !== 'function'\\n if (\\n noArguments ||\\n tooManyArguments ||\\n incorrectOptions ||\\n incorrectResponseCallback\\n ) {\\n throw Errors.NoMatchingSignature\\n }\\n\\n // At least 2 arguments are required before we even validate the extension ID\\n if (args.length < 2) {\\n throw Errors.MustSpecifyExtensionID\\n }\\n\\n // Now let's make sure we got a string as extension ID\\n if (typeof extensionId !== 'string') {\\n throw Errors.NoMatchingSignature\\n }\\n\\n if (!isValidExtensionID(extensionId)) {\\n throw Errors.InvalidExtensionID\\n }\\n\\n return undefined // Normal behavior\\n }\\n }\\n utils.mockWithProxy(\\n window.chrome.runtime,\\n 'sendMessage',\\n function sendMessage() {},\\n sendMessageHandler\\n )\\n\\n /**\\n * Mock `chrome.runtime.connect`\\n *\\n * @see https://developer.chrome.com/apps/runtime#method-connect\\n */\\n const connectHandler = {\\n apply: function(target, ctx, args) {\\n const [extensionId, connectInfo] = args || []\\n\\n // Define custom errors\\n const errorPreamble = `Error in invocation of runtime.connect(optional string extensionId, optional object connectInfo): `\\n const Errors = makeCustomRuntimeErrors(\\n errorPreamble,\\n `chrome.runtime.connect()`,\\n extensionId\\n )\\n\\n // Behavior differs a bit from sendMessage:\\n const noArguments = args.length === 0\\n const emptyStringArgument = args.length === 1 && extensionId === ''\\n if (noArguments || emptyStringArgument) {\\n throw Errors.MustSpecifyExtensionID\\n }\\n\\n const tooManyArguments = args.length > 2\\n const incorrectConnectInfoType =\\n connectInfo && typeof connectInfo !== 'object'\\n\\n if (tooManyArguments || incorrectConnectInfoType) {\\n throw Errors.NoMatchingSignature\\n }\\n\\n const extensionIdIsString = typeof extensionId === 'string'\\n if (extensionIdIsString && extensionId === '') {\\n throw Errors.MustSpecifyExtensionID\\n }\\n if (extensionIdIsString && !isValidExtensionID(extensionId)) {\\n throw Errors.InvalidExtensionID\\n }\\n\\n // There's another edge-case here: extensionId is optional so we might find a connectInfo object as first param, which we need to validate\\n const validateConnectInfo = ci => {\\n // More than a first param connectInfo as been provided\\n if (args.length > 1) {\\n throw Errors.NoMatchingSignature\\n }\\n // An empty connectInfo has been provided\\n if (Object.keys(ci).length === 0) {\\n throw Errors.MustSpecifyExtensionID\\n }\\n // Loop over all connectInfo props an check them\\n Object.entries(ci).forEach(([k, v]) => {\\n const isExpected = ['name', 'includeTlsChannelId'].includes(k)\\n if (!isExpected) {\\n throw new TypeError(\\n errorPreamble + `Unexpected property: '${k}'.`\\n )\\n }\\n const MismatchError = (propName, expected, found) =>\\n TypeError(\\n errorPreamble +\\n `Error at property '${propName}': Invalid type: expected ${expected}, found ${found}.`\\n )\\n if (k === 'name' && typeof v !== 'string') {\\n throw MismatchError(k, 'string', typeof v)\\n }\\n if (k === 'includeTlsChannelId' && typeof v !== 'boolean') {\\n throw MismatchError(k, 'boolean', typeof v)\\n }\\n })\\n }\\n if (typeof extensionId === 'object') {\\n validateConnectInfo(extensionId)\\n throw Errors.MustSpecifyExtensionID\\n }\\n\\n // Unfortunately even when the connect fails Chrome will return an object with methods we need to mock as well\\n return utils.patchToStringNested(makeConnectResponse())\\n }\\n }\\n utils.mockWithProxy(\\n window.chrome.runtime,\\n 'connect',\\n function connect() {},\\n connectHandler\\n )\\n\\n function makeConnectResponse() {\\n const onSomething = () => ({\\n addListener: function addListener() {},\\n dispatch: function dispatch() {},\\n hasListener: function hasListener() {},\\n hasListeners: function hasListeners() {\\n return false\\n },\\n removeListener: function removeListener() {}\\n })\\n\\n const response = {\\n name: '',\\n sender: undefined,\\n disconnect: function disconnect() {},\\n onDisconnect: onSomething(),\\n onMessage: onSomething(),\\n postMessage: function postMessage() {\\n if (!arguments.length) {\\n throw new TypeError(`Insufficient number of arguments.`)\\n }\\n throw new Error(`Attempting to use a disconnected port object`)\\n }\\n }\\n return response\\n }\\n }\",_args:[{opts:{runOnInsecureOrigins:!1},STATIC_DATA:{OnInstalledReason:{CHROME_UPDATE:\"chrome_update\",INSTALL:\"install\",SHARED_MODULE_UPDATE:\"shared_module_update\",UPDATE:\"update\"},OnRestartRequiredReason:{APP_UPDATE:\"app_update\",OS_UPDATE:\"os_update\",PERIODIC:\"periodic\"},PlatformArch:{ARM:\"arm\",ARM64:\"arm64\",MIPS:\"mips\",MIPS64:\"mips64\",X86_32:\"x86-32\",X86_64:\"x86-64\"},PlatformNaclArch:{ARM:\"arm\",MIPS:\"mips\",MIPS64:\"mips64\",X86_32:\"x86-32\",X86_64:\"x86-64\"},PlatformOs:{ANDROID:\"android\",CROS:\"cros\",LINUX:\"linux\",MAC:\"mac\",OPENBSD:\"openbsd\",WIN:\"win\"},RequestUpdateCheckStatus:{NO_UPDATE:\"no_update\",THROTTLED:\"throttled\",UPDATE_AVAILABLE:\"update_available\"}}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:\"() => {\\n utils.preloadCache()\\n}\",stripProxyFromErrors:\"(handler = {}) => {\\n const newHandler = {\\n setPrototypeOf: function (target, proto) {\\n if (proto === null)\\n throw new TypeError('Cannot convert object to primitive value')\\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\\n throw new TypeError('Cyclic __proto__ value')\\n }\\n return Reflect.setPrototypeOf(target, proto)\\n }\\n }\\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\\n const traps = Object.getOwnPropertyNames(handler)\\n traps.forEach(trap => {\\n newHandler[trap] = function () {\\n try {\\n // Forward the call to the defined proxy handler\\n return handler[trap].apply(this, arguments || [])\\n } catch (err) {\\n // Stack traces differ per browser, we only support chromium based ones currently\\n if (!err || !err.stack || !err.stack.includes(`at `)) {\\n throw err\\n }\\n\\n // When something throws within one of our traps the Proxy will show up in error stacks\\n // An earlier implementation of this code would simply strip lines with a blacklist,\\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\\n // We try to use a known \\\"anchor\\\" line for that and strip it with everything above it.\\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\\n\\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\\n const blacklist = [\\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\\n `at Object.${trap} `, // e.g. Object.get or Object.apply\\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\\n ]\\n return (\\n err.stack\\n .split('\\\\n')\\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\\n .filter((line, index) => !(index === 1 && stripFirstLine))\\n // Check if the line starts with one of our blacklisted strings\\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\\n .join('\\\\n')\\n )\\n }\\n\\n const stripWithAnchor = (stack, anchor) => {\\n const stackArr = stack.split('\\\\n')\\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\\n const anchorIndex = stackArr.findIndex(line =>\\n line.trim().startsWith(anchor)\\n )\\n if (anchorIndex === -1) {\\n return false // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n return stackArr.join('\\\\n')\\n }\\n\\n // Special cases due to our nested toString proxies\\n err.stack = err.stack.replace(\\n 'at Object.toString (',\\n 'at Function.toString ('\\n )\\n if ((err.stack || '').includes('at Function.toString (')) {\\n err.stack = stripWithBlacklist(err.stack, false)\\n throw err\\n }\\n\\n // Try using the anchor method, fallback to blacklist if necessary\\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\\n\\n throw err // Re-throw our now sanitized error\\n }\\n }\\n })\\n return newHandler\\n}\",stripErrorWithAnchor:\"(err, anchor) => {\\n const stackArr = err.stack.split('\\\\n')\\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\\n if (anchorIndex === -1) {\\n return err // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n err.stack = stackArr.join('\\\\n')\\n return err\\n}\",replaceProperty:\"(obj, propName, descriptorOverrides = {}) => {\\n return Object.defineProperty(obj, propName, {\\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\\n // Add our overrides (e.g. value, get())\\n ...descriptorOverrides\\n })\\n}\",preloadCache:\"() => {\\n if (utils.cache) {\\n return\\n }\\n utils.cache = {\\n // Used in our proxies\\n Reflect: {\\n get: Reflect.get.bind(Reflect),\\n apply: Reflect.apply.bind(Reflect)\\n },\\n // Used in `makeNativeString`\\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\\n }\\n}\",makeNativeString:\"(name = '') => {\\n return utils.cache.nativeToStringStr.replace('toString', name || '')\\n}\",patchToString:\"(obj, str = '') => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n // `toString` targeted at our proxied Object detected\\n if (ctx === obj) {\\n // We either return the optional string verbatim or derive the most desired result automatically\\n return str || utils.makeNativeString(obj.name)\\n }\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",patchToStringNested:\"(obj = {}) => {\\n return utils.execRecursively(obj, ['function'], utils.patchToString)\\n}\",redirectToString:\"(proxyObj, originalObj) => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n\\n // `toString` targeted at our proxied Object detected\\n if (ctx === proxyObj) {\\n const fallback = () =>\\n originalObj && originalObj.name\\n ? utils.makeNativeString(originalObj.name)\\n : utils.makeNativeString(proxyObj.name)\\n\\n // Return the toString representation of our original object if possible\\n return originalObj + '' || fallback()\\n }\\n\\n if (typeof ctx === 'undefined' || ctx === null) {\\n return target.call(ctx)\\n }\\n\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",replaceWithProxy:\"(obj, propName, handler) => {\\n const originalObj = obj[propName]\\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.redirectToString(proxyObj, originalObj)\\n\\n return true\\n}\",replaceGetterWithProxy:\"(obj, propName, handler) => {\\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\\n const fnStr = fn.toString() // special getter function string\\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { get: proxyObj })\\n utils.patchToString(proxyObj, fnStr)\\n\\n return true\\n}\",replaceGetterSetter:\"(obj, propName, handlerGetterSetter) => {\\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\\n const handler = { ...ownPropertyDescriptor }\\n\\n if (handlerGetterSetter.get !== undefined) {\\n const nativeFn = ownPropertyDescriptor.get\\n handler.get = function() {\\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.get, nativeFn)\\n }\\n\\n if (handlerGetterSetter.set !== undefined) {\\n const nativeFn = ownPropertyDescriptor.set\\n handler.set = function(newValue) {\\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.set, nativeFn)\\n }\\n\\n Object.defineProperty(obj, propName, handler)\\n}\",mockWithProxy:\"(obj, propName, pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.patchToString(proxyObj)\\n\\n return true\\n}\",createProxy:\"(pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n utils.patchToString(proxyObj)\\n\\n return proxyObj\\n}\",splitObjPath:\"objPath => ({\\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\\n objName: objPath.split('.').slice(0, -1).join('.'),\\n // Extract last dot entry ==> `canPlayType`\\n propName: objPath.split('.').slice(-1)[0]\\n})\",replaceObjPathWithProxy:\"(objPath, handler) => {\\n const { objName, propName } = utils.splitObjPath(objPath)\\n const obj = eval(objName) // eslint-disable-line no-eval\\n return utils.replaceWithProxy(obj, propName, handler)\\n}\",execRecursively:\"(obj = {}, typeFilter = [], fn) => {\\n function recurse(obj) {\\n for (const key in obj) {\\n if (obj[key] === undefined) {\\n continue\\n }\\n if (obj[key] && typeof obj[key] === 'object') {\\n recurse(obj[key])\\n } else {\\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\\n fn.call(this, obj[key])\\n }\\n }\\n }\\n }\\n recurse(obj)\\n return obj\\n}\",stringifyFns:\"(fnObj = { hello: () => 'world' }) => {\\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\\n // https://github.com/feross/fromentries\\n function fromEntries(iterable) {\\n return [...iterable].reduce((obj, [key, val]) => {\\n obj[key] = val\\n return obj\\n }, {})\\n }\\n return (Object.fromEntries || fromEntries)(\\n Object.entries(fnObj)\\n .filter(([key, value]) => typeof value === 'function')\\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\\n )\\n}\",materializeFns:\"(fnStrObj = { hello: \\\"() => 'world'\\\" }) => {\\n return Object.fromEntries(\\n Object.entries(fnStrObj).map(([key, value]) => {\\n if (value.startsWith('function')) {\\n // some trickery is needed to make oldschool functions work :-)\\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\\n } else {\\n // arrow functions just work\\n return [key, eval(value)] // eslint-disable-line no-eval\\n }\\n })\\n )\\n}\",makeHandler:\"() => ({\\n // Used by simple `navigator` getter evasions\\n getterValue: value => ({\\n apply(target, ctx, args) {\\n // Let's fetch the value first, to trigger and escalate potential errors\\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\\n utils.cache.Reflect.apply(...arguments)\\n return value\\n }\\n })\\n})\",arrayEquals:\"(array1, array2) => {\\n if (array1.length !== array2.length) {\\n return false\\n }\\n for (let i = 0; i < array1.length; ++i) {\\n if (array1[i] !== array2[i]) {\\n return false\\n }\\n }\\n return true\\n}\",memoize:\"fn => {\\n const cache = []\\n return function(...args) {\\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\\n cache.push({ key: args, value: fn.apply(this, args) })\\n }\\n return cache.find(c => utils.arrayEquals(c.key, args)).value\\n }\\n}\"},_mainFunction:\"utils => {\\n /**\\n * Input might look funky, we need to normalize it so e.g. whitespace isn't an issue for our spoofing.\\n *\\n * @example\\n * video/webm; codecs=\\\"vp8, vorbis\\\"\\n * video/mp4; codecs=\\\"avc1.42E01E\\\"\\n * audio/x-m4a;\\n * audio/ogg; codecs=\\\"vorbis\\\"\\n * @param {String} arg\\n */\\n const parseInput = arg => {\\n const [mime, codecStr] = arg.trim().split(';')\\n let codecs = []\\n if (codecStr && codecStr.includes('codecs=\\\"')) {\\n codecs = codecStr\\n .trim()\\n .replace(`codecs=\\\"`, '')\\n .replace(`\\\"`, '')\\n .trim()\\n .split(',')\\n .filter(x => !!x)\\n .map(x => x.trim())\\n }\\n return {\\n mime,\\n codecStr,\\n codecs\\n }\\n }\\n\\n const canPlayType = {\\n // Intercept certain requests\\n apply: function(target, ctx, args) {\\n if (!args || !args.length) {\\n return target.apply(ctx, args)\\n }\\n const { mime, codecs } = parseInput(args[0])\\n // This specific mp4 codec is missing in Chromium\\n if (mime === 'video/mp4') {\\n if (codecs.includes('avc1.42E01E')) {\\n return 'probably'\\n }\\n }\\n // This mimetype is only supported if no codecs are specified\\n if (mime === 'audio/x-m4a' && !codecs.length) {\\n return 'maybe'\\n }\\n\\n // This mimetype is only supported if no codecs are specified\\n if (mime === 'audio/aac' && !codecs.length) {\\n return 'probably'\\n }\\n // Everything else as usual\\n return target.apply(ctx, args)\\n }\\n }\\n\\n /* global HTMLMediaElement */\\n utils.replaceWithProxy(\\n HTMLMediaElement.prototype,\\n 'canPlayType',\\n canPlayType\\n )\\n }\",_args:[]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:\"() => {\\n utils.preloadCache()\\n}\",stripProxyFromErrors:\"(handler = {}) => {\\n const newHandler = {\\n setPrototypeOf: function (target, proto) {\\n if (proto === null)\\n throw new TypeError('Cannot convert object to primitive value')\\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\\n throw new TypeError('Cyclic __proto__ value')\\n }\\n return Reflect.setPrototypeOf(target, proto)\\n }\\n }\\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\\n const traps = Object.getOwnPropertyNames(handler)\\n traps.forEach(trap => {\\n newHandler[trap] = function () {\\n try {\\n // Forward the call to the defined proxy handler\\n return handler[trap].apply(this, arguments || [])\\n } catch (err) {\\n // Stack traces differ per browser, we only support chromium based ones currently\\n if (!err || !err.stack || !err.stack.includes(`at `)) {\\n throw err\\n }\\n\\n // When something throws within one of our traps the Proxy will show up in error stacks\\n // An earlier implementation of this code would simply strip lines with a blacklist,\\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\\n // We try to use a known \\\"anchor\\\" line for that and strip it with everything above it.\\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\\n\\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\\n const blacklist = [\\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\\n `at Object.${trap} `, // e.g. Object.get or Object.apply\\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\\n ]\\n return (\\n err.stack\\n .split('\\\\n')\\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\\n .filter((line, index) => !(index === 1 && stripFirstLine))\\n // Check if the line starts with one of our blacklisted strings\\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\\n .join('\\\\n')\\n )\\n }\\n\\n const stripWithAnchor = (stack, anchor) => {\\n const stackArr = stack.split('\\\\n')\\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\\n const anchorIndex = stackArr.findIndex(line =>\\n line.trim().startsWith(anchor)\\n )\\n if (anchorIndex === -1) {\\n return false // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n return stackArr.join('\\\\n')\\n }\\n\\n // Special cases due to our nested toString proxies\\n err.stack = err.stack.replace(\\n 'at Object.toString (',\\n 'at Function.toString ('\\n )\\n if ((err.stack || '').includes('at Function.toString (')) {\\n err.stack = stripWithBlacklist(err.stack, false)\\n throw err\\n }\\n\\n // Try using the anchor method, fallback to blacklist if necessary\\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\\n\\n throw err // Re-throw our now sanitized error\\n }\\n }\\n })\\n return newHandler\\n}\",stripErrorWithAnchor:\"(err, anchor) => {\\n const stackArr = err.stack.split('\\\\n')\\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\\n if (anchorIndex === -1) {\\n return err // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n err.stack = stackArr.join('\\\\n')\\n return err\\n}\",replaceProperty:\"(obj, propName, descriptorOverrides = {}) => {\\n return Object.defineProperty(obj, propName, {\\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\\n // Add our overrides (e.g. value, get())\\n ...descriptorOverrides\\n })\\n}\",preloadCache:\"() => {\\n if (utils.cache) {\\n return\\n }\\n utils.cache = {\\n // Used in our proxies\\n Reflect: {\\n get: Reflect.get.bind(Reflect),\\n apply: Reflect.apply.bind(Reflect)\\n },\\n // Used in `makeNativeString`\\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\\n }\\n}\",makeNativeString:\"(name = '') => {\\n return utils.cache.nativeToStringStr.replace('toString', name || '')\\n}\",patchToString:\"(obj, str = '') => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n // `toString` targeted at our proxied Object detected\\n if (ctx === obj) {\\n // We either return the optional string verbatim or derive the most desired result automatically\\n return str || utils.makeNativeString(obj.name)\\n }\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",patchToStringNested:\"(obj = {}) => {\\n return utils.execRecursively(obj, ['function'], utils.patchToString)\\n}\",redirectToString:\"(proxyObj, originalObj) => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n\\n // `toString` targeted at our proxied Object detected\\n if (ctx === proxyObj) {\\n const fallback = () =>\\n originalObj && originalObj.name\\n ? utils.makeNativeString(originalObj.name)\\n : utils.makeNativeString(proxyObj.name)\\n\\n // Return the toString representation of our original object if possible\\n return originalObj + '' || fallback()\\n }\\n\\n if (typeof ctx === 'undefined' || ctx === null) {\\n return target.call(ctx)\\n }\\n\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",replaceWithProxy:\"(obj, propName, handler) => {\\n const originalObj = obj[propName]\\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.redirectToString(proxyObj, originalObj)\\n\\n return true\\n}\",replaceGetterWithProxy:\"(obj, propName, handler) => {\\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\\n const fnStr = fn.toString() // special getter function string\\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { get: proxyObj })\\n utils.patchToString(proxyObj, fnStr)\\n\\n return true\\n}\",replaceGetterSetter:\"(obj, propName, handlerGetterSetter) => {\\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\\n const handler = { ...ownPropertyDescriptor }\\n\\n if (handlerGetterSetter.get !== undefined) {\\n const nativeFn = ownPropertyDescriptor.get\\n handler.get = function() {\\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.get, nativeFn)\\n }\\n\\n if (handlerGetterSetter.set !== undefined) {\\n const nativeFn = ownPropertyDescriptor.set\\n handler.set = function(newValue) {\\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.set, nativeFn)\\n }\\n\\n Object.defineProperty(obj, propName, handler)\\n}\",mockWithProxy:\"(obj, propName, pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.patchToString(proxyObj)\\n\\n return true\\n}\",createProxy:\"(pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n utils.patchToString(proxyObj)\\n\\n return proxyObj\\n}\",splitObjPath:\"objPath => ({\\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\\n objName: objPath.split('.').slice(0, -1).join('.'),\\n // Extract last dot entry ==> `canPlayType`\\n propName: objPath.split('.').slice(-1)[0]\\n})\",replaceObjPathWithProxy:\"(objPath, handler) => {\\n const { objName, propName } = utils.splitObjPath(objPath)\\n const obj = eval(objName) // eslint-disable-line no-eval\\n return utils.replaceWithProxy(obj, propName, handler)\\n}\",execRecursively:\"(obj = {}, typeFilter = [], fn) => {\\n function recurse(obj) {\\n for (const key in obj) {\\n if (obj[key] === undefined) {\\n continue\\n }\\n if (obj[key] && typeof obj[key] === 'object') {\\n recurse(obj[key])\\n } else {\\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\\n fn.call(this, obj[key])\\n }\\n }\\n }\\n }\\n recurse(obj)\\n return obj\\n}\",stringifyFns:\"(fnObj = { hello: () => 'world' }) => {\\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\\n // https://github.com/feross/fromentries\\n function fromEntries(iterable) {\\n return [...iterable].reduce((obj, [key, val]) => {\\n obj[key] = val\\n return obj\\n }, {})\\n }\\n return (Object.fromEntries || fromEntries)(\\n Object.entries(fnObj)\\n .filter(([key, value]) => typeof value === 'function')\\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\\n )\\n}\",materializeFns:\"(fnStrObj = { hello: \\\"() => 'world'\\\" }) => {\\n return Object.fromEntries(\\n Object.entries(fnStrObj).map(([key, value]) => {\\n if (value.startsWith('function')) {\\n // some trickery is needed to make oldschool functions work :-)\\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\\n } else {\\n // arrow functions just work\\n return [key, eval(value)] // eslint-disable-line no-eval\\n }\\n })\\n )\\n}\",makeHandler:\"() => ({\\n // Used by simple `navigator` getter evasions\\n getterValue: value => ({\\n apply(target, ctx, args) {\\n // Let's fetch the value first, to trigger and escalate potential errors\\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\\n utils.cache.Reflect.apply(...arguments)\\n return value\\n }\\n })\\n})\",arrayEquals:\"(array1, array2) => {\\n if (array1.length !== array2.length) {\\n return false\\n }\\n for (let i = 0; i < array1.length; ++i) {\\n if (array1[i] !== array2[i]) {\\n return false\\n }\\n }\\n return true\\n}\",memoize:\"fn => {\\n const cache = []\\n return function(...args) {\\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\\n cache.push({ key: args, value: fn.apply(this, args) })\\n }\\n return cache.find(c => utils.arrayEquals(c.key, args)).value\\n }\\n}\"},_mainFunction:\"(utils, { opts }) => {\\n utils.replaceGetterWithProxy(\\n Object.getPrototypeOf(navigator),\\n 'hardwareConcurrency',\\n utils.makeHandler().getterValue(opts.hardwareConcurrency)\\n )\\n }\",_args:[{opts:{hardwareConcurrency:4}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:\"() => {\\n utils.preloadCache()\\n}\",stripProxyFromErrors:\"(handler = {}) => {\\n const newHandler = {\\n setPrototypeOf: function (target, proto) {\\n if (proto === null)\\n throw new TypeError('Cannot convert object to primitive value')\\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\\n throw new TypeError('Cyclic __proto__ value')\\n }\\n return Reflect.setPrototypeOf(target, proto)\\n }\\n }\\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\\n const traps = Object.getOwnPropertyNames(handler)\\n traps.forEach(trap => {\\n newHandler[trap] = function () {\\n try {\\n // Forward the call to the defined proxy handler\\n return handler[trap].apply(this, arguments || [])\\n } catch (err) {\\n // Stack traces differ per browser, we only support chromium based ones currently\\n if (!err || !err.stack || !err.stack.includes(`at `)) {\\n throw err\\n }\\n\\n // When something throws within one of our traps the Proxy will show up in error stacks\\n // An earlier implementation of this code would simply strip lines with a blacklist,\\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\\n // We try to use a known \\\"anchor\\\" line for that and strip it with everything above it.\\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\\n\\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\\n const blacklist = [\\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\\n `at Object.${trap} `, // e.g. Object.get or Object.apply\\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\\n ]\\n return (\\n err.stack\\n .split('\\\\n')\\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\\n .filter((line, index) => !(index === 1 && stripFirstLine))\\n // Check if the line starts with one of our blacklisted strings\\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\\n .join('\\\\n')\\n )\\n }\\n\\n const stripWithAnchor = (stack, anchor) => {\\n const stackArr = stack.split('\\\\n')\\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\\n const anchorIndex = stackArr.findIndex(line =>\\n line.trim().startsWith(anchor)\\n )\\n if (anchorIndex === -1) {\\n return false // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n return stackArr.join('\\\\n')\\n }\\n\\n // Special cases due to our nested toString proxies\\n err.stack = err.stack.replace(\\n 'at Object.toString (',\\n 'at Function.toString ('\\n )\\n if ((err.stack || '').includes('at Function.toString (')) {\\n err.stack = stripWithBlacklist(err.stack, false)\\n throw err\\n }\\n\\n // Try using the anchor method, fallback to blacklist if necessary\\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\\n\\n throw err // Re-throw our now sanitized error\\n }\\n }\\n })\\n return newHandler\\n}\",stripErrorWithAnchor:\"(err, anchor) => {\\n const stackArr = err.stack.split('\\\\n')\\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\\n if (anchorIndex === -1) {\\n return err // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n err.stack = stackArr.join('\\\\n')\\n return err\\n}\",replaceProperty:\"(obj, propName, descriptorOverrides = {}) => {\\n return Object.defineProperty(obj, propName, {\\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\\n // Add our overrides (e.g. value, get())\\n ...descriptorOverrides\\n })\\n}\",preloadCache:\"() => {\\n if (utils.cache) {\\n return\\n }\\n utils.cache = {\\n // Used in our proxies\\n Reflect: {\\n get: Reflect.get.bind(Reflect),\\n apply: Reflect.apply.bind(Reflect)\\n },\\n // Used in `makeNativeString`\\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\\n }\\n}\",makeNativeString:\"(name = '') => {\\n return utils.cache.nativeToStringStr.replace('toString', name || '')\\n}\",patchToString:\"(obj, str = '') => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n // `toString` targeted at our proxied Object detected\\n if (ctx === obj) {\\n // We either return the optional string verbatim or derive the most desired result automatically\\n return str || utils.makeNativeString(obj.name)\\n }\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",patchToStringNested:\"(obj = {}) => {\\n return utils.execRecursively(obj, ['function'], utils.patchToString)\\n}\",redirectToString:\"(proxyObj, originalObj) => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n\\n // `toString` targeted at our proxied Object detected\\n if (ctx === proxyObj) {\\n const fallback = () =>\\n originalObj && originalObj.name\\n ? utils.makeNativeString(originalObj.name)\\n : utils.makeNativeString(proxyObj.name)\\n\\n // Return the toString representation of our original object if possible\\n return originalObj + '' || fallback()\\n }\\n\\n if (typeof ctx === 'undefined' || ctx === null) {\\n return target.call(ctx)\\n }\\n\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",replaceWithProxy:\"(obj, propName, handler) => {\\n const originalObj = obj[propName]\\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.redirectToString(proxyObj, originalObj)\\n\\n return true\\n}\",replaceGetterWithProxy:\"(obj, propName, handler) => {\\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\\n const fnStr = fn.toString() // special getter function string\\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { get: proxyObj })\\n utils.patchToString(proxyObj, fnStr)\\n\\n return true\\n}\",replaceGetterSetter:\"(obj, propName, handlerGetterSetter) => {\\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\\n const handler = { ...ownPropertyDescriptor }\\n\\n if (handlerGetterSetter.get !== undefined) {\\n const nativeFn = ownPropertyDescriptor.get\\n handler.get = function() {\\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.get, nativeFn)\\n }\\n\\n if (handlerGetterSetter.set !== undefined) {\\n const nativeFn = ownPropertyDescriptor.set\\n handler.set = function(newValue) {\\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.set, nativeFn)\\n }\\n\\n Object.defineProperty(obj, propName, handler)\\n}\",mockWithProxy:\"(obj, propName, pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.patchToString(proxyObj)\\n\\n return true\\n}\",createProxy:\"(pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n utils.patchToString(proxyObj)\\n\\n return proxyObj\\n}\",splitObjPath:\"objPath => ({\\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\\n objName: objPath.split('.').slice(0, -1).join('.'),\\n // Extract last dot entry ==> `canPlayType`\\n propName: objPath.split('.').slice(-1)[0]\\n})\",replaceObjPathWithProxy:\"(objPath, handler) => {\\n const { objName, propName } = utils.splitObjPath(objPath)\\n const obj = eval(objName) // eslint-disable-line no-eval\\n return utils.replaceWithProxy(obj, propName, handler)\\n}\",execRecursively:\"(obj = {}, typeFilter = [], fn) => {\\n function recurse(obj) {\\n for (const key in obj) {\\n if (obj[key] === undefined) {\\n continue\\n }\\n if (obj[key] && typeof obj[key] === 'object') {\\n recurse(obj[key])\\n } else {\\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\\n fn.call(this, obj[key])\\n }\\n }\\n }\\n }\\n recurse(obj)\\n return obj\\n}\",stringifyFns:\"(fnObj = { hello: () => 'world' }) => {\\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\\n // https://github.com/feross/fromentries\\n function fromEntries(iterable) {\\n return [...iterable].reduce((obj, [key, val]) => {\\n obj[key] = val\\n return obj\\n }, {})\\n }\\n return (Object.fromEntries || fromEntries)(\\n Object.entries(fnObj)\\n .filter(([key, value]) => typeof value === 'function')\\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\\n )\\n}\",materializeFns:\"(fnStrObj = { hello: \\\"() => 'world'\\\" }) => {\\n return Object.fromEntries(\\n Object.entries(fnStrObj).map(([key, value]) => {\\n if (value.startsWith('function')) {\\n // some trickery is needed to make oldschool functions work :-)\\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\\n } else {\\n // arrow functions just work\\n return [key, eval(value)] // eslint-disable-line no-eval\\n }\\n })\\n )\\n}\",makeHandler:\"() => ({\\n // Used by simple `navigator` getter evasions\\n getterValue: value => ({\\n apply(target, ctx, args) {\\n // Let's fetch the value first, to trigger and escalate potential errors\\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\\n utils.cache.Reflect.apply(...arguments)\\n return value\\n }\\n })\\n})\",arrayEquals:\"(array1, array2) => {\\n if (array1.length !== array2.length) {\\n return false\\n }\\n for (let i = 0; i < array1.length; ++i) {\\n if (array1[i] !== array2[i]) {\\n return false\\n }\\n }\\n return true\\n}\",memoize:\"fn => {\\n const cache = []\\n return function(...args) {\\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\\n cache.push({ key: args, value: fn.apply(this, args) })\\n }\\n return cache.find(c => utils.arrayEquals(c.key, args)).value\\n }\\n}\"},_mainFunction:\"(utils, { opts }) => {\\n const languages = opts.languages.length\\n ? opts.languages\\n : ['en-US', 'en']\\n utils.replaceGetterWithProxy(\\n Object.getPrototypeOf(navigator),\\n 'languages',\\n utils.makeHandler().getterValue(Object.freeze([...languages]))\\n )\\n }\",_args:[{opts:{languages:[]}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:\"() => {\\n utils.preloadCache()\\n}\",stripProxyFromErrors:\"(handler = {}) => {\\n const newHandler = {\\n setPrototypeOf: function (target, proto) {\\n if (proto === null)\\n throw new TypeError('Cannot convert object to primitive value')\\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\\n throw new TypeError('Cyclic __proto__ value')\\n }\\n return Reflect.setPrototypeOf(target, proto)\\n }\\n }\\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\\n const traps = Object.getOwnPropertyNames(handler)\\n traps.forEach(trap => {\\n newHandler[trap] = function () {\\n try {\\n // Forward the call to the defined proxy handler\\n return handler[trap].apply(this, arguments || [])\\n } catch (err) {\\n // Stack traces differ per browser, we only support chromium based ones currently\\n if (!err || !err.stack || !err.stack.includes(`at `)) {\\n throw err\\n }\\n\\n // When something throws within one of our traps the Proxy will show up in error stacks\\n // An earlier implementation of this code would simply strip lines with a blacklist,\\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\\n // We try to use a known \\\"anchor\\\" line for that and strip it with everything above it.\\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\\n\\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\\n const blacklist = [\\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\\n `at Object.${trap} `, // e.g. Object.get or Object.apply\\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\\n ]\\n return (\\n err.stack\\n .split('\\\\n')\\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\\n .filter((line, index) => !(index === 1 && stripFirstLine))\\n // Check if the line starts with one of our blacklisted strings\\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\\n .join('\\\\n')\\n )\\n }\\n\\n const stripWithAnchor = (stack, anchor) => {\\n const stackArr = stack.split('\\\\n')\\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\\n const anchorIndex = stackArr.findIndex(line =>\\n line.trim().startsWith(anchor)\\n )\\n if (anchorIndex === -1) {\\n return false // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n return stackArr.join('\\\\n')\\n }\\n\\n // Special cases due to our nested toString proxies\\n err.stack = err.stack.replace(\\n 'at Object.toString (',\\n 'at Function.toString ('\\n )\\n if ((err.stack || '').includes('at Function.toString (')) {\\n err.stack = stripWithBlacklist(err.stack, false)\\n throw err\\n }\\n\\n // Try using the anchor method, fallback to blacklist if necessary\\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\\n\\n throw err // Re-throw our now sanitized error\\n }\\n }\\n })\\n return newHandler\\n}\",stripErrorWithAnchor:\"(err, anchor) => {\\n const stackArr = err.stack.split('\\\\n')\\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\\n if (anchorIndex === -1) {\\n return err // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n err.stack = stackArr.join('\\\\n')\\n return err\\n}\",replaceProperty:\"(obj, propName, descriptorOverrides = {}) => {\\n return Object.defineProperty(obj, propName, {\\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\\n // Add our overrides (e.g. value, get())\\n ...descriptorOverrides\\n })\\n}\",preloadCache:\"() => {\\n if (utils.cache) {\\n return\\n }\\n utils.cache = {\\n // Used in our proxies\\n Reflect: {\\n get: Reflect.get.bind(Reflect),\\n apply: Reflect.apply.bind(Reflect)\\n },\\n // Used in `makeNativeString`\\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\\n }\\n}\",makeNativeString:\"(name = '') => {\\n return utils.cache.nativeToStringStr.replace('toString', name || '')\\n}\",patchToString:\"(obj, str = '') => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n // `toString` targeted at our proxied Object detected\\n if (ctx === obj) {\\n // We either return the optional string verbatim or derive the most desired result automatically\\n return str || utils.makeNativeString(obj.name)\\n }\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",patchToStringNested:\"(obj = {}) => {\\n return utils.execRecursively(obj, ['function'], utils.patchToString)\\n}\",redirectToString:\"(proxyObj, originalObj) => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n\\n // `toString` targeted at our proxied Object detected\\n if (ctx === proxyObj) {\\n const fallback = () =>\\n originalObj && originalObj.name\\n ? utils.makeNativeString(originalObj.name)\\n : utils.makeNativeString(proxyObj.name)\\n\\n // Return the toString representation of our original object if possible\\n return originalObj + '' || fallback()\\n }\\n\\n if (typeof ctx === 'undefined' || ctx === null) {\\n return target.call(ctx)\\n }\\n\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",replaceWithProxy:\"(obj, propName, handler) => {\\n const originalObj = obj[propName]\\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.redirectToString(proxyObj, originalObj)\\n\\n return true\\n}\",replaceGetterWithProxy:\"(obj, propName, handler) => {\\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\\n const fnStr = fn.toString() // special getter function string\\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { get: proxyObj })\\n utils.patchToString(proxyObj, fnStr)\\n\\n return true\\n}\",replaceGetterSetter:\"(obj, propName, handlerGetterSetter) => {\\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\\n const handler = { ...ownPropertyDescriptor }\\n\\n if (handlerGetterSetter.get !== undefined) {\\n const nativeFn = ownPropertyDescriptor.get\\n handler.get = function() {\\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.get, nativeFn)\\n }\\n\\n if (handlerGetterSetter.set !== undefined) {\\n const nativeFn = ownPropertyDescriptor.set\\n handler.set = function(newValue) {\\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.set, nativeFn)\\n }\\n\\n Object.defineProperty(obj, propName, handler)\\n}\",mockWithProxy:\"(obj, propName, pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.patchToString(proxyObj)\\n\\n return true\\n}\",createProxy:\"(pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n utils.patchToString(proxyObj)\\n\\n return proxyObj\\n}\",splitObjPath:\"objPath => ({\\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\\n objName: objPath.split('.').slice(0, -1).join('.'),\\n // Extract last dot entry ==> `canPlayType`\\n propName: objPath.split('.').slice(-1)[0]\\n})\",replaceObjPathWithProxy:\"(objPath, handler) => {\\n const { objName, propName } = utils.splitObjPath(objPath)\\n const obj = eval(objName) // eslint-disable-line no-eval\\n return utils.replaceWithProxy(obj, propName, handler)\\n}\",execRecursively:\"(obj = {}, typeFilter = [], fn) => {\\n function recurse(obj) {\\n for (const key in obj) {\\n if (obj[key] === undefined) {\\n continue\\n }\\n if (obj[key] && typeof obj[key] === 'object') {\\n recurse(obj[key])\\n } else {\\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\\n fn.call(this, obj[key])\\n }\\n }\\n }\\n }\\n recurse(obj)\\n return obj\\n}\",stringifyFns:\"(fnObj = { hello: () => 'world' }) => {\\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\\n // https://github.com/feross/fromentries\\n function fromEntries(iterable) {\\n return [...iterable].reduce((obj, [key, val]) => {\\n obj[key] = val\\n return obj\\n }, {})\\n }\\n return (Object.fromEntries || fromEntries)(\\n Object.entries(fnObj)\\n .filter(([key, value]) => typeof value === 'function')\\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\\n )\\n}\",materializeFns:\"(fnStrObj = { hello: \\\"() => 'world'\\\" }) => {\\n return Object.fromEntries(\\n Object.entries(fnStrObj).map(([key, value]) => {\\n if (value.startsWith('function')) {\\n // some trickery is needed to make oldschool functions work :-)\\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\\n } else {\\n // arrow functions just work\\n return [key, eval(value)] // eslint-disable-line no-eval\\n }\\n })\\n )\\n}\",makeHandler:\"() => ({\\n // Used by simple `navigator` getter evasions\\n getterValue: value => ({\\n apply(target, ctx, args) {\\n // Let's fetch the value first, to trigger and escalate potential errors\\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\\n utils.cache.Reflect.apply(...arguments)\\n return value\\n }\\n })\\n})\",arrayEquals:\"(array1, array2) => {\\n if (array1.length !== array2.length) {\\n return false\\n }\\n for (let i = 0; i < array1.length; ++i) {\\n if (array1[i] !== array2[i]) {\\n return false\\n }\\n }\\n return true\\n}\",memoize:\"fn => {\\n const cache = []\\n return function(...args) {\\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\\n cache.push({ key: args, value: fn.apply(this, args) })\\n }\\n return cache.find(c => utils.arrayEquals(c.key, args)).value\\n }\\n}\"},_mainFunction:\"(utils, opts) => {\\n const isSecure = document.location.protocol.startsWith('https')\\n\\n // In headful on secure origins the permission should be \\\"default\\\", not \\\"denied\\\"\\n if (isSecure) {\\n utils.replaceGetterWithProxy(Notification, 'permission', {\\n apply() {\\n return 'default'\\n }\\n })\\n }\\n\\n // Another weird behavior:\\n // On insecure origins in headful the state is \\\"denied\\\",\\n // whereas in headless it's \\\"prompt\\\"\\n if (!isSecure) {\\n const handler = {\\n apply(target, ctx, args) {\\n const param = (args || [])[0]\\n\\n const isNotifications =\\n param && param.name && param.name === 'notifications'\\n if (!isNotifications) {\\n return utils.cache.Reflect.apply(...arguments)\\n }\\n\\n return Promise.resolve(\\n Object.setPrototypeOf(\\n {\\n state: 'denied',\\n onchange: null\\n },\\n PermissionStatus.prototype\\n )\\n )\\n }\\n }\\n // Note: Don't use `Object.getPrototypeOf` here\\n utils.replaceWithProxy(Permissions.prototype, 'query', handler)\\n }\\n }\",_args:[{}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:\"() => {\\n utils.preloadCache()\\n}\",stripProxyFromErrors:\"(handler = {}) => {\\n const newHandler = {\\n setPrototypeOf: function (target, proto) {\\n if (proto === null)\\n throw new TypeError('Cannot convert object to primitive value')\\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\\n throw new TypeError('Cyclic __proto__ value')\\n }\\n return Reflect.setPrototypeOf(target, proto)\\n }\\n }\\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\\n const traps = Object.getOwnPropertyNames(handler)\\n traps.forEach(trap => {\\n newHandler[trap] = function () {\\n try {\\n // Forward the call to the defined proxy handler\\n return handler[trap].apply(this, arguments || [])\\n } catch (err) {\\n // Stack traces differ per browser, we only support chromium based ones currently\\n if (!err || !err.stack || !err.stack.includes(`at `)) {\\n throw err\\n }\\n\\n // When something throws within one of our traps the Proxy will show up in error stacks\\n // An earlier implementation of this code would simply strip lines with a blacklist,\\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\\n // We try to use a known \\\"anchor\\\" line for that and strip it with everything above it.\\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\\n\\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\\n const blacklist = [\\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\\n `at Object.${trap} `, // e.g. Object.get or Object.apply\\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\\n ]\\n return (\\n err.stack\\n .split('\\\\n')\\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\\n .filter((line, index) => !(index === 1 && stripFirstLine))\\n // Check if the line starts with one of our blacklisted strings\\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\\n .join('\\\\n')\\n )\\n }\\n\\n const stripWithAnchor = (stack, anchor) => {\\n const stackArr = stack.split('\\\\n')\\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\\n const anchorIndex = stackArr.findIndex(line =>\\n line.trim().startsWith(anchor)\\n )\\n if (anchorIndex === -1) {\\n return false // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n return stackArr.join('\\\\n')\\n }\\n\\n // Special cases due to our nested toString proxies\\n err.stack = err.stack.replace(\\n 'at Object.toString (',\\n 'at Function.toString ('\\n )\\n if ((err.stack || '').includes('at Function.toString (')) {\\n err.stack = stripWithBlacklist(err.stack, false)\\n throw err\\n }\\n\\n // Try using the anchor method, fallback to blacklist if necessary\\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\\n\\n throw err // Re-throw our now sanitized error\\n }\\n }\\n })\\n return newHandler\\n}\",stripErrorWithAnchor:\"(err, anchor) => {\\n const stackArr = err.stack.split('\\\\n')\\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\\n if (anchorIndex === -1) {\\n return err // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n err.stack = stackArr.join('\\\\n')\\n return err\\n}\",replaceProperty:\"(obj, propName, descriptorOverrides = {}) => {\\n return Object.defineProperty(obj, propName, {\\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\\n // Add our overrides (e.g. value, get())\\n ...descriptorOverrides\\n })\\n}\",preloadCache:\"() => {\\n if (utils.cache) {\\n return\\n }\\n utils.cache = {\\n // Used in our proxies\\n Reflect: {\\n get: Reflect.get.bind(Reflect),\\n apply: Reflect.apply.bind(Reflect)\\n },\\n // Used in `makeNativeString`\\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\\n }\\n}\",makeNativeString:\"(name = '') => {\\n return utils.cache.nativeToStringStr.replace('toString', name || '')\\n}\",patchToString:\"(obj, str = '') => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n // `toString` targeted at our proxied Object detected\\n if (ctx === obj) {\\n // We either return the optional string verbatim or derive the most desired result automatically\\n return str || utils.makeNativeString(obj.name)\\n }\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",patchToStringNested:\"(obj = {}) => {\\n return utils.execRecursively(obj, ['function'], utils.patchToString)\\n}\",redirectToString:\"(proxyObj, originalObj) => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n\\n // `toString` targeted at our proxied Object detected\\n if (ctx === proxyObj) {\\n const fallback = () =>\\n originalObj && originalObj.name\\n ? utils.makeNativeString(originalObj.name)\\n : utils.makeNativeString(proxyObj.name)\\n\\n // Return the toString representation of our original object if possible\\n return originalObj + '' || fallback()\\n }\\n\\n if (typeof ctx === 'undefined' || ctx === null) {\\n return target.call(ctx)\\n }\\n\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",replaceWithProxy:\"(obj, propName, handler) => {\\n const originalObj = obj[propName]\\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.redirectToString(proxyObj, originalObj)\\n\\n return true\\n}\",replaceGetterWithProxy:\"(obj, propName, handler) => {\\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\\n const fnStr = fn.toString() // special getter function string\\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { get: proxyObj })\\n utils.patchToString(proxyObj, fnStr)\\n\\n return true\\n}\",replaceGetterSetter:\"(obj, propName, handlerGetterSetter) => {\\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\\n const handler = { ...ownPropertyDescriptor }\\n\\n if (handlerGetterSetter.get !== undefined) {\\n const nativeFn = ownPropertyDescriptor.get\\n handler.get = function() {\\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.get, nativeFn)\\n }\\n\\n if (handlerGetterSetter.set !== undefined) {\\n const nativeFn = ownPropertyDescriptor.set\\n handler.set = function(newValue) {\\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.set, nativeFn)\\n }\\n\\n Object.defineProperty(obj, propName, handler)\\n}\",mockWithProxy:\"(obj, propName, pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.patchToString(proxyObj)\\n\\n return true\\n}\",createProxy:\"(pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n utils.patchToString(proxyObj)\\n\\n return proxyObj\\n}\",splitObjPath:\"objPath => ({\\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\\n objName: objPath.split('.').slice(0, -1).join('.'),\\n // Extract last dot entry ==> `canPlayType`\\n propName: objPath.split('.').slice(-1)[0]\\n})\",replaceObjPathWithProxy:\"(objPath, handler) => {\\n const { objName, propName } = utils.splitObjPath(objPath)\\n const obj = eval(objName) // eslint-disable-line no-eval\\n return utils.replaceWithProxy(obj, propName, handler)\\n}\",execRecursively:\"(obj = {}, typeFilter = [], fn) => {\\n function recurse(obj) {\\n for (const key in obj) {\\n if (obj[key] === undefined) {\\n continue\\n }\\n if (obj[key] && typeof obj[key] === 'object') {\\n recurse(obj[key])\\n } else {\\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\\n fn.call(this, obj[key])\\n }\\n }\\n }\\n }\\n recurse(obj)\\n return obj\\n}\",stringifyFns:\"(fnObj = { hello: () => 'world' }) => {\\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\\n // https://github.com/feross/fromentries\\n function fromEntries(iterable) {\\n return [...iterable].reduce((obj, [key, val]) => {\\n obj[key] = val\\n return obj\\n }, {})\\n }\\n return (Object.fromEntries || fromEntries)(\\n Object.entries(fnObj)\\n .filter(([key, value]) => typeof value === 'function')\\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\\n )\\n}\",materializeFns:\"(fnStrObj = { hello: \\\"() => 'world'\\\" }) => {\\n return Object.fromEntries(\\n Object.entries(fnStrObj).map(([key, value]) => {\\n if (value.startsWith('function')) {\\n // some trickery is needed to make oldschool functions work :-)\\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\\n } else {\\n // arrow functions just work\\n return [key, eval(value)] // eslint-disable-line no-eval\\n }\\n })\\n )\\n}\",makeHandler:\"() => ({\\n // Used by simple `navigator` getter evasions\\n getterValue: value => ({\\n apply(target, ctx, args) {\\n // Let's fetch the value first, to trigger and escalate potential errors\\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\\n utils.cache.Reflect.apply(...arguments)\\n return value\\n }\\n })\\n})\",arrayEquals:\"(array1, array2) => {\\n if (array1.length !== array2.length) {\\n return false\\n }\\n for (let i = 0; i < array1.length; ++i) {\\n if (array1[i] !== array2[i]) {\\n return false\\n }\\n }\\n return true\\n}\",memoize:\"fn => {\\n const cache = []\\n return function(...args) {\\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\\n cache.push({ key: args, value: fn.apply(this, args) })\\n }\\n return cache.find(c => utils.arrayEquals(c.key, args)).value\\n }\\n}\"},_mainFunction:\"(utils, { fns, data }) => {\\n fns = utils.materializeFns(fns)\\n\\n // That means we're running headful\\n const hasPlugins = 'plugins' in navigator && navigator.plugins.length\\n if (hasPlugins) {\\n return // nothing to do here\\n }\\n\\n const mimeTypes = fns.generateMimeTypeArray(utils, fns)(data.mimeTypes)\\n const plugins = fns.generatePluginArray(utils, fns)(data.plugins)\\n\\n // Plugin and MimeType cross-reference each other, let's do that now\\n // Note: We're looping through `data.plugins` here, not the generated `plugins`\\n for (const pluginData of data.plugins) {\\n pluginData.__mimeTypes.forEach((type, index) => {\\n plugins[pluginData.name][index] = mimeTypes[type]\\n\\n Object.defineProperty(plugins[pluginData.name], type, {\\n value: mimeTypes[type],\\n writable: false,\\n enumerable: false, // Not enumerable\\n configurable: true\\n })\\n Object.defineProperty(mimeTypes[type], 'enabledPlugin', {\\n value:\\n type === 'application/x-pnacl'\\n ? mimeTypes['application/x-nacl'].enabledPlugin // these reference the same plugin, so we need to re-use the Proxy in order to avoid leaks\\n : new Proxy(plugins[pluginData.name], {}), // Prevent circular references\\n writable: false,\\n enumerable: false, // Important: `JSON.stringify(navigator.plugins)`\\n configurable: true\\n })\\n })\\n }\\n\\n const patchNavigator = (name, value) =>\\n utils.replaceProperty(Object.getPrototypeOf(navigator), name, {\\n get() {\\n return value\\n }\\n })\\n\\n patchNavigator('mimeTypes', mimeTypes)\\n patchNavigator('plugins', plugins)\\n\\n // All done\\n }\",_args:[{fns:{generateMimeTypeArray:\"(utils, fns) => mimeTypesData => {\\n return fns.generateMagicArray(utils, fns)(\\n mimeTypesData,\\n MimeTypeArray.prototype,\\n MimeType.prototype,\\n 'type'\\n )\\n}\",generatePluginArray:\"(utils, fns) => pluginsData => {\\n return fns.generateMagicArray(utils, fns)(\\n pluginsData,\\n PluginArray.prototype,\\n Plugin.prototype,\\n 'name'\\n )\\n}\",generateMagicArray:\"(utils, fns) =>\\n function(\\n dataArray = [],\\n proto = MimeTypeArray.prototype,\\n itemProto = MimeType.prototype,\\n itemMainProp = 'type'\\n ) {\\n // Quick helper to set props with the same descriptors vanilla is using\\n const defineProp = (obj, prop, value) =>\\n Object.defineProperty(obj, prop, {\\n value,\\n writable: false,\\n enumerable: false, // Important for mimeTypes & plugins: `JSON.stringify(navigator.mimeTypes)`\\n configurable: true\\n })\\n\\n // Loop over our fake data and construct items\\n const makeItem = data => {\\n const item = {}\\n for (const prop of Object.keys(data)) {\\n if (prop.startsWith('__')) {\\n continue\\n }\\n defineProp(item, prop, data[prop])\\n }\\n return patchItem(item, data)\\n }\\n\\n const patchItem = (item, data) => {\\n let descriptor = Object.getOwnPropertyDescriptors(item)\\n\\n // Special case: Plugins have a magic length property which is not enumerable\\n // e.g. `navigator.plugins[i].length` should always be the length of the assigned mimeTypes\\n if (itemProto === Plugin.prototype) {\\n descriptor = {\\n ...descriptor,\\n length: {\\n value: data.__mimeTypes.length,\\n writable: false,\\n enumerable: false,\\n configurable: true // Important to be able to use the ownKeys trap in a Proxy to strip `length`\\n }\\n }\\n }\\n\\n // We need to spoof a specific `MimeType` or `Plugin` object\\n const obj = Object.create(itemProto, descriptor)\\n\\n // Virtually all property keys are not enumerable in vanilla\\n const blacklist = [...Object.keys(data), 'length', 'enabledPlugin']\\n return new Proxy(obj, {\\n ownKeys(target) {\\n return Reflect.ownKeys(target).filter(k => !blacklist.includes(k))\\n },\\n getOwnPropertyDescriptor(target, prop) {\\n if (blacklist.includes(prop)) {\\n return undefined\\n }\\n return Reflect.getOwnPropertyDescriptor(target, prop)\\n }\\n })\\n }\\n\\n const magicArray = []\\n\\n // Loop through our fake data and use that to create convincing entities\\n dataArray.forEach(data => {\\n magicArray.push(makeItem(data))\\n })\\n\\n // Add direct property access based on types (e.g. `obj['application/pdf']`) afterwards\\n magicArray.forEach(entry => {\\n defineProp(magicArray, entry[itemMainProp], entry)\\n })\\n\\n // This is the best way to fake the type to make sure this is false: `Array.isArray(navigator.mimeTypes)`\\n const magicArrayObj = Object.create(proto, {\\n ...Object.getOwnPropertyDescriptors(magicArray),\\n\\n // There's one ugly quirk we unfortunately need to take care of:\\n // The `MimeTypeArray` prototype has an enumerable `length` property,\\n // but headful Chrome will still skip it when running `Object.getOwnPropertyNames(navigator.mimeTypes)`.\\n // To strip it we need to make it first `configurable` and can then overlay a Proxy with an `ownKeys` trap.\\n length: {\\n value: magicArray.length,\\n writable: false,\\n enumerable: false,\\n configurable: true // Important to be able to use the ownKeys trap in a Proxy to strip `length`\\n }\\n })\\n\\n // Generate our functional function mocks :-)\\n const functionMocks = fns.generateFunctionMocks(utils)(\\n proto,\\n itemMainProp,\\n magicArray\\n )\\n\\n // We need to overlay our custom object with a JS Proxy\\n const magicArrayObjProxy = new Proxy(magicArrayObj, {\\n get(target, key = '') {\\n // Redirect function calls to our custom proxied versions mocking the vanilla behavior\\n if (key === 'item') {\\n return functionMocks.item\\n }\\n if (key === 'namedItem') {\\n return functionMocks.namedItem\\n }\\n if (proto === PluginArray.prototype && key === 'refresh') {\\n return functionMocks.refresh\\n }\\n // Everything else can pass through as normal\\n return utils.cache.Reflect.get(...arguments)\\n },\\n ownKeys(target) {\\n // There are a couple of quirks where the original property demonstrates \\\"magical\\\" behavior that makes no sense\\n // This can be witnessed when calling `Object.getOwnPropertyNames(navigator.mimeTypes)` and the absense of `length`\\n // My guess is that it has to do with the recent change of not allowing data enumeration and this being implemented weirdly\\n // For that reason we just completely fake the available property names based on our data to match what regular Chrome is doing\\n // Specific issues when not patching this: `length` property is available, direct `types` props (e.g. `obj['application/pdf']`) are missing\\n const keys = []\\n const typeProps = magicArray.map(mt => mt[itemMainProp])\\n typeProps.forEach((_, i) => keys.push(`${i}`))\\n typeProps.forEach(propName => keys.push(propName))\\n return keys\\n },\\n getOwnPropertyDescriptor(target, prop) {\\n if (prop === 'length') {\\n return undefined\\n }\\n return Reflect.getOwnPropertyDescriptor(target, prop)\\n }\\n })\\n\\n return magicArrayObjProxy\\n }\",generateFunctionMocks:\"utils => (\\n proto,\\n itemMainProp,\\n dataArray\\n) => ({\\n /** Returns the MimeType object with the specified index. */\\n item: utils.createProxy(proto.item, {\\n apply(target, ctx, args) {\\n if (!args.length) {\\n throw new TypeError(\\n `Failed to execute 'item' on '${\\n proto[Symbol.toStringTag]\\n }': 1 argument required, but only 0 present.`\\n )\\n }\\n // Special behavior alert:\\n // - Vanilla tries to cast strings to Numbers (only integers!) and use them as property index lookup\\n // - If anything else than an integer (including as string) is provided it will return the first entry\\n const isInteger = args[0] && Number.isInteger(Number(args[0])) // Cast potential string to number first, then check for integer\\n // Note: Vanilla never returns `undefined`\\n return (isInteger ? dataArray[Number(args[0])] : dataArray[0]) || null\\n }\\n }),\\n /** Returns the MimeType object with the specified name. */\\n namedItem: utils.createProxy(proto.namedItem, {\\n apply(target, ctx, args) {\\n if (!args.length) {\\n throw new TypeError(\\n `Failed to execute 'namedItem' on '${\\n proto[Symbol.toStringTag]\\n }': 1 argument required, but only 0 present.`\\n )\\n }\\n return dataArray.find(mt => mt[itemMainProp] === args[0]) || null // Not `undefined`!\\n }\\n }),\\n /** Does nothing and shall return nothing */\\n refresh: proto.refresh\\n ? utils.createProxy(proto.refresh, {\\n apply(target, ctx, args) {\\n return undefined\\n }\\n })\\n : undefined\\n})\"},data:{mimeTypes:[{type:\"application/pdf\",suffixes:\"pdf\",description:\"\",__pluginName:\"Chrome PDF Viewer\"},{type:\"application/x-google-chrome-pdf\",suffixes:\"pdf\",description:\"Portable Document Format\",__pluginName:\"Chrome PDF Plugin\"},{type:\"application/x-nacl\",suffixes:\"\",description:\"Native Client Executable\",__pluginName:\"Native Client\"},{type:\"application/x-pnacl\",suffixes:\"\",description:\"Portable Native Client Executable\",__pluginName:\"Native Client\"}],plugins:[{name:\"Chrome PDF Plugin\",filename:\"internal-pdf-viewer\",description:\"Portable Document Format\",__mimeTypes:[\"application/x-google-chrome-pdf\"]},{name:\"Chrome PDF Viewer\",filename:\"mhjfbmdgcfjbbpaeojofohoefgiehjai\",description:\"\",__mimeTypes:[\"application/pdf\"]},{name:\"Native Client\",filename:\"internal-nacl-plugin\",description:\"\",__mimeTypes:[\"application/x-nacl\",\"application/x-pnacl\"]}]}}]}),!1===navigator.webdriver||void 0===navigator.webdriver||delete Object.getPrototypeOf(navigator).webdriver,(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:\"() => {\\n utils.preloadCache()\\n}\",stripProxyFromErrors:\"(handler = {}) => {\\n const newHandler = {\\n setPrototypeOf: function (target, proto) {\\n if (proto === null)\\n throw new TypeError('Cannot convert object to primitive value')\\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\\n throw new TypeError('Cyclic __proto__ value')\\n }\\n return Reflect.setPrototypeOf(target, proto)\\n }\\n }\\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\\n const traps = Object.getOwnPropertyNames(handler)\\n traps.forEach(trap => {\\n newHandler[trap] = function () {\\n try {\\n // Forward the call to the defined proxy handler\\n return handler[trap].apply(this, arguments || [])\\n } catch (err) {\\n // Stack traces differ per browser, we only support chromium based ones currently\\n if (!err || !err.stack || !err.stack.includes(`at `)) {\\n throw err\\n }\\n\\n // When something throws within one of our traps the Proxy will show up in error stacks\\n // An earlier implementation of this code would simply strip lines with a blacklist,\\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\\n // We try to use a known \\\"anchor\\\" line for that and strip it with everything above it.\\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\\n\\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\\n const blacklist = [\\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\\n `at Object.${trap} `, // e.g. Object.get or Object.apply\\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\\n ]\\n return (\\n err.stack\\n .split('\\\\n')\\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\\n .filter((line, index) => !(index === 1 && stripFirstLine))\\n // Check if the line starts with one of our blacklisted strings\\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\\n .join('\\\\n')\\n )\\n }\\n\\n const stripWithAnchor = (stack, anchor) => {\\n const stackArr = stack.split('\\\\n')\\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\\n const anchorIndex = stackArr.findIndex(line =>\\n line.trim().startsWith(anchor)\\n )\\n if (anchorIndex === -1) {\\n return false // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n return stackArr.join('\\\\n')\\n }\\n\\n // Special cases due to our nested toString proxies\\n err.stack = err.stack.replace(\\n 'at Object.toString (',\\n 'at Function.toString ('\\n )\\n if ((err.stack || '').includes('at Function.toString (')) {\\n err.stack = stripWithBlacklist(err.stack, false)\\n throw err\\n }\\n\\n // Try using the anchor method, fallback to blacklist if necessary\\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\\n\\n throw err // Re-throw our now sanitized error\\n }\\n }\\n })\\n return newHandler\\n}\",stripErrorWithAnchor:\"(err, anchor) => {\\n const stackArr = err.stack.split('\\\\n')\\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\\n if (anchorIndex === -1) {\\n return err // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n err.stack = stackArr.join('\\\\n')\\n return err\\n}\",replaceProperty:\"(obj, propName, descriptorOverrides = {}) => {\\n return Object.defineProperty(obj, propName, {\\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\\n // Add our overrides (e.g. value, get())\\n ...descriptorOverrides\\n })\\n}\",preloadCache:\"() => {\\n if (utils.cache) {\\n return\\n }\\n utils.cache = {\\n // Used in our proxies\\n Reflect: {\\n get: Reflect.get.bind(Reflect),\\n apply: Reflect.apply.bind(Reflect)\\n },\\n // Used in `makeNativeString`\\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\\n }\\n}\",makeNativeString:\"(name = '') => {\\n return utils.cache.nativeToStringStr.replace('toString', name || '')\\n}\",patchToString:\"(obj, str = '') => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n // `toString` targeted at our proxied Object detected\\n if (ctx === obj) {\\n // We either return the optional string verbatim or derive the most desired result automatically\\n return str || utils.makeNativeString(obj.name)\\n }\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",patchToStringNested:\"(obj = {}) => {\\n return utils.execRecursively(obj, ['function'], utils.patchToString)\\n}\",redirectToString:\"(proxyObj, originalObj) => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n\\n // `toString` targeted at our proxied Object detected\\n if (ctx === proxyObj) {\\n const fallback = () =>\\n originalObj && originalObj.name\\n ? utils.makeNativeString(originalObj.name)\\n : utils.makeNativeString(proxyObj.name)\\n\\n // Return the toString representation of our original object if possible\\n return originalObj + '' || fallback()\\n }\\n\\n if (typeof ctx === 'undefined' || ctx === null) {\\n return target.call(ctx)\\n }\\n\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",replaceWithProxy:\"(obj, propName, handler) => {\\n const originalObj = obj[propName]\\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.redirectToString(proxyObj, originalObj)\\n\\n return true\\n}\",replaceGetterWithProxy:\"(obj, propName, handler) => {\\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\\n const fnStr = fn.toString() // special getter function string\\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { get: proxyObj })\\n utils.patchToString(proxyObj, fnStr)\\n\\n return true\\n}\",replaceGetterSetter:\"(obj, propName, handlerGetterSetter) => {\\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\\n const handler = { ...ownPropertyDescriptor }\\n\\n if (handlerGetterSetter.get !== undefined) {\\n const nativeFn = ownPropertyDescriptor.get\\n handler.get = function() {\\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.get, nativeFn)\\n }\\n\\n if (handlerGetterSetter.set !== undefined) {\\n const nativeFn = ownPropertyDescriptor.set\\n handler.set = function(newValue) {\\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.set, nativeFn)\\n }\\n\\n Object.defineProperty(obj, propName, handler)\\n}\",mockWithProxy:\"(obj, propName, pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.patchToString(proxyObj)\\n\\n return true\\n}\",createProxy:\"(pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n utils.patchToString(proxyObj)\\n\\n return proxyObj\\n}\",splitObjPath:\"objPath => ({\\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\\n objName: objPath.split('.').slice(0, -1).join('.'),\\n // Extract last dot entry ==> `canPlayType`\\n propName: objPath.split('.').slice(-1)[0]\\n})\",replaceObjPathWithProxy:\"(objPath, handler) => {\\n const { objName, propName } = utils.splitObjPath(objPath)\\n const obj = eval(objName) // eslint-disable-line no-eval\\n return utils.replaceWithProxy(obj, propName, handler)\\n}\",execRecursively:\"(obj = {}, typeFilter = [], fn) => {\\n function recurse(obj) {\\n for (const key in obj) {\\n if (obj[key] === undefined) {\\n continue\\n }\\n if (obj[key] && typeof obj[key] === 'object') {\\n recurse(obj[key])\\n } else {\\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\\n fn.call(this, obj[key])\\n }\\n }\\n }\\n }\\n recurse(obj)\\n return obj\\n}\",stringifyFns:\"(fnObj = { hello: () => 'world' }) => {\\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\\n // https://github.com/feross/fromentries\\n function fromEntries(iterable) {\\n return [...iterable].reduce((obj, [key, val]) => {\\n obj[key] = val\\n return obj\\n }, {})\\n }\\n return (Object.fromEntries || fromEntries)(\\n Object.entries(fnObj)\\n .filter(([key, value]) => typeof value === 'function')\\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\\n )\\n}\",materializeFns:\"(fnStrObj = { hello: \\\"() => 'world'\\\" }) => {\\n return Object.fromEntries(\\n Object.entries(fnStrObj).map(([key, value]) => {\\n if (value.startsWith('function')) {\\n // some trickery is needed to make oldschool functions work :-)\\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\\n } else {\\n // arrow functions just work\\n return [key, eval(value)] // eslint-disable-line no-eval\\n }\\n })\\n )\\n}\",makeHandler:\"() => ({\\n // Used by simple `navigator` getter evasions\\n getterValue: value => ({\\n apply(target, ctx, args) {\\n // Let's fetch the value first, to trigger and escalate potential errors\\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\\n utils.cache.Reflect.apply(...arguments)\\n return value\\n }\\n })\\n})\",arrayEquals:\"(array1, array2) => {\\n if (array1.length !== array2.length) {\\n return false\\n }\\n for (let i = 0; i < array1.length; ++i) {\\n if (array1[i] !== array2[i]) {\\n return false\\n }\\n }\\n return true\\n}\",memoize:\"fn => {\\n const cache = []\\n return function(...args) {\\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\\n cache.push({ key: args, value: fn.apply(this, args) })\\n }\\n return cache.find(c => utils.arrayEquals(c.key, args)).value\\n }\\n}\"},_mainFunction:\"(utils, opts) => {\\n const getParameterProxyHandler = {\\n apply: function(target, ctx, args) {\\n const param = (args || [])[0]\\n const result = utils.cache.Reflect.apply(target, ctx, args)\\n // UNMASKED_VENDOR_WEBGL\\n if (param === 37445) {\\n return opts.vendor || 'Intel Inc.' // default in headless: Google Inc.\\n }\\n // UNMASKED_RENDERER_WEBGL\\n if (param === 37446) {\\n return opts.renderer || 'Intel Iris OpenGL Engine' // default in headless: Google SwiftShader\\n }\\n return result\\n }\\n }\\n\\n // There's more than one WebGL rendering context\\n // https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext#Browser_compatibility\\n // To find out the original values here: Object.getOwnPropertyDescriptors(WebGLRenderingContext.prototype.getParameter)\\n const addProxy = (obj, propName) => {\\n utils.replaceWithProxy(obj, propName, getParameterProxyHandler)\\n }\\n // For whatever weird reason loops don't play nice with Object.defineProperty, here's the next best thing:\\n addProxy(WebGLRenderingContext.prototype, 'getParameter')\\n addProxy(WebGL2RenderingContext.prototype, 'getParameter')\\n }\",_args:[{}]}),(()=>{try{if(window.outerWidth&&window.outerHeight)return;const n=85;window.outerWidth=window.innerWidth,window.outerHeight=window.innerHeight+n}catch(n){}})(),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:\"() => {\\n utils.preloadCache()\\n}\",stripProxyFromErrors:\"(handler = {}) => {\\n const newHandler = {\\n setPrototypeOf: function (target, proto) {\\n if (proto === null)\\n throw new TypeError('Cannot convert object to primitive value')\\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\\n throw new TypeError('Cyclic __proto__ value')\\n }\\n return Reflect.setPrototypeOf(target, proto)\\n }\\n }\\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\\n const traps = Object.getOwnPropertyNames(handler)\\n traps.forEach(trap => {\\n newHandler[trap] = function () {\\n try {\\n // Forward the call to the defined proxy handler\\n return handler[trap].apply(this, arguments || [])\\n } catch (err) {\\n // Stack traces differ per browser, we only support chromium based ones currently\\n if (!err || !err.stack || !err.stack.includes(`at `)) {\\n throw err\\n }\\n\\n // When something throws within one of our traps the Proxy will show up in error stacks\\n // An earlier implementation of this code would simply strip lines with a blacklist,\\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\\n // We try to use a known \\\"anchor\\\" line for that and strip it with everything above it.\\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\\n\\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\\n const blacklist = [\\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\\n `at Object.${trap} `, // e.g. Object.get or Object.apply\\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\\n ]\\n return (\\n err.stack\\n .split('\\\\n')\\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\\n .filter((line, index) => !(index === 1 && stripFirstLine))\\n // Check if the line starts with one of our blacklisted strings\\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\\n .join('\\\\n')\\n )\\n }\\n\\n const stripWithAnchor = (stack, anchor) => {\\n const stackArr = stack.split('\\\\n')\\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\\n const anchorIndex = stackArr.findIndex(line =>\\n line.trim().startsWith(anchor)\\n )\\n if (anchorIndex === -1) {\\n return false // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n return stackArr.join('\\\\n')\\n }\\n\\n // Special cases due to our nested toString proxies\\n err.stack = err.stack.replace(\\n 'at Object.toString (',\\n 'at Function.toString ('\\n )\\n if ((err.stack || '').includes('at Function.toString (')) {\\n err.stack = stripWithBlacklist(err.stack, false)\\n throw err\\n }\\n\\n // Try using the anchor method, fallback to blacklist if necessary\\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\\n\\n throw err // Re-throw our now sanitized error\\n }\\n }\\n })\\n return newHandler\\n}\",stripErrorWithAnchor:\"(err, anchor) => {\\n const stackArr = err.stack.split('\\\\n')\\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\\n if (anchorIndex === -1) {\\n return err // 404, anchor not found\\n }\\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\\n stackArr.splice(1, anchorIndex)\\n err.stack = stackArr.join('\\\\n')\\n return err\\n}\",replaceProperty:\"(obj, propName, descriptorOverrides = {}) => {\\n return Object.defineProperty(obj, propName, {\\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\\n // Add our overrides (e.g. value, get())\\n ...descriptorOverrides\\n })\\n}\",preloadCache:\"() => {\\n if (utils.cache) {\\n return\\n }\\n utils.cache = {\\n // Used in our proxies\\n Reflect: {\\n get: Reflect.get.bind(Reflect),\\n apply: Reflect.apply.bind(Reflect)\\n },\\n // Used in `makeNativeString`\\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\\n }\\n}\",makeNativeString:\"(name = '') => {\\n return utils.cache.nativeToStringStr.replace('toString', name || '')\\n}\",patchToString:\"(obj, str = '') => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n // `toString` targeted at our proxied Object detected\\n if (ctx === obj) {\\n // We either return the optional string verbatim or derive the most desired result automatically\\n return str || utils.makeNativeString(obj.name)\\n }\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",patchToStringNested:\"(obj = {}) => {\\n return utils.execRecursively(obj, ['function'], utils.patchToString)\\n}\",redirectToString:\"(proxyObj, originalObj) => {\\n const handler = {\\n apply: function (target, ctx) {\\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \\\"\\\"`\\n if (ctx === Function.prototype.toString) {\\n return utils.makeNativeString('toString')\\n }\\n\\n // `toString` targeted at our proxied Object detected\\n if (ctx === proxyObj) {\\n const fallback = () =>\\n originalObj && originalObj.name\\n ? utils.makeNativeString(originalObj.name)\\n : utils.makeNativeString(proxyObj.name)\\n\\n // Return the toString representation of our original object if possible\\n return originalObj + '' || fallback()\\n }\\n\\n if (typeof ctx === 'undefined' || ctx === null) {\\n return target.call(ctx)\\n }\\n\\n // Check if the toString protype of the context is the same as the global prototype,\\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\\n const hasSameProto = Object.getPrototypeOf(\\n Function.prototype.toString\\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\\n if (!hasSameProto) {\\n // Pass the call on to the local Function.prototype.toString instead\\n return ctx.toString()\\n }\\n\\n return target.call(ctx)\\n }\\n }\\n\\n const toStringProxy = new Proxy(\\n Function.prototype.toString,\\n utils.stripProxyFromErrors(handler)\\n )\\n utils.replaceProperty(Function.prototype, 'toString', {\\n value: toStringProxy\\n })\\n}\",replaceWithProxy:\"(obj, propName, handler) => {\\n const originalObj = obj[propName]\\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.redirectToString(proxyObj, originalObj)\\n\\n return true\\n}\",replaceGetterWithProxy:\"(obj, propName, handler) => {\\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\\n const fnStr = fn.toString() // special getter function string\\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { get: proxyObj })\\n utils.patchToString(proxyObj, fnStr)\\n\\n return true\\n}\",replaceGetterSetter:\"(obj, propName, handlerGetterSetter) => {\\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\\n const handler = { ...ownPropertyDescriptor }\\n\\n if (handlerGetterSetter.get !== undefined) {\\n const nativeFn = ownPropertyDescriptor.get\\n handler.get = function() {\\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.get, nativeFn)\\n }\\n\\n if (handlerGetterSetter.set !== undefined) {\\n const nativeFn = ownPropertyDescriptor.set\\n handler.set = function(newValue) {\\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\\n }\\n utils.redirectToString(handler.set, nativeFn)\\n }\\n\\n Object.defineProperty(obj, propName, handler)\\n}\",mockWithProxy:\"(obj, propName, pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n\\n utils.replaceProperty(obj, propName, { value: proxyObj })\\n utils.patchToString(proxyObj)\\n\\n return true\\n}\",createProxy:\"(pseudoTarget, handler) => {\\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\\n utils.patchToString(proxyObj)\\n\\n return proxyObj\\n}\",splitObjPath:\"objPath => ({\\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\\n objName: objPath.split('.').slice(0, -1).join('.'),\\n // Extract last dot entry ==> `canPlayType`\\n propName: objPath.split('.').slice(-1)[0]\\n})\",replaceObjPathWithProxy:\"(objPath, handler) => {\\n const { objName, propName } = utils.splitObjPath(objPath)\\n const obj = eval(objName) // eslint-disable-line no-eval\\n return utils.replaceWithProxy(obj, propName, handler)\\n}\",execRecursively:\"(obj = {}, typeFilter = [], fn) => {\\n function recurse(obj) {\\n for (const key in obj) {\\n if (obj[key] === undefined) {\\n continue\\n }\\n if (obj[key] && typeof obj[key] === 'object') {\\n recurse(obj[key])\\n } else {\\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\\n fn.call(this, obj[key])\\n }\\n }\\n }\\n }\\n recurse(obj)\\n return obj\\n}\",stringifyFns:\"(fnObj = { hello: () => 'world' }) => {\\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\\n // https://github.com/feross/fromentries\\n function fromEntries(iterable) {\\n return [...iterable].reduce((obj, [key, val]) => {\\n obj[key] = val\\n return obj\\n }, {})\\n }\\n return (Object.fromEntries || fromEntries)(\\n Object.entries(fnObj)\\n .filter(([key, value]) => typeof value === 'function')\\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\\n )\\n}\",materializeFns:\"(fnStrObj = { hello: \\\"() => 'world'\\\" }) => {\\n return Object.fromEntries(\\n Object.entries(fnStrObj).map(([key, value]) => {\\n if (value.startsWith('function')) {\\n // some trickery is needed to make oldschool functions work :-)\\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\\n } else {\\n // arrow functions just work\\n return [key, eval(value)] // eslint-disable-line no-eval\\n }\\n })\\n )\\n}\",makeHandler:\"() => ({\\n // Used by simple `navigator` getter evasions\\n getterValue: value => ({\\n apply(target, ctx, args) {\\n // Let's fetch the value first, to trigger and escalate potential errors\\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\\n utils.cache.Reflect.apply(...arguments)\\n return value\\n }\\n })\\n})\",arrayEquals:\"(array1, array2) => {\\n if (array1.length !== array2.length) {\\n return false\\n }\\n for (let i = 0; i < array1.length; ++i) {\\n if (array1[i] !== array2[i]) {\\n return false\\n }\\n }\\n return true\\n}\",memoize:\"fn => {\\n const cache = []\\n return function(...args) {\\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\\n cache.push({ key: args, value: fn.apply(this, args) })\\n }\\n return cache.find(c => utils.arrayEquals(c.key, args)).value\\n }\\n}\"},_mainFunction:\"(utils, opts) => {\\n try {\\n // Adds a contentWindow proxy to the provided iframe element\\n const addContentWindowProxy = iframe => {\\n const contentWindowProxy = {\\n get(target, key) {\\n // Now to the interesting part:\\n // We actually make this thing behave like a regular iframe window,\\n // by intercepting calls to e.g. `.self` and redirect it to the correct thing. :)\\n // That makes it possible for these assertions to be correct:\\n // iframe.contentWindow.self === window.top // must be false\\n if (key === 'self') {\\n return this\\n }\\n // iframe.contentWindow.frameElement === iframe // must be true\\n if (key === 'frameElement') {\\n return iframe\\n }\\n // Intercept iframe.contentWindow[0] to hide the property 0 added by the proxy.\\n if (key === '0') {\\n return undefined\\n }\\n return Reflect.get(target, key)\\n }\\n }\\n\\n if (!iframe.contentWindow) {\\n const proxy = new Proxy(window, contentWindowProxy)\\n Object.defineProperty(iframe, 'contentWindow', {\\n get() {\\n return proxy\\n },\\n set(newValue) {\\n return newValue // contentWindow is immutable\\n },\\n enumerable: true,\\n configurable: false\\n })\\n }\\n }\\n\\n // Handles iframe element creation, augments `srcdoc` property so we can intercept further\\n const handleIframeCreation = (target, thisArg, args) => {\\n const iframe = target.apply(thisArg, args)\\n\\n // We need to keep the originals around\\n const _iframe = iframe\\n const _srcdoc = _iframe.srcdoc\\n\\n // Add hook for the srcdoc property\\n // We need to be very surgical here to not break other iframes by accident\\n Object.defineProperty(iframe, 'srcdoc', {\\n configurable: true, // Important, so we can reset this later\\n get: function() {\\n return _srcdoc\\n },\\n set: function(newValue) {\\n addContentWindowProxy(this)\\n // Reset property, the hook is only needed once\\n Object.defineProperty(iframe, 'srcdoc', {\\n configurable: false,\\n writable: false,\\n value: _srcdoc\\n })\\n _iframe.srcdoc = newValue\\n }\\n })\\n return iframe\\n }\\n\\n // Adds a hook to intercept iframe creation events\\n const addIframeCreationSniffer = () => {\\n /* global document */\\n const createElementHandler = {\\n // Make toString() native\\n get(target, key) {\\n return Reflect.get(target, key)\\n },\\n apply: function(target, thisArg, args) {\\n const isIframe =\\n args && args.length && `${args[0]}`.toLowerCase() === 'iframe'\\n if (!isIframe) {\\n // Everything as usual\\n return target.apply(thisArg, args)\\n } else {\\n return handleIframeCreation(target, thisArg, args)\\n }\\n }\\n }\\n // All this just due to iframes with srcdoc bug\\n utils.replaceWithProxy(\\n document,\\n 'createElement',\\n createElementHandler\\n )\\n }\\n\\n // Let's go\\n addIframeCreationSniffer()\\n } catch (err) {\\n // console.warn(err)\\n }\\n }\",_args:[]});" 4 | -------------------------------------------------------------------------------- /consts/type.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | type FeedType string 4 | 5 | const ( 6 | Recommend FeedType = "homefeed_recommend" 7 | Fasion FeedType = "homefeed.fashion_v3" 8 | Food FeedType = "homefeed.food_v3" 9 | Cosmetics FeedType = "homefeed.cosmetics_v3" 10 | Movie FeedType = "homefeed.movie_and_tv_v3" 11 | Career FeedType = "homefeed.career_v3" 12 | Emotion FeedType = "homefeed.love_v3" 13 | Household FeedType = "homefeed.household_product_v3" 14 | Game FeedType = "homefeed.gaming_v3" 15 | Travel FeedType = "homefeed.travel_v3" 16 | Fitness FeedType = "homefeed.fitness_v3" 17 | ) 18 | 19 | type NoteType string 20 | 21 | const ( 22 | Normal NoteType = "normal" 23 | Video NoteType = "video" 24 | ) 25 | 26 | type SearchSortType string 27 | 28 | const ( 29 | General SearchSortType = "general" 30 | MostPopular SearchSortType = "popularity_descending" 31 | Latest SearchSortType = "time_descending" 32 | ) 33 | 34 | type SearchNoteType string 35 | 36 | const ( 37 | All SearchNoteType = "0" 38 | Videos SearchNoteType = "1" 39 | Image SearchNoteType = "2" 40 | ) 41 | -------------------------------------------------------------------------------- /example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Esword618/xhs-go/consts" 6 | "github.com/Esword618/xhs-go/xhs" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | const cookieStr = "输入你的cookies" 12 | 13 | XHS := xhs.NewXhs() 14 | err := XHS.Initialize(cookieStr, false) 15 | if err != nil { 16 | fmt.Println("Failed to initialize XhsClient:", err) 17 | return 18 | } 19 | fmt.Println("--------------------------------》GetNoteById") 20 | newjson, err := XHS.GetNoteById("649989da0000000027028451") 21 | if err != nil { 22 | return 23 | } 24 | fmt.Println(*newjson) 25 | fmt.Println("--------------------------------》GetUserInfo") 26 | newjson, err = XHS.GetUserInfo("5ff0e6410000000001008400") 27 | if err != nil { 28 | return 29 | } 30 | fmt.Println(*newjson) 31 | fmt.Println("--------------------------------》GetUserNotes") 32 | newjson, err = XHS.GetUserNotes("5ff0e6410000000001008400") 33 | if err != nil { 34 | return 35 | } 36 | fmt.Println(*newjson) 37 | fmt.Println("--------------------------------》GetNoteByKeyword") 38 | newjson, err = XHS.GetNoteByKeyword("音乐节") 39 | if err != nil { 40 | return 41 | } 42 | fmt.Println(*newjson) 43 | fmt.Println("--------------------------------》GetHomeFeed") 44 | newjson, err = XHS.GetHomeFeed(consts.Recommend) 45 | if err != nil { 46 | return 47 | } 48 | fmt.Println(*newjson) 49 | 50 | go func() { 51 | time.Sleep(10 * time.Second) 52 | XHS.SendCloseSignal() 53 | fmt.Println("-------------------》CloseCh") 54 | }() 55 | //阻塞程序,等待关闭命令 56 | XHS.WaitForCloseSignal() 57 | // 关闭客户端 58 | XHS.Close() 59 | } 60 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Esword618/xhs-go 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/imroc/req/v3 v3.37.2 7 | github.com/playwright-community/playwright-go v0.3500.0 8 | ) 9 | 10 | require ( 11 | github.com/andybalholm/brotli v1.0.4 // indirect 12 | github.com/bitly/go-simplejson v0.5.1 // indirect 13 | github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect 14 | github.com/gaukas/godicttls v0.0.3 // indirect 15 | github.com/go-jose/go-jose/v3 v3.0.0 // indirect 16 | github.com/go-stack/stack v1.8.1 // indirect 17 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect 18 | github.com/golang/mock v1.6.0 // indirect 19 | github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect 20 | github.com/hashicorp/errwrap v1.1.0 // indirect 21 | github.com/hashicorp/go-multierror v1.1.1 // indirect 22 | github.com/klauspost/compress v1.15.15 // indirect 23 | github.com/onsi/ginkgo/v2 v2.10.0 // indirect 24 | github.com/quic-go/qpack v0.4.0 // indirect 25 | github.com/quic-go/qtls-go1-19 v0.3.2 // indirect 26 | github.com/quic-go/qtls-go1-20 v0.2.2 // indirect 27 | github.com/quic-go/quic-go v0.35.1 // indirect 28 | github.com/refraction-networking/utls v1.3.2 // indirect 29 | go.uber.org/multierr v1.11.0 // indirect 30 | golang.org/x/crypto v0.10.0 // indirect 31 | golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect 32 | golang.org/x/mod v0.11.0 // indirect 33 | golang.org/x/net v0.11.0 // indirect 34 | golang.org/x/sys v0.9.0 // indirect 35 | golang.org/x/text v0.10.0 // indirect 36 | golang.org/x/tools v0.10.0 // indirect 37 | ) 38 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= 2 | github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= 3 | github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pgdoow= 4 | github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q= 5 | github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= 6 | github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= 7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 9 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/gaukas/godicttls v0.0.3 h1:YNDIf0d9adcxOijiLrEzpfZGAkNwLRzPaG6OjU7EITk= 11 | github.com/gaukas/godicttls v0.0.3/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= 12 | github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= 13 | github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= 14 | github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= 15 | github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= 16 | github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= 17 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= 18 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= 19 | github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= 20 | github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 21 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 22 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 23 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 24 | github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= 25 | github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= 26 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 27 | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= 28 | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 29 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= 30 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= 31 | github.com/imroc/req/v3 v3.37.2 h1:vEemuA0cq9zJ6lhe+mSRhsZm951bT0CdiSH47+KTn6I= 32 | github.com/imroc/req/v3 v3.37.2/go.mod h1:DECzjVIrj6jcUr5n6e+z0ygmCO93rx4Jy0RjOEe1YCI= 33 | github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= 34 | github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= 35 | github.com/onsi/ginkgo/v2 v2.10.0 h1:sfUl4qgLdvkChZrWCYndY2EAu9BRIw1YphNAzy1VNWs= 36 | github.com/onsi/ginkgo/v2 v2.10.0/go.mod h1:UDQOh5wbQUlMnkLfVaIUMtQ1Vus92oM+P2JX1aulgcE= 37 | github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= 38 | github.com/playwright-community/playwright-go v0.3500.0 h1:pWUwUa+JDibO3IOOjWsZ6d0gVehsLVCt6ZpJitePJXM= 39 | github.com/playwright-community/playwright-go v0.3500.0/go.mod h1:5BciqynTw2vyGwuMfhqfsc7hktCoZvoYQ+TBHRxvUME= 40 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 41 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 42 | github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= 43 | github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= 44 | github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= 45 | github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= 46 | github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= 47 | github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= 48 | github.com/quic-go/quic-go v0.35.1 h1:b0kzj6b/cQAf05cT0CkQubHM31wiA+xH3IBkxP62poo= 49 | github.com/quic-go/quic-go v0.35.1/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g= 50 | github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8= 51 | github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvjQpqP7L2vcm/9KUfm/E= 52 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 53 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 54 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 55 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 56 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 57 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 58 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 59 | golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 60 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 61 | golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= 62 | golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= 63 | golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= 64 | golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= 65 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 66 | golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= 67 | golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 68 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 69 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 70 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 71 | golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= 72 | golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= 73 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 74 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 75 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 76 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 77 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 78 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 79 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 80 | golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= 81 | golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 82 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 83 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 84 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 85 | golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= 86 | golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 87 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 88 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 89 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 90 | golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= 91 | golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= 92 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 93 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 94 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 95 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 96 | google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= 97 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 98 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 99 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 100 | -------------------------------------------------------------------------------- /utils/cookie.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "strings" 4 | 5 | func ConvertStrCookieToDict(cookieStr string) map[string]string { 6 | cookieDict := make(map[string]string) 7 | 8 | if cookieStr == "" { 9 | return cookieDict 10 | } 11 | 12 | cookies := strings.Split(cookieStr, ";") 13 | for _, cookie := range cookies { 14 | cookie = strings.TrimSpace(cookie) 15 | if cookie == "" { 16 | continue 17 | } 18 | cookieArr := strings.Split(cookie, "=") 19 | cookieValue := cookieArr[1] 20 | if len(cookieValue) > 1 { 21 | cookieDict[cookieArr[0]] = cookieValue 22 | } 23 | } 24 | 25 | return cookieDict 26 | } 27 | -------------------------------------------------------------------------------- /utils/help.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/md5" 5 | "encoding/base64" 6 | "encoding/json" 7 | "fmt" 8 | "math/big" 9 | "math/rand" 10 | "net/url" 11 | "strconv" 12 | "time" 13 | "unsafe" 14 | ) 15 | 16 | func Sign(uri string, data map[string]interface{}, ctime int64, a1, b1 string) map[string]string { 17 | v := strconv.FormatInt(ctime, 10) 18 | raw_str := fmt.Sprintf("%s%s%s", v, "test", uri) 19 | if dataJSON, err := json.Marshal(data); err == nil { 20 | raw_str += string(dataJSON) 21 | } 22 | 23 | md5Str := fmt.Sprintf("%x", md5.Sum([]byte(raw_str))) 24 | x_s := h(md5Str) 25 | x_t := v 26 | 27 | common := map[string]interface{}{ 28 | "s0": 5, // getPlatformCode 29 | "s1": "", 30 | "x0": "1", // localStorage.getItem("b1b1") 31 | "x1": "3.2.0", // version 32 | "x2": "Windows", 33 | "x3": "xhs-pc-web", 34 | "x4": "2.3.1", 35 | "x5": a1, // cookie of a1 36 | "x6": x_t, 37 | "x7": x_s, 38 | "x8": b1, // localStorage.getItem("b1") 39 | "x9": mrc(x_t + x_s), // Assuming mrc is implemented elsewhere 40 | "x10": 1, // getSigCount 41 | } 42 | 43 | encodeStr, _ := json.Marshal(common) 44 | x_s_common := base64.StdEncoding.EncodeToString(encodeStr) 45 | 46 | return map[string]string{ 47 | "x-s": x_s, 48 | "x-t": x_t, 49 | "x-s-common": x_s_common, 50 | } 51 | } 52 | 53 | //func Sign(a1, b1, x_s, x_t string) map[string]string { 54 | // common := map[string]any{ 55 | // "s0": 5, // getPlatformCode 56 | // "s1": "", 57 | // "x0": "1", // localStorage.getItem("b1b1") 58 | // "x1": "3.3.0", // version 59 | // "x2": "Windows", 60 | // "x3": "xhs-pc-web", 61 | // "x4": "1.4.4", 62 | // "x5": a1, // cookie of a1 63 | // "x6": x_t, 64 | // "x7": x_s, 65 | // "x8": b1, // localStorage.getItem("b1") 66 | // "x9": mrc(x_t + x_s + b1), 67 | // "x10": 1, // getSigCount 68 | // } 69 | // 70 | // encodeStr, _ := json.Marshal(common) 71 | // x_s_common := base64.StdEncoding.EncodeToString(encodeStr) 72 | // x_b3_traceid := GetB3TraceID() 73 | // 74 | // return map[string]string{ 75 | // "x-s": x_s, 76 | // "x-t": x_t, 77 | // "x-s-common": x_s_common, 78 | // "x-b3-traceid": x_b3_traceid, 79 | // } 80 | //} 81 | 82 | func h(n string) string { 83 | m := "" 84 | d := "A4NjFqYu5wPHsO0XTdDgMa2r1ZQocVte9UJBvk6/7=yRnhISGKblCWi+LpfE8xzm3" 85 | for i := 0; i < 32; i += 3 { 86 | o := int(n[i]) 87 | g := 0 88 | h := 0 89 | if i+1 < 32 { 90 | g = int(n[i+1]) 91 | } 92 | if i+2 < 32 { 93 | h = int(n[i+2]) 94 | } 95 | x := ((o & 3) << 4) | (g >> 4) 96 | p := ((15 & g) << 2) | (h >> 6) 97 | v := o >> 2 98 | b := h & 63 99 | if h == 0 { 100 | b = 64 101 | } 102 | if g == 0 { 103 | p = 64 104 | b = 64 105 | } 106 | m += string(d[v]) + string(d[x]) + string(d[p]) + string(d[b]) 107 | } 108 | return m 109 | } 110 | 111 | func GetB3TraceID() string { 112 | re := "abcdef0123456789" 113 | je := 16 114 | e := "" 115 | 116 | random := rand.New(rand.NewSource(time.Now().UnixNano())) 117 | for t := 0; t < 16; t++ { 118 | index := random.Intn(je) 119 | e += string(re[index]) 120 | } 121 | 122 | return e 123 | } 124 | 125 | func mrc(e string) int32 { 126 | ie := []int{ 127 | 0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685, 128 | 2657392035, 249268274, 2044508324, 3772115230, 2547177864, 162941995, 129 | 2125561021, 3887607047, 2428444049, 498536548, 1789927666, 4089016648, 130 | 2227061214, 450548861, 1843258603, 4107580753, 2211677639, 325883990, 131 | 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755, 132 | 2366115317, 997073096, 1281953886, 3579855332, 2724688242, 1006888145, 133 | 1258607687, 3524101629, 2768942443, 901097722, 1119000684, 3686517206, 134 | 2898065728, 853044451, 1172266101, 3705015759, 2882616665, 651767980, 135 | 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705, 136 | 3099436303, 671266974, 1594198024, 3322730930, 2970347812, 795835527, 137 | 1483230225, 3244367275, 3060149565, 1994146192, 31158534, 2563907772, 138 | 4023717930, 1907459465, 112637215, 2680153253, 3904427059, 2013776290, 139 | 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719, 140 | 3865271297, 1802195444, 476864866, 2238001368, 4066508878, 1812370925, 141 | 453092731, 2181625025, 4111451223, 1706088902, 314042704, 2344532202, 142 | 4240017532, 1658658271, 366619977, 2362670323, 4224994405, 1303535960, 143 | 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733, 144 | 3554079995, 1131014506, 879679996, 2909243462, 3663771856, 1141124467, 145 | 855842277, 2852801631, 3708648649, 1342533948, 654459306, 3188396048, 146 | 3373015174, 1466479909, 544179635, 3110523913, 3462522015, 1591671054, 147 | 702138776, 2966460450, 3352799412, 1504918807, 783551873, 3082640443, 148 | 3233442989, 3988292384, 2596254646, 62317068, 1957810842, 3939845945, 149 | 2647816111, 81470997, 1943803523, 3814918930, 2489596804, 225274430, 150 | 2053790376, 3826175755, 2466906013, 167816743, 2097651377, 4027552580, 151 | 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225, 152 | 1852507879, 4275313526, 2312317920, 282753626, 1742555852, 4189708143, 153 | 2394877945, 397917763, 1622183637, 3604390888, 2714866558, 953729732, 154 | 1340076626, 3518719985, 2797360999, 1068828381, 1219638859, 3624741850, 155 | 2936675148, 906185462, 1090812512, 3747672003, 2825379669, 829329135, 156 | 1181335161, 3412177804, 3160834842, 628085408, 1382605366, 3423369109, 157 | 3138078467, 570562233, 1426400815, 3317316542, 2998733608, 733239954, 158 | 1555261956, 3268935591, 3050360625, 752459403, 1541320221, 2607071920, 159 | 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877, 160 | 83908371, 2512341634, 3803740692, 2075208622, 213261112, 2463272603, 161 | 3855990285, 2094854071, 198958881, 2262029012, 4057260610, 1759359992, 162 | 534414190, 2176718541, 4139329115, 1873836001, 414664567, 2282248934, 163 | 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795, 164 | 376229701, 2685067896, 3608007406, 1308918612, 956543938, 2808555105, 165 | 3495958263, 1231636301, 1047427035, 2932959818, 3654703836, 1088359270, 166 | 936918000, 2847714899, 3736837829, 1202900863, 817233897, 3183342108, 167 | 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449, 168 | 601450431, 3009837614, 3294710456, 1567103746, 711928724, 3020668471, 169 | 3272380065, 1510334235, 755167117, 170 | } 171 | 172 | o := -1 173 | 174 | rightWithoutSign := func(num uint32, bit int) int { 175 | val := uint32(uintptr(unsafe.Pointer(&num))) >> bit 176 | MAX32INT := uint32(4294967295) 177 | return (int(val+(MAX32INT+1)) % (2 * int(MAX32INT+1))) - int(MAX32INT) - 1 178 | } 179 | 180 | for n := 0; n < 57; n++ { 181 | o = ie[(o&255)^int(e[n])] ^ rightWithoutSign(uint32(o), 8) 182 | } 183 | return int32(o ^ -1 ^ 3988292384) 184 | } 185 | 186 | var lookup = []string{ 187 | "Z", "m", "s", "e", "r", "b", "B", "o", "H", "Q", "t", "N", "P", "+", "w", "O", "c", 188 | "z", "a", "/", "L", "p", "n", "g", "G", "8", "y", "J", "q", "4", "2", "K", "W", "Y", 189 | "j", "0", "D", "S", "f", "d", "i", "k", "x", "3", "V", "T", "1", "6", "I", "l", "U", 190 | "A", "F", "M", "9", "7", "h", "E", "C", "v", "u", "R", "X", "5", 191 | } 192 | 193 | func tripletToBase64(e uint32) string { 194 | return lookup[63&(e>>18)] + 195 | lookup[63&(e>>12)] + 196 | lookup[(e>>6)&63] + 197 | lookup[e&63] 198 | } 199 | 200 | func encodeChunk(e []byte, t, r int) string { 201 | m := make([]string, 0) 202 | for b := t; b < r; b += 3 { 203 | n := (16711680 & (int(e[b]) << 16)) + 204 | ((int(e[b+1]) << 8) & 65280) + 205 | (int(e[b+2]) & 255) 206 | m = append(m, tripletToBase64(uint32(n))) 207 | } 208 | return fmt.Sprintf("%s", m) 209 | } 210 | 211 | func b64Encode(e string) string { 212 | P := len(e) 213 | W := P % 3 214 | U := make([]string, 0) 215 | z := 16383 216 | H := 0 217 | Z := P - W 218 | for H < Z { 219 | U = append(U, encodeChunk([]byte(e), H, min(Z, H+z))) 220 | H += z 221 | } 222 | if W == 1 { 223 | F := int(e[P-1]) 224 | U = append(U, lookup[F>>2]+lookup[(F<<4)&63]+"==") 225 | } else if W == 2 { 226 | F := (int(e[P-2]) << 8) + int(e[P-1]) 227 | U = append(U, lookup[F>>10]+lookup[63&(F>>4)]+lookup[(F<<2)&63]+"=") 228 | } 229 | return fmt.Sprintf("%s", U) 230 | } 231 | 232 | func min(a, b int) int { 233 | if a < b { 234 | return a 235 | } 236 | return b 237 | } 238 | 239 | func encodeUtf8(e string) []int { 240 | b := []int{} 241 | m := url.QueryEscape(e) 242 | w := 0 243 | 244 | for w < len(m) { 245 | T := m[w] 246 | if T == '%' { 247 | E := m[w+1 : w+3] 248 | S := 0 249 | fmt.Sscanf(E, "%x", &S) 250 | b = append(b, S) 251 | w += 2 252 | } else { 253 | b = append(b, int(T)) 254 | } 255 | w++ 256 | } 257 | 258 | return b 259 | } 260 | 261 | func base36encode(number *big.Int, alphabet string) string { 262 | if number.Sign() < 0 { 263 | return "-" + base36encode(new(big.Int).Neg(number), alphabet) 264 | } 265 | 266 | base36 := "" 267 | length := big.NewInt(int64(len(alphabet))) 268 | 269 | zero := big.NewInt(0) 270 | div, mod := new(big.Int), new(big.Int) 271 | 272 | for number.Cmp(zero) != 0 { 273 | div.Mod(number, length) 274 | number.Div(number, length) 275 | mod.Abs(div) 276 | 277 | base36 = string(alphabet[mod.Int64()]) + base36 278 | } 279 | 280 | return base36 281 | } 282 | 283 | func base36decode(number string) *big.Int { 284 | result := new(big.Int) 285 | result.SetString(number, 36) 286 | return result 287 | } 288 | 289 | func GetSearchID() string { 290 | e := new(big.Int) 291 | timestamp := time.Now().UnixNano() / 1e6 292 | e.Lsh(big.NewInt(timestamp), 64) 293 | 294 | random := rand.New(rand.NewSource(time.Now().UnixNano())) 295 | t := new(big.Int) 296 | t.SetInt64(int64(random.Intn(2147483646))) 297 | 298 | result := new(big.Int) 299 | result.Add(e, t) 300 | 301 | alphabet := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 302 | return base36encode(result, alphabet) 303 | } 304 | -------------------------------------------------------------------------------- /utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func GetUserAgent() string { 10 | uaList := []string{ 11 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 12 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.79 Safari/537.36", 13 | "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36", 14 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36", 15 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36", 16 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36", 17 | } 18 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 19 | return uaList[r.Intn(len(uaList))] 20 | } 21 | 22 | // func ConvertInterfaceToMap(i interface{}) (map[string]string, error) { 23 | // if iMap, ok := i.(map[string]interface{}); ok { 24 | // result := make(map[string]string) 25 | // for key, value := range iMap { 26 | // if strValue, ok := value.(string); ok { 27 | // result[key] = strValue 28 | // } else { 29 | // return nil, fmt.Errorf("value for key %s is not a string", key) 30 | // } 31 | // } 32 | // return result, nil 33 | // } 34 | // return nil, fmt.Errorf("input is not a map[string]interface{}") 35 | // } 36 | func ConvertInterfaceToMap(i interface{}) (map[string]string, error) { 37 | if iMap, ok := i.(map[string]string); ok { 38 | return iMap, nil 39 | } 40 | return nil, fmt.Errorf("input is not a map[string]string") 41 | } 42 | -------------------------------------------------------------------------------- /xhs/api.go: -------------------------------------------------------------------------------- 1 | package xhs 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/Esword618/xhs-go/consts" 7 | "github.com/Esword618/xhs-go/utils" 8 | "github.com/bitly/go-simplejson" 9 | ) 10 | 11 | // GetNoteById 获取笔记通过 noteId 12 | func (x *xhsClient) GetNoteById(noteId string) (*simplejson.Json, error) { 13 | res, err := x.client.R(). 14 | SetBody(fmt.Sprintf(`{"source_note_id":"%s"}`, noteId)). 15 | Post("/api/sns/web/v1/feed") 16 | if err != nil { 17 | return simplejson.New(), err 18 | } 19 | return simplejson.NewFromReader(res.Body) 20 | } 21 | 22 | // GetUserInfo 获取用户信息通过 userId 23 | func (x *xhsClient) GetUserInfo(userId string) (*simplejson.Json, error) { 24 | res, err := x.client.R(). 25 | SetQueryParams(map[string]string{ 26 | "target_user_id": userId, 27 | }). 28 | Get("/api/sns/web/v1/user/otherinfo") 29 | if err != nil { 30 | return simplejson.New(), err 31 | } 32 | return simplejson.NewFromReader(res.Body) 33 | } 34 | 35 | // GetUserNotes 获取用户笔记通过 userId,cursor(可选参数) 36 | func (x *xhsClient) GetUserNotes(userId string, cursor ...string) (*simplejson.Json, error) { 37 | cursorValue := "" 38 | if len(cursor) > 0 { 39 | cursorValue = cursor[0] 40 | } 41 | res, err := x.client.R(). 42 | SetQueryParams(map[string]string{ 43 | "num": "30", 44 | "cursor": cursorValue, 45 | "user_id": userId, 46 | }). 47 | Get("/api/sns/web/v1/user_posted") 48 | if err != nil { 49 | return simplejson.New(), err 50 | } 51 | return simplejson.NewFromReader(res.Body) 52 | } 53 | 54 | // GetNoteByKeyword 获取笔记通过关键词 keyword,page默认1,page_size默认20,sort默认排序,noteType默认全部笔记类型 55 | func (x *xhsClient) GetNoteByKeyword(keyword string, args ...interface{}) (*simplejson.Json, error) { 56 | page := 1 57 | pageSize := 20 58 | sort := consts.General 59 | noteType := consts.All 60 | 61 | if len(args) >= 1 { 62 | if arg, ok := args[0].(int); ok { 63 | page = arg 64 | } 65 | } 66 | 67 | if len(args) >= 2 { 68 | if arg, ok := args[1].(int); ok { 69 | pageSize = arg 70 | } 71 | } 72 | 73 | if len(args) >= 3 { 74 | if arg, ok := args[2].(consts.SearchSortType); ok { 75 | sort = arg 76 | } 77 | } 78 | 79 | if len(args) >= 4 { 80 | if arg, ok := args[3].(consts.SearchNoteType); ok { 81 | noteType = arg 82 | } 83 | } 84 | data := map[string]any{ 85 | "keyword": keyword, 86 | "page": page, 87 | "page_size": pageSize, 88 | "search_id": utils.GetSearchID(), 89 | "sort": sort, 90 | "note_type": noteType, 91 | } 92 | dataStr, err := json.Marshal(data) 93 | if err != nil { 94 | return simplejson.New(), err 95 | } 96 | res, err := x.client.R(). 97 | SetBody(dataStr). 98 | Post("/api/sns/web/v1/search/notes") 99 | if err != nil { 100 | return simplejson.New(), err 101 | } 102 | return simplejson.NewFromReader(res.Body) 103 | } 104 | 105 | // GetHomeFeed .... 106 | func (x *xhsClient) GetHomeFeed(feedType consts.FeedType) (*simplejson.Json, error) { 107 | data := map[string]any{ 108 | "cursor_score": "", 109 | "num": 40, 110 | "refresh_type": 1, 111 | "note_index": 0, 112 | "unread_begin_note_id": "", 113 | "unread_end_note_id": "", 114 | "unread_note_count": 0, 115 | "category": feedType, 116 | } 117 | dataStr, err := json.Marshal(data) 118 | if err != nil { 119 | return simplejson.New(), err 120 | } 121 | res, err := x.client.R(). 122 | SetBody(dataStr). 123 | Post("/api/sns/web/v1/homefeed") 124 | if err != nil { 125 | return simplejson.New(), err 126 | } 127 | return simplejson.NewFromReader(res.Body) 128 | } 129 | -------------------------------------------------------------------------------- /xhs/xhs.go: -------------------------------------------------------------------------------- 1 | package xhs 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/Esword618/xhs-go/consts" 7 | "github.com/Esword618/xhs-go/utils" 8 | "github.com/bitly/go-simplejson" 9 | "github.com/imroc/req/v3" 10 | "github.com/playwright-community/playwright-go" 11 | "net/http" 12 | "net/url" 13 | "strings" 14 | ) 15 | 16 | type IXhsClient interface { 17 | Initialize(cookieStr string, headless ...bool) error 18 | SendCloseSignal() 19 | WaitForCloseSignal() 20 | Close() 21 | GetNoteById(noteId string) (*simplejson.Json, error) 22 | GetUserInfo(userId string) (*simplejson.Json, error) 23 | GetUserNotes(userId string, cursor ...string) (*simplejson.Json, error) 24 | GetNoteByKeyword(keyword string, args ...interface{}) (*simplejson.Json, error) 25 | GetHomeFeed(feedType consts.FeedType) (*simplejson.Json, error) 26 | } 27 | 28 | var xhsclient = xhsClient{} 29 | 30 | func NewXhs() IXhsClient { 31 | return &xhsclient 32 | } 33 | 34 | type xhsClient struct { 35 | client *req.Client 36 | PW *playwright.Playwright 37 | Browser playwright.Browser 38 | BrowserContext playwright.BrowserContext 39 | ContextPage playwright.Page 40 | CloseCh chan struct{} 41 | cookieMap map[string]string 42 | } 43 | 44 | // Initialize 初始化 45 | func (x *xhsClient) Initialize(cookieStr string, headless ...bool) error { 46 | headless1 := true 47 | if len(headless) > 0 { 48 | headless1 = headless[0] 49 | } 50 | runOption := &playwright.RunOptions{ 51 | SkipInstallBrowsers: true, 52 | } 53 | err := playwright.Install(runOption) 54 | if err != nil { 55 | return fmt.Errorf("could not install playwright dependencies: %v", err) 56 | } 57 | 58 | // 初始化一个pw 59 | pw, err := playwright.Run() 60 | if err != nil { 61 | return fmt.Errorf("failed to start Playwright: %v", err) 62 | } 63 | // browser 64 | browser, err := pw.Chromium.Launch(playwright.BrowserTypeLaunchOptions{ 65 | Channel: playwright.String("chrome"), 66 | Headless: playwright.Bool(headless1), 67 | }) 68 | if err != nil { 69 | return fmt.Errorf("failed to launch Chromium: %v", err) 70 | } 71 | 72 | // browserContext 73 | browserContext, err := browser.NewContext(playwright.BrowserNewContextOptions{ 74 | UserAgent: playwright.String("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"), 75 | Viewport: &playwright.ViewportSize{ 76 | Width: 1520, 77 | Height: 1080, 78 | }, 79 | }) 80 | if err != nil { 81 | return fmt.Errorf("failed to create browser context: %v", err) 82 | } 83 | err = browserContext.AddInitScript(playwright.BrowserContextAddInitScriptOptions{ 84 | Script: playwright.String(consts.StealthMinJs), 85 | }) 86 | if err != nil { 87 | return fmt.Errorf("执行js报错: %v", err) 88 | } 89 | var cookiesP []playwright.OptionalCookie 90 | var cookies []*http.Cookie 91 | cookiemap := utils.ConvertStrCookieToDict(cookieStr) 92 | for key, value := range cookiemap { 93 | cookiesP = append(cookiesP, playwright.OptionalCookie{ 94 | Name: playwright.String(key), 95 | Value: playwright.String(value), 96 | Domain: playwright.String(".xiaohongshu.com"), 97 | Path: playwright.String("/"), 98 | }) 99 | cookies = append(cookies, &http.Cookie{ 100 | Name: key, 101 | Value: value, 102 | Domain: ".xiaohongshu.com", 103 | Path: "/", 104 | }) 105 | } 106 | 107 | err = browserContext.AddCookies(cookiesP...) 108 | if err != nil { 109 | return fmt.Errorf("add cookie 失败: %v", err) 110 | } 111 | 112 | // contextPage 113 | contextPage, err := browserContext.NewPage() 114 | if err != nil { 115 | return fmt.Errorf("failed to create page: %v", err) 116 | } 117 | 118 | // 执行页面导航操作 119 | _, err = contextPage.Goto("https://www.xiaohongshu.com") 120 | if err != nil { 121 | return fmt.Errorf("Failed to navigate to URL:", err) 122 | } 123 | 124 | // client 125 | contextPage.WaitForTimeout(3000) 126 | client := req.C() 127 | client.SetTLSFingerprintChrome() 128 | client.SetCommonHeaders(map[string]string{ 129 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 130 | "content-type": "application/json;charset=UTF-8", 131 | }) 132 | client.SetBaseURL("https://edith.xiaohongshu.com") 133 | client.SetCommonCookies(cookies...) 134 | client.OnBeforeRequest(func(client *req.Client, req *req.Request) error { 135 | 136 | var rawURL string 137 | var data string 138 | switch req.Method { 139 | case http.MethodPost: 140 | rawURL = req.RawURL 141 | data = string(req.Body) 142 | case http.MethodGet: 143 | queryParams := url.Values{} 144 | for k, v := range req.QueryParams { 145 | queryParams.Set(k, v[0]) 146 | } 147 | 148 | queryString := queryParams.Encode() 149 | rawURL = fmt.Sprintf("%s?%s", req.RawURL, queryString) 150 | data = "" 151 | default: 152 | return errors.New("未知请求") 153 | } 154 | encryptParams, err := x.sign(rawURL, data, req.Method) 155 | if err != nil { 156 | fmt.Printf("before request,%v\n", err) 157 | } 158 | for key, value := range encryptParams { 159 | req.Headers.Add(key, value) 160 | } 161 | return nil 162 | }) 163 | x.PW = pw 164 | x.Browser = browser 165 | x.BrowserContext = browserContext 166 | x.ContextPage = contextPage 167 | x.CloseCh = make(chan struct{}) 168 | x.client = client 169 | x.cookieMap = cookiemap 170 | return nil 171 | } 172 | 173 | // SendCloseSignal 发送关闭信号 174 | func (x *xhsClient) SendCloseSignal() { 175 | x.CloseCh <- struct{}{} 176 | } 177 | 178 | // WaitForCloseSignal 等待关闭信号 179 | func (x *xhsClient) WaitForCloseSignal() { 180 | <-x.CloseCh 181 | } 182 | 183 | // Close 关闭 184 | func (x *xhsClient) Close() { 185 | if x.CloseCh != nil { 186 | close(x.CloseCh) 187 | } 188 | if x.ContextPage != nil { 189 | x.ContextPage.Close() 190 | } 191 | if x.BrowserContext != nil { 192 | x.BrowserContext.Close() 193 | } 194 | if x.Browser != nil { 195 | x.Browser.Close() 196 | } 197 | if x.PW != nil { 198 | x.PW.Stop() 199 | } 200 | } 201 | 202 | // sign值获取 203 | func (x *xhsClient) sign(rawUrl, data, method string) (map[string]string, error) { 204 | var jsStr string 205 | switch method { 206 | case http.MethodPost: 207 | jsStr = fmt.Sprintf(` 208 | const url = "%s"; 209 | const data = JSON.parse('%s'); 210 | window._webmsxyw(url, data); 211 | `, rawUrl, data) 212 | case http.MethodGet: 213 | jsStr = fmt.Sprintf(` 214 | const url = "%s"; 215 | const data = "%s"; 216 | window._webmsxyw(url); 217 | `, rawUrl, data) 218 | } 219 | encryptParams, err := x.ContextPage.Evaluate(jsStr) 220 | convertedParams := make(map[string]string) 221 | if err != nil { 222 | fmt.Println(err) 223 | return convertedParams, err 224 | } 225 | encryptParamsMap, ok := encryptParams.(map[string]interface{}) 226 | if !ok { 227 | // 处理类型不匹配的情况 228 | return convertedParams, fmt.Errorf("encryptParams is not a map[string]interface{}") 229 | } 230 | 231 | for key, value := range encryptParamsMap { 232 | strValue := fmt.Sprintf("%v", value) 233 | convertedParams[strings.ToLower(key)] = strValue 234 | } 235 | return convertedParams, nil 236 | } 237 | --------------------------------------------------------------------------------