mistress
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:\thaslo gen|get|put name\n\thaslo 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 = encode_base64 $buf;
54 writernppassword $target, $buf;
55}
56
57sub doget
58{
59 my $target = $ARGV[1] or usage;
60 $target = encode_base32 $target;
61 open RNP, '-|', 'rnp', '--decrypt', "$haslodir/$target.rnp"
62 or die "couldn't open pipe to rnp: $!\n";
63 my $password = <RNP>;
64 close RNP or die "rnp failed with exit code $?\n";
65 print $password;
66}
67
68sub dolist
69{
70 opendir DIR, $haslodir or die "couldn't open $haslodir: $!\n";
71 for(readdir DIR){
72 next unless s/.rnp$//;
73 my $decoded = decode_base32 $_;
74 print "$decoded\n";
75 }
76 close DIR;
77}
78
79sub doput
80{
81 my $target = $ARGV[1] or usage;
82 $target = encode_base32 $target;
83 my($password, $confirm);
84 do{
85 ReadMode 'noecho';
86 print STDERR "enter password for $ARGV[1]: ";
87 $password = ReadLine 0;
88 print STDERR "\n";
89 print STDERR "confirm password: ";
90 $confirm = ReadLine 0;
91 print STDERR "\n";
92 ReadMode 'restore';
93 }while($password ne $confirm);
94 writernppassword $target, $password;
95}
96
97my %commands = (
98 del => \&dodel,
99 gen => \&dogen,
100 get => \&doget,
101 list => \&dolist,
102 put => \&doput
103);
104my $argv0 = $ARGV[0] or usage;
105my $command = $commands{$argv0} or usage;
106$command->();