summaryrefslogtreecommitdiffstats
path: root/bin/hush/pass
blob: fd4a9aa61235148bbd45597b362652bcd054f9e6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env perl
use strict;
use warnings;

my $PASS = '/usr/bin/pass';

my $cmd = $ARGV[0];

if ($cmd && $cmd eq 'search') {
    shift @ARGV;

    chdir "$ENV{HOME}/.password-store"
        or die "password store not initialized";

    require Path::Class;

    my $pat_str = pop @ARGV;
    my $pattern = qr/$pat_str/;

    my $username = grep { $_ eq '-u' } @ARGV;
    @ARGV = grep { $_ ne '-u' } @ARGV;

    my $clipboard = grep { $_ eq '-c' || $_ eq '--clip' } @ARGV;

    my @found = Path::Class::Dir->new('.')->traverse(sub {
        my ($file, $c) = @_;
        return if $file eq '.git';
        return (
            $c->(),
            ((-f $file && $file =~ s/\.gpg$// && $file =~ $pattern)
                ? ($file)
                : ()),
        );
    });

    if (@found < 1) {
        die "No passwords found matching '$pat_str'\n";
    }
    elsif (@found > 1) {
        die "Ambiguous pattern '$pat_str': could match any of @found\n";
    }
    else {
        if (my $pass = `$PASS show '$found[0]'`) {
            if ($username) {
                if ($found[0] =~ m{^[^/]*/[^/]*/([^/]*)$}) {
                    my $user = $1;
                    if ($clipboard) {
                        clip($user);
                    }
                    else {
                        print "$user\n";
                    }
                }
                else {
                    die "$found[0] has no username";
                }
            }

            if ($clipboard) {
                $pass =~ s/\n.*//s;
                clip($pass);
            }
            else {
                print $pass;
            }
        }
    }
}
else {
    exec { $PASS } $PASS, @ARGV
}

sub clip {
    my ($text) = @_;
    my @pids;
    for my $selection (qw(primary clipboard)) {
        my $pid = fork;
        if (!$pid) {
            open my $fh, '|-', "timeout 1m xclip -loops 1 -quiet -selection $selection 2> /dev/null"
                or die "couldn't run xclip";
            $fh->write("$text\n");
            $fh->close;
            exit;
        }
        push @pids, $pid;
    }
    waitpid($_, 0) for @pids;
}