#! /usr/bin/env perl
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
use common::sense;

use File::Basename;
use lib dirname(__FILE__) . '/../../../lib/perl';
use OVH::Result;
use OVH::Bastion;
use OVH::Bastion::Plugin qw( :DEFAULT help );

my $remainingOptions = OVH::Bastion::Plugin::begin(
    argv    => \@ARGV,
    header  => "setup TOTP for your account",
    options => {
        'no-confirm' => \my $noConfirm,
    },
    helptext => <<'EOF'
Setup an additional credential (TOTP) to access your account

Usage: --osh SCRIPT_NAME [--no-confirm]

  --no-confirm  Bypass the confirmation step for TOTP enrollment phase
EOF
);

my $fnret;
my @command;

if (OVH::Bastion::config('accountMFAPolicy')->value eq 'disabled') {
    osh_exit('ERR_DISABLED_BY_POLICY',
        "Sorry, Multi-Factor Authentication has been disabled by policy on this bastion");
}

if ($ENV{'OSH_IN_INTERACTIVE_SESSION'}) {
    osh_exit('ERR_PRECONDITIONS_FAILED',
        "For security reasons, this plugin can't be used in interactive mode.\nTo ensure you're the owner of the account, please call it the regular way (i.e. --osh $scriptName)"
    );
}

# do the TOTP enrollment

my $TOTPProvider = OVH::Bastion::config("TOTPProvider")->value;

if ($TOTPProvider eq 'none') {

    # unconfigured: as we don't know which provider we have, just error out
    osh_exit(
        R(
            'ERR_CONFIGURATION_ERROR',
            msg => "No TOTP provider has been enabled, please check with your sysadmin if this is unexpected"
        )
    );
}
elsif ($TOTPProvider eq 'google-authenticator') {

    # first, check if the google-authenticator we have supports --issuer, if not, just omit it, it's not a deal-breaker
    $fnret = OVH::Bastion::execute(cmd => ['google-authenticator', '-h'], must_succeed => 1);
    $fnret or osh_exit($fnret);
    my @additional_params;
    if (grep { /--issuer/ } @{$fnret->value->{'stdout'}}) {
        push @additional_params, "--issuer=" . OVH::Bastion::config('bastionName')->value;
    }
    if ($noConfirm && grep { /--no-confirm/ } @{$fnret->value->{'stdout'}}) {
        push @additional_params, "--no-confirm";
    }

    @command = (
        'script',
        '-q',
        '-c',
        "google-authenticator -f -t -Q UTF8 -r 3 -R 15 -w 2 -D "
          . join(" ", @additional_params)
          . " -l $self -s $HOME/"
          . OVH::Bastion::TOTP_GAUTH_FILENAME,
        '/dev/null'
    );
    {
        local $ENV{'SHELL'} = '/bin/sh';
        $fnret = OVH::Bastion::execute(
            cmd           => \@command,
            noisy_stderr  => 1,
            noisy_stdout  => 1,
            expects_stdin => 1,
            is_binary     => 1,
            must_succeed  => 1
        );
    }

    if (!$fnret) {
        osh_exit('ERR_TOTP_SETUP_FAILED', msg => "Couldn't setup TOTP for your account, try again!");
    }

    chmod 0400, $HOME . '/' . OVH::Bastion::TOTP_GAUTH_FILENAME;
}
elsif ($TOTPProvider eq 'duo') {

    # nothing to do locally, apart from marking the user as TOTP-active, which is done after this block.
}
else {
    # unknown provider, this shouldn't happen
    osh_exit(
        R(
            'ERR_CONFIGURATION_ERROR',
            msg => "An unknown TOTP provider has been provided, please check with your sysadmin."
        )
    );
}

# it worked, add the account to the proper system group
@command = qw{ sudo -n -u root -- /usr/bin/env perl -T };
push @command, $OVH::Bastion::BASEPATH . '/bin/helper/osh-selfMFASetupTOTP';
push @command, '--account', $self;

osh_exit(OVH::Bastion::helper(cmd => \@command));
