patch: refactor permission code

This commit is contained in:
Edwin Joassart 2025-07-16 11:27:06 +02:00
parent 391164bf15
commit 4c2489d00f
No known key found for this signature in database
GPG Key ID: 6337EBE5AC716051
9 changed files with 28511 additions and 28576 deletions

View File

@ -98,7 +98,8 @@ async function connectToChildProcess(
): Promise<ChildApi | { failed: boolean }> { ): Promise<ChildApi | { failed: boolean }> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// TODO: default to IPC connections https://github.com/websockets/ws/blob/master/doc/ws.md#ipc-connections // TODO: default to IPC connections https://github.com/websockets/ws/blob/master/doc/ws.md#ipc-connections
// TOOD: use the path as cheap authentication // TODO: use the path as cheap authentication
console.log(etcherServerId); console.log(etcherServerId);
const url = `ws://${etcherServerAddress}:${etcherServerPort}`; const url = `ws://${etcherServerAddress}:${etcherServerPort}`;
@ -196,9 +197,9 @@ async function spawnChildAndConnect({
`etcher-${Math.random().toString(36).substring(7)}`; `etcher-${Math.random().toString(36).substring(7)}`;
console.log( console.log(
`Spawning ${ `Starting ${
withPrivileges ? 'priviledged' : 'unpriviledged' withPrivileges ? 'priviledged' : 'unpriviledged'
} sidecar on port ${etcherServerPort}`, } flasher sidecar on port ${etcherServerPort}`,
); );
// spawn the child process, which will act as the ws server // spawn the child process, which will act as the ws server
@ -212,11 +213,11 @@ async function spawnChildAndConnect({
etcherServerPort, etcherServerPort,
); );
if (result.cancelled) { if (result.cancelled) {
throw new Error('Spwaning the child process was cancelled'); throw new Error('Starting flasher sidecar process was cancelled');
} }
} catch (error) { } catch (error) {
console.error('Error spawning child process', error); console.error('Error starting flasher sidecar process', error);
throw new Error('Error spawning the child process'); throw new Error('Error starting flasher sidecar process');
} }
} }
@ -232,7 +233,7 @@ async function spawnChildAndConnect({
if (failed) { if (failed) {
retry++; retry++;
console.log( console.log(
`Retrying to connect to child process in ${connectionRetryDelay}... ${retry} / ${connectionRetryAttempts}`, `Connection to sidecar flasher process attempt ${retry} / ${connectionRetryAttempts} failed; retrying in ${connectionRetryDelay}ms...`,
); );
await new Promise((resolve) => await new Promise((resolve) =>
setTimeout(resolve, connectionRetryDelay), setTimeout(resolve, connectionRetryDelay),
@ -241,10 +242,11 @@ async function spawnChildAndConnect({
} }
return { failed, emit, registerHandler }; return { failed, emit, registerHandler };
} }
throw new Error('Connection to etcher-util timed out'); // TODO: raised an error to the user if we reach this point
throw new Error('Connection to sidecar flasher process timed out');
} catch (error) { } catch (error) {
console.error('Error connecting to child process', error); console.error('Error connecting to sidecar flasher process process', error);
throw new Error('Connection to etcher-util failed'); throw new Error('Connection to sidecar flasher process failed');
} }
} }

View File

@ -34,8 +34,6 @@ export function fromFlashState({
status: string; status: string;
position?: string; position?: string;
} { } {
console.log(i18next.t('progress.starting'));
if (type === undefined) { if (type === undefined) {
return { status: i18next.t('progress.starting') }; return { status: i18next.t('progress.starting') };
} else if (type === 'decompressing') { } else if (type === 'decompressing') {

View File

@ -14,16 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
/**
* TODO:
* This is convoluted and needlessly complex. It should be simplified and modernized.
* The environment variable setting and escaping should be greatly simplified by letting {linux|catalina}-sudo handle that.
* We shouldn't need to write a script to a file and then execute it. We should be able to forwatd the command to the sudo code directly.
*/
import { spawn, exec } from 'child_process'; import { spawn, exec } from 'child_process';
import { withTmpFile } from 'etcher-sdk/build/tmp';
import { promises as fs } from 'fs';
import { promisify } from 'util'; import { promisify } from 'util';
import * as _ from 'lodash'; import * as _ from 'lodash';
import * as os from 'os'; import * as os from 'os';
@ -66,74 +57,30 @@ export function isElevatedUnixSync(): boolean {
return process.geteuid!() === UNIX_SUPERUSER_USER_ID; return process.geteuid!() === UNIX_SUPERUSER_USER_ID;
} }
function escapeSh(value: any): string {
// Make sure it's a string
// Replace ' -> '\'' (closing quote, escaped quote, opening quote)
// Surround with quotes
return `'${String(value).replace(/'/g, "'\\''")}'`;
}
function escapeParamCmd(value: any): string {
// Make sure it's a string
// Escape " -> \"
// Surround with double quotes
return `"${String(value).replace(/"/g, '\\"')}"`;
}
function setEnvVarSh(value: any, name: string): string {
return `export ${name}=${escapeSh(value)}`;
}
function setEnvVarCmd(value: any, name: string): string {
return `set "${name}=${String(value)}"`;
}
// Exported for tests
export function createLaunchScript(
command: string,
argv: string[],
environment: _.Dictionary<string | undefined>,
): string {
const isWindows = os.platform() === 'win32';
const lines = [];
if (isWindows) {
// Switch to utf8
lines.push('chcp 65001');
}
const [setEnvVarFn, escapeFn] = isWindows
? [setEnvVarCmd, escapeParamCmd]
: [setEnvVarSh, escapeSh];
lines.push(..._.map(environment, setEnvVarFn));
lines.push([command, ...argv].map(escapeFn).join(' '));
return lines.join(os.EOL);
}
async function elevateScriptWindows( async function elevateScriptWindows(
path: string, command: string[],
name: string,
env: any, env: any,
): Promise<{ cancelled: false }> { ): Promise<{ cancelled: false }> {
// '&' needs to be escaped here (but not when written to a .cmd file) // '&' needs to be escaped here (but not when written to a .cmd file)
const cmd = ['cmd', '/c', escapeParamCmd(path).replace(/&/g, '^&')].join(' '); await winSudo(command, env);
await winSudo(cmd, name, env);
return { cancelled: false }; return { cancelled: false };
} }
async function elevateScriptUnix( async function elevateScriptUnix(
path: string, command: string[],
name: string, name: string,
env: any,
): Promise<{ cancelled: boolean }> { ): Promise<{ cancelled: boolean }> {
const cmd = ['bash', escapeSh(path)].join(' '); await linuxSudo(command, { name }, env);
await linuxSudo(cmd, { name });
return { cancelled: false }; return { cancelled: false };
} }
async function elevateScriptCatalina( async function elevateScriptCatalina(
path: string, command: string[],
env: any,
): Promise<{ cancelled: boolean }> { ): Promise<{ cancelled: boolean }> {
const cmd = ['bash', escapeSh(path)].join(' ');
try { try {
const { cancelled } = await darwinSudo(cmd); const { cancelled } = await darwinSudo(command, env);
return { cancelled }; return { cancelled };
} catch (error: any) { } catch (error: any) {
throw errors.createError({ title: error.stderr }); throw errors.createError({ title: error.stderr });
@ -147,38 +94,50 @@ export async function elevateCommand(
applicationName: string; applicationName: string;
}, },
): Promise<{ cancelled: boolean }> { ): Promise<{ cancelled: boolean }> {
// if we're running with elevated privileges, we can just spawn the command
if (await isElevated()) { if (await isElevated()) {
spawn(command[0], command.slice(1), { spawn(command[0], command.slice(1), {
env: options.env, env: options.env,
}); });
return { cancelled: false }; return { cancelled: false };
} }
const isWindows = os.platform() === 'win32'; const isWindows = os.platform() === 'win32';
const launchScript = createLaunchScript(
command[0], // Augment the command to pass the environment variables as args
command.slice(1), // Powershell (required to ask for elevated privileges) as of win10 cannot pass environment variables as a map, so we pass them as args
options.env, // For the sake of consistency, we do the same for Linux and macOS, but it's likely not required
); // Once we deprecate win10 we can move to a more elegant solution (passing the env to powershell)
return await withTmpFile( // const envFilter: string[] = [
{ // 'ETCHER_SERVER_ADDRESS',
keepOpen: false, // 'ETCHER_SERVER_PORT',
prefix: 'balena-etcher-electron-', // 'ETCHER_SERVER_ID',
postfix: '.cmd', // 'ETCHER_NO_SPAWN_UTIL',
}, // 'ETCHER_TERMINATE_TIMEOUT',
async ({ path }) => { // 'UV_THREADPOOL_SIZE',
await fs.writeFile(path, launchScript); // ];
// const preparedCmd = [
// command[0],
// ...command.slice(1),
// ...Object.keys(options.env)
// .filter((key) => Object.prototype.hasOwnProperty.call(options.env, key))
// .filter((key) => envFilter.includes(key))
// .map((key) => `--${key}=${options.env[key]}`),
// ];
if (isWindows) { if (isWindows) {
return elevateScriptWindows(path, options.applicationName, options.env); return elevateScriptWindows(command, options.env);
} }
if ( if (
os.platform() === 'darwin' && os.platform() === 'darwin' &&
semver.compare(os.release(), '19.0.0') >= 0 semver.compare(os.release(), '19.0.0') >= 0
) { ) {
// >= macOS Catalina // >= macOS Catalina
return elevateScriptCatalina(path); return elevateScriptCatalina(command, options.env);
} }
try { try {
return elevateScriptUnix(path, options.applicationName); return elevateScriptUnix(command, options.applicationName, options.env);
} catch (error: any) { } catch (error: any) {
// We're hardcoding internal error messages declared by `sudo-prompt`. // We're hardcoding internal error messages declared by `sudo-prompt`.
// There doesn't seem to be a better way to handle these errors, so // There doesn't seem to be a better way to handle these errors, so
@ -207,6 +166,4 @@ export async function elevateCommand(
} }
throw error; throw error;
} }
},
);
} }

View File

@ -16,15 +16,10 @@
import { spawn } from 'child_process'; import { spawn } from 'child_process';
import { join } from 'path'; import { join } from 'path';
import { env } from 'process';
// import { promisify } from "util";
import { supportedLocales } from '../../gui/app/i18n'; import { supportedLocales } from '../../gui/app/i18n';
// const execFileAsync = promisify(execFile);
const SUCCESSFUL_AUTH_MARKER = 'AUTHENTICATION SUCCEEDED'; const SUCCESSFUL_AUTH_MARKER = 'AUTHENTICATION SUCCEEDED';
const EXPECTED_SUCCESSFUL_AUTH_MARKER = `${SUCCESSFUL_AUTH_MARKER}\n`;
function getAskPassScriptPath(lang: string): string { function getAskPassScriptPath(lang: string): string {
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
@ -36,45 +31,56 @@ function getAskPassScriptPath(lang: string): string {
} }
export async function sudo( export async function sudo(
command: string, command: string[],
env: any,
): Promise<{ cancelled: boolean; stdout?: string; stderr?: string }> { ): Promise<{ cancelled: boolean; stdout?: string; stderr?: string }> {
try {
let lang = Intl.DateTimeFormat().resolvedOptions().locale; let lang = Intl.DateTimeFormat().resolvedOptions().locale;
lang = lang.substr(0, 2); lang = lang.substr(0, 2);
if (supportedLocales.indexOf(lang) > -1) { if (supportedLocales.indexOf(lang) === -1) {
// language should be present
} else {
// fallback to eng
lang = 'en'; lang = 'en';
} }
// Build the shell command string
const shellCmd = `echo ${SUCCESSFUL_AUTH_MARKER} && ${command[0]} ${command
.slice(1)
.map((a) => a.replace(/"/g, '"'))
.join(' ')}`;
let elevated = 'pending';
try {
const elevateProcess = spawn( const elevateProcess = spawn(
'sudo', 'sudo',
['--askpass', 'sh', '-c', `echo ${SUCCESSFUL_AUTH_MARKER} && ${command}`], ['-E', '--askpass', 'sh', '-c', shellCmd],
{ {
// encoding: "utf8",
env: { env: {
...env,
PATH: env.PATH, PATH: env.PATH,
SUDO_ASKPASS: getAskPassScriptPath(lang), SUDO_ASKPASS: getAskPassScriptPath(lang),
}, },
}, },
); );
let elevated = 'pending';
elevateProcess.stdout.on('data', (data) => { elevateProcess.stdout.on('data', (data) => {
// console.log(`stdout: ${data}`);
if (data.toString().includes(SUCCESSFUL_AUTH_MARKER)) { if (data.toString().includes(SUCCESSFUL_AUTH_MARKER)) {
// if the first data comming out of the sudo command is the expected marker we resolve the promise
elevated = 'granted'; elevated = 'granted';
} else { } else {
// if the first data comming out of the sudo command is not the expected marker we reject the promise
elevated = 'rejected'; elevated = 'rejected';
} }
}); });
// we don't spawn or read stdout in the promise otherwise resolving stop the process // elevateProcess.stderr.on('data', (data) => {
// console.log(`stderr: ${data}`);
// });
} catch (error: any) {
console.error('Error starting sudo process', error);
throw new Error('Error starting sudo process');
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const checkElevation = setInterval(() => { const checkElevation = setInterval(() => {
console.log('elevated', elevated);
if (elevated === 'granted') { if (elevated === 'granted') {
clearInterval(checkElevation); clearInterval(checkElevation);
resolve({ cancelled: false }); resolve({ cancelled: false });
@ -84,19 +90,9 @@ export async function sudo(
} }
}, 300); }, 300);
// if the elevation didn't occured in 30 seconds we reject the promise
setTimeout(() => { setTimeout(() => {
clearInterval(checkElevation); clearInterval(checkElevation);
reject(new Error('Elevation timeout')); reject(new Error('Elevation timeout'));
}, 30000); }, 30000);
}); });
} catch (error: any) {
if (error.code === 1) {
if (!error.stdout.startsWith(EXPECTED_SUCCESSFUL_AUTH_MARKER)) {
return { cancelled: true };
}
error.stdout = error.stdout.slice(EXPECTED_SUCCESSFUL_AUTH_MARKER.length);
}
throw error;
}
} }

View File

@ -30,7 +30,6 @@
import { spawn } from 'child_process'; import { spawn } from 'child_process';
import { access, constants } from 'fs/promises'; import { access, constants } from 'fs/promises';
import { env } from 'process';
// const execFileAsync = promisify(execFile); // const execFileAsync = promisify(execFile);
@ -62,8 +61,9 @@ function escapeDoubleQuotes(escapeString: string) {
} }
export async function sudo( export async function sudo(
command: string, command: string[],
{ name }: { name: string }, { name }: { name: string },
env: any,
): Promise<{ cancelled: boolean; stdout?: string; stderr?: string }> { ): Promise<{ cancelled: boolean; stdout?: string; stderr?: string }> {
const linuxBinary: string = (await checkLinuxBinary()) as string; const linuxBinary: string = (await checkLinuxBinary()) as string;
if (!linuxBinary) { if (!linuxBinary) {
@ -72,11 +72,11 @@ export async function sudo(
const parameters = []; const parameters = [];
// Add kdesudo or pkexec specific parameters
if (/kdesudo/i.test(linuxBinary)) { if (/kdesudo/i.test(linuxBinary)) {
parameters.push( parameters.push(
'--comment', '--comment',
`"${name} wants to make changes. `"${name} wants to make changes.\nEnter your password to allow this."`,
Enter your password to allow this."`,
); );
parameters.push('-d'); // Do not show the command to be run in the dialog. parameters.push('-d'); // Do not show the command to be run in the dialog.
parameters.push('--'); parameters.push('--');
@ -84,15 +84,19 @@ export async function sudo(
parameters.push('--disable-internal-agent'); parameters.push('--disable-internal-agent');
} }
// Build the shell command string
const shellCmd = `echo ${SUCCESSFUL_AUTH_MARKER} && ${escapeDoubleQuotes(command[0])} ${command
.slice(1)
.map((a) => escapeDoubleQuotes(a))
.join(' ')}`;
parameters.push('/bin/bash'); parameters.push('/bin/bash');
parameters.push('-c'); parameters.push('-c');
parameters.push( parameters.push(shellCmd);
`echo ${SUCCESSFUL_AUTH_MARKER} && ${escapeDoubleQuotes(command)}`,
);
const elevateProcess = spawn(linuxBinary, parameters, { const elevateProcess = spawn(linuxBinary, parameters, {
// encoding: "utf8",
env: { env: {
...env,
PATH: env.PATH, PATH: env.PATH,
}, },
}); });
@ -110,17 +114,6 @@ export async function sudo(
} }
}); });
// elevateProcess.stderr.on('data', (data) => {
// // console.log(`stderr: ${data.toString()}`);
// // if (data.toString().includes(SUCCESSFUL_AUTH_MARKER)) {
// // // if the first data comming out of the sudo command is the expected marker we resolve the promise
// // elevated = 'granted';
// // } else {
// // // if the first data comming out of the sudo command is not the expected marker we reject the promise
// // elevated = 'refused';
// // }
// });
// we don't spawn or read stdout in the promise otherwise resolving stop the process // we don't spawn or read stdout in the promise otherwise resolving stop the process
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const checkElevation = setInterval(() => { const checkElevation = setInterval(() => {

View File

@ -29,190 +29,74 @@
*/ */
import { spawn } from 'child_process'; import { spawn } from 'child_process';
// import { env } from 'process';
import { tmpdir } from 'os';
import { v4 as uuidv4 } from 'uuid';
import { join, sep } from 'path';
import { mkdir, writeFile, copyFile, readFile } from 'fs/promises';
/**
* TODO:
* Migrate, modernize and clenup the windows elevation code from the old @balena/sudo-prompt package in a similar way to linux-sudo.ts and catalina-sudo files.
*/
export async function sudo( export async function sudo(
command: string, command: string[],
_name: string,
env: any, env: any,
): Promise<{ cancelled: boolean; stdout?: string; stderr?: string }> { ): Promise<{ cancelled: boolean; stdout?: string; stderr?: string }> {
const uuid = uuidv4();
const temp = tmpdir();
if (!temp) {
throw new Error('os.tmpdir() not defined.');
}
const tmpFolder = join(temp, uuid);
if (/"/.test(tmpFolder)) {
// We expect double quotes to be reserved on Windows.
// Even so, we test for this and abort if they are present.
throw new Error('instance.path cannot contain double-quotes.');
}
const executeScriptPath = join(tmpFolder, 'execute.bat');
const commandScriptPath = join(tmpFolder, 'command.bat');
const stdoutPath = join(tmpFolder, 'stdout');
const stderrPath = join(tmpFolder, 'stderr');
const statusPath = join(tmpFolder, 'status');
const SUCCESSFUL_AUTH_MARKER = 'AUTHENTICATION SUCCEEDED';
try { try {
await mkdir(tmpFolder);
// WindowsWriteExecuteScript(instance, end)
const executeScript = `
@echo off\r\n
call "${commandScriptPath}" > "${stdoutPath}" 2> "${stderrPath}"\r\n
(echo %ERRORLEVEL%) > "${statusPath}"
`;
await writeFile(executeScriptPath, executeScript, 'utf-8');
// WindowsWriteCommandScript(instance, end) // WindowsWriteCommandScript(instance, end)
const cwd = process.cwd();
if (/"/.test(cwd)) {
// We expect double quotes to be reserved on Windows.
// Even so, we test for this and abort if they are present.
throw new Error('process.cwd() cannot contain double-quotes.');
}
const commandScriptArray = [];
commandScriptArray.push('@echo off');
// Set code page to UTF-8:
commandScriptArray.push('chcp 65001>nul');
// Preserve current working directory:
// We pass /d as an option in case the cwd is on another drive (issue 70).
commandScriptArray.push(`cd /d "${cwd}"`);
// Export environment variables:
for (const key in env) {
// "The characters <, >, |, &, ^ are special command shell characters, and
// they must be preceded by the escape character (^) or enclosed in
// quotation marks. If you use quotation marks to enclose a string that
// contains one of the special characters, the quotation marks are set as
// part of the environment variable value."
// In other words, Windows assigns everything that follows the equals sign
// to the value of the variable, whereas Unix systems ignore double quotes.
if (Object.prototype.hasOwnProperty.call(env, key)) {
const value = env[key];
commandScriptArray.push(
`set ${key}=${value!.replace(/([<>\\|&^])/g, '^$1')}`,
);
}
}
commandScriptArray.push(`echo ${SUCCESSFUL_AUTH_MARKER}`);
commandScriptArray.push(command);
await writeFile(
commandScriptPath,
commandScriptArray.join('\r\n'),
'utf-8',
);
// WindowsCopyCmd(instance, end)
if (windowsNeedsCopyCmd(tmpFolder)) {
// Work around https://github.com/jorangreef/sudo-prompt/issues/97
// Powershell can't properly escape amperstands in paths.
// We work around this by copying cmd.exe in our temporary folder and running
// it from here (see WindowsElevate below).
// That way, we don't have to pass the path containing the amperstand at all.
// A symlink would probably work too but you have to be an administrator in
// order to create symlinks on Windows.
await copyFile(
join(process.env.SystemRoot!, 'System32', 'cmd.exe'),
join(tmpFolder, 'cmd.exe'),
);
}
// WindowsElevate(instance, end)
// We used to use this for executing elevate.vbs:
// var command = 'cscript.exe //NoLogo "' + instance.pathElevate + '"';
const spawnCommand = []; const spawnCommand = [];
// spawnCommand.push("powershell.exe") // as we use spawn this one is out of the array
spawnCommand.push('Start-Process'); spawnCommand.push('Start-Process');
spawnCommand.push('-FilePath'); spawnCommand.push('-FilePath');
const options: any = { encoding: 'utf8' };
if (windowsNeedsCopyCmd(tmpFolder)) {
// Node.path.join('.', 'cmd.exe') would return 'cmd.exe'
spawnCommand.push(['.', 'cmd.exe'].join(sep));
spawnCommand.push('-ArgumentList');
spawnCommand.push('"/C","execute.bat"');
options.cwd = tmpFolder;
} else {
// Escape characters for cmd using double quotes: // Escape characters for cmd using double quotes:
// Escape characters for PowerShell using single quotes: // Escape characters for PowerShell using single quotes:
// Escape single quotes for PowerShell using backtick: // Escape single quotes for PowerShell using backtick:
// See: https://ss64.com/ps/syntax-esc.html // See: https://ss64.com/ps/syntax-esc.html
spawnCommand.push(`'${executeScriptPath.replace(/'/g, "`'")}'`); spawnCommand.push(`'${command[0].replace(/'/g, "`'")}'`);
} spawnCommand.push('-ArgumentList');
// Join and escape arguments for PowerShell
spawnCommand.push(
`'${command
.slice(1)
.map((a) => a.replace(/'/g, "`'"))
.join(' ')}'`,
);
spawnCommand.push('-WindowStyle hidden'); spawnCommand.push('-WindowStyle hidden');
spawnCommand.push('-Verb runAs'); spawnCommand.push('-Verb runAs');
spawn('powershell.exe', spawnCommand); const child = spawn('powershell.exe', spawnCommand, {
env,
// setTimeout(() => {elevated = "granted"}, 5000)
// we don't spawn or read stdout in the promise otherwise resolving stop the process
return new Promise((resolve, reject) => {
const checkElevation = setInterval(async () => {
try {
const result = await readFile(stdoutPath, 'utf-8');
const error = await readFile(stderrPath, 'utf-8');
if (error && error !== '') {
throw new Error(error);
}
// TODO: should track something more generic
if (result.includes(SUCCESSFUL_AUTH_MARKER)) {
clearInterval(checkElevation);
resolve({ cancelled: false });
}
} catch (error) {
console.log(
'Error while reading flasher elevation script output',
error,
);
}
}, 1000);
// if the elevation didn't occured in 30 seconds we reject the promise
setTimeout(() => {
clearInterval(checkElevation);
reject(new Error('Elevation timeout'));
}, 30000);
}); });
// WindowsWaitForStatus(instance, end) let result = { status: 'waiting' };
// WindowsResult(instance, end) child.on('close', (code) => {
if (code === 0) {
// User accepted UAC, process started
result = { status: 'granted' };
} else {
// User cancelled or error occurred
result = { status: 'cancelled' };
}
});
child.on('error', (err) => {
result = { status: err.message };
});
// we don't spawn directly in the promise otherwise resolving stop the process
return new Promise((resolve, reject) => {
setTimeout(() => {
if (result.status === 'waiting') {
// Still waiting for user input, don't resolve or reject yet
return;
} else if (result.status === 'granted') {
// User accepted the UAC prompt, process started
resolve({ cancelled: false });
} else if (result.status === 'cancelled') {
// User cancelled the UAC prompt
resolve({ cancelled: true });
} else {
// An error occurred, reject the promise
reject(new Error(`Elevation failed: ${result.status}`));
}
}, 300);
});
} catch (error) { } catch (error) {
throw new Error(`Can't elevate process ${error}`); throw new Error(`Can't elevate process ${error}`);
} finally {
// TODO: cleanup
// // Remove(instance.path, function (errorRemove) {
// // if (error) return callback(error)
// // if (errorRemove) return callback(errorRemove)
// // callback(undefined, stdout, stderr)
} }
} }
function windowsNeedsCopyCmd(path: string) {
const specialChars = ['&', '`', "'", '"', '<', '>', '|', '^'];
for (const specialChar of specialChars) {
if (path.includes(specialChar)) {
return true;
}
}
return false;
}

View File

@ -29,6 +29,28 @@ import { getSourceMetadata } from './source-metadata';
import type { DrivelistDrive } from '../shared/drive-constraints'; import type { DrivelistDrive } from '../shared/drive-constraints';
import type { SourceMetadata } from '../shared/typings/source-selector'; import type { SourceMetadata } from '../shared/typings/source-selector';
// Utility to parse --key=value arguments into process.env if not already set
function injectEnvFromArgs() {
for (const arg of process.argv.slice(2)) {
const match = arg.match(/^--([^=]+)=(.*)$/);
if (match) {
const key = match[1];
const value = match[2];
if (process.env[key] === undefined) {
process.env[key] = value;
}
}
}
}
// Inject env vars from arguments if not already present
injectEnvFromArgs();
console.log(
'Etcher child process started with the following environment variables:',
);
console.log(JSON.stringify(process.env, null, 2));
const ETCHER_SERVER_ADDRESS = process.env.ETCHER_SERVER_ADDRESS as string; const ETCHER_SERVER_ADDRESS = process.env.ETCHER_SERVER_ADDRESS as string;
const ETCHER_SERVER_PORT = process.env.ETCHER_SERVER_PORT as string; const ETCHER_SERVER_PORT = process.env.ETCHER_SERVER_PORT as string;
// const ETCHER_SERVER_ID = process.env.ETCHER_SERVER_ID as string; // const ETCHER_SERVER_ID = process.env.ETCHER_SERVER_ID as string;

361
npm-shrinkwrap.json generated
View File

@ -62,7 +62,7 @@
"@wdio/local-runner": "^8.36.1", "@wdio/local-runner": "^8.36.1",
"@wdio/mocha-framework": "^8.36.1", "@wdio/mocha-framework": "^8.36.1",
"@wdio/spec-reporter": "^8.36.1", "@wdio/spec-reporter": "^8.36.1",
"@yao-pkg/pkg": "^5.11.5", "@yao-pkg/pkg": "^6.5.1",
"catch-uncommitted": "^2.0.0", "catch-uncommitted": "^2.0.0",
"chai": "4.3.10", "chai": "4.3.10",
"css-loader": "5.2.7", "css-loader": "5.2.7",
@ -3715,6 +3715,19 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1" "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
} }
}, },
"node_modules/@isaacs/fs-minipass": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"minipass": "^7.0.4"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@jest/expect-utils": { "node_modules/@jest/expect-utils": {
"version": "29.7.0", "version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
@ -6490,40 +6503,45 @@
"dev": true "dev": true
}, },
"node_modules/@yao-pkg/pkg": { "node_modules/@yao-pkg/pkg": {
"version": "5.11.5", "version": "6.5.1",
"resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-5.11.5.tgz", "resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-6.5.1.tgz",
"integrity": "sha512-NPFXCn+5bAYZKej7jI92+mXiWG/LA6pEIJCXgI4MM3aYhUFrQOPrYKYr3cGXGs9lkgKGovlnMcKGDjwJ3B7rCQ==", "integrity": "sha512-z6XlySYfnqfm1AfVlBN8A3yeAQniIwL7TKQfDCGsswYSVYLt2snbRefQYsfQQ3pw5lVXrZdLqgTjzaqID9IkWA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/generator": "7.23.0", "@babel/generator": "^7.23.0",
"@babel/parser": "7.23.0", "@babel/parser": "^7.23.0",
"@babel/types": "7.23.0", "@babel/types": "^7.23.0",
"@yao-pkg/pkg-fetch": "3.5.9", "@yao-pkg/pkg-fetch": "3.5.23",
"chalk": "^4.1.2",
"fs-extra": "^9.1.0",
"globby": "^11.1.0",
"into-stream": "^6.0.0", "into-stream": "^6.0.0",
"is-core-module": "2.9.0",
"minimist": "^1.2.6", "minimist": "^1.2.6",
"multistream": "^4.1.0", "multistream": "^4.1.0",
"prebuild-install": "7.1.1", "picocolors": "^1.1.0",
"resolve": "^1.22.0", "picomatch": "^4.0.2",
"stream-meter": "^1.0.4" "prebuild-install": "^7.1.1",
"resolve": "^1.22.10",
"stream-meter": "^1.0.4",
"tar": "^7.4.3",
"tinyglobby": "^0.2.11",
"unzipper": "^0.12.3"
}, },
"bin": { "bin": {
"pkg": "lib-es5/bin.js" "pkg": "lib-es5/bin.js"
},
"engines": {
"node": ">=18.0.0"
} }
}, },
"node_modules/@yao-pkg/pkg-fetch": { "node_modules/@yao-pkg/pkg-fetch": {
"version": "3.5.9", "version": "3.5.23",
"resolved": "https://registry.npmjs.org/@yao-pkg/pkg-fetch/-/pkg-fetch-3.5.9.tgz", "resolved": "https://registry.npmjs.org/@yao-pkg/pkg-fetch/-/pkg-fetch-3.5.23.tgz",
"integrity": "sha512-usMwwqFCd2B7k+V87u6kiTesyDSlw+3LpiuYBWe+UgryvSOk/NXjx3XVCub8hQoi0bCREbdQ6NDBqminyHJJrg==", "integrity": "sha512-rn45sqVQSkcJNSBdTnYze3n+kyub4CN8aiWYlPgA9yp9FZeEF+BlpL68kSIm3HaVuANniF+7RBMH5DkC4zlHZA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"chalk": "^4.1.2",
"fs-extra": "^9.1.0",
"https-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0",
"node-fetch": "^2.6.6", "node-fetch": "^2.6.6",
"picocolors": "^1.1.0",
"progress": "^2.0.3", "progress": "^2.0.3",
"semver": "^7.3.5", "semver": "^7.3.5",
"tar-fs": "^2.1.1", "tar-fs": "^2.1.1",
@ -6537,39 +6555,27 @@
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
"dev": true "dev": true,
"license": "ISC"
}, },
"node_modules/@yao-pkg/pkg-fetch/node_modules/cliui": { "node_modules/@yao-pkg/pkg-fetch/node_modules/cliui": {
"version": "7.0.4", "version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true, "dev": true,
"license": "ISC",
"dependencies": { "dependencies": {
"string-width": "^4.2.0", "string-width": "^4.2.0",
"strip-ansi": "^6.0.0", "strip-ansi": "^6.0.0",
"wrap-ansi": "^7.0.0" "wrap-ansi": "^7.0.0"
} }
}, },
"node_modules/@yao-pkg/pkg-fetch/node_modules/fs-extra": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"dev": true,
"dependencies": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@yao-pkg/pkg-fetch/node_modules/strip-ansi": { "node_modules/@yao-pkg/pkg-fetch/node_modules/strip-ansi": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ansi-regex": "^5.0.1" "ansi-regex": "^5.0.1"
}, },
@ -6578,10 +6584,11 @@
} }
}, },
"node_modules/@yao-pkg/pkg-fetch/node_modules/tar-fs": { "node_modules/@yao-pkg/pkg-fetch/node_modules/tar-fs": {
"version": "2.1.1", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
"integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"chownr": "^1.1.1", "chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2", "mkdirp-classic": "^0.5.2",
@ -6594,6 +6601,7 @@
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"bl": "^4.0.3", "bl": "^4.0.3",
"end-of-stream": "^1.4.1", "end-of-stream": "^1.4.1",
@ -6610,6 +6618,7 @@
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ansi-styles": "^4.0.0", "ansi-styles": "^4.0.0",
"string-width": "^4.1.0", "string-width": "^4.1.0",
@ -6627,6 +6636,7 @@
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true, "dev": true,
"license": "ISC",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
} }
@ -6636,6 +6646,7 @@
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"cliui": "^7.0.2", "cliui": "^7.0.2",
"escalade": "^3.1.1", "escalade": "^3.1.1",
@ -6654,64 +6665,118 @@
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true, "dev": true,
"license": "ISC",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/@yao-pkg/pkg/node_modules/@babel/generator": { "node_modules/@yao-pkg/pkg/node_modules/chownr": {
"version": "7.23.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
"dev": true, "dev": true,
"dependencies": { "license": "BlueOak-1.0.0",
"@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
},
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=18"
}
},
"node_modules/@yao-pkg/pkg/node_modules/@babel/parser": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@yao-pkg/pkg/node_modules/@babel/types": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"dependencies": {
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
"node": ">=6.9.0"
} }
}, },
"node_modules/@yao-pkg/pkg/node_modules/fs-extra": { "node_modules/@yao-pkg/pkg/node_modules/fs-extra": {
"version": "9.1.0", "version": "11.3.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0", "graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1", "jsonfile": "^6.0.1",
"universalify": "^2.0.0" "universalify": "^2.0.0"
}, },
"engines": {
"node": ">=14.14"
}
},
"node_modules/@yao-pkg/pkg/node_modules/minizlib": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
"integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
"dev": true,
"license": "MIT",
"dependencies": {
"minipass": "^7.1.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@yao-pkg/pkg/node_modules/mkdirp": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
"dev": true,
"license": "MIT",
"bin": {
"mkdirp": "dist/cjs/src/bin.js"
},
"engines": { "engines": {
"node": ">=10" "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@yao-pkg/pkg/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/@yao-pkg/pkg/node_modules/tar": {
"version": "7.4.3",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
"dev": true,
"license": "ISC",
"dependencies": {
"@isaacs/fs-minipass": "^4.0.0",
"chownr": "^3.0.0",
"minipass": "^7.1.2",
"minizlib": "^3.0.1",
"mkdirp": "^3.0.1",
"yallist": "^5.0.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@yao-pkg/pkg/node_modules/unzipper": {
"version": "0.12.3",
"resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.3.tgz",
"integrity": "sha512-PZ8hTS+AqcGxsaQntl3IRBw65QrBI6lxzqDEL7IAo/XCEqRTKGfOX56Vea5TH9SZczRVxuzk1re04z/YjuYCJA==",
"dev": true,
"license": "MIT",
"dependencies": {
"bluebird": "~3.7.2",
"duplexer2": "~0.1.4",
"fs-extra": "^11.2.0",
"graceful-fs": "^4.2.2",
"node-int64": "^0.4.0"
}
},
"node_modules/@yao-pkg/pkg/node_modules/yallist": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
"dev": true,
"license": "BlueOak-1.0.0",
"engines": {
"node": ">=18"
} }
}, },
"node_modules/abbrev": { "node_modules/abbrev": {
@ -10840,18 +10905,6 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/depcheck/node_modules/is-core-module": {
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
"integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
"dev": true,
"dependencies": {
"hasown": "^2.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/depcheck/node_modules/js-yaml": { "node_modules/depcheck/node_modules/js-yaml": {
"version": "3.14.1", "version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
@ -12585,18 +12638,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/eslint-plugin-react/node_modules/is-core-module": {
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
"integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
"dev": true,
"dependencies": {
"hasown": "^2.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/eslint-plugin-react/node_modules/resolve": { "node_modules/eslint-plugin-react/node_modules/resolve": {
"version": "2.0.0-next.5", "version": "2.0.0-next.5",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
@ -14820,15 +14861,6 @@
"integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==",
"dev": true "dev": true
}, },
"node_modules/has": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
"integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==",
"dev": true,
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/has-ansi": { "node_modules/has-ansi": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
@ -15982,12 +16014,16 @@
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
}, },
"node_modules/is-core-module": { "node_modules/is-core-module": {
"version": "2.9.0", "version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"has": "^1.0.3" "hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
@ -18881,9 +18917,10 @@
} }
}, },
"node_modules/minipass": { "node_modules/minipass": {
"version": "7.0.4", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"license": "ISC",
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
} }
@ -20227,6 +20264,13 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
"integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
"dev": true,
"license": "MIT"
},
"node_modules/node-loader": { "node_modules/node-loader": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/node-loader/-/node-loader-2.0.0.tgz", "resolved": "https://registry.npmjs.org/node-loader/-/node-loader-2.0.0.tgz",
@ -21335,9 +21379,10 @@
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
}, },
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.0.0", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"license": "ISC"
}, },
"node_modules/picomatch": { "node_modules/picomatch": {
"version": "2.3.1", "version": "2.3.1",
@ -23276,18 +23321,22 @@
} }
}, },
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.8", "version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"is-core-module": "^2.13.0", "is-core-module": "^2.16.0",
"path-parse": "^1.0.7", "path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0" "supports-preserve-symlinks-flag": "^1.0.0"
}, },
"bin": { "bin": {
"resolve": "bin/resolve" "resolve": "bin/resolve"
}, },
"engines": {
"node": ">= 0.4"
},
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
@ -23332,18 +23381,6 @@
"npm": ">=2" "npm": ">=2"
} }
}, },
"node_modules/resolve/node_modules/is-core-module": {
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
"integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
"dev": true,
"dependencies": {
"hasown": "^2.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/responselike": { "node_modules/responselike": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
@ -25341,6 +25378,51 @@
"resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz",
"integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==" "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA=="
}, },
"node_modules/tinyglobby": {
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.4.4",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
"node_modules/tinyglobby/node_modules/fdir": {
"version": "6.4.6",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/tinyspy": { "node_modules/tinyspy": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz",
@ -25569,6 +25651,7 @@
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@cspotcode/source-map-support": "^0.8.0", "@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7", "@tsconfig/node10": "^1.0.7",

View File

@ -83,7 +83,7 @@
"@wdio/local-runner": "^8.36.1", "@wdio/local-runner": "^8.36.1",
"@wdio/mocha-framework": "^8.36.1", "@wdio/mocha-framework": "^8.36.1",
"@wdio/spec-reporter": "^8.36.1", "@wdio/spec-reporter": "^8.36.1",
"@yao-pkg/pkg": "^5.11.5", "@yao-pkg/pkg": "^6.5.1",
"catch-uncommitted": "^2.0.0", "catch-uncommitted": "^2.0.0",
"chai": "4.3.10", "chai": "4.3.10",
"css-loader": "5.2.7", "css-loader": "5.2.7",