<?php
declare(strict_types=1);

use SafeTun\Backend\Crypto\Base64Url;

require dirname(__DIR__) . '/src/autoload.php';

$serverArguments = $_SERVER['argv'] ?? null;
if (!is_array($serverArguments)) {
    fwrite(STDERR, "This command must run from a CLI that provides argv.\n");
    exit(2);
}
$arguments = [];
foreach ($serverArguments as $serverArgument) {
    if (!is_string($serverArgument)) {
        fwrite(STDERR, "Invalid CLI argument vector.\n");
        exit(2);
    }
    $arguments[] = $serverArgument;
}
$outDir = null;
$kid = null;
foreach (array_slice($arguments, 1) as $argument) {
    if (str_starts_with($argument, '--out-dir=')) {
        $outDir = substr($argument, 10);
    } elseif (str_starts_with($argument, '--kid=')) {
        $kid = substr($argument, 6);
    } else {
        fwrite(STDERR, "Usage: php safetun-keygen.php --out-dir=PATH --kid=KEY_ID\n");
        exit(2);
    }
}
if (!is_string($outDir) || !is_string($kid) || !preg_match('/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/D', $kid)
    || !extension_loaded('sodium')) {
    fwrite(STDERR, "Usage: php safetun-keygen.php --out-dir=PATH --kid=KEY_ID\n");
    exit(2);
}
if (is_link($outDir) || (!is_dir($outDir) && !@mkdir($outDir, 0700, true))) {
    fwrite(STDERR, "Unable to create secure key directory.\n");
    exit(1);
}
$secretPath = rtrim($outDir, '/\\') . DIRECTORY_SEPARATOR . $kid . '.key';
$publicPath = rtrim($outDir, '/\\') . DIRECTORY_SEPARATOR . $kid . '.pub';
if (file_exists($secretPath) || file_exists($publicPath)) {
    fwrite(STDERR, "Refusing to overwrite an existing key.\n");
    exit(1);
}
$pair = sodium_crypto_sign_keypair();
$secret = sodium_crypto_sign_secretkey($pair);
$public = sodium_crypto_sign_publickey($pair);
$secretHandle = @fopen($secretPath, 'x+b');
$publicHandle = @fopen($publicPath, 'x+b');
if (!is_resource($secretHandle) || !is_resource($publicHandle)) {
    if (is_resource($secretHandle)) {
        fclose($secretHandle);
    }
    if (is_resource($publicHandle)) {
        fclose($publicHandle);
    }
    @unlink($secretPath);
    @unlink($publicPath);
    sodium_memzero($secret);
    fwrite(STDERR, "Unable to create key files.\n");
    exit(1);
}
$ok = fwrite($secretHandle, $secret) === strlen($secret) && fflush($secretHandle)
    && fwrite($publicHandle, $public) === strlen($public) && fflush($publicHandle);
fclose($secretHandle);
fclose($publicHandle);
sodium_memzero($secret);
@chmod($outDir, 0700);
@chmod($secretPath, 0600);
@chmod($publicPath, 0644);
if (!$ok) {
    @unlink($secretPath);
    @unlink($publicPath);
    fwrite(STDERR, "Unable to persist key files.\n");
    exit(1);
}
echo "Created Ed25519 key pair '{$kid}'. Public fingerprint: "
    . hash('sha256', $public) . "\n";
echo "The private key was not printed.\n";
