mirror of
https://github.com/shivammathur/setup-php.git
synced 2026-07-25 18:35:52 +07:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 130d8a0fd3 | |||
| 8ca9579834 |
@@ -264,6 +264,18 @@ These tools can be set up globally using the `tools` input. It accepts a string
|
||||
|
||||
When you specify just the major version or the version in `major.minor` format, the latest patch version matching the input will be set up.
|
||||
|
||||
- To harden your workflow against supply chain attacks, you can pin a tool to a checksum in the form `tool:version@sha256:<hash>` or `tool:version@sha512:<hash>`. The downloaded tool is verified against the checksum and it is not set up if the verification fails, even if the tool is served from the tools cache.
|
||||
|
||||
```yaml
|
||||
- name: Setup PHP with tools pinned to a checksum
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.5'
|
||||
tools: composer:2.9.8@sha256:59b2c50e10cafa0d8efc19ede9a326d782f096c674a26baf98cf042ce23de890
|
||||
```
|
||||
|
||||
Checksum verification is supported for tools which are downloaded as phar archives. It is not supported for tools set up using `composer` packages or custom package scripts, specifying a checksum for these tools will result in an error. For checksum pinning to be effective, pin the tool to an exact version, as mutable versions like `latest` or `major.minor` can resolve to a different release with a different checksum.
|
||||
|
||||
- The latest stable version of `composer` is set up by default. You can set up the required `composer` version by specifying the major version `v1` or `v2`, or the version in `major.minor` or `semver` format. Additionally, for composer `snapshot` and `preview` can also be specified to set up the respective releases.
|
||||
|
||||
```yaml
|
||||
|
||||
+100
-11
@@ -222,17 +222,50 @@ describe('Tools tests', () => {
|
||||
});
|
||||
|
||||
it.each`
|
||||
input_list | filtered_list
|
||||
${'a, b'} | ${'composer, a, b'}
|
||||
${'a, b, composer'} | ${'composer, a, b'}
|
||||
${'a, b, composer:1.2.3'} | ${'composer:1.2.3, a, b'}
|
||||
${'a, b, composer:v1.2.3'} | ${'composer:1.2.3, a, b'}
|
||||
${'a, b, composer:snapshot'} | ${'composer:snapshot, a, b'}
|
||||
${'a, b, composer:preview'} | ${'composer:preview, a, b'}
|
||||
${'a, b, composer:1'} | ${'composer:1, a, b'}
|
||||
${'a, b, composer:2'} | ${'composer:2, a, b'}
|
||||
${'a, b, composer:v1'} | ${'composer:1, a, b'}
|
||||
${'a, b, composer:v2'} | ${'composer:2, a, b'}
|
||||
release | expected_release | checksum | error
|
||||
${'tool:1.2.3'} | ${'tool:1.2.3'} | ${undefined} | ${undefined}
|
||||
${'tool:1.2.3@sha256:' + 'a'.repeat(64)} | ${'tool:1.2.3'} | ${'sha256:' + 'a'.repeat(64)} | ${undefined}
|
||||
${'tool:1.2.3@sha256:' + 'A'.repeat(64)} | ${'tool:1.2.3'} | ${'sha256:' + 'a'.repeat(64)} | ${undefined}
|
||||
${'tool:1.2.3@SHA256:' + 'a'.repeat(64)} | ${'tool:1.2.3'} | ${'sha256:' + 'a'.repeat(64)} | ${undefined}
|
||||
${'tool:1.2.3@sha512:' + 'b'.repeat(128)} | ${'tool:1.2.3'} | ${'sha512:' + 'b'.repeat(128)} | ${undefined}
|
||||
${'composer:2.9.8@sha256:' + 'c'.repeat(64)} | ${'composer:2.9.8'} | ${'sha256:' + 'c'.repeat(64)} | ${undefined}
|
||||
${'tool:1.2.3@sha256:xyz'} | ${'tool:1.2.3'} | ${undefined} | ${'Invalid sha256 checksum, expected 64 hexadecimal characters'}
|
||||
${'tool:1.2.3@sha256:' + 'a'.repeat(63)} | ${'tool:1.2.3'} | ${undefined} | ${'Invalid sha256 checksum, expected 64 hexadecimal characters'}
|
||||
${'tool:1.2.3@sha512:' + 'b'.repeat(64)} | ${'tool:1.2.3'} | ${undefined} | ${'Invalid sha512 checksum, expected 128 hexadecimal characters'}
|
||||
${'tool:1.2.3@sha384:' + 'b'.repeat(96)} | ${'tool:1.2.3'} | ${undefined} | ${'Unsupported checksum algorithm sha384, expected sha256 or sha512'}
|
||||
${'tool:1.2.3@md5:' + 'b'.repeat(32)} | ${'tool:1.2.3'} | ${undefined} | ${'Unsupported checksum algorithm md5, expected sha256 or sha512'}
|
||||
${'tool:1.2.3@sha256' + 'a'.repeat(64)} | ${'tool:1.2.3'} | ${undefined} | ${'Invalid checksum syntax, expected @sha256:<hash> or @sha512:<hash>'}
|
||||
${'tool:1.0@dev'} | ${'tool:1.0@dev'} | ${undefined} | ${undefined}
|
||||
`(
|
||||
'checking extractChecksum: $release',
|
||||
({release, expected_release, checksum, error}) => {
|
||||
expect(tools.extractChecksum(release)).toStrictEqual({
|
||||
release: expected_release,
|
||||
...(checksum !== undefined && {checksum}),
|
||||
...(error !== undefined && {error})
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
it.each`
|
||||
input_list | filtered_list
|
||||
${'a, b'} | ${'composer, a, b'}
|
||||
${'a, b, composer'} | ${'composer, a, b'}
|
||||
${'a, b, composer:1.2.3'} | ${'composer:1.2.3, a, b'}
|
||||
${'a, b, composer:v1.2.3'} | ${'composer:1.2.3, a, b'}
|
||||
${'a, b, composer:snapshot'} | ${'composer:snapshot, a, b'}
|
||||
${'a, b, composer:preview'} | ${'composer:preview, a, b'}
|
||||
${'a, b, composer:1'} | ${'composer:1, a, b'}
|
||||
${'a, b, composer:2'} | ${'composer:2, a, b'}
|
||||
${'a, b, composer:v1'} | ${'composer:1, a, b'}
|
||||
${'a, b, composer:v2'} | ${'composer:2, a, b'}
|
||||
${'a, b, composer:2.7.1@sha256:' + 'a'.repeat(64)} | ${'composer:2.7.1@sha256:' + 'a'.repeat(64) + ', a, b'}
|
||||
${'a, b, composer:v2.7.1@sha256:' + 'a'.repeat(64)} | ${'composer:2.7.1@sha256:' + 'a'.repeat(64) + ', a, b'}
|
||||
${'a, b, composer:2.7.1@SHA256:' + 'a'.repeat(64)} | ${'composer:2.7.1@SHA256:' + 'a'.repeat(64) + ', a, b'}
|
||||
${'a, b, composer:2.7.1@sha384:' + 'a'.repeat(96)} | ${'composer:2.7.1@sha384:' + 'a'.repeat(96) + ', a, b'}
|
||||
${'a, b, composer:2.7.1@md5:' + 'a'.repeat(32)} | ${'composer:2.7.1@md5:' + 'a'.repeat(32) + ', a, b'}
|
||||
${'a, b, composer:2.7.1@sha256' + 'a'.repeat(64)} | ${'composer:2.7.1@sha256' + 'a'.repeat(64) + ', a, b'}
|
||||
${'a, b, composer@sha256:' + 'a'.repeat(64)} | ${'composer@sha256:' + 'a'.repeat(64) + ', a, b'}
|
||||
`('checking filterList $input_list', async ({input_list, filtered_list}) => {
|
||||
expect(await tools.filterList(input_list.split(', '))).toStrictEqual(
|
||||
filtered_list.split(', ')
|
||||
@@ -304,6 +337,23 @@ describe('Tools tests', () => {
|
||||
expect(await tools.addArchive(data)).toContain(script);
|
||||
});
|
||||
|
||||
it.each`
|
||||
os | script
|
||||
${'linux'} | ${'add_tool https://example.com/tool.phar tool "-v" sha256:' + 'a'.repeat(64)}
|
||||
${'darwin'} | ${'add_tool https://example.com/tool.phar tool "-v" sha256:' + 'a'.repeat(64)}
|
||||
${'win32'} | ${'Add-Tool https://example.com/tool.phar tool "-v" sha256:' + 'a'.repeat(64)}
|
||||
`('checking addArchive with checksum: $os', async ({os, script}) => {
|
||||
const data = getData({
|
||||
tool: 'tool',
|
||||
version: '1.2.3',
|
||||
version_parameter: JSON.stringify('-v'),
|
||||
os: os,
|
||||
url: 'https://example.com/tool.phar'
|
||||
});
|
||||
data.checksum = 'sha256:' + 'a'.repeat(64);
|
||||
expect(await tools.addArchive(data)).toContain(script);
|
||||
});
|
||||
|
||||
it.each`
|
||||
os | release | scope | script
|
||||
${'linux'} | ${'tool:1.2.3'} | ${'global'} | ${'add_composer_tool tool tool:1.2.3 user/ global'}
|
||||
@@ -774,6 +824,45 @@ describe('Tools tests', () => {
|
||||
expect(await tools.addTools(tools_csv, '7.4', 'linux')).toContain(script);
|
||||
});
|
||||
|
||||
it.each`
|
||||
tools_csv | os | script
|
||||
${'phpunit:9.5.0@sha256:' + 'a'.repeat(64)} | ${'linux'} | ${'add_tool https://phar.phpunit.de/phpunit-9.5.0.phar,https://phar.phpunit.de/phpunit-9.phar phpunit "--version" sha256:' + 'a'.repeat(64)}
|
||||
${'phpunit:9.5.0@sha256:' + 'a'.repeat(64)} | ${'win32'} | ${'Add-Tool https://phar.phpunit.de/phpunit-9.5.0.phar,https://phar.phpunit.de/phpunit-9.phar phpunit "--version" sha256:' + 'a'.repeat(64)}
|
||||
${'composer:2.9.8@sha256:' + 'b'.repeat(64)} | ${'linux'} | ${'composer 2.9.8 sha256:' + 'b'.repeat(64)}
|
||||
${'cs2pr:1.2.3@sha256:' + 'd'.repeat(64)} | ${'linux'} | ${'add_tool https://github.com/staabm/annotate-pull-request-from-checkstyle/releases/download/1.2.3/cs2pr cs2pr "-V" sha256:' + 'd'.repeat(64)}
|
||||
${'phive:0.15.3@sha512:' + 'c'.repeat(128)} | ${'darwin'} | ${'add_tool https://github.com/phar-io/phive/releases/download/0.15.3/phive-0.15.3.phar phive "status" sha512:' + 'c'.repeat(128)}
|
||||
${'phinx:1.2.3@sha256:' + 'a'.repeat(64)} | ${'linux'} | ${'add_log "$cross" "phinx" "Checksum verification is not supported for phinx"'}
|
||||
${'pecl@sha256:' + 'a'.repeat(64)} | ${'linux'} | ${'add_log "$cross" "pecl" "Checksum verification is not supported for pecl"'}
|
||||
${'phpunit:9.5.0@sha256:invalid'} | ${'linux'} | ${'add_log "$cross" "phpunit" "Invalid sha256 checksum, expected 64 hexadecimal characters"'}
|
||||
${'composer:2.9.8@SHA256:' + 'b'.repeat(64)} | ${'linux'} | ${'composer 2.9.8 sha256:' + 'b'.repeat(64)}
|
||||
${'composer:2.9.8@sha384:' + 'b'.repeat(96)} | ${'linux'} | ${'add_log "$cross" "composer" "Unsupported checksum algorithm sha384, expected sha256 or sha512"'}
|
||||
${'composer:2.9.8@md5:' + 'b'.repeat(32)} | ${'linux'} | ${'add_log "$cross" "composer" "Unsupported checksum algorithm md5, expected sha256 or sha512"'}
|
||||
${'composer:2.9.8@sha256' + 'b'.repeat(64)} | ${'linux'} | ${'add_log "$cross" "composer" "Invalid checksum syntax, expected @sha256:<hash> or @sha512:<hash>"'}
|
||||
`(
|
||||
'checking addTools with checksum: $tools_csv, $os',
|
||||
async ({tools_csv, os, script}) => {
|
||||
expect(await tools.addTools(tools_csv, '7.4', os)).toContain(script);
|
||||
}
|
||||
);
|
||||
|
||||
it.each`
|
||||
type | tool_function | supported
|
||||
${'phar'} | ${undefined} | ${true}
|
||||
${'custom-function'} | ${undefined} | ${true}
|
||||
${'custom-function'} | ${'composer'} | ${true}
|
||||
${'custom-function'} | ${'pecl'} | ${false}
|
||||
${'custom-function'} | ${'dev_tools'} | ${false}
|
||||
${'composer'} | ${undefined} | ${false}
|
||||
${'custom-package'} | ${undefined} | ${false}
|
||||
`(
|
||||
'checking supportsChecksum: $type, $tool_function',
|
||||
async ({type, tool_function, supported}) => {
|
||||
const data = getData({tool: 'tool', type: type});
|
||||
data.function = tool_function;
|
||||
expect(await tools.supportsChecksum(data)).toBe(supported);
|
||||
}
|
||||
);
|
||||
|
||||
it.each`
|
||||
tools_csv | token | script
|
||||
${'cs2pr:1.2'} | ${'invalid_token'} | ${'add_log "$cross" "cs2pr" "Invalid token"'}
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -144,6 +144,21 @@ Function Test-MutableToolUrl() {
|
||||
return ($Url -match $mutableUrlRegex) -or (($Url -match '\.phar([?#].*)?$') -and -not ($Url -match $versionLikeRegex))
|
||||
}
|
||||
|
||||
# Function to verify the checksum of a file.
|
||||
Function Test-ToolChecksum() {
|
||||
Param(
|
||||
[Parameter(Position = 0, Mandatory = $true)]
|
||||
[string]
|
||||
$Path,
|
||||
[Parameter(Position = 1, Mandatory = $true)]
|
||||
[string]
|
||||
$Checksum
|
||||
)
|
||||
$checksum_parts = $Checksum -split ':'
|
||||
$actual_checksum = (Get-FileHash -Path $Path -Algorithm $checksum_parts[0]).Hash
|
||||
return $actual_checksum -eq $checksum_parts[1]
|
||||
}
|
||||
|
||||
# Function to extract tool version.
|
||||
Function Get-ToolVersion() {
|
||||
Param (
|
||||
@@ -229,8 +244,18 @@ Function Add-Tool() {
|
||||
[Parameter(Position = 2, Mandatory = $false)]
|
||||
$ver_param,
|
||||
[Parameter(Position = 3, Mandatory = $false)]
|
||||
$skip_composer_github_auth
|
||||
$skip_composer_github_auth,
|
||||
[Parameter(Position = 4, Mandatory = $false)]
|
||||
$checksum
|
||||
)
|
||||
$checksum_regex = '^sha(256|512):[0-9a-fA-F]+$'
|
||||
if("$ver_param" -match $checksum_regex) {
|
||||
$checksum = $ver_param
|
||||
$ver_param = $null
|
||||
} elseif("$skip_composer_github_auth" -match $checksum_regex) {
|
||||
$checksum = $skip_composer_github_auth
|
||||
$skip_composer_github_auth = $null
|
||||
}
|
||||
if($tool -eq "composer") {
|
||||
$script:skip_composer_github_auth = $skip_composer_github_auth -eq 'true'
|
||||
}
|
||||
@@ -245,7 +270,12 @@ Function Add-Tool() {
|
||||
$use_cache = -not (Test-MutableToolUrl $urls[0])
|
||||
$status_code = 200
|
||||
if ($use_cache -and (Test-Path $cache_path -PathType Leaf)) {
|
||||
Copy-Item $cache_path -Destination $tool_path -Force
|
||||
if($checksum -and -not(Test-ToolChecksum $cache_path $checksum)) {
|
||||
Remove-Item $cache_path -Force -ErrorAction SilentlyContinue
|
||||
$status_code = 'checksum_mismatch'
|
||||
} else {
|
||||
Copy-Item $cache_path -Destination $tool_path -Force
|
||||
}
|
||||
} else {
|
||||
$backup_path = "$tool_path.bak"
|
||||
if (Test-Path $tool_path) { Copy-Item $tool_path -Destination $backup_path -Force }
|
||||
@@ -265,18 +295,31 @@ Function Add-Tool() {
|
||||
}
|
||||
}
|
||||
if($status_code -eq 200 -and (Test-Path $tool_path)) {
|
||||
if ($use_cache) {
|
||||
Copy-Item $tool_path -Destination $cache_path -Force
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if($status_code -eq 200 -and (Test-Path $tool_path)) {
|
||||
if($checksum -and -not(Test-ToolChecksum $tool_path $checksum)) {
|
||||
Remove-Item @($tool_path, $cache_path) -Force -ErrorAction SilentlyContinue
|
||||
$status_code = 'checksum_mismatch'
|
||||
} elseif($use_cache) {
|
||||
Copy-Item $tool_path -Destination $cache_path -Force
|
||||
}
|
||||
}
|
||||
if ($status_code -ne 200 -and (Test-Path $backup_path)) {
|
||||
Copy-Item $backup_path -Destination $tool_path -Force
|
||||
}
|
||||
Remove-Item $backup_path -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
if($status_code -eq 'checksum_mismatch') {
|
||||
if($tool -eq "composer") {
|
||||
$env:fail_fast = 'true'
|
||||
}
|
||||
Add-Log $cross $tool "Checksum verification failed for $tool"
|
||||
return
|
||||
}
|
||||
|
||||
$escaped_tool = [regex]::Escape($tool)
|
||||
if (((Get-ChildItem -Path $bin_dir/* | Where-Object Name -Match "^$escaped_tool(\.exe|\.phar)?$").Count -gt 0)) {
|
||||
$bat_content = @()
|
||||
|
||||
@@ -201,8 +201,15 @@ add_tool() {
|
||||
url=$1
|
||||
tool=$2
|
||||
ver_param=$3
|
||||
checksum=
|
||||
local arg
|
||||
for arg in "$@"; do
|
||||
[[ "$arg" =~ ^sha(256|512):[0-9a-fA-F]+$ ]] && checksum="$arg"
|
||||
done
|
||||
[[ "$ver_param" =~ ^sha(256|512): ]] && ver_param=
|
||||
if [ "$tool" = "composer" ]; then
|
||||
skip_composer_github_auth="${4:-false}"
|
||||
[[ "$skip_composer_github_auth" =~ ^sha(256|512): ]] && skip_composer_github_auth=false
|
||||
fi
|
||||
tool_path="$tool_path_dir/$tool"
|
||||
if ! [ -d "$tool_path_dir" ]; then
|
||||
@@ -220,7 +227,12 @@ add_tool() {
|
||||
is_mutable_tool_url "${url[0]}" && use_cache=false
|
||||
status_code="200"
|
||||
if [ "$use_cache" = "true" ] && [ -f "$cache_path" ]; then
|
||||
sudo cp -a "$cache_path" "$tool_path"
|
||||
if [ -n "$checksum" ] && ! verify_checksum "$cache_path" "$checksum"; then
|
||||
sudo rm -f "$cache_path"
|
||||
status_code="checksum_mismatch"
|
||||
else
|
||||
sudo cp -a "$cache_path" "$tool_path"
|
||||
fi
|
||||
else
|
||||
[ -f "$tool_path" ] && sudo cp -a "$tool_path" "$tool_path.bak"
|
||||
status_code=$(get -v -e "$tool_path" "${url[@]}")
|
||||
@@ -229,8 +241,14 @@ add_tool() {
|
||||
status_code=$(get -v -e "$tool_path" "${url[0]}")
|
||||
fi
|
||||
if [ "$status_code" = "200" ]; then
|
||||
[ "$use_cache" = "true" ] && sudo cp -a "$tool_path" "$cache_path"
|
||||
elif [ -f "$tool_path.bak" ]; then
|
||||
if [ -n "$checksum" ] && ! verify_checksum "$tool_path" "$checksum"; then
|
||||
sudo rm -f "$tool_path" "$cache_path"
|
||||
status_code="checksum_mismatch"
|
||||
elif [ "$use_cache" = "true" ]; then
|
||||
sudo cp -a "$tool_path" "$cache_path"
|
||||
fi
|
||||
fi
|
||||
if [ "$status_code" != "200" ] && [ -f "$tool_path.bak" ]; then
|
||||
sudo mv "$tool_path.bak" "$tool_path"
|
||||
fi
|
||||
sudo rm -f "$tool_path.bak"
|
||||
@@ -244,7 +262,9 @@ add_tool() {
|
||||
if [ "$tool" = "composer" ]; then
|
||||
export fail_fast=true
|
||||
fi
|
||||
if [ "$status_code" = "404" ]; then
|
||||
if [ "$status_code" = "checksum_mismatch" ]; then
|
||||
add_log "$cross" "$tool" "Checksum verification failed for $tool"
|
||||
elif [ "$status_code" = "404" ]; then
|
||||
add_log "$cross" "$tool" "Failed to download $tool from ${url[*]}"
|
||||
else
|
||||
add_log "$cross" "$tool" "Could not setup $tool"
|
||||
|
||||
@@ -122,6 +122,25 @@ get_sha256() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to verify the checksum of a file.
|
||||
# checksum format: sha256:<hash> or sha512:<hash>
|
||||
verify_checksum() {
|
||||
local file_path=$1
|
||||
local checksum=$2
|
||||
local algo="${checksum%%:*}"
|
||||
local expected="${checksum#*:}"
|
||||
local actual=
|
||||
local hash_command=
|
||||
if hash_command="$(command -v "${algo}sum")"; then
|
||||
actual="$(sudo "$hash_command" "$file_path" | cut -d' ' -f1)"
|
||||
elif hash_command="$(command -v shasum)"; then
|
||||
actual="$(sudo "$hash_command" -a "${algo#sha}" "$file_path" | cut -d' ' -f1)"
|
||||
elif hash_command="$(command -v openssl)"; then
|
||||
actual="$(sudo "$hash_command" dgst -"$algo" "$file_path" | awk '{print $NF}')"
|
||||
fi
|
||||
[ -n "$actual" ] && [ "$(echo "$actual" | tr '[:upper:]' '[:lower:]')" = "$(echo "$expected" | tr '[:upper:]' '[:lower:]')" ]
|
||||
}
|
||||
|
||||
# Function to download a file using cURL.
|
||||
# mode: -s pipe to stdout, -v save file and return status code
|
||||
# execute: -e save file as executable
|
||||
|
||||
+87
-3
@@ -27,6 +27,7 @@ type ToolFunction =
|
||||
export interface ToolData {
|
||||
tool: string;
|
||||
version: string;
|
||||
checksum?: string;
|
||||
os: string;
|
||||
php_version: string;
|
||||
github: string;
|
||||
@@ -73,6 +74,53 @@ interface ToolConfig {
|
||||
packagist?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regex to match a checksum suffix in a tool release - tool:version@sha256:<hash>
|
||||
*/
|
||||
const checksum_suffix_regex = /@([a-z][a-z0-9-]*):([^@]*)$/i;
|
||||
const checksum_like_suffix_regex = /@sha[^@]*$/i;
|
||||
|
||||
/**
|
||||
* Function to parse the checksum suffix in the tool release
|
||||
*
|
||||
* @param release
|
||||
*/
|
||||
export function extractChecksum(release: string): {
|
||||
release: string;
|
||||
checksum?: string;
|
||||
error?: string;
|
||||
} {
|
||||
const matches = release.match(checksum_suffix_regex);
|
||||
if (!matches) {
|
||||
const checksum_like_matches = release.match(checksum_like_suffix_regex);
|
||||
if (checksum_like_matches) {
|
||||
return {
|
||||
release: release.slice(0, -checksum_like_matches[0].length),
|
||||
error:
|
||||
'Invalid checksum syntax, expected @sha256:<hash> or @sha512:<hash>'
|
||||
};
|
||||
}
|
||||
return {release};
|
||||
}
|
||||
release = release.slice(0, -matches[0].length);
|
||||
const algo = matches[1].toLowerCase();
|
||||
if (!['sha256', 'sha512'].includes(algo)) {
|
||||
return {
|
||||
release,
|
||||
error: `Unsupported checksum algorithm ${algo}, expected sha256 or sha512`
|
||||
};
|
||||
}
|
||||
const hash = matches[2].toLowerCase();
|
||||
const hash_length = algo === 'sha256' ? 64 : 128;
|
||||
if (!new RegExp(`^[a-f0-9]{${hash_length}}$`).test(hash)) {
|
||||
return {
|
||||
release,
|
||||
error: `Invalid ${algo} checksum, expected ${hash_length} hexadecimal characters`
|
||||
};
|
||||
}
|
||||
return {release, checksum: `${algo}:${hash}`};
|
||||
}
|
||||
|
||||
/**
|
||||
* GitHub reference object from API response
|
||||
*/
|
||||
@@ -260,9 +308,13 @@ export async function filterList(tools_list: string[]): Promise<string[]> {
|
||||
const regex_any = /^composer($|:.*)/;
|
||||
const regex_valid =
|
||||
/^composer:?($|preview$|snapshot$|v?\d+(\.\d+)?$|v?\d+\.\d+\.\d+[\w-]*$)/;
|
||||
const matches: string[] = tools_list.filter(tool => regex_valid.test(tool));
|
||||
const matches: string[] = tools_list.filter(tool =>
|
||||
regex_valid.test(extractChecksum(tool).release)
|
||||
);
|
||||
let composer = 'composer';
|
||||
tools_list = tools_list.filter(tool => !regex_any.test(tool));
|
||||
tools_list = tools_list.filter(
|
||||
tool => !regex_any.test(extractChecksum(tool).release)
|
||||
);
|
||||
switch (true) {
|
||||
case matches[0] == undefined:
|
||||
break;
|
||||
@@ -335,7 +387,8 @@ export async function getPharUrl(data: ToolData): Promise<string> {
|
||||
export async function addArchive(data: ToolData): Promise<string> {
|
||||
return (
|
||||
(await utils.getCommand(data.os, 'tool')) +
|
||||
(await utils.joins(data.url, data.tool, data.version_parameter))
|
||||
(await utils.joins(data.url, data.tool, data.version_parameter)) +
|
||||
(data.checksum ? ' ' + data.checksum : '')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -612,6 +665,8 @@ export async function getData(
|
||||
const json_file: string = fs.readFileSync(json_file_path, 'utf8');
|
||||
const json_objects: Record<string, ToolConfig> = JSON.parse(json_file);
|
||||
release = release.replace(/\s+/g, '');
|
||||
const checksum_data = extractChecksum(release);
|
||||
release = checksum_data.release;
|
||||
const parts: string[] = release.split(':');
|
||||
const tool = parts[0];
|
||||
const version = parts[1];
|
||||
@@ -663,6 +718,8 @@ export async function getData(
|
||||
function: config.function,
|
||||
alias: config.alias
|
||||
};
|
||||
data.checksum = checksum_data.checksum;
|
||||
data.error = checksum_data.error;
|
||||
data.release = await getRelease(release, data);
|
||||
data.version = version
|
||||
? await getVersion(version, data)
|
||||
@@ -688,6 +745,25 @@ export const functionRecord: Record<
|
||||
wp_cli: addWPCLI
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to check if a tool supports checksum verification
|
||||
*
|
||||
* Only tools downloaded as archives via add_tool support it, so composer
|
||||
* packages and tools set up using custom package scripts do not.
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function supportsChecksum(data: ToolData): Promise<boolean> {
|
||||
switch (data.type) {
|
||||
case 'phar':
|
||||
return true;
|
||||
case 'custom-function':
|
||||
return !['pecl', 'dev_tools'].includes(data.function ?? '');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup tools
|
||||
*
|
||||
@@ -714,6 +790,14 @@ export async function addTools(
|
||||
case data.error !== undefined:
|
||||
script += await utils.addLog('$cross', data.tool, data.error, data.os);
|
||||
break;
|
||||
case data.checksum !== undefined && !(await supportsChecksum(data)):
|
||||
script += await utils.addLog(
|
||||
'$cross',
|
||||
data.tool,
|
||||
'Checksum verification is not supported for ' + data.tool,
|
||||
data.os
|
||||
);
|
||||
break;
|
||||
case 'phar' === data.type:
|
||||
script += await addArchive(data);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user