mirror of
https://github.com/shivammathur/setup-php.git
synced 2026-06-13 20:40:58 +07:00
GHSA-pqwm-q9pv-ph8r - Fix CWE-78 [skip ci]
This commit is contained in:
+5
-2
@@ -16,7 +16,7 @@ export async function addINIValuesUnix(
|
||||
});
|
||||
return (
|
||||
'echo "' +
|
||||
ini_values.join('\n') +
|
||||
ini_values.map(v => utils.escapeForShell(v, 'linux')).join('\n') +
|
||||
'" | sudo tee -a "${pecl_file:-${ini_file[@]}}" >/dev/null 2>&1' +
|
||||
script
|
||||
);
|
||||
@@ -37,7 +37,10 @@ export async function addINIValuesWindows(
|
||||
(await utils.addLog('$tick', line, 'Added to php.ini', 'win32')) + '\n';
|
||||
});
|
||||
return (
|
||||
'Add-Content "$php_dir\\php.ini" "' + ini_values.join('\n') + '"' + script
|
||||
'Add-Content "$php_dir\\php.ini" "' +
|
||||
ini_values.map(v => utils.escapeForShell(v, 'win32')).join('\n') +
|
||||
'"' +
|
||||
script
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -18,7 +18,10 @@ export async function getScript(os: string): Promise<string> {
|
||||
const filename = os + (await utils.scriptExtension(os));
|
||||
const script_path = path.join(__dirname, '../src/scripts', filename);
|
||||
const run_path = script_path.replace(os, 'run');
|
||||
const extension_csv: string = await utils.getInput('extensions', false);
|
||||
const extension_csv: string = utils.sanitizeShellInput(
|
||||
await utils.getInput('extensions', false),
|
||||
true
|
||||
);
|
||||
const ini_values_csv: string = await utils.getInput('ini-values', false);
|
||||
const coverage_driver: string = await utils.getInput('coverage', false);
|
||||
const tools_csv: string = await utils.getInput('tools', false);
|
||||
@@ -28,7 +31,7 @@ export async function getScript(os: string): Promise<string> {
|
||||
const ini_file: string = await utils.parseIniFile(
|
||||
await utils.getInput('ini-file', false)
|
||||
);
|
||||
let script = await utils.joins('.', script_path, version, ini_file);
|
||||
let script = await utils.joins('.', script_path, `'${version}'`, ini_file);
|
||||
if (extension_csv) {
|
||||
script += await extensions.addExtension(extension_csv, version, os);
|
||||
}
|
||||
|
||||
+4
-7
@@ -231,7 +231,7 @@ export async function getVersion(
|
||||
case !!data.repository && major_minor_regex.test(data.version):
|
||||
return await getSemverVersion(data);
|
||||
default:
|
||||
return data.version.replace(/[><=^~]*/, '');
|
||||
return data.version.replace(/[^a-zA-Z0-9_.:@+,/-]/g, '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,12 +347,9 @@ export async function addArchive(data: ToolData): Promise<string> {
|
||||
export async function addPackage(data: ToolData): Promise<string> {
|
||||
const command = await utils.getCommand(data.os, 'composer_tool');
|
||||
const parts: string[] = data.repository.split('/');
|
||||
const args: string = await utils.joins(
|
||||
parts[1],
|
||||
data.release,
|
||||
parts[0] + '/',
|
||||
data.scope
|
||||
);
|
||||
const args = [parts[1], data.release, parts[0] + '/', data.scope]
|
||||
.map(a => utils.safeArg(a, data.os))
|
||||
.join(' ');
|
||||
return command + args;
|
||||
}
|
||||
|
||||
|
||||
+75
-27
@@ -62,15 +62,31 @@ export async function getManifestURLS(): Promise<string[]> {
|
||||
*/
|
||||
export async function parseVersion(version: string): Promise<string> {
|
||||
switch (true) {
|
||||
case /^pre(-installed)?$/.test(version):
|
||||
return 'pre';
|
||||
case /^(latest|lowest|highest|nightly|master|\d+\.x)$/.test(version):
|
||||
for (const manifestURL of await getManifestURLS()) {
|
||||
const fetchResult = await fetch.fetch(manifestURL);
|
||||
if (fetchResult['data'] ?? false) {
|
||||
return JSON.parse(fetchResult['data'])[version];
|
||||
const resolved: string | undefined = JSON.parse(fetchResult['data'])[
|
||||
version
|
||||
];
|
||||
if (resolved === undefined) {
|
||||
throw new Error(`Invalid PHP version: ${version.slice(0, 20)}`);
|
||||
}
|
||||
if (!/^\d+\.\d+$/.test(resolved)) {
|
||||
throw new Error(
|
||||
`Invalid PHP version in manifest: ${resolved.slice(0, 10)}`
|
||||
);
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
throw new Error(`Could not fetch the PHP version manifest.`);
|
||||
default:
|
||||
if (!/^\d+(\.\d+){0,2}$/.test(version)) {
|
||||
throw new Error(`Invalid PHP version: ${version.slice(0, 20)}`);
|
||||
}
|
||||
switch (true) {
|
||||
case version.length > 1:
|
||||
return version.slice(0, 3);
|
||||
@@ -86,14 +102,11 @@ export async function parseVersion(version: string): Promise<string> {
|
||||
* @param ini_file
|
||||
*/
|
||||
export async function parseIniFile(ini_file: string): Promise<string> {
|
||||
switch (true) {
|
||||
case /^(production|development|none)$/.test(ini_file):
|
||||
return ini_file;
|
||||
case /php\.ini-(production|development)$/.test(ini_file):
|
||||
return ini_file.split('-')[1];
|
||||
default:
|
||||
return 'production';
|
||||
if (/^(production|development|none)$/.test(ini_file)) {
|
||||
return ini_file;
|
||||
}
|
||||
const match = ini_file.match(/php\.ini-(production|development)$/);
|
||||
return match ? match[1] : 'production';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,10 +185,10 @@ export async function log(
|
||||
export async function stepLog(message: string, os: string): Promise<string> {
|
||||
switch (os) {
|
||||
case 'win32':
|
||||
return 'Step-Log "' + message + '"';
|
||||
return 'Step-Log "' + escapeForShell(message, os) + '"';
|
||||
case 'linux':
|
||||
case 'darwin':
|
||||
return 'step_log "' + message + '"';
|
||||
return 'step_log "' + escapeForShell(message, os) + '"';
|
||||
default:
|
||||
return await log('Platform ' + os + ' is not supported', os, 'error');
|
||||
}
|
||||
@@ -194,17 +207,40 @@ export async function addLog(
|
||||
message: string,
|
||||
os: string
|
||||
): Promise<string> {
|
||||
const sub = escapeForShell(subject, os);
|
||||
const msg = escapeForShell(message, os);
|
||||
switch (os) {
|
||||
case 'win32':
|
||||
return 'Add-Log "' + mark + '" "' + subject + '" "' + message + '"';
|
||||
return `Add-Log "${mark}" "${sub}" "${msg}"`;
|
||||
case 'linux':
|
||||
case 'darwin':
|
||||
return 'add_log "' + mark + '" "' + subject + '" "' + message + '"';
|
||||
return `add_log "${mark}" "${sub}" "${msg}"`;
|
||||
default:
|
||||
return await log('Platform ' + os + ' is not supported', os, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
export function escapeForShell(value: string, os: string): string {
|
||||
if (os === 'win32') {
|
||||
return value.replace(/[`$"]/g, '`$&');
|
||||
}
|
||||
return value.replace(/[\\`$"]/g, '\\$&');
|
||||
}
|
||||
|
||||
export function safeArg(value: string, os: string): string {
|
||||
if (!/^[a-zA-Z0-9_./:@+,~^-]*$/.test(value)) {
|
||||
return '"' + escapeForShell(value, os) + '"';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function sanitizeShellInput(value: string, strict = false): string {
|
||||
const pattern = strict
|
||||
? /[$`"';|&(){}[\]\\<>*?\n\r\t]/g
|
||||
: /[$`"';|&(){}[\]\\\n\r\t]/g;
|
||||
return value.replace(pattern, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to break extension csv into an array
|
||||
*
|
||||
@@ -431,22 +467,35 @@ export async function parseExtensionSource(
|
||||
);
|
||||
}
|
||||
|
||||
const VERSION_INPUT_REGEX =
|
||||
/^(latest|lowest|highest|nightly|master|pre|pre-installed|\d+\.x|\d+(\.\d+){0,2})$/;
|
||||
|
||||
function validatePHPVersionInput(version: string, source: string): string {
|
||||
if (!VERSION_INPUT_REGEX.test(version)) {
|
||||
throw new Error(
|
||||
`Invalid PHP version in ${source}: ${version.slice(0, 20)}`
|
||||
);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read php version from input or file
|
||||
*/
|
||||
export async function readPHPVersion(): Promise<string> {
|
||||
const version = await getInput('php-version', false);
|
||||
if (version) {
|
||||
return version;
|
||||
return validatePHPVersionInput(version, 'php-version input');
|
||||
}
|
||||
const versionFile =
|
||||
(await getInput('php-version-file', false)) || '.php-version';
|
||||
if (fs.existsSync(versionFile)) {
|
||||
const contents: string = fs.readFileSync(versionFile, 'utf8');
|
||||
const match: RegExpMatchArray | null = contents.match(
|
||||
/^(?:php\s)?(\d+\.\d+\.\d+)$/m
|
||||
const match = contents.match(/^(?:php\s)?(\d+\.\d+\.\d+)$/m);
|
||||
return validatePHPVersionInput(
|
||||
match ? match[1] : contents.trim(),
|
||||
versionFile
|
||||
);
|
||||
return match ? match[1] : contents.trim();
|
||||
} else if (versionFile !== '.php-version') {
|
||||
throw new Error(`Could not find '${versionFile}' file.`);
|
||||
}
|
||||
@@ -456,11 +505,11 @@ export async function readPHPVersion(): Promise<string> {
|
||||
if (fs.existsSync(composerLock)) {
|
||||
const lockFileContents = JSON.parse(fs.readFileSync(composerLock, 'utf8'));
|
||||
/* istanbul ignore next */
|
||||
if (
|
||||
lockFileContents['platform-overrides'] &&
|
||||
lockFileContents['platform-overrides']['php']
|
||||
) {
|
||||
return lockFileContents['platform-overrides']['php'];
|
||||
if (lockFileContents['platform-overrides']?.['php']) {
|
||||
return validatePHPVersionInput(
|
||||
lockFileContents['platform-overrides']['php'],
|
||||
'composer.lock platform-overrides.php'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,12 +519,11 @@ export async function readPHPVersion(): Promise<string> {
|
||||
fs.readFileSync(composerJson, 'utf8')
|
||||
);
|
||||
/* istanbul ignore next */
|
||||
if (
|
||||
composerFileContents['config'] &&
|
||||
composerFileContents['config']['platform'] &&
|
||||
composerFileContents['config']['platform']['php']
|
||||
) {
|
||||
return composerFileContents['config']['platform']['php'];
|
||||
if (composerFileContents['config']?.['platform']?.['php']) {
|
||||
return validatePHPVersionInput(
|
||||
composerFileContents['config']['platform']['php'],
|
||||
'composer.json config.platform.php'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user