#!/usr/local/bin/perl use strict; use warnings; use YAML; use Pod::Usage; use Getopt::Long; use Crypt::OpenPGP; use Term::ReadKey; use AppConfig qw( :argcount :expand ); my $config_file = _get_conf_file(); my $c = AppConfig->new( { GLOBAL => { ARGCOUNT => ARGCOUNT_ONE, EXPAND => EXPAND_ENV } }, qw( secrets ) ); $c->file( $config_file ); my ( $add, $secret, $tell, $delete, $pass, $everything, %secrets ); my $pgp = Crypt::OpenPGP->new( Compat => 'GnuPG', ); GetOptions( "add=s" => \$add, "secret=s" => \$secret, "tell=s" => \$tell, "delete=s" => \$delete, "everything" => \$everything, ); if ( $add ) { unless ( $secret ) { $secret = _ask_for_something( "and the secret is?" ) or die "Need a secret"; } if ( _secrets_store_exists() ) { %secrets = %{ Load( _get_file_content( $c->secrets ) ) }; } if ( exists $secrets{ $add } ) { exit unless _ask_for_something( "secret $add already exists, do you want to overwrite (y/N)?" ) =~ /^y/i; print "overwriting $add\n"; } $secrets{ $add } = $secret; _put_file_content( $c->secrets, Dump \%secrets ); exit; } if ( $tell ) { if ( _secrets_store_exists() ) { %secrets = %{ Load( _get_file_content( $c->secrets ) ) }; } print "$tell: $secrets{$tell}\n"; exit; } if ( $delete ) { if ( _secrets_store_exists() ) { %secrets = %{ Load( _get_file_content( $c->secrets ) ) }; } delete $secrets{ $delete }; _put_file_content( $c->secrets, Dump \%secrets ); exit; } if ( $everything ) { if ( _secrets_store_exists() ) { %secrets = %{ Load( _get_file_content( $c->secrets ) ) }; } print "$_: $secrets{ $_ }\n" for keys %secrets; exit; } pod2usage(); sub _ask_for_something { my $question = shift; my $answer; print "$question\n"; $answer = ReadLine 0; chomp $answer; return $answer; } sub _get_passphrase { ReadMode 2; print "Please enter your passphrase:"; my $pass = ReadLine 0; ReadMode 0; chomp $pass; print "\n"; return $pass; } sub _secrets_store_exists { return -e $c->secrets && -f _; } sub _get_file_content { my $file = shift; my $encrypted; { local $/ = undef; open FH, "<$file" or die "Failed to open $file: $!"; $encrypted = ; close FH; } unless ( $pass ) { $pass = _get_passphrase(); } my $content = $pgp->decrypt( Data => $encrypted, Passphrase => $pass, ); return $content; } sub _put_file_content { my $file = shift; my $content = shift; $pass = _get_passphrase() unless $pass; my $encrypted = $pgp->encrypt( Data => $content, Passphrase => $pass, ); open FH, ">$file" or die "Failed to open $file: $!"; print FH $encrypted; close FH; } sub _get_conf_file { my $conf_file = shift; my @possible_locs = ( $ENV{HOME} . "/.secretkeeperrc", '/etc/sekretkeeperrc' ); unshift @possible_locs, $conf_file if $conf_file; for ( @possible_locs ) { return $_ if -e $_; } die "failed to find a configuration file"; } __END__ =head1 NAME secretkeeper - store passwords in a encrypted file =head1 SYNOPSIS sk -a secretname -s secret Add a secret sk -t secretname Tell a secret sk -d secretname Delete a secret =head1 DESCRIPTION =head1 AUTHOR Struan Donald =head1 LICENSE Same Terms as Perl. =head1 COPYRIGHT Struan Donald 2005