#!/usr/bin/perl

use constant 'POLC_ARN' => 'arn:aws:iam::290365479392:policy/';
use constant 'ROLE_ARN' => 'arn:aws:iam::290365479392:role/';
use constant 'SERVERID' => 's-1e6fa3454e42484ba';

use strict;
use warnings;
use open ':std', ':encoding(UTF-8)';

use JSON::XS;
use FileHandle;
use Capture::Tiny(qw/capture/);
use Text::CSV::Easy(qw/csv_build csv_parse/);

use lib '/app/tools/common/lib';
use Common::Session;
use Common::RunCommand;

my ( $opt, $usage ) = clopt(
    [ 'username|u=s' => 'username to add to SFTP server', { 'required' => 1 } ],
    [ 'norole|n'     => 'Do not add roles/policy for user - if exists already' ],
    [ 'help|?|h'     => "print usage message and exit" ]
);
if ( $opt->help ) {
    logMessage( 'info', $usage->text, 'options' );
    exit 1;
}

my $username = $opt->username;

## verify username isn't already registered
my $users;
my $output = Common::RunCommand::execute_die( "aws transfer list-users --server-id " . SERVERID );
my $stdin  = JSON::XS::decode_json( $output->[0] );
map { $users->{ $_->{'UserName'} }++ } @{ $stdin->{'Users'} };
if ( defined $users->{$username} ) {
    logMessage( 'fatal', "$username is already registered on SFTP server-id: " . SERVERID );
    exit 1;
}

## set our role & policy filename & ARN
my $policyFile = "/tmp/${username}.policy";
my $policyName = 'RoyaltyshareFTPUserPolicy-' . $username;
my $policyARN  = POLC_ARN . 'RoyaltyshareFTPUserPolicy-' . $username;
my $roleName   = 'RoyaltyshareFTPUserRole-' . $username;
my $roleARN    = ROLE_ARN . 'RoyaltyshareFTPUserRole-' . $username;

## if role and policy already created use norole - mainly for debugging
if ( not $opt->norole ) {
    my $policyTemplate = FileHandle->new( 'sftp-user.policy', 'r' );
    my $policyDocument = FileHandle->new( $policyFile,        "w" );
    while (<$policyTemplate>) {
        $_ =~ s/<<USERNAME>>/$username/;
        $policyDocument->print($_);
    }
    $policyTemplate->close;
    $policyDocument->close;

    Common::RunCommand::execute_die_log("aws iam create-policy --policy-name $policyName --policy-document file://$policyFile");
    Common::RunCommand::execute_die_log(
        "aws iam create-role --role-name $roleName --assume-role-policy-document file://sftp-transfer.role");
}

## attach policy to role - doesn't affect existing pairs
Common::RunCommand::execute_die_log("aws iam attach-role-policy --role-name $roleName --policy-arn $policyARN");

## generate SSH keys or ssh-add key to testing
my $sshPublicString;
my $sshPrivateString;

my $sshPrivateFile = "$ENV{'HOME'}/.ssh/id_rsa.${username}";
my $sshPublicFile  = "${sshPrivateFile}.pub";

if ( -f $sshPrivateFile ) {
    Common::RunCommand::execute_die_log("chmod 400 ${sshPrivateFile}*");
    $sshPublicString  = getContents($sshPublicFile);
    $sshPrivateString = getContents($sshPrivateFile);
} else {
    Common::RunCommand::execute_die_log("ssh-keygen -t rsa -b 4096 -C '${username}' -N '' -f $sshPrivateFile");
    if ( -f $sshPrivateFile ) {
        Common::RunCommand::execute_die_log("chmod 400 ${sshPrivateFile}*");
        $sshPublicString  = getContents($sshPublicFile);
        $sshPrivateString = getContents($sshPrivateFile);
    }
}

Common::RunCommand::execute_die_log("ssh-add -k $sshPrivateFile");

my $href = {
    'HomeDirectory'    => "/royaltyshare-ftp-bucket/home/$username",
    'Role'             => $roleARN,
    'ServerId'         => 's-1e6fa3454e42484ba',
    'SshPublicKeyBody' => $sshPublicString,
    'UserName'         => $username
};
my $userFile = "/tmp/${username}.json";
my $userJSON = JSON::XS::encode_json($href);
my $fh       = FileHandle->new( $userFile, "w" );
$fh->print($userJSON);
$fh->close;

## create initial homedir
Common::RunCommand::execute_die_log("aws s3 cp .keepme s3://royaltyshare-ftp-bucket/home/${username}/");

Common::RunCommand::execute_die_log("aws transfer create-user --cli-input-json file://$userFile");

## add info to report.sys_aws_sftp_user table for records
my $rec = {
    'username'    => $username,
    'ssh_public'  => $sshPublicString,
    'ssh_private' => $sshPrivateString
};

my $dbx = Common::Session::getdbx('report01');
my $row = $dbx->resultset('Report::SysAwsSftpUser')->update_or_create( $rec, { key => 'uidx_username' } );

sub getContents {
    my $file = shift;
    my $fh = FileHandle->new( $file, 'r' );
    my $contents;
    read $fh, $contents, -s $fh;
    $fh->close;
    $contents;
}
