From c6030012937fedfb674796c89134b153955bdf17 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Tue, 17 Mar 2015 02:52:33 +0100 Subject: edit command --- icevault | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ icevault.1 | 11 +++++++++++ 2 files changed, 61 insertions(+) diff --git a/icevault b/icevault index 1c0ba1b..4690842 100755 --- a/icevault +++ b/icevault @@ -82,6 +82,7 @@ sub usage($) { ." or: $0 [OPTIONS] insert [identity]\n" ." or: $0 [OPTIONS] dump scheme://hostname/identity\n" ." or: $0 [OPTIONS] clip scheme://hostname/identity\n" + ." or: $0 [OPTIONS] edit scheme://hostname/identity\n" . "Consult the manual page for more information.\n"; exit $rv; } @@ -717,6 +718,55 @@ elsif ($command eq 'dump') { print STDOUT (defined $LOCALE ? $LOCALE->encode(YAML::Tiny::Dump $form) : YAML::Tiny::Dump $form); } +elsif ($command eq 'edit') { + usage(1) unless $#ARGV == 0; + my $id = shift; + my $file = getIdentityFile $id; + error "No such identity C<%s>", $id unless -f $file; + + error "C<%s> is not set", '$EDITOR' unless defined $ENV{EDITOR}; + $ENV{EDITOR} =~ /\A(\p{Print}+)\z/ or error "Insecure C<%s>", "\$EDITOR"; + my $EDITOR = $1; # untaint $EDITOR + + my $fh = File::Temp::->new(SUFFIX => '.yaml', UNLINK => 0, TMPDIR => 1); + END { unlink $fh->filename if defined $fh; } # never leave cleartext lying around + myprintf \*STDERR, "Decrypting identity file C<%s>", $file if $CONFIG{debug}; + + # XXX use loadIdentityFile + open my $NULL, '<', '/dev/null'; + my $pid = open2(">&".$fh->fileno, "<&".fileno($NULL), $CONFIG{gpg}, qw/-o - --decrypt --/, $file) + or error "Can't fork: %s", $!; + waitpid $pid, 0; + error "C<%s> exited with value %d", $CONFIG{gpg}, ($? >> 8) if $? and $? != -1; + $fh->close; + + my $h = sha256_file $fh->filename; + system $EDITOR, $fh->filename; + error "C<%s> exited with value %d", $EDITOR, ($? >> 8) if $? and $? != -1; + + if ($h eq sha256_file $fh->filename) { + print "No modification made\n"; + } + else { + # XXX use saveIdentityFile + # don't encrypt directly into the destination $file so we don't + # end up with a messed up $file if something goes wrong + myprintf "Saving user changes for identity C<%s>", $id; + my $outfh = File::Temp::->new(SUFFIX => '.gpg', UNLINK => 0, TMPDIR => 1); + my $pid = open2(">&".$outfh->fileno, "<&".fileno($NULL), + $CONFIG{gpg}, qw/-o - --no-encrypt-to --recipient/, $CONFIG{keyid}, + '--encrypt', '--', $fh->filename) + or error "Can't fork: %s", $!; + waitpid $pid, 0; + error "C<%s> exited with value %d", $CONFIG{gpg}, ($? >> 8) if $? and $? != -1; + $outfh->close; + + move $outfh->filename, $file or error "Can't move C<%s>: %s", $outfh->filename, $!; + } + + close $NULL; +} + elsif ($command eq 'clip') { usage(1) unless $#ARGV == 0; my $id = shift; diff --git a/icevault.1 b/icevault.1 index a58a1e1..f2b3b76 100644 --- a/icevault.1 +++ b/icevault.1 @@ -11,6 +11,8 @@ IceVault \- IceVault client user interface .B icevault\fR [\fIOPTIONS\fR] \fBdump\fR \fIscheme\fR://\fIhostname\fR/\fIidentity\fR .br .B icevault\fR [\fIOPTIONS\fR] \fBclip\fR \fIscheme\fR://\fIhostname\fR/\fIidentity\fR +.br +.B icevault\fR [\fIOPTIONS\fR] \fBedit\fR \fIscheme\fR://\fIhostname\fR/\fIidentity\fR .SH DESCRIPTION @@ -77,11 +79,20 @@ Decrypt the \fIidentity\fR file and dump its content on the standard output. Note that while the output is a valid YAML document, original formatting may not be preserved; in particular, comments and empty lines are stripped. + .TP .B clip\fR \fIscheme\fR://\fIhostname\fR/\fIidentity\fR Decrypt the \fIidentity\fR file and copy the first password to the clipboard using \fIxclip\fR(1), with a maximum number of pastes of 1. +.TP +.B edit\fR \fIscheme\fR://\fIhostname\fR/\fIidentity\fR +Decrypt the \fIidentity\fR file to a temporary file and opens it using +the editor specified by the EDITOR environment variable. When the +editor exits, the file is reencrypted if the SHA-256 digest of its +content differs. Note that formatting and comments may not be preserved +by subsequent updates of the \fIidentity\fR file. + .SH OPTIONS .TP -- cgit v1.2.3