/* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { hookNative } from './anti-detection' const CHUNK_PUSH_FN = /^function [^r]\(\w\){/ interface Module { (module, exports, __webpack_require__): void; } type WebpackJson = [(number | string)[], { [id: string]: Module }, any[]?][] const moduleLookup = (id: string, globalWebpackJson: WebpackJson) => { const pack = globalWebpackJson.find(x => x[1][id])! return pack[1][id] } /** * Retrieve (webpack_require) a module from the page's webpack package * * I know this is super hacky. */ export const webpackHook = (moduleId: string, moduleOverrides: { [id: string]: Module } = {}, globalWebpackJson: WebpackJson = window['webpackJsonpmusescore']) => { const t = Object.assign((id: string, override = true) => { const r: any = {} const m: Module = (override && moduleOverrides[id]) ? moduleOverrides[id] : moduleLookup(id, globalWebpackJson) m(r, r, t) if (r.exports) return r.exports return r }, { d (exp, name, fn) { return Object.prototype.hasOwnProperty.call(exp, name) || Object.defineProperty(exp, name, { enumerable: true, get: fn }) }, n (e) { const m = e.__esModule ? () => e.default : () => e t.d(m, 'a', m) return m }, r (r) { Object.defineProperty(r, '__esModule', { value: true }) }, e () { return Promise.resolve() }, }) return t(moduleId) } export const ALL = '*' export const [webpackGlobalOverride, onPackLoad] = (() => { type OnPackLoadFn = (pack: WebpackJson[0]) => any const moduleOverrides: { [id: string]: Module } = {} const onPackLoadFns: OnPackLoadFn[] = [] function applyOverride (pack: WebpackJson[0]) { let entries = Object.entries(moduleOverrides) // apply to all const all = moduleOverrides[ALL] if (all) { entries = Object.keys(pack[1]).map(id => [id, all]) } entries.forEach(([id, override]) => { const mod = pack[1][id] if (mod) { pack[1][id] = function (n, r, t) { // make exports configurable t = Object.assign(t, { d (exp, name, fn) { return Object.defineProperty(exp, name, { enumerable: true, get: fn, configurable: true }) }, }) mod(n, r, t) override(n, r, t) } } }) } // hook `webpackJsonpmusescore.push` as soon as `webpackJsonpmusescore` is available let jsonp = window['webpackJsonpmusescore'] let hooked = false Object.defineProperty(window, 'webpackJsonpmusescore', { get () { return jsonp }, set (v: WebpackJson) { jsonp = v if (!hooked && v.push.toString().match(CHUNK_PUSH_FN)) { hooked = true hookNative(v, 'push', (_fn) => { return function (pack) { onPackLoadFns.forEach(fn => fn(pack)) applyOverride(pack) return _fn.call(this, pack) } }) } }, }) return [ // set overrides (moduleId: string, override: Module) => { moduleOverrides[moduleId] = override }, // set onPackLoad listeners (fn: OnPackLoadFn) => { onPackLoadFns.push(fn) }, ] as const })() export const webpackContext = new Promise((resolve) => { webpackGlobalOverride(ALL, (n, r, t) => { resolve(t) }) }) export default webpackHook