setName('backup:key:kit') ->setDescription('Write the recovery kit (passphrase-protected key) to a file or stdout') ->addOption('output', 'o', InputOption::VALUE_REQUIRED, 'File to write (default: stdout)'); } protected function execute(InputInterface $input, OutputInterface $output): int { if (!$this->keys->isInitialized()) { $output->writeln('No backup key yet: run occ backup:key:init first.'); return 1; } $this->alerts->securityEvent('kit_downloaded'); $json = json_encode($this->keys->recoveryKit(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n"; $file = $input->getOption('output'); if ($file === null) { $output->write($json, false, OutputInterface::OUTPUT_RAW); return 0; } // Created owner-only from the start (no window where it is world-readable), never over an // existing file or symlink someone else may have placed at a predictable path. $old = umask(0077); try { $fh = @fopen($file, 'xb'); } finally { umask($old); } if ($fh === false || fwrite($fh, $json) !== strlen($json) || !fclose($fh)) { $output->writeln("Cannot write $file (it must not exist yet)"); return 1; } $output->writeln("Recovery kit written to $file. Copy it off this server, then run occ backup:key:confirm."); return 0; } }