README.md
Rendering markdown...
import { fileURLToPath } from 'url';
import path from 'path';
import fs from 'fs';
import crypto, { webcrypto } from 'crypto';
import { TextEncoder, TextDecoder } from 'util';
import { performance } from 'perf_hooks';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const EXTENSION_ID = '';
const EXTENSION_ORIGIN = `chrome-extension://${EXTENSION_ID}`;
function spoofExtensionOrigin() {
const locationMock = {
origin: EXTENSION_ORIGIN,
href: `${EXTENSION_ORIGIN}/worker.js`,
protocol: 'chrome-extension:',
host: EXTENSION_ID,
hostname: EXTENSION_ID,
port: '',
pathname: '/worker.js',
search: '',
hash: '',
ancestorOrigins: [],
assign: () => {},
reload: () => {},
replace: () => {},
toString: () => `${EXTENSION_ORIGIN}/worker.js`,
};
try {
Object.defineProperty(globalThis, 'location', {
value: locationMock,
writable: false,
configurable: true,
});
} catch (e) {
if (globalThis.location) {
try {
Object.defineProperty(globalThis.location, 'origin', { value: EXTENSION_ORIGIN, writable: false });
Object.defineProperty(globalThis.location, 'href', { value: `${EXTENSION_ORIGIN}/worker.js`, writable: false });
Object.defineProperty(globalThis.location, 'protocol', { value: 'chrome-extension:', writable: false });
} catch (e2) {}
}
}
if (globalThis.self && globalThis.self !== globalThis) {
try {
Object.defineProperty(globalThis.self, 'location', {
value: locationMock,
writable: false,
configurable: true,
});
} catch (e) {}
}
}
function spoofServiceWorkerGlobalScope() {
class ServiceWorkerGlobalScope {
constructor() {
this.registration = {
scope: EXTENSION_ORIGIN + '/',
active: { state: 'activated' },
installing: null,
waiting: null,
navigationPreload: { enable: () => Promise.resolve() },
showNotification: () => Promise.resolve(),
getNotifications: () => Promise.resolve([]),
update: () => Promise.resolve(),
unregister: () => Promise.resolve(true),
};
this.serviceWorker = this.registration.active;
this.clients = {
claim: () => Promise.resolve(),
get: () => Promise.resolve(null),
matchAll: () => Promise.resolve([]),
openWindow: () => Promise.resolve(null),
};
this.skipWaiting = () => Promise.resolve();
}
}
globalThis.ServiceWorkerGlobalScope = ServiceWorkerGlobalScope;
const swgsMethods = {
registration: {
scope: EXTENSION_ORIGIN + '/',
active: { state: 'activated', scriptURL: `${EXTENSION_ORIGIN}/worker.js` },
installing: null,
waiting: null,
update: () => Promise.resolve(),
unregister: () => Promise.resolve(true),
},
skipWaiting: () => Promise.resolve(),
clients: globalThis.clients || {
claim: () => Promise.resolve(),
get: () => Promise.resolve(null),
matchAll: () => Promise.resolve([]),
openWindow: () => Promise.resolve(null),
},
};
Object.keys(swgsMethods).forEach(key => {
if (!(key in globalThis)) {
try {
Object.defineProperty(globalThis, key, {
value: swgsMethods[key],
writable: true,
configurable: true,
});
} catch (e) {}
}
});
try {
Object.setPrototypeOf(globalThis, ServiceWorkerGlobalScope.prototype);
} catch (e) {}
}
function spoofSelf() {
if (typeof globalThis.self === 'undefined' || globalThis.self !== globalThis) {
try {
Object.defineProperty(globalThis, 'self', {
value: globalThis,
writable: false,
configurable: true,
});
} catch (e) {}
}
try {
Object.defineProperty(globalThis, 'origin', {
value: EXTENSION_ORIGIN,
writable: false,
configurable: true,
});
} catch (e) {}
}
function spoofImportScripts() {
if (typeof globalThis.importScripts === 'undefined') {
globalThis.importScripts = (...urls) => {
console.log('[Spoof] importScripts called with:', urls);
// Load and execute scripts synchronously
urls.forEach(url => {
try {
let scriptPath;
if (url.startsWith('chrome-extension://') || url.startsWith(EXTENSION_ORIGIN)) {
// Extract filename from extension URL
const filename = url.split('/').pop();
scriptPath = path.join(__dirname, filename);
} else {
scriptPath = path.join(__dirname, url);
}
if (fs.existsSync(scriptPath)) {
const scriptContent = fs.readFileSync(scriptPath, 'utf-8');
// Execute in global scope
eval(scriptContent);
console.log('[Spoof] Loaded script:', url);
} else {
console.warn('[Spoof] Script not found:', scriptPath);
}
} catch (err) {
console.error('[Spoof] Error loading script:', url, err.message);
}
});
};
}
}
function spoofCachesAPI() {
if (typeof globalThis.caches === 'undefined') {
const cachesMap = new Map();
globalThis.caches = {
open: async (cacheName) => {
if (!cachesMap.has(cacheName)) {
const cache = {
_items: new Map(),
match: async (request) => cache._items.get(typeof request === 'string' ? request : request.url),
matchAll: async () => Array.from(cache._items.values()),
add: async (request) => {},
addAll: async (requests) => {},
put: async (request, response) => {
cache._items.set(typeof request === 'string' ? request : request.url, response);
},
delete: async (request) => {
return cache._items.delete(typeof request === 'string' ? request : request.url);
},
keys: async () => Array.from(cache._items.keys()),
};
cachesMap.set(cacheName, cache);
}
return cachesMap.get(cacheName);
},
has: async (cacheName) => cachesMap.has(cacheName),
delete: async (cacheName) => cachesMap.delete(cacheName),
keys: async () => Array.from(cachesMap.keys()),
match: async (request) => {
for (const cache of cachesMap.values()) {
const response = await cache.match(request);
if (response) return response;
}
return undefined;
},
};
}
}
function spoofServiceWorkerEvents() {
if (typeof globalThis.ExtendableEvent === 'undefined') {
globalThis.ExtendableEvent = class ExtendableEvent extends Event {
constructor(type, eventInitDict) {
super(type, eventInitDict);
this._extendLifetimePromises = [];
}
waitUntil(promise) {
this._extendLifetimePromises.push(promise);
}
};
}
if (typeof globalThis.FetchEvent === 'undefined') {
globalThis.FetchEvent = class FetchEvent extends globalThis.ExtendableEvent {
constructor(type, eventInitDict) {
super(type, eventInitDict);
this.request = eventInitDict.request;
this.clientId = eventInitDict.clientId || '';
this.resultingClientId = eventInitDict.resultingClientId || '';
this.handled = Promise.resolve();
}
respondWith(response) {
this._response = response;
}
};
}
if (typeof globalThis.InstallEvent === 'undefined') {
globalThis.InstallEvent = class InstallEvent extends globalThis.ExtendableEvent {};
}
if (typeof globalThis.ActivateEvent === 'undefined') {
globalThis.ActivateEvent = class ActivateEvent extends globalThis.ExtendableEvent {};
}
}
function initExtensionContextSpoof() {
spoofSelf();
spoofExtensionOrigin();
spoofServiceWorkerGlobalScope();
spoofImportScripts();
spoofCachesAPI();
spoofServiceWorkerEvents();
}
//polyfills
if (typeof globalThis.performance === 'undefined') {
globalThis.performance = performance;
}
if (typeof globalThis.TextEncoder === 'undefined') {
globalThis.TextEncoder = TextEncoder;
}
if (typeof globalThis.TextDecoder === 'undefined') {
globalThis.TextDecoder = TextDecoder;
}
if (typeof globalThis.crypto === 'undefined') {
globalThis.crypto = webcrypto;
}
globalThis.clients = {
matchAll: async (options = {}) => [],
claim: async () => undefined,
get: async (id) => null,
openWindow: async (url) => null,
};
try {
if (!globalThis.navigator || !globalThis.navigator.userAgent) {
Object.defineProperty(globalThis, 'navigator', {
value: {
userAgent: 'Mozilla/5.0 (X11; CrOS x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36',
onLine: true,
},
writable: true,
configurable: true,
});
}
} catch (e) {}
try {
if (typeof globalThis.window === 'undefined') {
globalThis.window = globalThis;
}
} catch (e) {}
try {
if (typeof globalThis.document === 'undefined') {
Object.defineProperty(globalThis, 'document', {
value: {
createElement: () => ({}),
body: {},
},
writable: true,
configurable: true,
});
}
} catch (e) {}
// chrome api
const createEventListener = () => ({
addListener: (callback) => {},
removeListener: (callback) => {},
hasListener: (callback) => false,
});
const wrapWithProxy = (obj) => {
return new Proxy(obj, {
get(target, prop) {
if (prop in target) {
return target[prop];
}
if (typeof prop === 'string' && prop.startsWith('on')) {
return createEventListener();
}
return undefined;
}
});
};
const chromeMock = {
runtime: wrapWithProxy({
id: EXTENSION_ID,
getURL: (path) => `${EXTENSION_ORIGIN}/${path}`,
getManifest: () => ({
"paste-your": "manifest-here",
}),
getPlatformInfo: (callback) => {
const info = { os: 'cros', arch: 'x86-64', nacl_arch: 'x86-64' };
if (callback) {
callback(info);
return;
}
return Promise.resolve(info);
},
lastError: null,
sendMessage: (extensionId, message, options, callback) => {
if (typeof extensionId === 'object') {
callback = message;
message = extensionId;
}
if (typeof callback === 'function') callback();
return Promise.resolve();
},
onMessage: createEventListener(),
onInstalled: createEventListener(),
onStartup: createEventListener(),
onSuspend: createEventListener(),
onUpdateAvailable: createEventListener(),
onConnect: createEventListener(),
getContexts: (filter, callback) => {
const contexts = [{
contextType: 'SERVICE_WORKER',
contextId: `${EXTENSION_ID}_sw`,
documentUrl: `${EXTENSION_ORIGIN}/worker.js`,
documentOrigin: EXTENSION_ORIGIN,
}];
if (callback) {
callback(contexts);
return;
}
return Promise.resolve(contexts);
},
}),
storage: {
local: (() => {
const store = new Map();
return {
get: (keys, callback) => {
const result = {};
if (keys === null || keys === undefined) {
store.forEach((v, k) => { result[k] = v; });
} else if (Array.isArray(keys)) {
keys.forEach(k => { result[k] = store.get(k); });
} else if (typeof keys === 'string') {
result[keys] = store.get(keys);
} else if (typeof keys === 'object') {
Object.keys(keys).forEach(k => {
result[k] = store.has(k) ? store.get(k) : keys[k];
});
}
if (callback) callback(result);
return Promise.resolve(result);
},
set: (items, callback) => {
Object.entries(items).forEach(([k, v]) => store.set(k, v));
if (callback) callback();
return Promise.resolve();
},
remove: (keys, callback) => {
const keyArray = Array.isArray(keys) ? keys : [keys];
keyArray.forEach(k => store.delete(k));
if (callback) callback();
return Promise.resolve();
},
clear: (callback) => {
store.clear();
if (callback) callback();
return Promise.resolve();
},
};
})(),
sync: (() => {
const store = new Map();
return {
get: (keys, callback) => {
const result = {};
if (Array.isArray(keys)) {
keys.forEach(k => { result[k] = store.get(k); });
} else if (typeof keys === 'string') {
result[keys] = store.get(keys);
}
if (callback) callback(result);
return Promise.resolve(result);
},
set: (items, callback) => {
Object.entries(items).forEach(([k, v]) => store.set(k, v));
if (callback) callback();
return Promise.resolve();
},
};
})(),
},
tabs: new Proxy({
get: (tabId, callback) => {
const tab = { id: tabId, url: 'about:blank', active: true, windowId: 1 };
if (callback) callback(tab);
return Promise.resolve(tab);
},
query: (queryInfo, callback) => {
const tabs = [];
if (callback) callback(tabs);
return Promise.resolve(tabs);
},
create: (createProperties, callback) => {
const tab = { id: 1, ...createProperties };
if (callback) callback(tab);
return Promise.resolve(tab);
},
update: (tabId, updateProperties, callback) => {
const tab = { id: tabId, ...updateProperties };
if (callback) callback(tab);
return Promise.resolve(tab);
},
remove: (tabIds, callback) => {
if (callback) callback();
return Promise.resolve();
},
captureVisibleTab: (windowId, options, callback) => {
const dataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; // blank pixel
if (callback) callback(dataUrl);
return Promise.resolve(dataUrl);
},
sendMessage: (tabId, message, options, callback) => {
if (typeof options === 'function') {
callback = options;
}
if (callback) callback();
return Promise.resolve();
},
onUpdated: {
addListener: (callback) => {},
removeListener: (callback) => {},
hasListener: (callback) => false,
},
onActivated: {
addListener: (callback) => {},
removeListener: (callback) => {},
hasListener: (callback) => false,
},
onRemoved: {
addListener: (callback) => {},
removeListener: (callback) => {},
hasListener: (callback) => false,
},
onCreated: {
addListener: (callback) => {},
removeListener: (callback) => {},
hasListener: (callback) => false,
},
onHighlighted: {
addListener: (callback) => {},
removeListener: (callback) => {},
hasListener: (callback) => false,
},
}, {
get(target, prop) {
if (prop in target) {
return target[prop];
}
if (typeof prop === 'string' && prop.startsWith('on')) {
return {
addListener: (callback) => {},
removeListener: (callback) => {},
hasListener: (callback) => false,
};
}
return undefined;
}
}),
identity: {
getProfileUserInfo: (callback) => {
if (typeof callback === 'function') {
callback(identity);
}
return Promise.resolve(identity);
},
getAuthToken: (details, callback) => {
if (typeof details === 'function') {
callback = details;
}
const token = '';
if (callback) callback(token);
return Promise.resolve({ token });
},
},
enterprise: {
deviceAttributes: {
getDirectoryDeviceId: (callback) => {
if (callback) callback(cId);
return Promise.resolve(cId);
},
getDeviceSerialNumber: (callback) => {
if (callback) callback('');
return Promise.resolve('');
},
getDeviceAssetId: (callback) => {
if (callback) callback('');
return Promise.resolve('');
},
},
},
notifications: wrapWithProxy({
create: (notificationId, options, callback) => {
const id = notificationId || crypto.randomUUID();
if (callback) callback(id);
return Promise.resolve(id);
},
update: (notificationId, options, callback) => {
if (callback) callback(true);
return Promise.resolve(true);
},
clear: (notificationId, callback) => {
if (callback) callback(true);
return Promise.resolve(true);
},
getAll: (callback) => {
const notifications = {};
if (callback) callback(notifications);
return Promise.resolve(notifications);
},
getPermissionLevel: (callback) => {
if (callback) callback('granted');
return Promise.resolve('granted');
},
onClicked: createEventListener(),
onButtonClicked: createEventListener(),
onClosed: createEventListener(),
onShown: createEventListener(),
onPermissionLevelChanged: createEventListener(),
TemplateType: {
BASIC: 'basic',
IMAGE: 'image',
LIST: 'list',
PROGRESS: 'progress',
},
PermissionLevel: {
GRANTED: 'granted',
DENIED: 'denied',
},
}),
webRequest: wrapWithProxy({
onBeforeRequest: createEventListener(),
onBeforeSendHeaders: createEventListener(),
onSendHeaders: createEventListener(),
onHeadersReceived: createEventListener(),
onAuthRequired: createEventListener(),
onResponseStarted: createEventListener(),
onBeforeRedirect: createEventListener(),
onCompleted: createEventListener(),
onErrorOccurred: createEventListener(),
handlerBehaviorChanged: (callback) => {
if (callback) callback();
return Promise.resolve();
},
MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES: 20,
ResourceType: {
MAIN_FRAME: 'main_frame',
SUB_FRAME: 'sub_frame',
STYLESHEET: 'stylesheet',
SCRIPT: 'script',
IMAGE: 'image',
FONT: 'font',
OBJECT: 'object',
XMLHTTPREQUEST: 'xmlhttprequest',
PING: 'ping',
CSP_REPORT: 'csp_report',
MEDIA: 'media',
WEBSOCKET: 'websocket',
WEBTRANSPORT: 'webtransport',
WEBBUNDLE: 'webbundle',
OTHER: 'other',
},
OnBeforeRequestOptions: {
BLOCKING: 'blocking',
REQUEST_BODY: 'requestBody',
},
OnBeforeSendHeadersOptions: {
REQUEST_HEADERS: 'requestHeaders',
BLOCKING: 'blocking',
EXTRA_HEADERS: 'extraHeaders',
},
OnHeadersReceivedOptions: {
BLOCKING: 'blocking',
RESPONSE_HEADERS: 'responseHeaders',
EXTRA_HEADERS: 'extraHeaders',
},
}),
windows: wrapWithProxy({
get: (windowId, getInfo, callback) => {
if (typeof getInfo === 'function') {
callback = getInfo;
getInfo = {};
}
const window = { id: windowId, focused: true, state: 'normal' };
if (callback) callback(window);
return Promise.resolve(window);
},
getCurrent: (getInfo, callback) => {
if (typeof getInfo === 'function') {
callback = getInfo;
getInfo = {};
}
const window = { id: 1, focused: true, state: 'normal' };
if (callback) callback(window);
return Promise.resolve(window);
},
getLastFocused: (getInfo, callback) => {
if (typeof getInfo === 'function') {
callback = getInfo;
getInfo = {};
}
const window = { id: 1, focused: true, state: 'normal' };
if (callback) callback(window);
return Promise.resolve(window);
},
getAll: (getInfo, callback) => {
if (typeof getInfo === 'function') {
callback = getInfo;
getInfo = {};
}
const windows = [{ id: 1, focused: true, state: 'normal' }];
if (callback) callback(windows);
return Promise.resolve(windows);
},
create: (createData, callback) => {
const window = { id: 2, focused: true, state: 'normal', ...createData };
if (callback) callback(window);
return Promise.resolve(window);
},
update: (windowId, updateInfo, callback) => {
const window = { id: windowId, ...updateInfo };
if (callback) callback(window);
return Promise.resolve(window);
},
remove: (windowId, callback) => {
if (callback) callback();
return Promise.resolve();
},
onFocusChanged: createEventListener(),
onCreated: createEventListener(),
onRemoved: createEventListener(),
onBoundsChanged: createEventListener(),
WINDOW_ID_NONE: -1,
WINDOW_ID_CURRENT: -2,
}),
idle: {
onStateChanged: {
addListener: (callback) => {},
removeListener: (callback) => {},
hasListener: (callback) => false,
},
queryState: (detectionIntervalInSeconds, callback) => {
if (callback) callback('active');
return Promise.resolve('active');
},
},
alarms: {
create: (name, alarmInfo) => {},
onAlarm: {
addListener: (callback) => {},
removeListener: (callback) => {},
hasListener: (callback) => false,
},
},
offscreen: {
createDocument: (parameters, callback) => {
if (callback) callback();
return Promise.resolve();
},
closeDocument: (callback) => {
if (callback) callback();
return Promise.resolve();
},
},
desktopCapture: {
chooseDesktopMedia: (sources, targetTab, callback) => {
if (typeof targetTab === 'function') {
callback = targetTab;
}
const streamId = 'mock-stream-id-' + Date.now();
if (callback) callback(streamId);
return 1;
},
},
tabCapture: {
onStatusChanged: {
addListener: (callback) => {},
removeListener: (callback) => {},
hasListener: (callback) => false,
},
},
bookmarks: {
onCreated: {
addListener: (callback) => {},
removeListener: (callback) => {},
hasListener: (callback) => false,
},
},
};
globalThis.chrome = wrapWithProxy(chromeMock);
// fetch api
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url, options = {}) => {
const urlStr = typeof url === 'string' ? url : url.url;
if (urlStr.startsWith('http://') || urlStr.startsWith('https://')) {
return originalFetch(url, options);
}
if (urlStr.includes('manifest.json')) {
const manifest = chromeMock.runtime.getManifest();
const manifestJson = JSON.stringify(manifest);
const manifestBuffer = new TextEncoder().encode(manifestJson);
return new globalThis.Response(manifestBuffer, {
status: 200,
headers: { 'Content-Type': 'application/json' },
url: urlStr
});
}
if (urlStr.endsWith('.wasm')) {
const filename = urlStr.split('/').pop();
const filePath = path.join(__dirname, filename);
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath);
return new globalThis.Response(content, {
status: 200,
headers: { 'Content-Type': 'application/wasm' },
url: urlStr
});
}
}
if (urlStr.includes('worker.js') || urlStr.endsWith('.js')) {
const filename = urlStr.split('/').pop();
const filePath = path.join(__dirname, filename);
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath);
return new globalThis.Response(content, {
status: 200,
headers: { 'Content-Type': 'application/javascript' },
url: urlStr
});
}
}
if (urlStr.startsWith('chrome-extension://') || urlStr.startsWith(EXTENSION_ORIGIN)) {
const filename = urlStr.split('/').pop();
const filePath = path.join(__dirname, filename);
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath);
let contentType = 'application/octet-stream';
if (filename.endsWith('.json')) contentType = 'application/json';
else if (filename.endsWith('.html')) contentType = 'text/html';
else if (filename.endsWith('.css')) contentType = 'text/css';
return new globalThis.Response(content, {
status: 200,
headers: { 'Content-Type': contentType },
url: urlStr
});
}
return new globalThis.Response('', {
status: 200,
headers: { 'Content-Type': 'text/plain' }
});
}
return originalFetch(url, options);
};
// worker runner
let jwtResolveCallback = null;
let shouldExit = false;
// check for jwt
function pollForJWT(interval = 100, timeout = 10000) {
return new Promise((resolve, reject) => {
const startTime = Date.now();
const checkJWT = setInterval(() => {
if (globalThis.__LIGHTSPEED_JWT__) {
clearInterval(checkJWT);
resolve(globalThis.__LIGHTSPEED_JWT__);
shouldExit = true;
return;
}
if (Date.now() - startTime > timeout) {
clearInterval(checkJWT);
reject(new Error(`JWT extraction timeout after ${timeout}ms`));
}
}, interval);
});
}
export async function runServiceWorker(options = {}) {
const { timeout = 10000, pollInterval = 100, exitOnJwt = false } = options;
initExtensionContextSpoof();
const workerPath = path.join(__dirname, 'worker_node.js');
if (!fs.existsSync(workerPath)) {
throw new Error('worker.js not found at: ' + workerPath);
}
const workerContent = fs.readFileSync(workerPath, 'utf-8');
//console.log(workerPath)
globalThis.identity = {
email: options.email
}
globalThis.cId = options.cId;
try {
eval(workerContent);
console.log('Worker executed successfully');
} catch (err) {
console.error('Error executing worker:', err);
throw err;
}
await new Promise(resolve => setTimeout(resolve, 1000));
if (typeof globalThis.oninstall === 'function') {
console.log('install event');
const installEvent = new globalThis.InstallEvent('install');
globalThis.oninstall(installEvent);
}
if (typeof globalThis.onactivate === 'function') {
console.log('activate event');
const activateEvent = new globalThis.ActivateEvent('activate');
globalThis.onactivate(activateEvent);
}
console.log('polling jwt...');
const jwt = await pollForJWT(pollInterval, timeout);
console.log('JWT obtained:', jwt);
if (exitOnJwt) {
console.log('Exiting..');
process.exit(0);
}
return jwt;
}
export function getJWT() {
return globalThis.__LIGHTSPEED_JWT__;
}
export function killServiceWorker() {
console.log('killing service worker...');
shouldExit = true;
globalThis.__LIGHTSPEED_JWT__ = null;
jwtResolveCallback = null;
return true;
}
export default {
runServiceWorker,
getJWT,
killServiceWorker,
};