mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-18 02:39:44 +00:00
Change manifest service to MeshMS2
This commit is contained in:
parent
2fa1cb3aec
commit
68bf04f69d
4
meshms.c
4
meshms.c
@ -119,7 +119,7 @@ static int get_database_conversations(const sid_t *my_sid, const sid_t *their_si
|
||||
sqlite3_stmt *statement = sqlite_prepare(&retry,
|
||||
"SELECT id, version, filesize, tail, sender, recipient "
|
||||
"FROM manifests "
|
||||
"WHERE service = 'MeshMS1' "
|
||||
"WHERE service = '"RHIZOME_SERVICE_MESHMS2"' "
|
||||
"AND (sender=?1 or recipient=?1) "
|
||||
"AND (sender=?2 or recipient=?2)");
|
||||
if (!statement)
|
||||
@ -197,7 +197,7 @@ static int create_ply(const sid_t *my_sid, struct conversations *conv, rhizome_m
|
||||
m->journalTail = 0;
|
||||
const char *my_sidhex = alloca_tohex_sid(my_sid->binary);
|
||||
const char *their_sidhex = alloca_tohex_sid(conv->them.binary);
|
||||
rhizome_manifest_set(m, "service", RHIZOME_SERVICE_MESHMS);
|
||||
rhizome_manifest_set(m, "service", RHIZOME_SERVICE_MESHMS2);
|
||||
rhizome_manifest_set(m, "sender", my_sidhex);
|
||||
rhizome_manifest_set(m, "recipient", their_sidhex);
|
||||
rhizome_manifest_set_ll(m, "tail", m->journalTail);
|
||||
|
59
rhizome.c
59
rhizome.c
@ -137,36 +137,22 @@ int rhizome_bundle_import_files(rhizome_manifest *m, const char *manifest_path,
|
||||
// This feels like a hack...
|
||||
m->manifest_bytes=m->manifest_all_bytes;
|
||||
|
||||
/* Do we already have this manifest or newer? */
|
||||
int64_t dbVersion = -1;
|
||||
const char *id=rhizome_manifest_get(m, "id", NULL, 0);
|
||||
if (sqlite_exec_int64(&dbVersion, "SELECT version FROM MANIFESTS WHERE id='%s';", id) == -1)
|
||||
return WHY("Select failure");
|
||||
|
||||
if (dbVersion>=m->version)
|
||||
return 2;
|
||||
|
||||
int status = rhizome_import_file(m, filepath);
|
||||
if (status<0)
|
||||
return status;
|
||||
|
||||
status = rhizome_manifest_check_duplicate(m, NULL, 0);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return rhizome_add_manifest(m, 1);
|
||||
}
|
||||
|
||||
/* Import a bundle from a finalised manifest struct. The dataFileName element must give the path
|
||||
of a readable file containing the payload unless the payload is null (zero length). The logic is
|
||||
all in rhizome_add_manifest(). This function just wraps that function and manages object buffers
|
||||
and lifetimes.
|
||||
*/
|
||||
|
||||
int rhizome_bundle_import(rhizome_manifest *m, int ttl)
|
||||
{
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("(m=%p, ttl=%d)", m, ttl);
|
||||
int ret = rhizome_manifest_check_duplicate(m, NULL, 0);
|
||||
if (ret == 0) {
|
||||
ret = rhizome_add_manifest(m, ttl);
|
||||
if (ret == -1)
|
||||
WHY("rhizome_add_manifest() failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rhizome_manifest_check_sanity(rhizome_manifest *m_in)
|
||||
{
|
||||
/* Ensure manifest meets basic sanity checks. */
|
||||
@ -188,7 +174,8 @@ int rhizome_manifest_check_sanity(rhizome_manifest *m_in)
|
||||
const char *name = rhizome_manifest_get(m_in, "name", NULL, 0);
|
||||
if (name == NULL)
|
||||
return WHY("Manifest missing 'name' field");
|
||||
} else if (strcasecmp(service, RHIZOME_SERVICE_MESHMS) == 0) {
|
||||
} else if (strcasecmp(service, RHIZOME_SERVICE_MESHMS) == 0
|
||||
|| strcasecmp(service, RHIZOME_SERVICE_MESHMS2) == 0) {
|
||||
if (sender == NULL || !sender[0])
|
||||
return WHY("MeshMS Manifest missing 'sender' field");
|
||||
if (!str_is_subscriber_id(sender))
|
||||
@ -254,30 +241,6 @@ int rhizome_manifest_bind_id(rhizome_manifest *m_in)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if a manifest is already stored for the same payload with the same details.
|
||||
This catches the case of "rhizome add file <filename>" on the same file more than once.
|
||||
(Debounce!) */
|
||||
int rhizome_manifest_check_duplicate(rhizome_manifest *m_in, rhizome_manifest **m_out, int check_author)
|
||||
{
|
||||
if (config.debug.rhizome) DEBUG("Checking for duplicate");
|
||||
if (m_out) *m_out = NULL;
|
||||
rhizome_manifest *dupm = NULL;
|
||||
if (rhizome_find_duplicate(m_in, &dupm, check_author) == -1)
|
||||
return WHY("Errors encountered searching for duplicate manifest");
|
||||
if (dupm) {
|
||||
/* If the caller wants the duplicate manifest, it must be finalised, otherwise discarded. */
|
||||
if (m_out) {
|
||||
*m_out = dupm;
|
||||
}
|
||||
else
|
||||
rhizome_manifest_free(dupm);
|
||||
if (config.debug.rhizome) DEBUG("Found a duplicate");
|
||||
return 2;
|
||||
}
|
||||
if (config.debug.rhizome) DEBUG("No duplicate found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rhizome_add_manifest(rhizome_manifest *m_in,int ttl)
|
||||
{
|
||||
if (config.debug.rhizome)
|
||||
|
17
rhizome.h
17
rhizome.h
@ -108,6 +108,8 @@ typedef struct rhizome_manifest {
|
||||
except the creator. */
|
||||
unsigned char cryptoSignPublic[crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES];
|
||||
unsigned char cryptoSignSecret[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES];
|
||||
/* Whether we have the secret for this manifest on hand */
|
||||
int haveSecret;
|
||||
|
||||
int var_count;
|
||||
char *vars[MAX_MANIFEST_VARS];
|
||||
@ -121,7 +123,13 @@ typedef struct rhizome_manifest {
|
||||
*/
|
||||
unsigned char signatureTypes[MAX_MANIFEST_VARS];
|
||||
|
||||
int errors; /* if non-zero, then manifest should not be trusted */
|
||||
// errors only involve the correctness of fields that are mandatory for
|
||||
// proper operation of the transport and storage layer
|
||||
int errors;
|
||||
// a warning indicates that the manifest cannot be perfectly understood by this version of rhizome
|
||||
// during add, the manifest should not be finalised and imported
|
||||
// during extract an error should be displayed.
|
||||
int warnings;
|
||||
time_ms_t inserttime;
|
||||
|
||||
/* Set non-zero after variables have been packed and
|
||||
@ -149,8 +157,6 @@ typedef struct rhizome_manifest {
|
||||
unsigned char payloadKey[RHIZOME_CRYPT_KEY_BYTES];
|
||||
unsigned char payloadNonce[crypto_stream_xsalsa20_NONCEBYTES];
|
||||
|
||||
/* Whether we have the secret for this manifest on hand */
|
||||
int haveSecret;
|
||||
/* Whether the manifest contains a signature that corresponds to the
|
||||
manifest id (ie public key) */
|
||||
int selfSigned;
|
||||
@ -174,6 +180,7 @@ typedef struct rhizome_manifest {
|
||||
*/
|
||||
#define RHIZOME_SERVICE_FILE "file"
|
||||
#define RHIZOME_SERVICE_MESHMS "MeshMS1"
|
||||
#define RHIZOME_SERVICE_MESHMS2 "MeshMS2"
|
||||
|
||||
extern int64_t rhizome_space;
|
||||
extern unsigned short rhizome_http_server_port;
|
||||
@ -259,12 +266,10 @@ int rhizome_manifest_add_group(rhizome_manifest *m,char *groupid);
|
||||
int rhizome_clean_payload(const char *fileidhex);
|
||||
int rhizome_store_file(rhizome_manifest *m,const unsigned char *key);
|
||||
int rhizome_bundle_import_files(rhizome_manifest *m, const char *manifest_path, const char *filepath);
|
||||
int rhizome_bundle_import(rhizome_manifest *m, int ttl);
|
||||
int rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t *authorSid, rhizome_bk_t *bsk);
|
||||
|
||||
int rhizome_manifest_verify(rhizome_manifest *m);
|
||||
int rhizome_manifest_check_sanity(rhizome_manifest *m_in);
|
||||
int rhizome_manifest_check_duplicate(rhizome_manifest *m_in,rhizome_manifest **m_out, int check_author);
|
||||
|
||||
int rhizome_manifest_bind_id(rhizome_manifest *m_in);
|
||||
int rhizome_manifest_finalise(rhizome_manifest *m, rhizome_manifest **mout);
|
||||
@ -321,7 +326,7 @@ int _sqlite_vexec_strbuf_retry(struct __sourceloc, sqlite_retry_state *retry, st
|
||||
double rhizome_manifest_get_double(rhizome_manifest *m,char *var,double default_value);
|
||||
int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs);
|
||||
int rhizome_update_file_priority(const char *fileid);
|
||||
int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found, int check_author);
|
||||
int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found);
|
||||
int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar);
|
||||
int64_t rhizome_bar_version(const unsigned char *bar);
|
||||
uint64_t rhizome_bar_bidprefix_ll(unsigned char *bar);
|
||||
|
164
rhizome_bundle.c
164
rhizome_bundle.c
@ -84,29 +84,22 @@ int rhizome_manifest_verify(rhizome_manifest *m)
|
||||
else return 0;
|
||||
}
|
||||
|
||||
int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bufferP)
|
||||
int read_whole_file(const char *filename, unsigned char *buffer, int buffer_size)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
if (f == NULL)
|
||||
return WHYF("Could not open file %s for reading", filename);
|
||||
int ret = fread(buffer, 1, buffer_size, f);
|
||||
if (ret == -1)
|
||||
ret = WHY_perror("fread");
|
||||
if (fclose(f) == EOF)
|
||||
ret = WHY_perror("fclose");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rhizome_manifest_parse(rhizome_manifest *m)
|
||||
{
|
||||
IN();
|
||||
if (bufferP>MAX_MANIFEST_BYTES) RETURN(WHY("Buffer too big"));
|
||||
if (!m) RETURN(WHY("Null manifest"));
|
||||
|
||||
if (bufferP) {
|
||||
m->manifest_bytes=bufferP;
|
||||
memcpy(m->manifestdata, filename, m->manifest_bytes);
|
||||
} else {
|
||||
FILE *f = fopen(filename, "r");
|
||||
if (f == NULL)
|
||||
RETURN(WHYF("Could not open manifest file %s for reading.", filename));
|
||||
m->manifest_bytes = fread(m->manifestdata, 1, MAX_MANIFEST_BYTES, f);
|
||||
int ret = 0;
|
||||
if (m->manifest_bytes == -1)
|
||||
ret = WHY_perror("fread");
|
||||
if (fclose(f) == EOF)
|
||||
ret = WHY_perror("fclose");
|
||||
if (ret == -1)
|
||||
RETURN(-1);
|
||||
}
|
||||
|
||||
m->manifest_all_bytes=m->manifest_bytes;
|
||||
m->var_count=0;
|
||||
m->journalTail=-1;
|
||||
@ -118,6 +111,7 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
int have_date = 0;
|
||||
int have_filesize = 0;
|
||||
int have_filehash = 0;
|
||||
|
||||
int ofs = 0;
|
||||
while (ofs < m->manifest_bytes && m->manifestdata[ofs]) {
|
||||
char line[1024];
|
||||
@ -143,9 +137,7 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
p = strchr(line, '=');
|
||||
if (p == NULL || p == line) {
|
||||
m->errors++;
|
||||
WARNF(bufferP ? "Malformed manifest line in buffer %p: %s"
|
||||
: "Malformed manifest line in file %s: %s",
|
||||
filename, alloca_toprint(80, line, linelen));
|
||||
WARNF("Malformed manifest line: %s", alloca_toprint(80, line, linelen));
|
||||
} else {
|
||||
*p++ = '\0';
|
||||
char *var = line;
|
||||
@ -161,6 +153,9 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
} else {
|
||||
m->vars[m->var_count] = strdup(var);
|
||||
m->values[m->var_count] = strdup(value);
|
||||
|
||||
// if any of these fields are not well formed, the manifest is invalid and cannot be imported
|
||||
|
||||
if (strcasecmp(var, "id") == 0) {
|
||||
have_id = 1;
|
||||
if (fromhexstr(m->cryptoSignPublic, value, RHIZOME_MANIFEST_ID_BYTES) == -1) {
|
||||
@ -182,15 +177,6 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
str_toupper_inplace(m->values[m->var_count]);
|
||||
strcpy(m->fileHexHash, m->values[m->var_count]);
|
||||
}
|
||||
} else if (strcasecmp(var, "BK") == 0) {
|
||||
if (!rhizome_str_is_bundle_key(value)) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Invalid BK: %s", value);
|
||||
m->errors++;
|
||||
} else {
|
||||
/* Force to upper case to avoid case sensitive comparison problems later. */
|
||||
str_toupper_inplace(m->values[m->var_count]);
|
||||
}
|
||||
} else if (strcasecmp(var, "filesize") == 0) {
|
||||
have_filesize = 1;
|
||||
char *ep = value;
|
||||
@ -202,14 +188,6 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
} else {
|
||||
m->fileLength = filesize;
|
||||
}
|
||||
} else if (strcasecmp(var, "service") == 0) {
|
||||
have_service = 1;
|
||||
if ( strcasecmp(value, RHIZOME_SERVICE_FILE) == 0
|
||||
|| strcasecmp(value, RHIZOME_SERVICE_MESHMS) == 0) {
|
||||
} else {
|
||||
INFOF("Unsupported service: %s", value);
|
||||
// This is not an error... older rhizome nodes must carry newer manifests.
|
||||
}
|
||||
} else if (strcasecmp(var, "version") == 0) {
|
||||
have_version = 1;
|
||||
char *ep = value;
|
||||
@ -221,6 +199,40 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
} else {
|
||||
m->version = version;
|
||||
}
|
||||
|
||||
// since rhizome *MUST* be able to carry future manifest versions
|
||||
// if any of these fields are not well formed, the manifest can still be imported and exported
|
||||
// but the bundle should not be added or exported
|
||||
|
||||
} else if (strcasecmp(var, "tail") == 0) {
|
||||
char *ep = value;
|
||||
long long tail = strtoll(value, &ep, 10);
|
||||
if (ep == value || *ep || tail < 0) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Invalid tail: %s", value);
|
||||
m->warnings++;
|
||||
} else {
|
||||
m->journalTail = tail;
|
||||
}
|
||||
} else if (strcasecmp(var, "BK") == 0) {
|
||||
if (!rhizome_str_is_bundle_key(value)) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Invalid BK: %s", value);
|
||||
m->warnings++;
|
||||
} else {
|
||||
/* Force to upper case to avoid case sensitive comparison problems later. */
|
||||
str_toupper_inplace(m->values[m->var_count]);
|
||||
}
|
||||
} else if (strcasecmp(var, "service") == 0) {
|
||||
have_service = 1;
|
||||
if ( strcasecmp(value, RHIZOME_SERVICE_FILE) == 0
|
||||
|| strcasecmp(value, RHIZOME_SERVICE_MESHMS) == 0
|
||||
|| strcasecmp(value, RHIZOME_SERVICE_MESHMS2) == 0) {
|
||||
} else {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Unsupported service: %s", value);
|
||||
m->warnings++;
|
||||
}
|
||||
} else if (strcasecmp(var, "date") == 0) {
|
||||
have_date = 1;
|
||||
char *ep = value;
|
||||
@ -228,14 +240,14 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
if (ep == value || *ep || date < 0) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Invalid date: %s", value);
|
||||
m->errors++;
|
||||
m->warnings++;
|
||||
}
|
||||
// TODO: store date in manifest struct
|
||||
} else if (strcasecmp(var, "sender") == 0 || strcasecmp(var, "recipient") == 0) {
|
||||
if (!str_is_subscriber_id(value)) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Invalid %s: %s", var, value);
|
||||
m->errors++;
|
||||
m->warnings++;
|
||||
} else {
|
||||
/* Force to upper case to avoid case sensitive comparison problems later. */
|
||||
str_toupper_inplace(m->values[m->var_count]);
|
||||
@ -244,30 +256,18 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
if (value[0] == '\0') {
|
||||
if (config.debug.rejecteddata)
|
||||
WARN("Empty name");
|
||||
m->errors++;
|
||||
m->warnings++;
|
||||
}
|
||||
// TODO: complain if service is not MeshMS
|
||||
} else if (strcasecmp(var, "crypt") == 0) {
|
||||
if (!(strcmp(value, "0") == 0 || strcmp(value, "1") == 0)) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Invalid crypt: %s", value);
|
||||
m->errors++;
|
||||
m->warnings++;
|
||||
} else {
|
||||
m->payloadEncryption = atoi(value);
|
||||
}
|
||||
} else if (strcasecmp(var, "tail") == 0) {
|
||||
char *ep = value;
|
||||
long long tail = strtoll(value, &ep, 10);
|
||||
if (ep == value || *ep || tail < 0) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Invalid tail: %s", value);
|
||||
m->errors++;
|
||||
} else {
|
||||
m->journalTail = tail;
|
||||
}
|
||||
} else {
|
||||
INFOF("Unsupported field: %s=%s", var, value);
|
||||
// This is not an error... older rhizome nodes must carry newer manifests.
|
||||
// An unknown field is not an error... older rhizome nodes must carry newer manifests.
|
||||
}
|
||||
m->var_count++;
|
||||
}
|
||||
@ -281,11 +281,7 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
int end_of_text=ofs;
|
||||
m->manifest_bytes = end_of_text;
|
||||
|
||||
if (!have_service) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Missing service field");
|
||||
m->errors++;
|
||||
}
|
||||
// verify that all required fields are consistent.
|
||||
if (!have_id) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Missing manifest id field");
|
||||
@ -296,11 +292,6 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
WARNF("Missing version field");
|
||||
m->errors++;
|
||||
}
|
||||
if (!have_date) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Missing date field");
|
||||
m->errors++;
|
||||
}
|
||||
if (!have_filesize) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Missing filesize field");
|
||||
@ -317,9 +308,21 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
m->errors++;
|
||||
}
|
||||
|
||||
// warn if expected fields are missing
|
||||
if (!have_service) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Missing service field");
|
||||
m->warnings++;
|
||||
}
|
||||
if (!have_date) {
|
||||
if (config.debug.rejecteddata)
|
||||
WARNF("Missing date field");
|
||||
m->warnings++;
|
||||
}
|
||||
|
||||
// TODO Determine group membership here.
|
||||
|
||||
if (m->errors) {
|
||||
if (m->errors || m->warnings) {
|
||||
if (config.debug.rejecteddata)
|
||||
dump("manifest body",m->manifestdata,m->manifest_bytes);
|
||||
}
|
||||
@ -328,6 +331,24 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
OUT();
|
||||
}
|
||||
|
||||
int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bufferP)
|
||||
{
|
||||
if (!m)
|
||||
return WHY("Null manifest");
|
||||
if (bufferP>sizeof(m->manifestdata))
|
||||
return WHY("Buffer too big");
|
||||
|
||||
if (bufferP) {
|
||||
m->manifest_bytes=bufferP;
|
||||
memcpy(m->manifestdata, filename, m->manifest_bytes);
|
||||
} else {
|
||||
m->manifest_bytes = read_whole_file(filename, m->manifestdata, sizeof(m->manifestdata));
|
||||
if (m->manifest_bytes == -1)
|
||||
return -1;
|
||||
}
|
||||
return rhizome_manifest_parse(m);
|
||||
}
|
||||
|
||||
int rhizome_hash_file(rhizome_manifest *m,const char *filename,char *hash_out)
|
||||
{
|
||||
/* Gnarf! NaCl's crypto_hash() function needs the whole file passed in in one
|
||||
@ -680,11 +701,8 @@ int rhizome_manifest_finalise(rhizome_manifest *m, rhizome_manifest **mout)
|
||||
// if a manifest was supplied with an ID, don't bother to check for a duplicate.
|
||||
// we only want to filter out added files with no existing manifest.
|
||||
if (m->haveSecret==NEW_BUNDLE_ID){
|
||||
if (rhizome_manifest_check_duplicate(m, mout, 1) == 2) {
|
||||
/* duplicate found -- verify it so that we can write it out later */
|
||||
rhizome_manifest_verify(*mout);
|
||||
if (rhizome_find_duplicate(m, mout)==1)
|
||||
RETURN(2);
|
||||
}
|
||||
}
|
||||
|
||||
*mout=m;
|
||||
|
@ -1232,171 +1232,96 @@ int rhizome_update_file_priority(const char *fileid)
|
||||
|
||||
@author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found, int check_author)
|
||||
int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found)
|
||||
{
|
||||
// TODO, add service, name, sender & recipient to manifests table so we can simply query them.
|
||||
|
||||
const char *service = rhizome_manifest_get(m, "service", NULL, 0);
|
||||
const char *name = NULL;
|
||||
const char *sender = NULL;
|
||||
const char *recipient = NULL;
|
||||
if (service == NULL) {
|
||||
if (service == NULL)
|
||||
return WHY("Manifest has no service");
|
||||
} else if (strcasecmp(service, RHIZOME_SERVICE_FILE) == 0) {
|
||||
name = rhizome_manifest_get(m, "name", NULL, 0);
|
||||
if (!name) return WHY("Manifest has no name");
|
||||
} else if (strcasecmp(service, RHIZOME_SERVICE_MESHMS) == 0) {
|
||||
sender = rhizome_manifest_get(m, "sender", NULL, 0);
|
||||
recipient = rhizome_manifest_get(m, "recipient", NULL, 0);
|
||||
if (!sender) return WHY("Manifest has no sender");
|
||||
if (!recipient) return WHY("Manifest has no recipient");
|
||||
} else {
|
||||
return WHYF("Unsupported service '%s'", service);
|
||||
}
|
||||
|
||||
const char *name = rhizome_manifest_get(m, "name", NULL, 0);
|
||||
const char *sender = rhizome_manifest_get(m, "sender", NULL, 0);
|
||||
const char *recipient = rhizome_manifest_get(m, "recipient", NULL, 0);
|
||||
|
||||
char sqlcmd[1024];
|
||||
strbuf b = strbuf_local(sqlcmd, sizeof sqlcmd);
|
||||
strbuf_puts(b, "SELECT id, manifest, version, author FROM manifests WHERE ");
|
||||
if (m->fileLength != 0) {
|
||||
strbuf_puts(b, "filehash = ?");
|
||||
} else
|
||||
strbuf_puts(b, "filesize = 0");
|
||||
strbuf_puts(b, "SELECT id, manifest, author FROM manifests WHERE filesize = ? AND service = ?");
|
||||
|
||||
if (m->fileLength != 0)
|
||||
strbuf_puts(b, " AND filehash = ?");
|
||||
if (name)
|
||||
strbuf_puts(b, " AND name = ?");
|
||||
if (sender)
|
||||
strbuf_puts(b, " AND sender = ?");
|
||||
if (recipient)
|
||||
strbuf_puts(b, " AND recipient = ?");
|
||||
|
||||
if (strbuf_overrun(b))
|
||||
return WHYF("SQL command too long: %s", strbuf_str(b));
|
||||
|
||||
int ret = 0;
|
||||
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
|
||||
sqlite3_stmt *statement = sqlite_prepare(&retry, "%s", strbuf_str(b));
|
||||
if (!statement)
|
||||
return -1;
|
||||
|
||||
int field = 1;
|
||||
char filehash[RHIZOME_FILEHASH_STRLEN + 1];
|
||||
if (m->fileLength != 0) {
|
||||
strncpy(filehash, m->fileHexHash, sizeof filehash);
|
||||
str_toupper_inplace(filehash);
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("filehash=\"%s\"", filehash);
|
||||
sqlite3_bind_text(statement, field++, filehash, -1, SQLITE_STATIC);
|
||||
}
|
||||
sqlite3_bind_int(statement, field++, m->fileLength);
|
||||
sqlite3_bind_text(statement, field++, service, -1, SQLITE_STATIC);
|
||||
|
||||
if (m->fileLength != 0)
|
||||
sqlite3_bind_text(statement, field++, m->fileHexHash, -1, SQLITE_STATIC);
|
||||
if (name)
|
||||
sqlite3_bind_text(statement, field++, name, -1, SQLITE_STATIC);
|
||||
if (sender)
|
||||
sqlite3_bind_text(statement, field++, sender, -1, SQLITE_STATIC);
|
||||
if (recipient)
|
||||
sqlite3_bind_text(statement, field++, recipient, -1, SQLITE_STATIC);
|
||||
|
||||
int rows = 0;
|
||||
while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) {
|
||||
++rows;
|
||||
if (config.debug.rhizome) DEBUGF("Row %d", rows);
|
||||
if (!( sqlite3_column_count(statement) == 4
|
||||
&& sqlite3_column_type(statement, 0) == SQLITE_TEXT
|
||||
&& sqlite3_column_type(statement, 1) == SQLITE_BLOB
|
||||
&& sqlite3_column_type(statement, 2) == SQLITE_INTEGER
|
||||
&& ( sqlite3_column_type(statement, 3) == SQLITE_TEXT
|
||||
|| sqlite3_column_type(statement, 3) == SQLITE_NULL
|
||||
)
|
||||
)) {
|
||||
ret = WHY("Incorrect statement columns");
|
||||
break;
|
||||
}
|
||||
const char *q_manifestid = (const char *) sqlite3_column_text(statement, 0);
|
||||
size_t manifestidsize = sqlite3_column_bytes(statement, 0); // must call after sqlite3_column_text()
|
||||
unsigned char manifest_id[RHIZOME_MANIFEST_ID_BYTES];
|
||||
if ( manifestidsize != crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES * 2
|
||||
|| fromhexstr(manifest_id, q_manifestid, RHIZOME_MANIFEST_ID_BYTES) == -1
|
||||
) {
|
||||
ret = WHYF("Malformed manifest.id from query: %s", q_manifestid);
|
||||
break;
|
||||
}
|
||||
const char *manifestblob = (char *) sqlite3_column_blob(statement, 1);
|
||||
size_t manifestblobsize = sqlite3_column_bytes(statement, 1); // must call after sqlite3_column_blob()
|
||||
int64_t q_version = sqlite3_column_int64(statement, 2);
|
||||
const char *q_author = (const char *) sqlite3_column_text(statement, 3);
|
||||
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("Row %d", rows);
|
||||
|
||||
rhizome_manifest *blob_m = rhizome_new_manifest();
|
||||
if (blob_m == NULL) {
|
||||
ret = WHY("Out of manifests");
|
||||
break;
|
||||
}
|
||||
|
||||
const unsigned char *q_manifestid = sqlite3_column_text(statement, 0);
|
||||
|
||||
const char *manifestblob = (char *) sqlite3_column_blob(statement, 1);
|
||||
size_t manifestblobsize = sqlite3_column_bytes(statement, 1); // must call after sqlite3_column_blob()
|
||||
if (rhizome_read_manifest_file(blob_m, manifestblob, manifestblobsize) == -1) {
|
||||
WARNF("MANIFESTS row id=%s has invalid manifest blob -- skipped", q_manifestid);
|
||||
} else if (rhizome_manifest_verify(blob_m)) {
|
||||
WARNF("MANIFESTS row id=%s fails verification -- skipped", q_manifestid);
|
||||
} else {
|
||||
const char *blob_service = rhizome_manifest_get(blob_m, "service", NULL, 0);
|
||||
const char *blob_id = rhizome_manifest_get(blob_m, "id", NULL, 0);
|
||||
int64_t blob_version = rhizome_manifest_get_ll(blob_m, "version");
|
||||
const char *blob_filehash = rhizome_manifest_get(blob_m, "filehash", NULL, 0);
|
||||
int64_t blob_filesize = rhizome_manifest_get_ll(blob_m, "filesize");
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("Consider manifest.service=%s manifest.id=%s manifest.version=%"PRId64, blob_service, q_manifestid, blob_version);
|
||||
if (q_author) {
|
||||
if (config.debug.rhizome)
|
||||
strbuf_sprintf(b, " .author=%s", q_author);
|
||||
stowSid(blob_m->author, 0, q_author);
|
||||
}
|
||||
|
||||
/* Perform consistency checks, because we're paranoid. */
|
||||
int inconsistent = 0;
|
||||
if (blob_id && strcasecmp(blob_id, q_manifestid)) {
|
||||
WARNF("MANIFESTS row id=%s has inconsistent blob with id=%s -- skipped", q_manifestid, blob_id);
|
||||
++inconsistent;
|
||||
}
|
||||
if (blob_version != q_version) {
|
||||
WARNF("MANIFESTS row id=%s has inconsistent blob: manifests.version=%"PRId64", blob.version=%"PRId64" -- skipped",
|
||||
q_manifestid, q_version, blob_version);
|
||||
++inconsistent;
|
||||
}
|
||||
if (blob_filesize != -1 && blob_filesize != m->fileLength) {
|
||||
WARNF("MANIFESTS row id=%s has inconsistent blob: known file size %"PRId64", blob.filesize=%"PRId64" -- skipped",
|
||||
q_manifestid, m->fileLength, blob_filesize);
|
||||
++inconsistent;
|
||||
}
|
||||
if (m->fileLength != 0) {
|
||||
if (!blob_filehash && strcasecmp(blob_filehash, m->fileHexHash)) {
|
||||
WARNF("MANIFESTS row id=%s has inconsistent blob: manifests.filehash=%s, blob.filehash=%s -- skipped",
|
||||
q_manifestid, m->fileHexHash, blob_filehash);
|
||||
++inconsistent;
|
||||
}
|
||||
} else {
|
||||
if (blob_filehash) {
|
||||
WARNF("MANIFESTS row id=%s has inconsistent blob: blob.filehash should be absent -- skipped",
|
||||
q_manifestid);
|
||||
++inconsistent;
|
||||
}
|
||||
}
|
||||
if (blob_service == NULL) {
|
||||
WARNF("MANIFESTS row id=%s has blob with no 'service' -- skipped", q_manifestid);
|
||||
++inconsistent;
|
||||
}
|
||||
if (!inconsistent) {
|
||||
strbuf b = strbuf_alloca(1024);
|
||||
if (strcasecmp(service, RHIZOME_SERVICE_FILE) == 0) {
|
||||
const char *blob_name = rhizome_manifest_get(blob_m, "name", NULL, 0);
|
||||
if (blob_name && !strcmp(blob_name, name)) {
|
||||
if (config.debug.rhizome)
|
||||
strbuf_sprintf(b, " name=\"%s\"", blob_name);
|
||||
}else
|
||||
++inconsistent;
|
||||
} else if (strcasecmp(service, RHIZOME_SERVICE_MESHMS) == 0) {
|
||||
const char *blob_sender = rhizome_manifest_get(blob_m, "sender", NULL, 0);
|
||||
const char *blob_recipient = rhizome_manifest_get(blob_m, "recipient", NULL, 0);
|
||||
if (blob_sender && !strcasecmp(blob_sender, sender) && blob_recipient && !strcasecmp(blob_recipient, recipient)) {
|
||||
if (config.debug.rhizome)
|
||||
strbuf_sprintf(b, " sender=%s recipient=%s", blob_sender, blob_recipient);
|
||||
}else
|
||||
++inconsistent;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!inconsistent) && check_author) {
|
||||
// check that we can re-author this manifest
|
||||
if (rhizome_extract_privatekey(blob_m, NULL))
|
||||
++inconsistent;
|
||||
}
|
||||
|
||||
if (!inconsistent) {
|
||||
*found = blob_m;
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("Found duplicate payload: service=%s%s version=%"PRIu64" hexhash=%s",
|
||||
blob_service, strbuf_str(b), blob_m->version, blob_m->fileHexHash
|
||||
);
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (rhizome_manifest_verify(blob_m)) {
|
||||
WARNF("MANIFESTS row id=%s fails verification -- skipped", q_manifestid);
|
||||
goto next;
|
||||
}
|
||||
|
||||
const char *q_author = (const char *) sqlite3_column_text(statement, 2);
|
||||
if (q_author) {
|
||||
if (config.debug.rhizome)
|
||||
strbuf_sprintf(b, " .author=%s", q_author);
|
||||
stowSid(blob_m->author, 0, q_author);
|
||||
}
|
||||
|
||||
// check that we can re-author this manifest
|
||||
if (rhizome_extract_privatekey(blob_m, NULL)){
|
||||
goto next;
|
||||
}
|
||||
|
||||
*found = blob_m;
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("Found duplicate payload, %s", q_manifestid);
|
||||
ret = 1;
|
||||
break;
|
||||
|
||||
next:
|
||||
if (blob_m)
|
||||
rhizome_manifest_free(blob_m);
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ static int rhizome_import_received_bundle(struct rhizome_manifest *m)
|
||||
m->manifest_bytes, m->sig_count,(long long)m->fileLength);
|
||||
dump("manifest", m->manifestdata, m->manifest_all_bytes);
|
||||
}
|
||||
return rhizome_bundle_import(m, m->ttl - 1 /* TTL */);
|
||||
return rhizome_add_manifest(m, m->ttl - 1 /* TTL */);
|
||||
}
|
||||
|
||||
static int schedule_fetch(struct rhizome_fetch_slot *slot)
|
||||
|
Loading…
Reference in New Issue
Block a user