#!/usr/bin/env perl

use v5.36;
use re '/aa';

use FindBin::libs;

use Crypt::Misc  ();
use Crypt::PRNG  ();
use Getopt::Long qw{GetOptions};

use Trog::Vault ();

=head1 SYNOPSIS

Write a vault key into config/secrets.key, for an installation that is not run
by systemd.

=head2 USAGE

    bin/tcms-vault-key --file

=head2 YOU PROBABLY DO NOT WANT THIS

tPSGI's bin/build_service makes the key and puts it in systemd's credential
store, sealed to this machine if it has a TPM to seal it to, and its unit hands
it to tCMS before it chroots.  That is the way to do this, and it needs nothing
from here.

This is the fallback for a machine with no systemd, and it is genuinely weaker:
a key file beside the database it protects is a key file in the same backup as
the database it protects.  Take the trade knowingly or not at all.

=head2 WHAT THE KEY IS

Every secret a user stores through /secrets is encrypted under a key derived
from this one.  It is not in the database, which is the whole point: without it
config/auth.db is ciphertext.

There is one key per installation and it does not need rotating on a schedule.
It is meant to live and die with the machine -- nothing backs it up, and
trog-provisioner does not carry it onto a rebuilt guest -- so a rebuild loses
every stored secret and each user stores theirs again.  That is the intended
cost of the key not being anywhere the database is.

Replacing it has the same effect.  Everything sealed under the old one stops
opening and says so, on /secrets and wherever it was going to be used, rather
than presenting as corruption or as a thing worth trying again.

=cut

my ( $file, $help );
GetOptions(
    'file' => \$file,
    'help' => \$help,
) or exit 2;

if ( $help || !$file ) {
    print "Usage: bin/tcms-vault-key --file\n\n";
    print "Writes $Trog::Vault::key_file for an installation with no systemd.\n";
    print "Under systemd, tPSGI's bin/build_service does this properly; see perldoc bin/tcms-vault-key.\n";
    exit( $help ? 0 : 2 );
}

# Printed and exited rather than died: Carp::Always is in the dependency chain,
# and refusing to clobber a key is not a crash.
if ( -e $Trog::Vault::key_file ) {    ## no critic (ProhibitFiletest_e) -- refusing to overwrite the one thing that cannot be regenerated
    print STDERR "There is already a key at $Trog::Vault::key_file.  Move it out of the way if you really mean to replace it, and read what that costs first: perldoc bin/tcms-vault-key\n";
    exit 2;
}

open( my $fh, '>', $Trog::Vault::key_file ) or die "Could not write $Trog::Vault::key_file: $!\n";
print {$fh} Crypt::Misc::encode_b64( Crypt::PRNG::random_bytes(32) ) . "\n";
close($fh);
chmod( oct('600'), $Trog::Vault::key_file ) or die "Could not chmod $Trog::Vault::key_file: $!\n";

print "Wrote $Trog::Vault::key_file.  Restart tCMS to pick it up.\n";
print "Back it up somewhere that is not where you back up config/auth.db, or do not back it up at all.\n";
