aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcli/icevault67
1 files changed, 46 insertions, 21 deletions
diff --git a/cli/icevault b/cli/icevault
index ef186d0..73136d1 100755
--- a/cli/icevault
+++ b/cli/icevault
@@ -343,7 +343,9 @@ sub getIdentityFile($) {
return $1;
}
-# Decrypt the given identity file and return the YAML-parsed form.
+# Decrypt the given identity file. In scalar context, return the
+# YAML-parsed form; in void context, must be given a file handle (closed
+# afterwards) where to dump the (unparsed) decrypted content.
open my $NULL, '<', '/dev/null';
sub loadIdentityFile($;$) {
my ($filename, $fh) = @_;
@@ -366,7 +368,10 @@ sub loadIdentityFile($;$) {
return YAML::Tiny::Load(decode_utf8 $str) if defined wantarray;
}
-# Dump and encrypt a form into the given filename.
+# Encrypt a form into the given filename. If $form is a HASH
+# reference, its YAML-formatted (and UTF8-encoded) content is encrypted;
+# if $form is a GLOB reference, the file handle is duped, given as input
+# to gpg(1), and closed afterwards.
sub saveIdentityFile($$) {
my ($form, $filename) = @_;
myprintf \*STDERR, "Saving identity file C<%s>", $filename if $CONFIG{debug};
@@ -375,23 +380,23 @@ sub saveIdentityFile($$) {
require 'File/Path.pm';
require 'File/Temp.pm';
require 'IPC/Open2.pm';
- require 'YAML/Tiny.pm' if ref $form; # XXX use Tiny::YAML instead?
+
+ if (ref $form eq 'HASH') {
+ require 'YAML/Tiny.pm'; # XXX use Tiny::YAML instead?
+ $form->{fields} = [ grep defined, @{$form->{fields}} ]; # remove undefined fields
+ $form = encode_utf8(YAML::Tiny::Dump($form)); # dump the form as UTF8
+ }
# don't encrypt directly into the destination file so we don't
# end up with a messed up file if something goes wrong
+ my $infh = "<&".fileno($form) if ref $form eq 'GLOB';
my $outfh = File::Temp->new(SUFFIX => '.gpg', UNLINK => 0, TMPDIR => 1) or die;
- my $pid = IPC::Open2::open2( ">&".$outfh->fileno
- , (ref $form ? my $infh : "<&".fileno($NULL))
+ my $pid = IPC::Open2::open2( ">&".$outfh->fileno, $infh
, $CONFIG{gpg}, qw/-o - --no-encrypt-to --recipient/, $CONFIG{keyid}
- , '--encrypt', '--', (ref $form ? () : $form)
- )
+ , '--encrypt' )
or error "Can't fork: %s", $!;
-
- if (ref $form) {
- $form->{fields} = [ grep defined, @{$form->{fields}} ]; # remove undefined fields
- print $infh encode_utf8(YAML::Tiny::Dump($form)); # dump the form as UTF8
- close $infh;
- }
+ print $infh $form unless ref $form;
+ close $infh;
waitpid $pid, 0;
error "C<%s> exited with value %d", $CONFIG{gpg}, ($? >> 8) if $? and $? != -1;
$outfh->close;
@@ -849,15 +854,35 @@ elsif ($command eq 'edit') {
loadIdentityFile $filename, $fh;
my $h = sha256_file $fh->filename;
- system $EDITOR, $fh->filename;
- error "C<%s> exited with value %d", $EDITOR, ($? >> 8) if $? and $? != -1;
+ while (1) {
+ system $EDITOR, $fh->filename;
+ error "C<%s> exited with value %d", $EDITOR, ($? >> 8) if $? and $? != -1;
+ my $h2 = sha256_file $fh->filename;
+
+ my $fh2;
+ unless ($h eq $h2) {
+ require 'YAML/Tiny.pm'; # XXX use Tiny::YAML instead?
+ eval { my $str = YAML::Tiny::LoadFile($fh->filename) };
+ if ($@ eq '') {
+ open $fh2, '<', $fh->filename or error "Can't open C<%s>: %s", $fh->filename, $!;
+ } else {
+ print STDERR $@;
+ my $r = promptYN "Not a valid YAML file! Reedit?", 1;
+ next if $r;
+ }
+ }
- if ($h eq sha256_file $fh->filename) {
- print "No modification made\n";
- }
- else {
- myprintf "Saving user changes for identity C<%s>", $id;
- saveIdentityFile($fh->filename, $filename);
+ unlink $fh->filename or error "Can't unlink C<%s>: %s", $fh->filename, $!;
+ if ($h eq $h2) {
+ print "No modification made\n";
+ } elsif (defined $fh2) {
+ myprintf "Saving user changes for identity C<%s>", $id;
+ saveIdentityFile($fh2, $filename); # use the FH we opened before unlinking
+ } else {
+ print "Aborting\n";
+ exit 1;
+ }
+ last;
}
}