diff --git a/src/rnpkeys/rnpkeys.cpp b/src/rnpkeys/rnpkeys.cpp index 1a6997c28..471ce00c7 100644 --- a/src/rnpkeys/rnpkeys.cpp +++ b/src/rnpkeys/rnpkeys.cpp @@ -80,6 +80,7 @@ const char *usage = " --password Password, which should be used during operation.\n" " --pass-fd Read password(s) from the file descriptor.\n" " --force Force operation (like secret key removal).\n" + " --keyfile Load key(s) only from the file specified.\n" " --output [file, -] Write data to the specified file or stdout.\n" " --overwrite Overwrite output file without a prompt.\n" " --notty Do not write anything to the TTY.\n" @@ -141,6 +142,7 @@ struct option options[] = { {"set-expire", required_argument, NULL, OPT_SET_EXPIRE}, {"current-time", required_argument, NULL, OPT_CURTIME}, {"allow-weak-hash", no_argument, NULL, OPT_ALLOW_WEAK_HASH}, + {"keyfile", required_argument, NULL, OPT_KEYFILE}, {NULL, 0, NULL, 0}, }; @@ -614,6 +616,10 @@ setoption(rnp_cfg &cfg, optdefs_t *cmd, int val, const char *arg) case OPT_SET_EXPIRE: cfg.set_str(CFG_SET_KEY_EXPIRE, arg); return true; + case OPT_KEYFILE: + cfg.set_str(CFG_KEYFILE, arg); + cfg.set_bool(CFG_KEYSTORE_DISABLED, true); + return true; default: *cmd = CMD_HELP; return true; @@ -642,7 +648,18 @@ rnpkeys_init(cli_rnp_t &rnp, const rnp_cfg &cfg) "want to use it."); return false; } - /* TODO: at some point we should check for error here */ - (void) rnp.load_keyrings(true); + + bool disable_ks = rnp.cfg().get_bool(CFG_KEYSTORE_DISABLED); + if (!disable_ks && !rnp.load_keyrings(true)) { + ERR_MSG("fatal: failed to load keys"); + return false; + } + + /* load the keyfile if any */ + if (disable_ks && !rnp.cfg().get_str(CFG_KEYFILE).empty() && !cli_rnp_add_key(&rnp)) { + ERR_MSG("fatal: failed to load key(s) from the file"); + return false; + } + return true; } diff --git a/src/rnpkeys/rnpkeys.h b/src/rnpkeys/rnpkeys.h index 611fcc10e..de212ade3 100644 --- a/src/rnpkeys/rnpkeys.h +++ b/src/rnpkeys/rnpkeys.h @@ -58,6 +58,7 @@ typedef enum { OPT_CURTIME, OPT_ADD_SUBKEY, OPT_SET_EXPIRE, + OPT_KEYFILE, /* debug */ OPT_DEBUG diff --git a/src/tests/cli_tests.py b/src/tests/cli_tests.py index e6f5ed76b..c037ebcbf 100755 --- a/src/tests/cli_tests.py +++ b/src/tests/cli_tests.py @@ -2282,6 +2282,17 @@ def test_rnpkeys_g10_list_order(self): else: self.assertEqual(file_text(data_path('test_cli_rnpkeys/g10_list_keys_sec_no_bp')), out, 'g10 secret key listing failed') + def test_rnpkeys_list_from_keyfile(self): + KEYRING_2 = data_path('keyrings/2') + ret, out, err = run_proc(RNPK, ['--homedir', KEYRING_2, '--list-keys', '--keyfile', data_path(KEY_ALICE_PUB)]) + self.assertEqual(ret, 0) + self.assertRegex(out, r'1 key found.*') + self.assertRegex(out, r'(?s)^.*73edcc9119afc8e2dbbdcde50451409669ffde3c.*Alice') + self.assertNotRegex(out, r'(?s)^.*c80aa54aa5c6ac73a373687134abe4bd') + ret, out, err = run_proc(RNPK, ['--homedir', KEYRING_2, '--list-keys', '--keyfile', 'wrongkeyfile']) + self.assertEqual(ret, 1) + self.assertRegex(err, r'(?s)^.*fatal: failed to load key\(s\) from the file') + def test_rnpkeys_g10_def_key(self): RE_SIG = r'(?s)^.*' \ r'Good signature made .*' \ @@ -2921,7 +2932,6 @@ def test_empty_keyrings(self): self.assertEqual(ret, 1) self.assertRegex(err, r'(?s)^.*Error: failed to load keyring from \'.*pubring\.gpg\'') self.assertNotRegex(err, r'(?s)^.*Error: failed to load keyring from \'.*secring\.gpg\'') - self.assertRegex(out, r'(?s)^.*Key\(s\) not found.') # Run with .rnp home directory with empty keyrings shutil.rmtree(RNPDIR, ignore_errors=True) os.mkdir(RNPDIR, 0o700)