#!/usr/bin/perl

use strict;
use warnings;

use LWP::UserAgent;
use JSON;

use Getopt::Long;
use Pod::Usage;
use DateTime;

=head1 NAME

    rla-sshkey

=head1 SYNOPSIS

    rla-sshkey -u http://comptes/

=head1 DESCRIPTION

Query existing ssh-key in Latmos-Accounts base and push the keys inside user's home.

Before writing the tools checks:

=over 4

=item the user's home directory exists

=item the home directory is really owned by the user

=back

=head1 OPTIONS

=over 4

=item -u|--url http://...

The url of the base Latmos-Accounts website

=item -c|--create

Only create .ssh/autorized_keys, dont modify it if it already exists

=item -h|--help

Display this help

=back

=cut

GetOptions(
    'u|url=s'  => \my $url,
    'c|create' => \my $create,
    'h|help'   => sub { pod2usage(0) },
) or pod2usage(0);

my $ua = LWP::UserAgent->new;
$ua->timeout(10);

$ua->ssl_opts(
    verify_hostname => 0,
    SSL_verify_mode => 0x00
) if ($ua->can('ssl_opts'));

my $json = JSON->new->utf8(1);

my $response = $ua->post(
    $url . '/remote/listing',
    {
        otype     => 'user',
        q         => [ 'exported=1', 'authorizedKeys=*' ],
        attribute => [ qw(authorizedKeys delUnknownSshKey uidNumber gidNumber homeDirectory rev) ],
    }
);

if (!$response->is_success) {
    die('Cannot fetch url: ' . $response->status_line);
}

my $res = $response->decoded_content();

my $var = $json->decode($res);

foreach my $user (keys %{ $var }) {

    my ($uid,$gid) = ($var->{$user}->{uidNumber}[0], $var->{$user}->{gidNumber}[0]);
    my $rev = $var->{$user}->{rev}[0];

    my $home = $var->{$user}->{homeDirectory}[0];
    my $delUnknownSshKey = $var->{$user}->{delUnknownSshKey}[0];
    my @keys = @{ $var->{$user}->{authorizedKeys} || [] };

    my @stat = stat($home) or do {
        warn "Cannot stat $user\'s home: $!, skiping\n";
        next;
    };
    if( $stat[4] != $uid) {
        warn "$user\'s home is owned by $stat[4] instead " . $var->{$user}->{uidNumber}[0] . ", skipping\n";
        next;
    }

    if ($create && -f "$home/.ssh/authorized_keys") {
        next;
    }

    my @curkeys;
    if (open(my $handle, '<', "$home/.ssh/authorized_keys")) {
        while (my $line = <$handle>) {
            $line =~ /^# RLA:/ and next;
            chomp($line);
            push(@curkeys, $line);
        }
        close($handle);
    }

    my $needWrite = 0;

    my @newkeys;
    foreach my $key (@keys) {
        my $need = 1;
        foreach my $curkey (@curkeys) {
            if ($key eq $curkey) {
                $need = 0;
                last;
            }
        }
        if ($need) {
            push(@newkeys, $key);
            $needWrite = 1;
        }
    }

    if ($delUnknownSshKey) {
        my %existing = map { $_ => 1 } @keys;
        my @ncurkeys = grep { $existing{ $_ } } @curkeys;
        if (scalar(@ncurkeys) != scalar(@curkeys)) {
            @curkeys = @ncurkeys;
            $needWrite = 1;
        }
    }

    $needWrite or next;

    if (! -d "$home/.ssh") {
        mkdir("$home/.ssh", 0700) or do {
            warn "Cannot create $home/.ssh: $!\n";
            next;
        };
	    chown($uid, $gid, "$home/.ssh");	
    }

    if (open(my $handle, '>', "$home/.ssh/authorized_keys")) {
        print $handle "# RLA: $rev, " . DateTime->now->iso8601 . "\n";
        print $handle "$_\n" foreach(@curkeys, @newkeys);
        close($handle);
	    chown($uid, $gid, "$home/.ssh/authorized_keys");	
    } else {
        warn "Cannot open $home/.ssh/authorized_keys: $!\n";
    }
}
