Perl utility to pipe email messages from the debian security announce list to an incoming slack hook.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
3.6 KiB

#!/usr/bin/env perl
use strictures version => 2;
use Cwd ();
use Config::Tiny ();
use Data::Structure::Util ();
use MIME::Parser;
use HTTP::Tiny;
use Try::Tiny;
use JSON::Tiny;
use Time::Piece;
my $config = _get_config();
my $parser = MIME::Parser->new();
$parser->output_to_core(1);
my $ent = $parser->parse( \*STDIN )
or die "hook.pl: parse failed: $!\n";
chomp( my $date = $ent->head->get( 'Date' ) );
chomp( my $from = $ent->head->get( 'From' ) );
chomp( my $to = $ent->head->get( 'To' ) );
chomp( my $subject = $ent->head->get( 'Subject' ) );
my $body = $ent->stringify_body;
my ( $dsa_number ) = $body =~ /Debian Security Advisory (DSA-\d+)-\d+/;
my $time_piece = Time::Piece->strptime( $date, '%a, %d %b %Y %H:%M:%S %z' );
my $dsa_link = 'https://www.debian.org/security/' . $time_piece->strftime( '%Y' ) . '/' . lc $dsa_number;
my ( $security_tracker_link ) = $body =~ /(https:\/\/security-tracker\.debian\.org\/tracker\/.+)/;
my $webhook_uri = $config->{slack}{uri};
my $payload = {
channel => $config->{slack}{channel},
username => $config->{slack}{username},
attachments => [
{
fallback => $subject,
color => '#FF0000',
author_name => $from,
title => $subject,
fields => [
{
title => 'Security Advisory',
value => $dsa_link,
},
{
title => 'Security Tracker',
value => $security_tracker_link,
},
],
},
],
};
my $json = try {
return JSON::Tiny::encode_json( $payload );
}
catch {
my $exception = $_;
die "encode JSON for request was not successful: $exception\n";
};
my $http = HTTP::Tiny->new();
my $response = $http->request(
'POST', $webhook_uri,
{ headers => { 'content-type' => 'application/json' }, content => $json }
);
unless ( $response->{success} ) {
die 'request was not successful: ' . $response->{reason} . "\n";
}
sub _get_config {
my $config = _load_config();
_validate_config($config);
return $config;
}
sub _load_config {
my $module_path = Cwd::realpath(__FILE__);
$module_path =~ s/\w+\.pl//;
my $rc = Cwd::realpath( $module_path . '/../.email-pipe-to-slack-hookrc' );
unless ( -f $rc ) {
die "$rc is not present\n";
}
return Data::Structure::Util::unbless( Config::Tiny->read($rc) );
}
sub _validate_config {
my $config = shift;
# verify required config sections
foreach my $required (qw{ slack }) {
unless ( exists $config->{$required} ) {
die "config section $required is required\n";
}
}
foreach my $sub_required (qw{ uri channel username }) {
unless ( exists $config->{slack}{$sub_required} && defined $config->{slack}{$sub_required} ) {
die "config section slack $sub_required is required\n";
}
}
if ( $config->{slack}{uri} eq 'https://hooks.slack.com/services/exampleuri' ) {
die "config section slack uri is the default string and must be updated\n";
}
if ( $config->{slack}{channel} eq '#examplechannel' ) {
die "config section slack channel is the default string and must be updated\n";
}
if ( $config->{slack}{channel} !~ /^#/ ) {
die "config section slack channel is not properly formatted and must begin with a # symbol\n";
}
if ( $config->{slack}{username} eq 'exampleusername' ) {
die "config section slack channel is the default string and must be updated\n";
}
return 1;
}
exit 0;