diff options
author | Tom Ryder <tom@sanctum.geek.nz> | 2014-05-26 14:31:54 +1200 |
---|---|---|
committer | Tom Ryder <tom@sanctum.geek.nz> | 2014-05-26 14:45:56 +1200 |
commit | b712b14f4a73f81cd0e372d1261162df51524bc6 (patch) | |
tree | ab267598fe0747e68a2cb0d24ced7753b7b82583 /bin | |
parent | Set a minimum Perl version for clarity (diff) | |
download | Mail-Run-Crypt-b712b14f4a73f81cd0e372d1261162df51524bc6.tar.gz Mail-Run-Crypt-b712b14f4a73f81cd0e372d1261162df51524bc6.zip |
Move into logical bindir
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/croncrypt | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/bin/croncrypt b/bin/croncrypt new file mode 100755 index 0000000..59f4fcd --- /dev/null +++ b/bin/croncrypt @@ -0,0 +1,128 @@ +#!/usr/bin/env perl + +# +# croncrypt: Wrapper to sign and encrypt cron output and errors with PGP/MIME +# before sending them to the default MAILTO destination. +# +# CRONCRYPT_KEYID=0x0A1B2C3D4E5F6G7H +# CRONCRYPT_PASSPHRASE=hibbityboo +# MAILTO=tom@sanctum.geek.nz +# 0 1 * * * tom croncrypt rsync /home/tom/important-file /home/backups +# +# The main design goal is simplicity; just whack a «croncrypt» in front of all +# your cron tasks, provided they don't use pipes or stderr/stdout redirects, +# in which case you should consider putting it all into a script file anyway. +# +# Don't use your own GPG key for signing! Create a dedicated key just for +# croncrypt, and sign it locally with «gpg --lsign» maybe. +# +# Author: Tom Ryder <tom@sanctum.geek.nz> +# Copyright: 2014 Sanctum +# License: Artistic <http://dev.perl.org/licenses/artistic.html> +# +# $Id$ +# +package Sanctum::Croncrypt; + +# Force me to write this properly +use strict; +use utf8; +use warnings; + +# Decree minimum Perl version required (v5.8). +use 5.008_001; + +# Decree package version to pacify Perl::Critic +our $VERSION = 0.1; + +# Pull in some required modules +use Carp; +use IPC::Open3; +use Mail::GnuPG; +use MIME::Entity; +use Symbol 'gensym'; + +# Bail if run without arguments +if ( !@ARGV ) { + printf "%s\n", 'USAGE: croncrypt <command>'; + exit 1; +} + +# Bail if we don't have the environment variables we need +my @fails = (); +if ( !exists $ENV{'CRONCRYPT_KEYID'} ) { + push @fails, 'CRONCRYPT_KEYID is not set; set it to your key ID.'; +} +if ( !exists $ENV{'CRONCRYPT_PASSPHRASE'} ) { + push @fails, + 'CRONCRYPT_PASSPHRASE is not set; set it to your key\'s passphrase.'; +} +if ( !exists $ENV{'MAILTO'} ) { + push @fails, 'MAILTO is not set; set it to the message\'s destination.'; +} +if (@fails) { + foreach my $fail (@fails) { + printf {*STDERR} "croncrypt: FAIL: %s\n", $fail; + } + exit 1; +} + +# Read details from environment +my $recipient = $ENV{MAILTO}; +my $key = $ENV{CRONCRYPT_KEYID}; +my $passphrase = $ENV{CRONCRYPT_PASSPHRASE}; + +# Establish filehandles; need to specifically create symbol for stderr +my ( $stdin, $stdout, $stderr ); +$stderr = gensym; + +# Run the command in the arguments and wait for it to finish +my $pid = open3( $stdin, $stdout, $stderr, @ARGV ); +waitpid $pid, 0; + +# Read any and all output and errors +my @output = <$stdout>; +my @errors = <$stderr>; + +# Close the filehandles, placating Perl::Critic with return checks +close $stdin + or croak('Could not close stdin'); +close $stdout + or croak('Could not close stdout'); +close $stderr + or croak('Could not close stderr'); + +# If there was output, mail it +if (@output) { + my $subject = sprintf 'croncrypt output: %s', join q{ }, @ARGV; + mail( $subject, \@output ); +} + +# If there were errors, mail them +if (@errors) { + my $subject = sprintf 'croncrypt errors: %s', join q{ }, @ARGV; + mail( $subject, \@errors ); +} + +# Send the message to the address in $ENV{MAILTO} +sub mail { + my ( $subject, $content ) = @_; + + # Build MIME object with plaintext message + my $mime = MIME::Entity->build( + To => $recipient, + Subject => $subject, + Data => $content, + ); + + # Encrypt the MIME object + my $mgpg = Mail::GnuPG->new( + key => $key, + passphrase => $passphrase, + ); + $mgpg->mime_signencrypt( $mime, $recipient ); + + # Send it + return $mime->send(); +} + |