aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcli/icevault29
-rw-r--r--cli/icevault.114
2 files changed, 43 insertions, 0 deletions
diff --git a/cli/icevault b/cli/icevault
index 5ad8ff2..fdc1b74 100755
--- a/cli/icevault
+++ b/cli/icevault
@@ -713,11 +713,13 @@ unless (@ARGV) {
my @USAGE = (
fill => "[-f, --force] [-p, --show-passwords] [-s, --socket=PATH] scheme://hostname/identity",
clip => "scheme://hostname/identity",
+ cp => "[-f, --force] scheme://hostname/identity1 scheme://hostname/identity2",
dump => "[-p, --show-passwords] scheme://hostname/identity",
edit => "scheme://hostname/identity",
git => "GIT-COMMAND [GIT-ARG ...]",
insert => "[-f, --force] [-s, --socket=PATH] [identity]",
ls => "[-0, --zero] [-r, --recursive] [scheme://[hostname/[identity]] ...]",
+ mv => "[-f, --force] scheme://hostname/identity1 scheme://hostname/identity2",
reencrypt => "[scheme://[hostname/[identity]] ...]",
);
@@ -1187,6 +1189,33 @@ elsif ($COMMAND eq 'reencrypt') {
, map {$_->{filename}} @filenames );
}
+elsif ($COMMAND eq 'cp' or $COMMAND eq 'mv') {
+ getopts('force|f' => "-f, --force\tOverwrite preexisting destination");
+ usage() if $#ARGV != 1;
+ my $source = shift;
+ my $target = shift;
+
+ my $sourceFilename = identity2File($source);
+ $sourceFilename =~ /\A(\/\p{Print}+)\z/ or error "Insecure C<%s>", $sourceFilename;
+ $sourceFilename = $1; # untaint $sourceFilename
+
+ my $targetFilename = identity2File($target);
+ $targetFilename =~ /\A(\/\p{Print}+)\z/ or error "Insecure C<%s>", $targetFilename;
+ $targetFilename = $1; # untaint $target
+
+ error "Source and destination are the same identity C<%s>", $source if $source eq $target;
+ error "No such identity C<%s>", $source unless -f $sourceFilename;
+ exit 1 if -f $targetFilename and !$CONFIG{force} and !promptYN "Overwrite C<%s>?", 0, $target;
+
+ copyIdentityFile $sourceFilename, $targetFilename;
+ my @filenames = $targetFilename;
+ if ($COMMAND eq 'mv') {
+ unlink $sourceFilename or error "Can't unlink C<%s>: %s", $sourceFilename, $!;
+ push @filenames, $sourceFilename;
+ }
+ commit(($COMMAND eq 'cp' ? 'copy' : 'move')." $source to $target", @filenames);
+}
+
else {
print STDERR "Usage: $NAME [COMMAND] [OPTION ...] [ARG ...]\n";
error "Unknown command C<%s>. Try C<%s> for more information.", $COMMAND, "$NAME --help";
diff --git a/cli/icevault.1 b/cli/icevault.1
index d49601f..2e40af3 100644
--- a/cli/icevault.1
+++ b/cli/icevault.1
@@ -64,6 +64,13 @@ Decrypt the \fIidentity\fR file and copy its first password to the
clipboard using \fIxclip\fR(1), with a maximum number of pastes of 1.
.TP
+.B cp\fR [\fB-f\fR, \fB--force\fR] \fIscheme\fR://\fIhostname\fR/\fIidentity1\fR \fIscheme\fR://\fIhostname\fR/\fIidentity2\fR
+Copy \fIscheme\fR://\fIhostname\fR/\fIidentity1\fR to
+\fIscheme\fR://\fIhostname\fR/\fIidentity2\fR. The destination is
+reencrypted on the fly. If \fB-f\fR is set, don't ask before overriding
+an existing destination identity.
+
+.TP
.B dump\fR [\fB-p\fR, \fB--show-passwords\fR] \fIscheme\fR://\fIhostname\fR/\fIidentity\fR
Decrypt the \fIidentity\fR file and dump its content on the standard
output. Note that while the output is a valid YAML document, original
@@ -131,6 +138,13 @@ recursively all identities under \fIscheme\fR://\fIhostname\fR/ (resp.
\fIscheme\fR://).
.TP
+.B mv\fR [\fB-f\fR, \fB--force\fR] \fIscheme\fR://\fIhostname\fR/\fIidentity1\fR \fIscheme\fR://\fIhostname\fR/\fIidentity2\fR
+Rename \fIscheme\fR://\fIhostname\fR/\fIidentity1\fR as
+\fIscheme\fR://\fIhostname\fR/\fIidentity2\fR. The destination is
+reencrypted on the fly. If \fB-f\fR is set, don't ask before overriding
+an existing destination identity.
+
+.TP
.B reencrypt\fR [\fIscheme\fR://[\fIhostname\fR/[\fIidentity\fR]] ...]
Reencrypt each given identity prefix(es) with the \fIkeyid\fR(s) found in
the configuration file as recpient(s). If no argument is given,