package NGCP::Gather::TLSCerts 0.001;

use strict;
use warnings;

our @EXPORT = qw(
    scan_tls_certs
    get_tls_cert_metadata
);

use Exporter qw(import);
use Time::Piece;
use File::Find;
use IPC::Cmd;

=encoding utf8

=head1 NAME

NGCP::Gather::TLSCerts - Gather TLS Certificate information

=head1 DESCRIPTION

This module provides support functions to gather TLS Certificates information
for monitoring purposes.

=head1 FUNCTIONS

=over 4

=item $cert = get_tls_certs_metadata($pathname)

Get the metadata for the given TLS certificate (single or bundle). This
includes splitting any bundle into individual TLS certificates, and fetching
the fingerprint the expiration date, and the text representation of the
certificate.

=cut

sub get_tls_certs_metadata {
    my ($certfile) = shift;

    my @cmd = qw(openssl x509 -text -fingerprint -enddate);

    my $certdata = '';
    my %cert;

    open my $certfh, '<', $certfile or return;
    while (<$certfh>) {
        $certdata .= $_;

        if (m/^-{5}END(?:\s(?:X509|TRUSTED))?\sCERTIFICATE-{5}$/) {
            my $res = IPC::Cmd::run_forked([ @cmd ], {
                child_stdin => $certdata,
            });
            my $date = '<unknown>';
            if ($res->{stdout} =~ m/^notAfter=(.*)$/m) {
                $date = Time::Piece->strptime($1, "%b %d %T %Y %Z");
            }
            my $fingerprint = '';
            if ($res->{stdout} =~ m/^.*Fingerprint=(.*)$/m) {
                $fingerprint = $1;
            }
            my $certtext = '';
            if ($res->{stdout} =~ m/^(Certificate:.*(?:\n[\s].*)*)/m) {
                $certtext = $1;
            }

            $cert{$fingerprint} = {
                filename => $certfile,
                fingerprint => $fingerprint,
                expires_on => $date,
                text => $certtext,
                data => $certdata,
            };
            $certdata = '';
        }
    }
    close $certfh;

    return \%cert;
}

=item $certs = scan_tls_certs()

Scan all NGCP TLS certificates and returns a hash with metadata representing
them.

=cut

sub scan_tls_certs {
    my $dir = shift;

    my $certs_dir = $dir // '/etc/ngcp-config/shared-files/ssl';
    my $certs;

    my $scan_certs = sub {
        return unless m/\.crt$/;

        my $certsmeta = get_tls_certs_metadata($File::Find::name);

        # Emit a warning when we cannot parse the cert?
        return unless $certsmeta;

        foreach my $certfgr (keys %{$certsmeta}) {
            $certs->{$certfgr} = $certsmeta->{$certfgr};
        }
    };

    find($scan_certs, $certs_dir) if -r $certs_dir;

    return $certs;
}

=back

=head1 CHANGES

=head2 Version 0.xxx

This is a private module.

=head1 AUTHOR

Guillem Jover, C<< <gjover@sipwise.com> >>

=head1 BUGS

Please report any bugs to Sipwise GmbH.

=head1 LICENSE

Copyright (c) 2020-2022 Sipwise GmbH, Austria.

GPL-3+, Sipwise GmbH, Austria.

=cut

1;
