| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | import { Buffer } from 'buffer'; | 
					
						
							| 
									
										
										
										
											2023-09-25 13:17:24 +02:00
										 |  |  | import { constants } from 'fs'; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | import * as path from 'path'; | 
					
						
							|  |  |  | import * as util from 'util'; | 
					
						
							| 
									
										
										
										
											2021-09-09 14:49:01 -07:00
										 |  |  | import type * as Crypto from 'crypto'; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | const asar = process._linkedBinding('electron_common_asar'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-07 00:04:25 +02:00
										 |  |  | const Module = require('module') as NodeJS.ModuleInternal; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-08 03:01:23 +02:00
										 |  |  | const Promise: PromiseConstructor = global.Promise; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | const envNoAsar = process.env.ELECTRON_NO_ASAR && | 
					
						
							|  |  |  |     process.type !== 'browser' && | 
					
						
							|  |  |  |     process.type !== 'renderer'; | 
					
						
							|  |  |  | const isAsarDisabled = () => process.noAsar || envNoAsar; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-08 03:01:23 +02:00
										 |  |  | const internalBinding = process.internalBinding!; | 
					
						
							|  |  |  | delete process.internalBinding; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | const nextTick = (functionToCall: Function, args: any[] = []) => { | 
					
						
							|  |  |  |   process.nextTick(() => functionToCall(...args)); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Cache asar archive objects.
 | 
					
						
							|  |  |  | const cachedArchives = new Map<string, NodeJS.AsarArchive>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const getOrCreateArchive = (archivePath: string) => { | 
					
						
							|  |  |  |   const isCached = cachedArchives.has(archivePath); | 
					
						
							|  |  |  |   if (isCached) { | 
					
						
							| 
									
										
										
										
											2023-09-11 11:51:14 -07:00
										 |  |  |     return cachedArchives.get(archivePath)!; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 17:37:55 -07:00
										 |  |  |   try { | 
					
						
							|  |  |  |     const newArchive = new asar.Archive(archivePath); | 
					
						
							|  |  |  |     cachedArchives.set(archivePath, newArchive); | 
					
						
							|  |  |  |     return newArchive; | 
					
						
							|  |  |  |   } catch { | 
					
						
							|  |  |  |     return null; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-11 11:51:14 -07:00
										 |  |  | process._getOrCreateArchive = getOrCreateArchive; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-26 03:19:35 +00:00
										 |  |  | const asarRe = /\.asar/i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 17:38:07 -07:00
										 |  |  | const { getValidatedPath } = __non_webpack_require__('internal/fs/utils'); | 
					
						
							|  |  |  | // In the renderer node internals use the node global URL but we do not set that to be
 | 
					
						
							|  |  |  | // the global URL instance.  We need to do instanceof checks against the internal URL impl
 | 
					
						
							|  |  |  | const { URL: NodeURL } = __non_webpack_require__('internal/url'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | // Separate asar package's path from full path.
 | 
					
						
							| 
									
										
										
										
											2023-08-30 17:38:07 -07:00
										 |  |  | const splitPath = (archivePathOrBuffer: string | Buffer | URL) => { | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   // Shortcut for disabled asar.
 | 
					
						
							|  |  |  |   if (isAsarDisabled()) return { isAsar: <const>false }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Check for a bad argument type.
 | 
					
						
							|  |  |  |   let archivePath = archivePathOrBuffer; | 
					
						
							|  |  |  |   if (Buffer.isBuffer(archivePathOrBuffer)) { | 
					
						
							|  |  |  |     archivePath = archivePathOrBuffer.toString(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-08-30 17:38:07 -07:00
										 |  |  |   if (archivePath instanceof NodeURL) { | 
					
						
							|  |  |  |     archivePath = getValidatedPath(archivePath); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   if (typeof archivePath !== 'string') return { isAsar: <const>false }; | 
					
						
							| 
									
										
										
										
											2020-10-26 03:19:35 +00:00
										 |  |  |   if (!asarRe.test(archivePath)) return { isAsar: <const>false }; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return asar.splitPath(path.normalize(archivePath)); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Convert asar archive's Stats object to fs's Stats object.
 | 
					
						
							|  |  |  | let nextInode = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 10:11:04 +02:00
										 |  |  | const uid = process.getuid?.() ?? 0; | 
					
						
							|  |  |  | const gid = process.getgid?.() ?? 0; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | const fakeTime = new Date(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-25 13:17:24 +02:00
										 |  |  | enum AsarFileType { | 
					
						
							|  |  |  |   kFile = (constants as any).UV_DIRENT_FILE, | 
					
						
							|  |  |  |   kDirectory = (constants as any).UV_DIRENT_DIR, | 
					
						
							|  |  |  |   kLink = (constants as any).UV_DIRENT_LINK, | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-25 13:17:24 +02:00
										 |  |  | const fileTypeToMode = new Map<AsarFileType, number>([ | 
					
						
							|  |  |  |   [AsarFileType.kFile, constants.S_IFREG], | 
					
						
							|  |  |  |   [AsarFileType.kDirectory, constants.S_IFDIR], | 
					
						
							|  |  |  |   [AsarFileType.kLink, constants.S_IFLNK] | 
					
						
							|  |  |  | ]); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-25 13:17:24 +02:00
										 |  |  | const asarStatsToFsStats = function (stats: NodeJS.AsarFileStat) { | 
					
						
							|  |  |  |   const { Stats } = require('fs'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const mode = constants.S_IROTH | constants.S_IRGRP | constants.S_IRUSR | constants.S_IWUSR | fileTypeToMode.get(stats.type)!; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return new Stats( | 
					
						
							|  |  |  |     1, // dev
 | 
					
						
							|  |  |  |     mode, // mode
 | 
					
						
							|  |  |  |     1, // nlink
 | 
					
						
							|  |  |  |     uid, | 
					
						
							|  |  |  |     gid, | 
					
						
							|  |  |  |     0, // rdev
 | 
					
						
							|  |  |  |     undefined, // blksize
 | 
					
						
							|  |  |  |     ++nextInode, // ino
 | 
					
						
							|  |  |  |     stats.size, | 
					
						
							|  |  |  |     undefined, // blocks,
 | 
					
						
							|  |  |  |     fakeTime.getTime(), // atim_msec
 | 
					
						
							|  |  |  |     fakeTime.getTime(), // mtim_msec
 | 
					
						
							|  |  |  |     fakeTime.getTime(), // ctim_msec
 | 
					
						
							|  |  |  |     fakeTime.getTime() // birthtim_msec
 | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const enum AsarError { | 
					
						
							|  |  |  |   NOT_FOUND = 'NOT_FOUND', | 
					
						
							|  |  |  |   NOT_DIR = 'NOT_DIR', | 
					
						
							|  |  |  |   NO_ACCESS = 'NO_ACCESS', | 
					
						
							|  |  |  |   INVALID_ARCHIVE = 'INVALID_ARCHIVE' | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type AsarErrorObject = Error & { code?: string, errno?: number }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const createError = (errorType: AsarError, { asarPath, filePath }: { asarPath?: string, filePath?: string } = {}) => { | 
					
						
							|  |  |  |   let error: AsarErrorObject; | 
					
						
							|  |  |  |   switch (errorType) { | 
					
						
							|  |  |  |     case AsarError.NOT_FOUND: | 
					
						
							|  |  |  |       error = new Error(`ENOENT, ${filePath} not found in ${asarPath}`); | 
					
						
							|  |  |  |       error.code = 'ENOENT'; | 
					
						
							|  |  |  |       error.errno = -2; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case AsarError.NOT_DIR: | 
					
						
							|  |  |  |       error = new Error('ENOTDIR, not a directory'); | 
					
						
							|  |  |  |       error.code = 'ENOTDIR'; | 
					
						
							|  |  |  |       error.errno = -20; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case AsarError.NO_ACCESS: | 
					
						
							|  |  |  |       error = new Error(`EACCES: permission denied, access '${filePath}'`); | 
					
						
							|  |  |  |       error.code = 'EACCES'; | 
					
						
							|  |  |  |       error.errno = -13; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case AsarError.INVALID_ARCHIVE: | 
					
						
							|  |  |  |       error = new Error(`Invalid package ${asarPath}`); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       throw new Error(`Invalid error type "${errorType}" passed to createError.`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return error; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const overrideAPISync = function (module: Record<string, any>, name: string, pathArgumentIndex?: number | null, fromAsync: boolean = false) { | 
					
						
							|  |  |  |   if (pathArgumentIndex == null) pathArgumentIndex = 0; | 
					
						
							|  |  |  |   const old = module[name]; | 
					
						
							|  |  |  |   const func = function (this: any, ...args: any[]) { | 
					
						
							|  |  |  |     const pathArgument = args[pathArgumentIndex!]; | 
					
						
							|  |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return old.apply(this, args); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) throw createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const newPath = archive.copyFileOut(filePath); | 
					
						
							|  |  |  |     if (!newPath) throw createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     args[pathArgumentIndex!] = newPath; | 
					
						
							|  |  |  |     return old.apply(this, args); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   if (fromAsync) { | 
					
						
							|  |  |  |     return func; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   module[name] = func; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const overrideAPI = function (module: Record<string, any>, name: string, pathArgumentIndex?: number | null) { | 
					
						
							|  |  |  |   if (pathArgumentIndex == null) pathArgumentIndex = 0; | 
					
						
							|  |  |  |   const old = module[name]; | 
					
						
							|  |  |  |   module[name] = function (this: any, ...args: any[]) { | 
					
						
							|  |  |  |     const pathArgument = args[pathArgumentIndex!]; | 
					
						
							|  |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return old.apply(this, args); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const callback = args[args.length - 1]; | 
					
						
							|  |  |  |     if (typeof callback !== 'function') { | 
					
						
							|  |  |  |       return overrideAPISync(module, name, pathArgumentIndex!, true)!.apply(this, args); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) { | 
					
						
							|  |  |  |       const error = createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |       nextTick(callback, [error]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const newPath = archive.copyFileOut(filePath); | 
					
						
							|  |  |  |     if (!newPath) { | 
					
						
							|  |  |  |       const error = createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |       nextTick(callback, [error]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     args[pathArgumentIndex!] = newPath; | 
					
						
							|  |  |  |     return old.apply(this, args); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (old[util.promisify.custom]) { | 
					
						
							|  |  |  |     module[name][util.promisify.custom] = makePromiseFunction(old[util.promisify.custom], pathArgumentIndex); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (module.promises && module.promises[name]) { | 
					
						
							|  |  |  |     module.promises[name] = makePromiseFunction(module.promises[name], pathArgumentIndex); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-09 14:49:01 -07:00
										 |  |  | let crypto: typeof Crypto; | 
					
						
							|  |  |  | function validateBufferIntegrity (buffer: Buffer, integrity: NodeJS.AsarFileInfo['integrity']) { | 
					
						
							|  |  |  |   if (!integrity) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Delay load crypto to improve app boot performance
 | 
					
						
							|  |  |  |   // when integrity protection is not enabled
 | 
					
						
							|  |  |  |   crypto = crypto || require('crypto'); | 
					
						
							|  |  |  |   const actual = crypto.createHash(integrity.algorithm).update(buffer).digest('hex'); | 
					
						
							|  |  |  |   if (actual !== integrity.hash) { | 
					
						
							|  |  |  |     console.error(`ASAR Integrity Violation: got a hash mismatch (${actual} vs ${integrity.hash})`); | 
					
						
							|  |  |  |     process.exit(1); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | const makePromiseFunction = function (orig: Function, pathArgumentIndex: number) { | 
					
						
							|  |  |  |   return function (this: any, ...args: any[]) { | 
					
						
							|  |  |  |     const pathArgument = args[pathArgumentIndex]; | 
					
						
							|  |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return orig.apply(this, args); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) { | 
					
						
							|  |  |  |       return Promise.reject(createError(AsarError.INVALID_ARCHIVE, { asarPath })); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const newPath = archive.copyFileOut(filePath); | 
					
						
							|  |  |  |     if (!newPath) { | 
					
						
							|  |  |  |       return Promise.reject(createError(AsarError.NOT_FOUND, { asarPath, filePath })); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     args[pathArgumentIndex] = newPath; | 
					
						
							|  |  |  |     return orig.apply(this, args); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Override fs APIs.
 | 
					
						
							|  |  |  | export const wrapFsWithAsar = (fs: Record<string, any>) => { | 
					
						
							| 
									
										
										
										
											2020-10-19 02:24:51 +02:00
										 |  |  |   const logFDs = new Map<string, number>(); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   const logASARAccess = (asarPath: string, filePath: string, offset: number) => { | 
					
						
							|  |  |  |     if (!process.env.ELECTRON_LOG_ASAR_READS) return; | 
					
						
							| 
									
										
										
										
											2020-10-19 02:24:51 +02:00
										 |  |  |     if (!logFDs.has(asarPath)) { | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |       const logFilename = `${path.basename(asarPath, '.asar')}-access-log.txt`; | 
					
						
							|  |  |  |       const logPath = path.join(require('os').tmpdir(), logFilename); | 
					
						
							| 
									
										
										
										
											2020-10-19 02:24:51 +02:00
										 |  |  |       logFDs.set(asarPath, fs.openSync(logPath, 'a')); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-19 02:24:51 +02:00
										 |  |  |     fs.writeSync(logFDs.get(asarPath), `${offset}: ${filePath}\n`); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-16 09:35:25 -07:00
										 |  |  |   const shouldThrowStatError = (options: any) => { | 
					
						
							|  |  |  |     if (options && typeof options === 'object' && options.throwIfNoEntry === false) { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   const { lstatSync } = fs; | 
					
						
							|  |  |  |   fs.lstatSync = (pathArgument: string, options: any) => { | 
					
						
							|  |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return lstatSync(pathArgument, options); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							| 
									
										
										
										
											2023-10-16 09:35:25 -07:00
										 |  |  |     if (!archive) { | 
					
						
							|  |  |  |       if (shouldThrowStatError(options)) throw createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const stats = archive.stat(filePath); | 
					
						
							| 
									
										
										
										
											2023-10-16 09:35:25 -07:00
										 |  |  |     if (!stats) { | 
					
						
							|  |  |  |       if (shouldThrowStatError(options)) throw createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return asarStatsToFsStats(stats); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { lstat } = fs; | 
					
						
							| 
									
										
										
										
											2022-08-29 09:55:36 -04:00
										 |  |  |   fs.lstat = (pathArgument: string, options: any, callback: any) => { | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (typeof options === 'function') { | 
					
						
							|  |  |  |       callback = options; | 
					
						
							|  |  |  |       options = {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return lstat(pathArgument, options, callback); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) { | 
					
						
							|  |  |  |       const error = createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |       nextTick(callback, [error]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const stats = archive.stat(filePath); | 
					
						
							|  |  |  |     if (!stats) { | 
					
						
							|  |  |  |       const error = createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |       nextTick(callback, [error]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const fsStats = asarStatsToFsStats(stats); | 
					
						
							|  |  |  |     nextTick(callback, [null, fsStats]); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fs.promises.lstat = util.promisify(fs.lstat); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { statSync } = fs; | 
					
						
							|  |  |  |   fs.statSync = (pathArgument: string, options: any) => { | 
					
						
							|  |  |  |     const { isAsar } = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!isAsar) return statSync(pathArgument, options); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Do not distinguish links for now.
 | 
					
						
							|  |  |  |     return fs.lstatSync(pathArgument, options); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { stat } = fs; | 
					
						
							|  |  |  |   fs.stat = (pathArgument: string, options: any, callback: any) => { | 
					
						
							|  |  |  |     const { isAsar } = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (typeof options === 'function') { | 
					
						
							|  |  |  |       callback = options; | 
					
						
							|  |  |  |       options = {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!isAsar) return stat(pathArgument, options, callback); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Do not distinguish links for now.
 | 
					
						
							|  |  |  |     process.nextTick(() => fs.lstat(pathArgument, options, callback)); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fs.promises.stat = util.promisify(fs.stat); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const wrapRealpathSync = function (realpathSync: Function) { | 
					
						
							|  |  |  |     return function (this: any, pathArgument: string, options: any) { | 
					
						
							|  |  |  |       const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |       if (!pathInfo.isAsar) return realpathSync.apply(this, arguments); | 
					
						
							|  |  |  |       const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |       if (!archive) { | 
					
						
							|  |  |  |         throw createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fileRealPath = archive.realpath(filePath); | 
					
						
							|  |  |  |       if (fileRealPath === false) { | 
					
						
							|  |  |  |         throw createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return path.join(realpathSync(asarPath, options), fileRealPath); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { realpathSync } = fs; | 
					
						
							|  |  |  |   fs.realpathSync = wrapRealpathSync(realpathSync); | 
					
						
							|  |  |  |   fs.realpathSync.native = wrapRealpathSync(realpathSync.native); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const wrapRealpath = function (realpath: Function) { | 
					
						
							|  |  |  |     return function (this: any, pathArgument: string, options: any, callback: any) { | 
					
						
							|  |  |  |       const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |       if (!pathInfo.isAsar) return realpath.apply(this, arguments); | 
					
						
							|  |  |  |       const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (arguments.length < 3) { | 
					
						
							|  |  |  |         callback = options; | 
					
						
							|  |  |  |         options = {}; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |       if (!archive) { | 
					
						
							|  |  |  |         const error = createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |         nextTick(callback, [error]); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fileRealPath = archive.realpath(filePath); | 
					
						
							|  |  |  |       if (fileRealPath === false) { | 
					
						
							|  |  |  |         const error = createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |         nextTick(callback, [error]); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       realpath(asarPath, options, (error: Error | null, archiveRealPath: string) => { | 
					
						
							|  |  |  |         if (error === null) { | 
					
						
							|  |  |  |           const fullPath = path.join(archiveRealPath, fileRealPath); | 
					
						
							|  |  |  |           callback(null, fullPath); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           callback(error); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { realpath } = fs; | 
					
						
							|  |  |  |   fs.realpath = wrapRealpath(realpath); | 
					
						
							|  |  |  |   fs.realpath.native = wrapRealpath(realpath.native); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fs.promises.realpath = util.promisify(fs.realpath.native); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-29 09:55:36 -04:00
										 |  |  |   const { exists: nativeExists } = fs; | 
					
						
							|  |  |  |   fs.exists = function exists (pathArgument: string, callback: any) { | 
					
						
							| 
									
										
										
										
											2023-08-30 17:38:07 -07:00
										 |  |  |     let pathInfo: ReturnType<typeof splitPath>; | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     } catch { | 
					
						
							|  |  |  |       nextTick(callback, [false]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-29 09:55:36 -04:00
										 |  |  |     if (!pathInfo.isAsar) return nativeExists(pathArgument, callback); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) { | 
					
						
							|  |  |  |       const error = createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |       nextTick(callback, [error]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const pathExists = (archive.stat(filePath) !== false); | 
					
						
							|  |  |  |     nextTick(callback, [pathExists]); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-29 09:55:36 -04:00
										 |  |  |   fs.exists[util.promisify.custom] = function exists (pathArgument: string) { | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							| 
									
										
										
										
											2022-08-29 09:55:36 -04:00
										 |  |  |     if (!pathInfo.isAsar) return nativeExists[util.promisify.custom](pathArgument); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) { | 
					
						
							|  |  |  |       const error = createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |       return Promise.reject(error); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return Promise.resolve(archive.stat(filePath) !== false); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { existsSync } = fs; | 
					
						
							|  |  |  |   fs.existsSync = (pathArgument: string) => { | 
					
						
							| 
									
										
										
										
											2023-08-30 17:38:07 -07:00
										 |  |  |     let pathInfo: ReturnType<typeof splitPath>; | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     } catch { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     if (!pathInfo.isAsar) return existsSync(pathArgument); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return archive.stat(filePath) !== false; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { access } = fs; | 
					
						
							|  |  |  |   fs.access = function (pathArgument: string, mode: any, callback: any) { | 
					
						
							|  |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return access.apply(this, arguments); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (typeof mode === 'function') { | 
					
						
							|  |  |  |       callback = mode; | 
					
						
							|  |  |  |       mode = fs.constants.F_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) { | 
					
						
							|  |  |  |       const error = createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |       nextTick(callback, [error]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const info = archive.getFileInfo(filePath); | 
					
						
							|  |  |  |     if (!info) { | 
					
						
							|  |  |  |       const error = createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |       nextTick(callback, [error]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (info.unpacked) { | 
					
						
							|  |  |  |       const realPath = archive.copyFileOut(filePath); | 
					
						
							|  |  |  |       return fs.access(realPath, mode, callback); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const stats = archive.stat(filePath); | 
					
						
							|  |  |  |     if (!stats) { | 
					
						
							|  |  |  |       const error = createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |       nextTick(callback, [error]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mode & fs.constants.W_OK) { | 
					
						
							|  |  |  |       const error = createError(AsarError.NO_ACCESS, { asarPath, filePath }); | 
					
						
							|  |  |  |       nextTick(callback, [error]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     nextTick(callback); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fs.promises.access = util.promisify(fs.access); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { accessSync } = fs; | 
					
						
							|  |  |  |   fs.accessSync = function (pathArgument: string, mode: any) { | 
					
						
							|  |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return accessSync.apply(this, arguments); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mode == null) mode = fs.constants.F_OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) { | 
					
						
							|  |  |  |       throw createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const info = archive.getFileInfo(filePath); | 
					
						
							|  |  |  |     if (!info) { | 
					
						
							|  |  |  |       throw createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (info.unpacked) { | 
					
						
							|  |  |  |       const realPath = archive.copyFileOut(filePath); | 
					
						
							|  |  |  |       return fs.accessSync(realPath, mode); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const stats = archive.stat(filePath); | 
					
						
							|  |  |  |     if (!stats) { | 
					
						
							|  |  |  |       throw createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mode & fs.constants.W_OK) { | 
					
						
							|  |  |  |       throw createError(AsarError.NO_ACCESS, { asarPath, filePath }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |   function fsReadFileAsar (pathArgument: string, options: any, callback: any) { | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |     if (pathInfo.isAsar) { | 
					
						
							|  |  |  |       const { asarPath, filePath } = pathInfo; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |       if (typeof options === 'function') { | 
					
						
							|  |  |  |         callback = options; | 
					
						
							|  |  |  |         options = { encoding: null }; | 
					
						
							|  |  |  |       } else if (typeof options === 'string') { | 
					
						
							|  |  |  |         options = { encoding: options }; | 
					
						
							|  |  |  |       } else if (options === null || options === undefined) { | 
					
						
							|  |  |  |         options = { encoding: null }; | 
					
						
							|  |  |  |       } else if (typeof options !== 'object') { | 
					
						
							|  |  |  |         throw new TypeError('Bad arguments'); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |       const { encoding } = options; | 
					
						
							|  |  |  |       const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |       if (!archive) { | 
					
						
							|  |  |  |         const error = createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |         nextTick(callback, [error]); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |       const info = archive.getFileInfo(filePath); | 
					
						
							|  |  |  |       if (!info) { | 
					
						
							|  |  |  |         const error = createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |         nextTick(callback, [error]); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |       if (info.size === 0) { | 
					
						
							|  |  |  |         nextTick(callback, [null, encoding ? '' : Buffer.alloc(0)]); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |       if (info.unpacked) { | 
					
						
							|  |  |  |         const realPath = archive.copyFileOut(filePath); | 
					
						
							|  |  |  |         return fs.readFile(realPath, options, callback); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const buffer = Buffer.alloc(info.size); | 
					
						
							| 
									
										
										
										
											2021-09-09 14:49:01 -07:00
										 |  |  |       const fd = archive.getFdAndValidateIntegrityLater(); | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |       if (!(fd >= 0)) { | 
					
						
							|  |  |  |         const error = createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |         nextTick(callback, [error]); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       logASARAccess(asarPath, filePath, info.offset); | 
					
						
							|  |  |  |       fs.read(fd, buffer, 0, info.size, info.offset, (error: Error) => { | 
					
						
							| 
									
										
										
										
											2021-09-09 14:49:01 -07:00
										 |  |  |         validateBufferIntegrity(buffer, info.integrity); | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |         callback(error, encoding ? buffer.toString(encoding) : buffer); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |   const { readFile } = fs; | 
					
						
							|  |  |  |   fs.readFile = function (pathArgument: string, options: any, callback: any) { | 
					
						
							|  |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) { | 
					
						
							|  |  |  |       return readFile.apply(this, arguments); | 
					
						
							| 
									
										
										
										
											2021-03-15 11:42:54 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |     return fsReadFileAsar(pathArgument, options, callback); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 21:19:39 +02:00
										 |  |  |   const { readFile: readFilePromise } = fs.promises; | 
					
						
							|  |  |  |   fs.promises.readFile = function (pathArgument: string, options: any) { | 
					
						
							|  |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) { | 
					
						
							|  |  |  |       return readFilePromise.apply(this, arguments); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const p = util.promisify(fsReadFileAsar); | 
					
						
							|  |  |  |     return p(pathArgument, options); | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const { readFileSync } = fs; | 
					
						
							|  |  |  |   fs.readFileSync = function (pathArgument: string, options: any) { | 
					
						
							|  |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return readFileSync.apply(this, arguments); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) throw createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const info = archive.getFileInfo(filePath); | 
					
						
							|  |  |  |     if (!info) throw createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (info.size === 0) return (options) ? '' : Buffer.alloc(0); | 
					
						
							|  |  |  |     if (info.unpacked) { | 
					
						
							|  |  |  |       const realPath = archive.copyFileOut(filePath); | 
					
						
							|  |  |  |       return fs.readFileSync(realPath, options); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!options) { | 
					
						
							|  |  |  |       options = { encoding: null }; | 
					
						
							|  |  |  |     } else if (typeof options === 'string') { | 
					
						
							|  |  |  |       options = { encoding: options }; | 
					
						
							|  |  |  |     } else if (typeof options !== 'object') { | 
					
						
							|  |  |  |       throw new TypeError('Bad arguments'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const { encoding } = options; | 
					
						
							| 
									
										
										
										
											2021-03-15 11:42:54 -07:00
										 |  |  |     const buffer = Buffer.alloc(info.size); | 
					
						
							| 
									
										
										
										
											2021-09-09 14:49:01 -07:00
										 |  |  |     const fd = archive.getFdAndValidateIntegrityLater(); | 
					
						
							| 
									
										
										
										
											2021-03-15 11:42:54 -07:00
										 |  |  |     if (!(fd >= 0)) throw createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     logASARAccess(asarPath, filePath, info.offset); | 
					
						
							| 
									
										
										
										
											2021-03-15 11:42:54 -07:00
										 |  |  |     fs.readSync(fd, buffer, 0, info.size, info.offset); | 
					
						
							| 
									
										
										
										
											2021-09-09 14:49:01 -07:00
										 |  |  |     validateBufferIntegrity(buffer, info.integrity); | 
					
						
							| 
									
										
										
										
											2021-03-15 11:42:54 -07:00
										 |  |  |     return (encoding) ? buffer.toString(encoding) : buffer; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { readdir } = fs; | 
					
						
							| 
									
										
										
										
											2023-01-10 03:16:39 -08:00
										 |  |  |   fs.readdir = function (pathArgument: string, options?: { encoding?: string | null; withFileTypes?: boolean } | null, callback?: Function) { | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (typeof options === 'function') { | 
					
						
							|  |  |  |       callback = options; | 
					
						
							| 
									
										
										
										
											2023-01-10 03:16:39 -08:00
										 |  |  |       options = undefined; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return readdir.apply(this, arguments); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) { | 
					
						
							|  |  |  |       const error = createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |       nextTick(callback!, [error]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const files = archive.readdir(filePath); | 
					
						
							|  |  |  |     if (!files) { | 
					
						
							|  |  |  |       const error = createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |       nextTick(callback!, [error]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 03:16:39 -08:00
										 |  |  |     if (options?.withFileTypes) { | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |       const dirents = []; | 
					
						
							|  |  |  |       for (const file of files) { | 
					
						
							| 
									
										
										
										
											2020-12-15 04:21:49 +02:00
										 |  |  |         const childPath = path.join(filePath, file); | 
					
						
							|  |  |  |         const stats = archive.stat(childPath); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |         if (!stats) { | 
					
						
							| 
									
										
										
										
											2020-12-15 04:21:49 +02:00
										 |  |  |           const error = createError(AsarError.NOT_FOUND, { asarPath, filePath: childPath }); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |           nextTick(callback!, [error]); | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-09-25 13:17:24 +02:00
										 |  |  |         dirents.push(new fs.Dirent(file, stats.type)); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |       nextTick(callback!, [null, dirents]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     nextTick(callback!, [null, files]); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fs.promises.readdir = util.promisify(fs.readdir); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-29 21:41:59 +01:00
										 |  |  |   type ReaddirSyncOptions = { encoding: BufferEncoding | null; withFileTypes?: false }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   const { readdirSync } = fs; | 
					
						
							| 
									
										
										
										
											2021-01-29 21:41:59 +01:00
										 |  |  |   fs.readdirSync = function (pathArgument: string, options: ReaddirSyncOptions | BufferEncoding | null) { | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return readdirSync.apply(this, arguments); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) { | 
					
						
							|  |  |  |       throw createError(AsarError.INVALID_ARCHIVE, { asarPath }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const files = archive.readdir(filePath); | 
					
						
							|  |  |  |     if (!files) { | 
					
						
							|  |  |  |       throw createError(AsarError.NOT_FOUND, { asarPath, filePath }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-29 21:41:59 +01:00
										 |  |  |     if (options && (options as ReaddirSyncOptions).withFileTypes) { | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |       const dirents = []; | 
					
						
							|  |  |  |       for (const file of files) { | 
					
						
							| 
									
										
										
										
											2020-12-15 04:21:49 +02:00
										 |  |  |         const childPath = path.join(filePath, file); | 
					
						
							|  |  |  |         const stats = archive.stat(childPath); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |         if (!stats) { | 
					
						
							| 
									
										
										
										
											2020-12-15 04:21:49 +02:00
										 |  |  |           throw createError(AsarError.NOT_FOUND, { asarPath, filePath: childPath }); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-09-25 13:17:24 +02:00
										 |  |  |         dirents.push(new fs.Dirent(file, stats.type)); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |       return dirents; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return files; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { internalModuleReadJSON } = internalBinding('fs'); | 
					
						
							|  |  |  |   internalBinding('fs').internalModuleReadJSON = (pathArgument: string) => { | 
					
						
							|  |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return internalModuleReadJSON(pathArgument); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							| 
									
										
										
										
											2020-07-27 09:12:29 -07:00
										 |  |  |     if (!archive) return []; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const info = archive.getFileInfo(filePath); | 
					
						
							| 
									
										
										
										
											2020-07-27 09:12:29 -07:00
										 |  |  |     if (!info) return []; | 
					
						
							|  |  |  |     if (info.size === 0) return ['', false]; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     if (info.unpacked) { | 
					
						
							|  |  |  |       const realPath = archive.copyFileOut(filePath); | 
					
						
							| 
									
										
										
										
											2020-12-02 11:33:39 +06:00
										 |  |  |       const str = fs.readFileSync(realPath, { encoding: 'utf8' }); | 
					
						
							|  |  |  |       return [str, str.length > 0]; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-15 11:42:54 -07:00
										 |  |  |     const buffer = Buffer.alloc(info.size); | 
					
						
							| 
									
										
										
										
											2021-09-09 14:49:01 -07:00
										 |  |  |     const fd = archive.getFdAndValidateIntegrityLater(); | 
					
						
							| 
									
										
										
										
											2021-03-15 11:42:54 -07:00
										 |  |  |     if (!(fd >= 0)) return []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |     logASARAccess(asarPath, filePath, info.offset); | 
					
						
							| 
									
										
										
										
											2021-03-15 11:42:54 -07:00
										 |  |  |     fs.readSync(fd, buffer, 0, info.size, info.offset); | 
					
						
							| 
									
										
										
										
											2021-09-09 14:49:01 -07:00
										 |  |  |     validateBufferIntegrity(buffer, info.integrity); | 
					
						
							| 
									
										
										
										
											2020-07-27 09:12:29 -07:00
										 |  |  |     const str = buffer.toString('utf8'); | 
					
						
							|  |  |  |     return [str, str.length > 0]; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { internalModuleStat } = internalBinding('fs'); | 
					
						
							|  |  |  |   internalBinding('fs').internalModuleStat = (pathArgument: string) => { | 
					
						
							|  |  |  |     const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |     if (!pathInfo.isAsar) return internalModuleStat(pathArgument); | 
					
						
							|  |  |  |     const { asarPath, filePath } = pathInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // -ENOENT
 | 
					
						
							|  |  |  |     const archive = getOrCreateArchive(asarPath); | 
					
						
							|  |  |  |     if (!archive) return -34; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // -ENOENT
 | 
					
						
							|  |  |  |     const stats = archive.stat(filePath); | 
					
						
							|  |  |  |     if (!stats) return -34; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-25 13:17:24 +02:00
										 |  |  |     return (stats.type === AsarFileType.kDirectory) ? 1 : 0; | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Calling mkdir for directory inside asar archive should throw ENOTDIR
 | 
					
						
							|  |  |  |   // error, but on Windows it throws ENOENT.
 | 
					
						
							|  |  |  |   if (process.platform === 'win32') { | 
					
						
							|  |  |  |     const { mkdir } = fs; | 
					
						
							|  |  |  |     fs.mkdir = (pathArgument: string, options: any, callback: any) => { | 
					
						
							|  |  |  |       if (typeof options === 'function') { | 
					
						
							|  |  |  |         callback = options; | 
					
						
							|  |  |  |         options = {}; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |       if (pathInfo.isAsar && pathInfo.filePath.length > 0) { | 
					
						
							|  |  |  |         const error = createError(AsarError.NOT_DIR); | 
					
						
							|  |  |  |         nextTick(callback, [error]); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       mkdir(pathArgument, options, callback); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fs.promises.mkdir = util.promisify(fs.mkdir); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const { mkdirSync } = fs; | 
					
						
							|  |  |  |     fs.mkdirSync = function (pathArgument: string, options: any) { | 
					
						
							|  |  |  |       const pathInfo = splitPath(pathArgument); | 
					
						
							|  |  |  |       if (pathInfo.isAsar && pathInfo.filePath.length) throw createError(AsarError.NOT_DIR); | 
					
						
							|  |  |  |       return mkdirSync(pathArgument, options); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function invokeWithNoAsar (func: Function) { | 
					
						
							|  |  |  |     return function (this: any) { | 
					
						
							|  |  |  |       const processNoAsarOriginalValue = process.noAsar; | 
					
						
							|  |  |  |       process.noAsar = true; | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         return func.apply(this, arguments); | 
					
						
							|  |  |  |       } finally { | 
					
						
							|  |  |  |         process.noAsar = processNoAsarOriginalValue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Strictly implementing the flags of fs.copyFile is hard, just do a simple
 | 
					
						
							|  |  |  |   // implementation for now. Doing 2 copies won't spend much time more as OS
 | 
					
						
							|  |  |  |   // has filesystem caching.
 | 
					
						
							|  |  |  |   overrideAPI(fs, 'copyFile'); | 
					
						
							|  |  |  |   overrideAPISync(fs, 'copyFileSync'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   overrideAPI(fs, 'open'); | 
					
						
							|  |  |  |   overrideAPISync(process, 'dlopen', 1); | 
					
						
							|  |  |  |   overrideAPISync(Module._extensions, '.node', 1); | 
					
						
							|  |  |  |   overrideAPISync(fs, 'openSync'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const overrideChildProcess = (childProcess: Record<string, any>) => { | 
					
						
							|  |  |  |     // Executing a command string containing a path to an asar archive
 | 
					
						
							|  |  |  |     // confuses `childProcess.execFile`, which is internally called by
 | 
					
						
							|  |  |  |     // `childProcess.{exec,execSync}`, causing Electron to consider the full
 | 
					
						
							|  |  |  |     // command as a single path to an archive.
 | 
					
						
							|  |  |  |     const { exec, execSync } = childProcess; | 
					
						
							|  |  |  |     childProcess.exec = invokeWithNoAsar(exec); | 
					
						
							|  |  |  |     childProcess.exec[util.promisify.custom] = invokeWithNoAsar(exec[util.promisify.custom]); | 
					
						
							|  |  |  |     childProcess.execSync = invokeWithNoAsar(execSync); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     overrideAPI(childProcess, 'execFile'); | 
					
						
							|  |  |  |     overrideAPISync(childProcess, 'execFileSync'); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-03 07:59:56 +02:00
										 |  |  |   const asarReady = new WeakSet(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |   // Lazily override the child_process APIs only when child_process is
 | 
					
						
							|  |  |  |   // fetched the first time.  We will eagerly override the child_process APIs
 | 
					
						
							|  |  |  |   // when this env var is set so that stack traces generated inside node unit
 | 
					
						
							|  |  |  |   // tests will match. This env var will only slow things down in users apps
 | 
					
						
							|  |  |  |   // and should not be used.
 | 
					
						
							|  |  |  |   if (process.env.ELECTRON_EAGER_ASAR_HOOK_FOR_TESTING) { | 
					
						
							|  |  |  |     overrideChildProcess(require('child_process')); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     const originalModuleLoad = Module._load; | 
					
						
							|  |  |  |     Module._load = (request: string, ...args: any[]) => { | 
					
						
							|  |  |  |       const loadResult = originalModuleLoad(request, ...args); | 
					
						
							| 
									
										
										
										
											2023-06-14 11:03:53 +02:00
										 |  |  |       if (request === 'child_process' || request === 'node:child_process') { | 
					
						
							| 
									
										
										
										
											2021-06-03 07:59:56 +02:00
										 |  |  |         if (!asarReady.has(loadResult)) { | 
					
						
							|  |  |  |           asarReady.add(loadResult); | 
					
						
							| 
									
										
										
										
											2020-07-16 11:38:31 -07:00
										 |  |  |           // Just to make it obvious what we are dealing with here
 | 
					
						
							|  |  |  |           const childProcess = loadResult; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           overrideChildProcess(childProcess); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return loadResult; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; |