Automatic WordPress security: local firewall, malware and file-integrity scanning, vulnerability protection, quarantine, scheduled backups, an optional page cache, and automatic global threat intelligence. See README.md for installation, update, and uninstall instructions.
83 lines
2.5 KiB
PHP
83 lines
2.5 KiB
PHP
<?php
|
|
|
|
array_shift( $argv );
|
|
$zip_path = $argv[0] ?? null;
|
|
$package_url = $argv[1] ?? null;
|
|
$critical = in_array( '--critical', $argv, true );
|
|
|
|
if ( ! $zip_path || ! $package_url || ! file_exists( $zip_path ) ) {
|
|
fwrite( STDERR, "Usage: ARGUS_RELEASE_SECRET_KEY=<base64> php generate-manifest.php <zip-path> <package-url> [--critical]\n" );
|
|
exit( 1 );
|
|
}
|
|
|
|
$secret_b64 = getenv( 'ARGUS_RELEASE_SECRET_KEY' );
|
|
if ( ! $secret_b64 ) {
|
|
fwrite( STDERR, "ARGUS_RELEASE_SECRET_KEY environment variable is not set.\n" );
|
|
exit( 1 );
|
|
}
|
|
$secret_key = base64_decode( $secret_b64, true );
|
|
if ( false === $secret_key || SODIUM_CRYPTO_SIGN_SECRETKEYBYTES !== strlen( $secret_key ) ) {
|
|
fwrite( STDERR, "ARGUS_RELEASE_SECRET_KEY is not a valid base64-encoded Ed25519 secret key.\n" );
|
|
exit( 1 );
|
|
}
|
|
|
|
$zip = new ZipArchive();
|
|
if ( true !== $zip->open( $zip_path ) ) {
|
|
fwrite( STDERR, "Could not open {$zip_path}\n" );
|
|
exit( 1 );
|
|
}
|
|
$header = null;
|
|
for ( $i = 0; $i < $zip->numFiles; $i++ ) {
|
|
$name = $zip->getNameIndex( $i );
|
|
if ( preg_match( '#(^|/)argus-wordpress-defence\.php$#', $name ) ) {
|
|
$header = $zip->getFromIndex( $i );
|
|
break;
|
|
}
|
|
}
|
|
$zip->close();
|
|
if ( ! $header ) {
|
|
fwrite( STDERR, "Could not find argus-wordpress-defence.php inside the archive.\n" );
|
|
exit( 1 );
|
|
}
|
|
|
|
preg_match( '/Version:\s*([^\r\n]+)/', $header, $m_version );
|
|
preg_match( '/Requires at least:\s*([^\r\n]+)/', $header, $m_wp );
|
|
preg_match( '/Requires PHP:\s*([^\r\n]+)/', $header, $m_php );
|
|
|
|
$version = trim( $m_version[1] ?? '' );
|
|
$min_wp = trim( $m_wp[1] ?? '0' );
|
|
$min_php = trim( $m_php[1] ?? '0' );
|
|
|
|
if ( '' === $version ) {
|
|
fwrite( STDERR, "Could not read Version from the archive's plugin header.\n" );
|
|
exit( 1 );
|
|
}
|
|
|
|
$sha256 = hash_file( 'sha256', $zip_path );
|
|
|
|
$payload = array(
|
|
'version' => $version,
|
|
'released_at' => gmdate( 'Y-m-d\TH:i:s\Z' ),
|
|
'package_url' => $package_url,
|
|
'sha256' => $sha256,
|
|
'min_php' => $min_php,
|
|
'min_wp' => $min_wp,
|
|
'critical' => $critical,
|
|
);
|
|
|
|
$canonical = wp_json_encode_stable( $payload );
|
|
$signature = sodium_crypto_sign_detached( $canonical, $secret_key );
|
|
|
|
$manifest = $payload;
|
|
$manifest['signature'] = base64_encode( $signature );
|
|
|
|
echo json_encode( $manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) . "\n";
|
|
|
|
function wp_json_encode_stable( array $payload ) {
|
|
$ordered = array();
|
|
foreach ( array( 'version', 'released_at', 'package_url', 'sha256', 'min_php', 'min_wp', 'critical' ) as $key ) {
|
|
$ordered[ $key ] = $payload[ $key ];
|
|
}
|
|
return json_encode( $ordered, JSON_UNESCAPED_SLASHES );
|
|
}
|