1.1 haslo
  1#!/usr/bin/env perl
  2
  3# Public domain
  4
  5use strict;
  6use warnings;
  7use MIME::Base32 qw(decode_base32 encode_base32);
  8use MIME::Base64 qw(encode_base64);
  9use Term::ReadKey qw(ReadMode ReadLine);
 10
 11sub usage
 12{
 13	die "usage: haslo gen|get|put name\n       haslo list\n";
 14}
 15
 16my $home = $ENV{'HOME'} or die "\$HOME not set\n";
 17my $hasloemail = $ENV{'HASLOEMAIL'} or die "\$HASLOEMAIL not set\n";
 18my $haslodir = $ENV{'HASLODIR'} || "$home/.haslo";
 19
 20sub writernppassword
 21{
 22	unless (-d $haslodir) {
 23		print STDERR "creating directory $haslodir\n";
 24		mkdir $haslodir
 25			or die "couldn't create directory $haslodir: $!\n";
 26	}
 27	my $target = shift;
 28	my $password = shift;
 29	open RNP, '|-', 'rnp', '--encrypt', '--recipient', $hasloemail,
 30		'--output', "$haslodir/$target.rnp"
 31		or die "couldn't open pipe to rnp: $!\n";
 32	print RNP $password;
 33	close RNP or die "rnp failed with exit code $?\n";
 34}
 35
 36sub dodel
 37{
 38	my $target = $ARGV[1] or usage;
 39	$target = encode_base32 $target;
 40	system 'rm', '-i', "$haslodir/$target.rnp"
 41		and die "rm failed with exit code $?\n";
 42}
 43
 44sub dogen
 45{
 46	my $target = $ARGV[1] or usage;
 47	$target = encode_base32 $target;
 48	open URANDOM, '<', '/dev/urandom'
 49		or die "couldn't open /dev/urandom: $!\n";
 50	read URANDOM, my $buf, 128
 51		or die "couldn't read from /dev/urandom: $!\n";
 52	close URANDOM;
 53	($buf) = split /\n/, encode_base64 $buf;
 54	writernppassword $target, $buf;
 55	print "$buf\n";
 56}
 57
 58sub doget
 59{
 60	my $target = $ARGV[1] or usage;
 61	$target = encode_base32 $target;
 62	open RNP, '-|', 'rnp', '--decrypt', "$haslodir/$target.rnp"
 63		or die "couldn't open pipe to rnp: $!\n";
 64	my $password = <RNP>;
 65	close RNP or die "rnp failed with exit code $?\n";
 66	# this dance is needed because Perl prints some garbage at the end
 67	# otherwise??
 68	chomp $password;
 69	print "$password\n";
 70}
 71
 72sub dolist
 73{
 74	opendir DIR, $haslodir or die "couldn't open $haslodir: $!\n";
 75	for (readdir DIR) {
 76		next unless s/.rnp$//;
 77		my $decoded = decode_base32 $_;
 78		print "$decoded\n";
 79	}
 80	close DIR;
 81}
 82
 83sub doput
 84{
 85	my $target = $ARGV[1] or usage;
 86	$target = encode_base32 $target;
 87	my ($password, $confirm);
 88	do {
 89		ReadMode 'noecho';
 90		print STDERR "enter password for $ARGV[1]: ";
 91		$password = ReadLine 0;
 92		print STDERR "\n";
 93		print STDERR "confirm password: ";
 94		$confirm = ReadLine 0;
 95		print STDERR "\n";
 96		ReadMode 'restore';
 97	} while ($password ne $confirm);
 98	writernppassword $target, $password;
 99}
100
101my %commands = (
102	del => \&dodel,
103	gen => \&dogen,
104	get => \&doget,
105	list => \&dolist,
106	put => \&doput
107);
108my $argv0 = $ARGV[0] or usage;
109my $command = $commands{$argv0} or usage;
110$command->();