#! /usr/bin/env perl
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
use common::sense;
use Term::ReadKey;
use Term::ANSIColor;
use POSIX qw{ strftime };

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

my $remainingOptions = OVH::Bastion::Plugin::begin(
    argv    => \@ARGV,
    header  => "create a new group",
    options => {
        "group=s"   => \my $group,
        "owner=s"   => \my $owner,
        "algo=s"    => \my $algo,
        "size=i"    => \my $size,
        "encrypted" => \my $encrypted,
        "no-key"    => \my $no_key,
    },
    help => \&help,
);

sub help {
    osh_info <<"EOF";
Create a group

Usage: --osh $scriptName --group GROUP --owner ACCOUNT <--algo ALGO --size SIZE [--encrypted]|--no-key>

  --group       Group name to create

  --owner       Preexisting bastion account to assign as owner (can be you)

  --encrypted   Add a passphrase to the key. Beware that you'll have to enter it for each use.
                  Do NOT add the passphrase after this option, you'll be prompted interactively for it.

  --algo        Specifies the algo of the key, either rsa, ecdsa or ed25519.
  --size        Specifies the size of the key to be generated.
                  For RSA, choose between 2048 and 8192 (4096 is good).
                  For ECDSA, choose either 256, 384 or 521.
                  For ED25519, size is always 256.

  --no-key      Don't generate an egress SSH key at all for this group

EOF
    OVH::Bastion::print_accepted_key_algorithms(way => "egress", generate => 0);
    return 0;
}

#
# code
#
my $fnret;

#
# params check
#

if (!$group || !$owner) {
    help();
    osh_exit 'ERR_MISSING_PARAMETER', "Group name or owner is missing";
}

# first, check that the name doesn't start with 'key' (see https://github.com/ovh/the-bastion/issues/178)
# as the is_valid_group() internally automatically guesses whether the input is from a user (in that case
# the $group is a bastion group name) or some other part of the code (in that case the $group might be
# the name of the OS group mapped to the bastion group name, hence starting with 'key')
if ($group =~ /^key/) {
    osh_exit 'ERR_INVALID_PARAMETER', "The group name can't start with 'key' (reserved prefix)";
}

if ($algo && !$size && lc($algo) eq 'ed25519') {
    $size = 256;    # ed25519 size is always 256
}

if (!$no_key && (!$algo || !$size)) {
    help();
    osh_exit 'ERR_MISSING_PARAMETER', "Group algorithm or size is missing";
}

$fnret = OVH::Bastion::is_valid_group(group => $group, groupType => "key");
$fnret or osh_exit($fnret);

# get returned untainted value
$group = $fnret->value->{'group'};
my $shortGroup = $fnret->value->{'shortGroup'};

# check if algo is supported by system
if ($algo) {
    $algo  = lc($algo);
    $fnret = OVH::Bastion::is_allowed_algo_and_size(algo => $algo, size => $size, way => 'egress');
    $fnret or osh_exit $fnret;
}

#
# Now create it
#

my @command = qw{ sudo -n -u root -- /usr/bin/env perl -T };
push @command, $OVH::Bastion::BASEPATH . '/bin/helper/osh-groupCreate';
push @command, "--group", $group, "--owner", $owner;
push @command, "--algo",  $algo if $algo;
push @command, "--size",  $size if $size;
push @command, "--encrypted" if $encrypted;
push @command, "--no-key"    if $no_key;

ReadMode('noecho');
$fnret = OVH::Bastion::helper(cmd => \@command, expects_stdin => 1);
ReadMode('restore');
$fnret or osh_exit $fnret;

my $result_hash = $fnret->value;

if ($no_key) {
    osh_info 'Group creation complete!';
}
else {
    osh_info 'Group creation complete! The public key of this group is:';
    $fnret = OVH::Bastion::get_bastion_ips();
    my $from;
    if ($fnret) {
        my @ips = @{$fnret->value};
        $from = 'from="' . join(',', @ips) . '"';
    }

    $fnret = OVH::Bastion::get_group_keys(group => $group);
    if ($fnret and $from) {
        foreach my $keyfile (@{$fnret->value->{'sortedKeys'}}) {
            my $key = $fnret->value->{'keys'}{$keyfile};
            $key->{'prefix'} = $from;
            OVH::Bastion::print_public_key(key => $key);
            $result_hash->{'public_key'} = $key;
        }
    }
}

osh_ok $result_hash;
