#!/usr/bin/env php /api/v1/users/token * * Output is a single JSON document on stdout: * { * "username": "...", // SMTP username (what PeerTube reuses) * "password": "...", // DECRYPTED password (only when --with-pwd) * "smtp": {... probe result }, * "peertube": {... probe result } * } * * Usage: * php creds-probe.php [--db ] [--with-pwd] [--instance ] [--channel ] * * Exit code 0 when BOTH probes succeed, 1 otherwise. Never prints the password to * stderr/log; only prints it to stdout when --with-pwd is given. */ $opts = [ 'db' => null, 'with-pwd' => false, 'instance' => null, // override the stored instance URL (optional) 'channel' => null, // override the stored channel handle (optional) ]; $args = $argv ?? ($GLOBALS['argv'] ?? $_SERVER['argv'] ?? []); $args = is_array($args) ? $args : []; array_shift($args); for ($i = 0; $i < count($args); $i++) { $a = $args[$i]; if ($a === '--with-pwd') { $opts['with-pwd'] = true; continue; } if (in_array($a, ['--db', '--instance', '--channel'], true)) { $opts[ltrim($a, '-')] = $args[$i + 1] ?? null; $i++; } } // ── Locate app root (script lives in scripts/ next to app/) ────────────────── $candidates = [__DIR__ . '/../app', __DIR__ . '/..']; $appRoot = null; foreach ($candidates as $c) { if (file_exists(realpath($c) . '/src/Crypto.php')) { $appRoot = realpath($c); break; } } if ($appRoot === null) { throw new RuntimeException('Could not locate app root (src/Crypto.php).'); } define('APP_ROOT', $appRoot); // Autoload dependencies (PHPMailer, GuzzleHttp) from composer. $autoloads = [ $appRoot . '/../vendor/autoload.php', // repo root / vendor $appRoot . '/vendor/autoload.php', // app / vendor ]; foreach ($autoloads as $a) { if (is_file($a)) { require_once $a; break; } } // Read-only probe: we must NOT run schema migrations against the live DB. // If DatabaseMigrations isn't loaded yet, provide a no-op runner so that // Database's constructor just opens a PDO connection. if (!class_exists('DatabaseMigrations', false)) { class DatabaseMigrations { public function run(): void {} } } require_once $appRoot . '/src/Crypto.php'; require_once $appRoot . '/src/Database.php'; require_once $appRoot . '/src/SmtpRelay.php'; require_once $appRoot . '/src/PeerTubeService.php'; $dbPath = $opts['db'] ?: $appRoot . '/storage/xamxam.db'; if (!is_file($dbPath)) { throw new RuntimeException("Database not found: $dbPath"); } $out = ['username' => '', 'password' => '', 'smtp' => null, 'peertube' => null]; $db = new Database($dbPath); $smtp = SmtpRelay::getSettings($db); $out['username'] = $smtp['username']; $out['password'] = $opts['with-pwd'] ? $smtp['password'] : ''; // ── Probe 1: SMTP (connect + AUTH + close, no message sent) ────────────────── if ($smtp['host'] !== '') { $t = SmtpRelay::test($db); $out['smtp'] = ['ok' => $t['ok'], 'error' => $t['error'], 'field' => $t['field']]; } else { $out['smtp'] = ['ok' => false, 'error' => 'SMTP not configured.', 'field' => null]; } // ── Probe 2: PeerTube OAuth password grant ──────────────────────────────────── $peertube = PeerTubeService::getSettings($db); if ($opts['instance']) { $peertube['instance_url'] = rtrim($opts['instance'], '/'); } if ($opts['channel']) { $peertube['channel_name'] = $opts['channel']; } if ($peertube['instance_url'] === '') { $out['peertube'] = ['ok' => false, 'error' => 'PeerTube instance not configured.', 'token' => false]; } else { try { $a = PeerTubeService::probeAuth($peertube); $out['peertube'] = ['ok' => $a['ok'], 'error' => $a['error'], 'token' => $a['ok']]; } catch (\Throwable $e) { $out['peertube'] = ['ok' => false, 'error' => $e->getMessage(), 'token' => false]; } } echo json_encode($out, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), "\n"; // Exit 0 only if BOTH probes succeeded. exit(($out['smtp']['ok'] === true) && ($out['peertube']['ok'] === true) ? 0 : 1);