aboutsummaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2014-05-26 14:31:54 +1200
committerTom Ryder <tom@sanctum.geek.nz>2014-05-26 14:45:56 +1200
commitb712b14f4a73f81cd0e372d1261162df51524bc6 (patch)
treeab267598fe0747e68a2cb0d24ced7753b7b82583 /bin
parentSet a minimum Perl version for clarity (diff)
downloadMail-Run-Crypt-b712b14f4a73f81cd0e372d1261162df51524bc6.tar.gz
Mail-Run-Crypt-b712b14f4a73f81cd0e372d1261162df51524bc6.zip
Move into logical bindir
Diffstat (limited to 'bin')
-rwxr-xr-xbin/croncrypt128
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();
+}
+