Files
argus-wp-defence/bin/generate-manifest.php
T
root df0f2fccb8 ARGUS WordPress Defence 1.0.0 — first production release
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.
2026-08-09 13:40:16 +00:00

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 );
}