Files
Mitgliederverwaltung/scripts/sign-release.php
T
shahondin1624 d48e2b7d9d feat: v0.2.0 — backup system, self-update with Ed25519 signing, column pickers, import fixes
Major features:
- Full backup & restore system (JSON snapshots of all 20 tables + settings)
  - Web UI, REST API, OCC CLI commands, scheduled background job
- Self-update from Gitea releases with Ed25519 signature verification
- Configurable column visibility on all data tables (persisted via localStorage)

Fixes:
- NC admin group fallback for PermissionService (IGroupManager)
- Bundle import inline error correction (editable error rows)

New files: BackupService, BackupSettingsService, BackupController, BackupJob,
SelfUpdateService, 4 OCC commands, ColumnPicker component, Backup.vue,
Ed25519 signing scripts, signature verification tests (18 tests)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:11:51 +02:00

68 lines
1.8 KiB
PHP

#!/usr/bin/env php
<?php
/**
* Sign a release tarball with Ed25519.
*
* Usage: php scripts/sign-release.php <tarball-path>
*
* Reads the private key from ~/.mv-release-key (base64-encoded).
* Produces <tarball-path>.sig (raw 64-byte Ed25519 signature).
*/
if ($argc < 2) {
fwrite(STDERR, "Usage: php scripts/sign-release.php <tarball-path>\n");
exit(1);
}
$tarballPath = $argv[1];
if (!file_exists($tarballPath)) {
fwrite(STDERR, "ERROR: File not found: $tarballPath\n");
exit(1);
}
if (!function_exists('sodium_crypto_sign_detached')) {
fwrite(STDERR, "ERROR: sodium extension is required.\n");
exit(1);
}
// Read private key
$keyFile = $_SERVER['HOME'] . '/.mv-release-key';
if (!file_exists($keyFile)) {
fwrite(STDERR, "ERROR: Private key not found at $keyFile\n");
fwrite(STDERR, "Run: php scripts/generate-keypair.php\n");
exit(1);
}
$secretKeyBase64 = trim(file_get_contents($keyFile));
$secretKey = base64_decode($secretKeyBase64, true);
if ($secretKey === false || strlen($secretKey) !== SODIUM_CRYPTO_SIGN_SECRETKEYBYTES) {
fwrite(STDERR, "ERROR: Invalid private key in $keyFile\n");
exit(1);
}
// Read tarball
$content = file_get_contents($tarballPath);
if ($content === false) {
fwrite(STDERR, "ERROR: Could not read $tarballPath\n");
exit(1);
}
// Sign
$signature = sodium_crypto_sign_detached($content, $secretKey);
// Write signature
$sigPath = $tarballPath . '.sig';
file_put_contents($sigPath, $signature);
echo "Signed: $sigPath (" . strlen($signature) . " bytes)\n";
// Verify as sanity check
$publicKey = sodium_crypto_sign_publickey_from_secretkey($secretKey);
if (sodium_crypto_sign_verify_detached($signature, $content, $publicKey)) {
echo "Verification: OK\n";
} else {
fwrite(STDERR, "ERROR: Self-verification failed!\n");
exit(1);
}