package System::Introspector::Users;
use Moo;
use IPC::Run qw( run );

sub gather {
    my ($self) = @_;
    my $fh = $self->_open_passwd_fh;
    my %user;
    while (defined( my $line = <$fh> )) {
        my $data = $self->_deparse_htpasswd_line($line);
        my $user = $data->{username};
        my $home = $data->{home};
        $data->{groups}    = $self->_gather_user_groups($user);
        $data->{ssh}{keys} = $self->_gather_ssh_keys($user, $home);
        $data->{crontab}   = $self->_gather_crontab($user);
        $user{ $data->{uid} } = $data;
    }
    return \%user;
}

sub _gather_crontab {
    my ($self, $user) = @_;
    my ($in, $out, $err) = (('') x 3);
    run(['crontab', '-u', $user, '-l'], \$in, \$out, \$err);
    if (length $err) {
        return {}
            if $err =~ m{^no crontab}i;
        return { error => $err };
    }
    return { body => $out };
}

sub _gather_ssh_keys {
    my ($self, $user, $home) = @_;
    my $ssh_dir = "$home/.ssh/";
    return {}
        unless -d $ssh_dir;
    my $dh;
    opendir $dh, $ssh_dir
        or return { error => $! };
    my %key;
    while (defined( my $item = readdir $dh )) {
        next unless $item =~ m{\.pub$};
        my $item_path = "$ssh_dir/$item";
        open my $key_fh, '<', $item_path;
        if ($key_fh) {
            $key{ $item }{body} = do { local $/; <$key_fh> };
        }
        else {
            $key{ $item }{error} = $!;
        }
    }
    return { files => \%key };
}

sub _gather_user_groups {
    my ($self, $user) = @_;
    return [split m{\s+}, `groups $user`];
}

sub _deparse_htpasswd_line {
    my ($self, $line) = @_;
    chomp $line;
    my %value;
    @value{qw( username uid gid comment home shell )}
        = (split m{:}, $line)[0, 2..6];
    return \%value;
}

sub _open_passwd_fh {
    my ($self) = @_;
    open my $fh, '<', '/etc/passwd'
        or die "Unable to open /etc/passwd: $!\n";
    return $fh;
}

1;

__END__

=head1 NAME

System::Introspector::Users - Gather user information

=head1 DESCRIPTION

Gathers information for all users in C</etc/passwd>, including cronjobs and
installed SSH public keys.

=head1 SEE ALSO

=over

=item L<System::Introspector>

=back

=cut

