mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-18 02:39:44 +00:00
Issue #17, improve "rhizome extract manifest" command
Add ".readonly" output field, add logic to detect bundle author and update MANIFESTS table 'author' column accordingly. Add two 'rhizomeops' test cases to deal with authorless logic. Rename some 'rhizomeops' test cases for consistency and to help filtering.
This commit is contained in:
parent
37495e4794
commit
c43a7ba8e6
@ -1211,13 +1211,16 @@ int app_rhizome_import_bundle(int argc, const char *const *argv, struct command_
|
||||
int app_rhizome_extract_manifest(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||
{
|
||||
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||
const char *manifestid, *manifestpath;
|
||||
const char *pins, *manifestid, *manifestpath;
|
||||
cli_arg(argc, argv, o, "pin,pin...", &pins, NULL, "");
|
||||
if (cli_arg(argc, argv, o, "manifestid", &manifestid, cli_manifestid, NULL)
|
||||
|| cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, NULL) == -1)
|
||||
return -1;
|
||||
/* Ensure the Rhizome database exists and is open */
|
||||
if (create_serval_instance_dir() == -1)
|
||||
return -1;
|
||||
if (!(keyring = keyring_open_with_pins(pins)))
|
||||
return -1;
|
||||
if (rhizome_opendb() == -1)
|
||||
return -1;
|
||||
/* Extract the manifest from the database */
|
||||
@ -1277,8 +1280,8 @@ int app_rhizome_extract_file(int argc, const char *const *argv, struct command_l
|
||||
int app_rhizome_list(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||
{
|
||||
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||
const char *pin, *service, *sender_sid, *recipient_sid, *offset, *limit;
|
||||
cli_arg(argc, argv, o, "pin,pin...", &pin, NULL, "");
|
||||
const char *pins, *service, *sender_sid, *recipient_sid, *offset, *limit;
|
||||
cli_arg(argc, argv, o, "pin,pin...", &pins, NULL, "");
|
||||
cli_arg(argc, argv, o, "service", &service, NULL, "");
|
||||
cli_arg(argc, argv, o, "sender_sid", &sender_sid, cli_optional_sid, "");
|
||||
cli_arg(argc, argv, o, "recipient_sid", &recipient_sid, cli_optional_sid, "");
|
||||
@ -1287,7 +1290,7 @@ int app_rhizome_list(int argc, const char *const *argv, struct command_line_opti
|
||||
/* Create the instance directory if it does not yet exist */
|
||||
if (create_serval_instance_dir() == -1)
|
||||
return -1;
|
||||
if (!(keyring = keyring_open_with_pins(pin)))
|
||||
if (!(keyring = keyring_open_with_pins(pins)))
|
||||
return -1;
|
||||
if (rhizome_opendb() == -1)
|
||||
return -1;
|
||||
@ -1307,9 +1310,9 @@ int app_keyring_create(int argc, const char *const *argv, struct command_line_op
|
||||
int app_keyring_list(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||
{
|
||||
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||
const char *pin;
|
||||
cli_arg(argc, argv, o, "pin,pin...", &pin, NULL, "");
|
||||
keyring_file *k = keyring_open_with_pins(pin);
|
||||
const char *pins;
|
||||
cli_arg(argc, argv, o, "pin,pin...", &pins, NULL, "");
|
||||
keyring_file *k = keyring_open_with_pins(pins);
|
||||
if (!k)
|
||||
return -1;
|
||||
int cn, in;
|
||||
@ -1708,7 +1711,7 @@ struct command_line_option command_line_options[]={
|
||||
"Import a payload/manifest pair into Rhizome"},
|
||||
{app_rhizome_list,{"rhizome","list","<pin,pin...>","[<service>]","[<sender_sid>]","[<recipient_sid>]","[<offset>]","[<limit>]",NULL},CLIFLAG_STANDALONE,
|
||||
"List all manifests and files in Rhizome"},
|
||||
{app_rhizome_extract_manifest,{"rhizome","extract","manifest","<manifestid>","[<manifestpath>]",NULL},CLIFLAG_STANDALONE,
|
||||
{app_rhizome_extract_manifest,{"rhizome","extract","manifest","<manifestid>","[<manifestpath>]","[<pin,pin...>]",NULL},CLIFLAG_STANDALONE,
|
||||
"Extract a manifest from Rhizome and write it to the given path"},
|
||||
{app_rhizome_extract_file,{"rhizome","extract","file","<fileid>","[<filepath>]","[<key>]",NULL},CLIFLAG_STANDALONE,
|
||||
"Extract a file from Rhizome and write it to the given path"},
|
||||
|
@ -153,7 +153,7 @@ int rhizome_extract_privatekey(rhizome_manifest *m)
|
||||
result = WHY("rhizome_bk_xor() failed");
|
||||
else {
|
||||
if (debug & DEBUG_RHIZOME) DEBUGF("identity sid=%s is not the author of bundle with BK=%s", alloca_tohex_sid(m->author), bk);
|
||||
result = 3;
|
||||
result = 4;
|
||||
}
|
||||
}
|
||||
memset(m->cryptoSignSecret, 0, sizeof m->cryptoSignSecret);
|
||||
|
@ -1355,6 +1355,9 @@ int rhizome_retrieve_manifest(const char *manifestid, rhizome_manifest **mp)
|
||||
}
|
||||
const char *q_manifestid = (const char *) sqlite3_column_text(statement, 0);
|
||||
const char *manifestblob = (char *) sqlite3_column_blob(statement, 1);
|
||||
long long q_version = (long long) sqlite3_column_int64(statement, 2);
|
||||
long long q_inserttime = (long long) sqlite3_column_int64(statement, 3);
|
||||
const char *q_author = (const char *) sqlite3_column_text(statement, 4);
|
||||
size_t manifestblobsize = sqlite3_column_bytes(statement, 1); // must call after sqlite3_column_blob()
|
||||
if (mp) {
|
||||
m = rhizome_new_manifest();
|
||||
@ -1385,7 +1388,7 @@ int rhizome_retrieve_manifest(const char *manifestid, rhizome_manifest **mp)
|
||||
}
|
||||
} else {
|
||||
if (blob_filehash != NULL)
|
||||
WARN("Manifest contains spurious 'filehash' field");
|
||||
WARN("Manifest contains spurious 'filehash' field -- ignored");
|
||||
m->fileHexHash[0] = '\0';
|
||||
m->fileHashedP = 0;
|
||||
}
|
||||
@ -1394,20 +1397,61 @@ int rhizome_retrieve_manifest(const char *manifestid, rhizome_manifest **mp)
|
||||
ret = WHY("Manifest is missing 'version' field");
|
||||
else
|
||||
m->version = blob_version;
|
||||
int read_only = 1;
|
||||
if (q_author == NULL) {
|
||||
// Search for the author in the keyring.
|
||||
// TODO optimise: if manifest 'sender' is set, try that identity first.
|
||||
int result = rhizome_find_bundle_author(m);
|
||||
switch (result) {
|
||||
case -1:
|
||||
ret = WHY("Error searching keyring for bundle author");
|
||||
break;
|
||||
case 0:
|
||||
read_only = 0;
|
||||
if (sqlite_exec_void("UPDATE MANIFESTS SET author='%s' WHERE id='%s';", alloca_tohex_sid(m->author), manifestIdUpper) == -1)
|
||||
WHY("Error updating MANIFESTS author column");
|
||||
break;
|
||||
}
|
||||
} else if (strcmp(q_author, "unknown") == 0) {
|
||||
q_author = NULL; // don't output the ".author" field
|
||||
} else if (stowSid(m->author, 0, q_author) == -1) {
|
||||
WARNF("MANIFESTS row id=%s contains invalid author=%s -- ignored", q_manifestid, alloca_str_toprint(q_author));
|
||||
} else {
|
||||
// If the AUTHOR column contains a valid SID, then it means that author verification has
|
||||
// already been done (either implicitly when the bundle was added locally, or explicitly
|
||||
// the last time this verification was performed), so we trust that this bundle is
|
||||
// writable if the AUTHOR is also present in the keyring and possesses a Rhizome Secret.
|
||||
int result = rhizome_extract_privatekey(m);
|
||||
switch (result) {
|
||||
case -1:
|
||||
ret = WHY("Error extracting manifest private key");
|
||||
break;
|
||||
case 0:
|
||||
read_only = 0;
|
||||
break;
|
||||
case 4: // author is in keyring, but does not verify
|
||||
WARNF("MANIFESTS row id=%s author=%s fails verification -- ignored", q_manifestid, q_author);
|
||||
memset(m->author, 0, sizeof m->author);
|
||||
if (sqlite_exec_void("UPDATE MANIFESTS SET author=NULL WHERE id='%s';", manifestIdUpper) == -1)
|
||||
WHY("Error updating MANIFESTS author column");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret == 1) {
|
||||
const char *q_author = (const char *) sqlite3_column_text(statement, 4);
|
||||
cli_puts("service"); cli_delim(":");
|
||||
cli_puts(blob_service); cli_delim("\n");
|
||||
cli_puts("manifestid"); cli_delim(":");
|
||||
cli_puts(q_manifestid); cli_delim("\n");
|
||||
cli_puts("version"); cli_delim(":");
|
||||
cli_printf("%lld", (long long) sqlite3_column_int64(statement, 2)); cli_delim("\n");
|
||||
cli_printf("%lld", q_version); cli_delim("\n");
|
||||
cli_puts("inserttime"); cli_delim(":");
|
||||
cli_printf("%lld", (long long) sqlite3_column_int64(statement, 3)); cli_delim("\n");
|
||||
if (q_author) {
|
||||
cli_printf("%lld", q_inserttime); cli_delim("\n");
|
||||
if (!is_sid_any(m->author)) {
|
||||
cli_puts(".author"); cli_delim(":");
|
||||
cli_puts(q_author); cli_delim("\n");
|
||||
cli_puts(alloca_tohex_sid(m->author)); cli_delim("\n");
|
||||
}
|
||||
cli_puts(".readonly"); cli_delim(":");
|
||||
cli_printf("%d", read_only); cli_delim("\n");
|
||||
cli_puts("filesize"); cli_delim(":");
|
||||
cli_printf("%lld", (long long) m->fileLength); cli_delim("\n");
|
||||
if (m->fileLength != 0) {
|
||||
|
@ -164,8 +164,8 @@ test_AddThenList() {
|
||||
assert_rhizome_list file1@$SIDB1 file2@$SIDB1
|
||||
}
|
||||
|
||||
doc_AddThenExtractManifest="Extract manifest after one add"
|
||||
setup_AddThenExtractManifest() {
|
||||
doc_ExtractManifestAfterAdd="Extract manifest after one add"
|
||||
setup_ExtractManifestAfterAdd() {
|
||||
setup_servald
|
||||
setup_rhizome
|
||||
echo "A test file" >file1
|
||||
@ -176,7 +176,34 @@ setup_AddThenExtractManifest() {
|
||||
extract_manifest_version version file1.manifest
|
||||
extract_manifest_filehash filehash file1.manifest
|
||||
}
|
||||
test_AddThenExtractManifest() {
|
||||
test_ExtractManifestAfterAdd() {
|
||||
executeOk_servald rhizome extract manifest $manifestid file1x.manifest
|
||||
assert cmp file1.manifest file1x.manifest
|
||||
assertStdoutLineCount '==' 8
|
||||
local size=$(( $(cat file1 | wc -c) + 0 ))
|
||||
assertStdoutGrep --matches=1 "^service:file$"
|
||||
assertStdoutGrep --matches=1 "^manifestid:$manifestid\$"
|
||||
assertStdoutGrep --matches=1 "^version:$version\$"
|
||||
assertStdoutGrep --matches=1 "^inserttime:$rexp_date\$"
|
||||
assertStdoutGrep --matches=1 "^filehash:$filehash\$"
|
||||
assertStdoutGrep --matches=1 "^filesize:$size\$"
|
||||
assertStdoutGrep --matches=1 "^\.author:$SIDB1\$"
|
||||
assertStdoutGrep --matches=1 "^\.readonly:0\$"
|
||||
}
|
||||
|
||||
doc_ExtractManifestAfterAddNoAuthor="Extract manifest after one add with no author"
|
||||
setup_ExtractManifestAfterAddNoAuthor() {
|
||||
setup_servald
|
||||
setup_rhizome
|
||||
echo "A test file" >file1
|
||||
executeOk_servald rhizome add file '' '' file1 file1.manifest
|
||||
executeOk_servald rhizome list ''
|
||||
assert_rhizome_list file1!
|
||||
extract_manifest_id manifestid file1.manifest
|
||||
extract_manifest_version version file1.manifest
|
||||
extract_manifest_filehash filehash file1.manifest
|
||||
}
|
||||
test_ExtractManifestAfterAddNoAuthor() {
|
||||
executeOk_servald rhizome extract manifest $manifestid file1x.manifest
|
||||
assert cmp file1.manifest file1x.manifest
|
||||
assertStdoutLineCount '==' 7
|
||||
@ -184,19 +211,19 @@ test_AddThenExtractManifest() {
|
||||
assertStdoutGrep --matches=1 "^service:file$"
|
||||
assertStdoutGrep --matches=1 "^manifestid:$manifestid\$"
|
||||
assertStdoutGrep --matches=1 "^version:$version\$"
|
||||
assertStdoutGrep --matches=1 "^inserttime:[0-9]\+\$"
|
||||
assertStdoutGrep --matches=1 "^\.author:$SIDB1\$"
|
||||
assertStdoutGrep --matches=1 "^inserttime:$rexp_date\$"
|
||||
assertStdoutGrep --matches=1 "^filehash:$filehash\$"
|
||||
assertStdoutGrep --matches=1 "^filesize:$size\$"
|
||||
assertStdoutGrep --matches=1 "^\.readonly:1\$"
|
||||
}
|
||||
|
||||
doc_ExtractMissingManifest="Extract non-existent manifest"
|
||||
setup_ExtractMissingManifest() {
|
||||
doc_ExtractManifestNonExistent="Extract non-existent manifest"
|
||||
setup_ExtractManifestNonExistent() {
|
||||
setup_servald
|
||||
setup_rhizome
|
||||
manifestid=0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
|
||||
}
|
||||
test_ExtractMissingManifest() {
|
||||
test_ExtractManifestNonExistent() {
|
||||
execute --exit-status=1 $servald rhizome extract manifest $manifestid foo.manifest
|
||||
assertStdoutLineCount '==' 0
|
||||
assert [ ! -e foo.manifest ]
|
||||
@ -219,8 +246,8 @@ test_ExtractManifestInvalidID() {
|
||||
assert [ ! -e foo.manifest ]
|
||||
}
|
||||
|
||||
doc_AddThenExtractFile="Extract file after one add"
|
||||
setup_AddThenExtractFile() {
|
||||
doc_ExtractFileAfterAdd="Extract file after one add"
|
||||
setup_ExtractFileAfterAdd() {
|
||||
setup_servald
|
||||
setup_rhizome
|
||||
echo "A test file" >file1
|
||||
@ -230,7 +257,7 @@ setup_AddThenExtractFile() {
|
||||
assert_rhizome_list file1@$SIDB1
|
||||
extract_manifest_filehash filehash file1.manifest
|
||||
}
|
||||
test_AddThenExtractFile() {
|
||||
test_ExtractFileAfterAdd() {
|
||||
executeOk_servald rhizome extract file $filehash file1x
|
||||
assert cmp file1 file1x
|
||||
local size=$(( $(cat file1 | wc -c) + 0 ))
|
||||
@ -239,13 +266,13 @@ test_AddThenExtractFile() {
|
||||
assertStdoutGrep --matches=1 "^filesize:$size$"
|
||||
}
|
||||
|
||||
doc_ExtractMissingFile="Extract non-existent file"
|
||||
setup_ExtractMissingFile() {
|
||||
doc_ExtractFileMissing="Extract non-existent file"
|
||||
setup_ExtractFileMissing() {
|
||||
setup_servald
|
||||
setup_rhizome
|
||||
filehash=0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
|
||||
}
|
||||
test_ExtractMissingFile() {
|
||||
test_ExtractFileMissing() {
|
||||
execute --exit-status=1 $servald rhizome extract file $filehash foo
|
||||
assertStdoutLineCount '==' 0
|
||||
assert [ ! -e foo ]
|
||||
@ -608,4 +635,43 @@ test_ImportForeignBundle() {
|
||||
assert_rhizome_list fileA!
|
||||
}
|
||||
|
||||
doc_ImportOwnBundle="Can import a bundle created by same instance"
|
||||
setup_ImportOwnBundle() {
|
||||
setup_servald
|
||||
setup_rhizome
|
||||
echo "Hello from B" >fileB
|
||||
executeOk_servald rhizome add file $SIDB2 '' fileB fileB.manifest
|
||||
assert_stdout_add_file fileB
|
||||
extract_manifest_id manifestid fileB.manifest
|
||||
extract_manifest_version version fileB.manifest
|
||||
extract_manifest_filehash filehash fileB.manifest
|
||||
rm -f $SERVALINSTANCE_PATH/rhizome.db
|
||||
executeOk_servald rhizome list ''
|
||||
assert_rhizome_list
|
||||
}
|
||||
test_ImportOwnBundle() {
|
||||
executeOk_servald rhizome import bundle fileB fileB.manifest
|
||||
assert_stdout_import_bundle fileB
|
||||
# Bundle author and sender are unknown, so appears not to be from here
|
||||
executeOk_servald rhizome list ''
|
||||
assert_rhizome_list fileB!
|
||||
# Extracting the manifest discovers that it is ours.
|
||||
executeOk_servald rhizome extract manifest $manifestid fileBx.manifest
|
||||
tfw_cat --stderr
|
||||
assert cmp fileB.manifest fileBx.manifest
|
||||
assertStdoutLineCount '==' 8
|
||||
local size=$(( $(cat fileB | wc -c) + 0 ))
|
||||
assertStdoutGrep --matches=1 "^service:file$"
|
||||
assertStdoutGrep --matches=1 "^manifestid:$manifestid\$"
|
||||
assertStdoutGrep --matches=1 "^version:$version\$"
|
||||
assertStdoutGrep --matches=1 "^inserttime:$rexp_date\$"
|
||||
assertStdoutGrep --matches=1 "^filehash:$filehash\$"
|
||||
assertStdoutGrep --matches=1 "^filesize:$size\$"
|
||||
assertStdoutGrep --matches=1 "^\.author:$SIDB2\$"
|
||||
assertStdoutGrep --matches=1 "^\.readonly:0\$"
|
||||
# Now bundle author is known, so appears to be from here
|
||||
executeOk_servald rhizome list ''
|
||||
assert_rhizome_list fileB@$SIDB2
|
||||
}
|
||||
|
||||
runTests "$@"
|
||||
|
Loading…
Reference in New Issue
Block a user