File-KeePass-Agent

 view release on metacpan or  search on metacpan

lib/File/KeePass/Agent/unix.pm  view on Meta::CPAN


my $raw;
sub _term_raw { ReadMode 'raw', \*STDOUT; $raw = 1 }
sub _term_restore { ReadMode 'restore', \*STDOUT; ($raw, my $prev) = (0, $raw); return $prev }

sub init {
    my $self = shift;
    $self->{'no_menus'} = grep {$_ eq '--no_menus'} @ARGV;
}

sub prompt_for_file {
    my ($self, $args) = @_;
    my $last_file = $self->read_config('last_file');
    if ($last_file && $last_file =~ m{ ^./..(/.+)$ }x) {
        $last_file = $self->home_dir . $1;
    }
    $last_file = '' if $last_file && grep {$_->[0] eq $last_file} @{ $self->keepass };
    my $file = $self->_file_prompt("Choose the KeePass database file to open: ", $last_file);
    if ($last_file
        && $file
        && $last_file ne $file
        && -e $file
        && !$args->{'no_save'}
        && require IO::Prompt
        && IO::Prompt::prompt("Save $file as default KeePass database? ", -yn, -d => 'y', -tty)) {
        my $home = $self->home_dir;
        my $copy = ($file =~ m{^\Q$home\E(/.+)$ }x) ? "./..$1" : $file;
        $self->write_config(last_file => $copy);
    }

    return $file;
}

sub prompt_for_pass {
    my ($self, $file) = @_;
    require IO::Prompt;
    return ''.IO::Prompt::prompt("Enter your master password for $file: ", -e => '*', -tty);
}

sub prompt_for_keyfile {
    my ($self, $file) = @_;
    return $self->_file_prompt("Enter a master key filename (optional) for $file: ");
}

sub _file_prompt {
    my ($self, $msg, $def) = @_;
    #$msg =~ s/(:\s*)$/ [$def]$1/ or $msg .= " [$def] " if $def;
    require Term::ReadLine;

    my $was_raw = _term_restore();
    my $out = Term::ReadLine->new('fkp')->readline($msg, $def);
    _term_raw() if $was_raw;

    $out = '' if ! defined $out;
    $out =~ s/\s+$//;
    $out =~ s{~/}{$self->home_dir.'/'}e;
    return length($out) ? $out : $def;
}

sub home_dir {
    my ($user,$passwd,$uid,$gid,$quota,$comment,$gcos,$home,$shell,$expire) = getpwuid($<);
    return $home || croak "Couldn't find home dir for uid $<";
}

sub _config_file {
    my $self = shift;
    my $home = $self->home_dir;
    return "$home/.keepassx/config" if -e "$home/.keepassx/config";
    return "$home/.config/keepassx/config.ini";
}

my %map = (
    last_file => 'LastFile',
    pre_gap   => 'AutoTypePreGap',
    key_delay => 'AutoTypeKeyStrokeDelay',
    );

sub read_config {
    my ($self, $key) = @_;
    my $c = $self->{'config'} ||= $self->_ini_parse($self->_config_file);
    if (! $key) {
        return $c;
    } elsif (my $_key = $map{$key}) {
        return $c->{'Options'}->{$_key};
    }
    elsif ($key eq 'global_shortcut') {
        return if ! defined(my $key = $c->{'Options'}->{'GlobalShortcutKey'});
        my $mod = $c->{'Options'}->{'GlobalShortcutMods'};
        return if !$mod || $mod !~ m{ ^\@Variant\( \\0\\0\\0\\r\\0\\0\\0\\x5\\x? ([a-f0-9]+) \)$ }x; # non-portable - qvariant \r should be QBitArray, \x5 is 5 bits
        my $val = hex($1);
        my $s = {
            key   => chr($key),
            ctrl  => $val & 0b00001 ? 1 : 0,
            shift => $val & 0b00010 ? 1 : 0,
            alt   => $val & 0b00100 ? 1 : 0,
            altgr => $val & 0b01000 ? 1 : 0,
            win   => $val & 0b10000 ? 1 : 0,
        };
        @{ $s }{qw(ctrl alt)} = (1, 1) if delete $s->{'altgr'};
        return $s;
    } else {
        die "Unknown key $key";
    }
}

sub write_config {
    my ($self, $key, $val) = @_;
    my $c = $self->_ini_parse($self->_config_file, 1);
    if (my $_key = $map{$key}) {
        $c->{'Options'}->{$_key} = $val;
    } else {
        return;
    }
    $self->_ini_write($c, $self->_config_file);
    delete $self->{'config'};
}

sub x {
    shift->{'x'} ||= do {
        my $x = X11::Protocol->new;
        $x->{'error_handler'} = sub { my ($x, $d) = @_; die $x->format_error_msg($d) };



( run in 1.208 second using v1.01-cache-2.11-cpan-39bf76dae61 )