mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-30 09:58:55 +00:00
Pass author SID parameters in binary, not hex
This commit is contained in:
parent
f5998b3862
commit
7a71a521f8
@ -1140,17 +1140,20 @@ int cli_optional_bundle_key(const char *arg)
|
|||||||
|
|
||||||
int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_option *o)
|
int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_option *o)
|
||||||
{
|
{
|
||||||
const char *filepath, *manifestpath, *authorSid, *pin, *bskhex;
|
const char *filepath, *manifestpath, *authorSidHex, *pin, *bskhex;
|
||||||
cli_arg(argc, argv, o, "filepath", &filepath, NULL, "");
|
cli_arg(argc, argv, o, "filepath", &filepath, NULL, "");
|
||||||
if (cli_arg(argc, argv, o, "author_sid", &authorSid, cli_optional_sid, "") == -1)
|
if (cli_arg(argc, argv, o, "author_sid", &authorSidHex, cli_optional_sid, "") == -1)
|
||||||
return -1;
|
return -1;
|
||||||
cli_arg(argc, argv, o, "pin", &pin, NULL, "");
|
cli_arg(argc, argv, o, "pin", &pin, NULL, "");
|
||||||
cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, "");
|
cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, "");
|
||||||
if (cli_arg(argc, argv, o, "bsk", &bskhex, cli_optional_bundle_key, "") == -1)
|
if (cli_arg(argc, argv, o, "bsk", &bskhex, cli_optional_bundle_key, "") == -1)
|
||||||
return -1;
|
return -1;
|
||||||
unsigned char bsk[RHIZOME_BUNDLE_KEY_STRLEN + 1];
|
unsigned char authorSid[SID_SIZE];
|
||||||
if (bskhex[0] && stowBytes(bsk, bskhex, RHIZOME_BUNDLE_KEY_BYTES) == -1)
|
if (authorSidHex[0] && fromhexstr(authorSid, authorSidHex, SID_SIZE) == -1)
|
||||||
return -1;
|
return WHYF("invalid author_sid: %s", authorSidHex);
|
||||||
|
unsigned char bsk[RHIZOME_BUNDLE_KEY_BYTES];
|
||||||
|
if (bskhex[0] && fromhexstr(bsk, bskhex, RHIZOME_BUNDLE_KEY_BYTES) == -1)
|
||||||
|
return WHYF("invalid bsk: %s", bskhex);
|
||||||
if (create_serval_instance_dir() == -1)
|
if (create_serval_instance_dir() == -1)
|
||||||
return -1;
|
return -1;
|
||||||
if (!(keyring = keyring_open_with_pins((char *)pin)))
|
if (!(keyring = keyring_open_with_pins((char *)pin)))
|
||||||
@ -1206,8 +1209,8 @@ int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_
|
|||||||
|
|
||||||
/* Bind an ID to the manifest, and also bind the file. Then finalise the manifest.
|
/* Bind an ID to the manifest, and also bind the file. Then finalise the manifest.
|
||||||
But if the manifest already contains an ID, don't override it. */
|
But if the manifest already contains an ID, don't override it. */
|
||||||
if (rhizome_manifest_get(m, "id", NULL, 0)==NULL) {
|
if (rhizome_manifest_get(m, "id", NULL, 0) == NULL) {
|
||||||
if (rhizome_manifest_bind_id(m, authorSid)) {
|
if (rhizome_manifest_bind_id(m, authorSidHex[0] ? authorSid : NULL)) {
|
||||||
rhizome_manifest_free(m);
|
rhizome_manifest_free(m);
|
||||||
m = NULL;
|
m = NULL;
|
||||||
return WHY("Could not bind manifest to an ID");
|
return WHY("Could not bind manifest to an ID");
|
||||||
@ -1219,14 +1222,18 @@ int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_
|
|||||||
m = NULL;
|
m = NULL;
|
||||||
return WHY("Incorrect BID secret key.");
|
return WHY("Incorrect BID secret key.");
|
||||||
}
|
}
|
||||||
} else {
|
} else if (authorSidHex[0]) {
|
||||||
/* User supplied manifest has a BID, so see if we can extract the
|
/* User supplied manifest has a BID, so see if we can extract the
|
||||||
private key from a BK entry */
|
private key from a BK entry */
|
||||||
if (rhizome_extract_privatekey(m,authorSid) == -1) {
|
if (rhizome_extract_privatekey(m, authorSid) == -1) {
|
||||||
rhizome_manifest_free(m);
|
rhizome_manifest_free(m);
|
||||||
m = NULL;
|
m = NULL;
|
||||||
return WHY("Could not extract BID secret key. Does the manifest have a BK, did you supply the correct author SID?");
|
return WHY("Could not extract BID secret key. Does the manifest have a BK?");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
rhizome_manifest_free(m);
|
||||||
|
m = NULL;
|
||||||
|
return WHY("Author SID not specified");
|
||||||
}
|
}
|
||||||
#warning need to sanely determine whether to encrypt a file
|
#warning need to sanely determine whether to encrypt a file
|
||||||
#warning payload encryption disabled for now
|
#warning payload encryption disabled for now
|
||||||
@ -1239,7 +1246,7 @@ int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_
|
|||||||
/* Add the manifest and its associated file to the Rhizome database, generating an "id" in the
|
/* Add the manifest and its associated file to the Rhizome database, generating an "id" in the
|
||||||
* process */
|
* process */
|
||||||
rhizome_manifest *mout = NULL;
|
rhizome_manifest *mout = NULL;
|
||||||
if (debug & DEBUG_RHIZOME) DEBUGF("rhizome_add_manifest(author='%s')", authorSid);
|
if (debug & DEBUG_RHIZOME) DEBUGF("rhizome_add_manifest(author='%s')", authorSidHex);
|
||||||
|
|
||||||
int ret=0;
|
int ret=0;
|
||||||
if (rhizome_manifest_check_duplicate(m,&mout)==2)
|
if (rhizome_manifest_check_duplicate(m,&mout)==2)
|
||||||
@ -1349,7 +1356,7 @@ int app_rhizome_extract_file(int argc, const char *const *argv, struct command_l
|
|||||||
return -1;
|
return -1;
|
||||||
cli_arg(argc, argv, o, "key", &keyhex, cli_optional_bundle_crypt_key, "");
|
cli_arg(argc, argv, o, "key", &keyhex, cli_optional_bundle_crypt_key, "");
|
||||||
unsigned char key[RHIZOME_CRYPT_KEY_STRLEN + 1];
|
unsigned char key[RHIZOME_CRYPT_KEY_STRLEN + 1];
|
||||||
if (keyhex[0] && stowBytes(key, keyhex, RHIZOME_CRYPT_KEY_BYTES) == -1)
|
if (keyhex[0] && fromhexstr(key, keyhex, RHIZOME_CRYPT_KEY_BYTES) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
/* Ensure the Rhizome database exists and is open */
|
/* Ensure the Rhizome database exists and is open */
|
||||||
if (create_serval_instance_dir() == -1)
|
if (create_serval_instance_dir() == -1)
|
||||||
|
114
dataformats.c
114
dataformats.c
@ -18,8 +18,38 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "serval.h"
|
#include "serval.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
int hexdigit[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
char hexdigit[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||||||
|
|
||||||
|
char *tohex(char *dstHex, const unsigned char *srcBinary, size_t bytes)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
for (p = dstHex; bytes--; ++srcBinary) {
|
||||||
|
*p++ = hexdigit[*srcBinary >> 4];
|
||||||
|
*p++ = hexdigit[*srcBinary & 0xf];
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
return dstHex;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fromhex(unsigned char *dstBinary, const char *srcHex, size_t bytes)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
while (count != bytes) {
|
||||||
|
unsigned char high = hexvalue(*srcHex++);
|
||||||
|
if (high & 0xf0) return -1;
|
||||||
|
unsigned char low = hexvalue(*srcHex++);
|
||||||
|
if (low & 0xf0) return -1;
|
||||||
|
dstBinary[count++] = (high << 4) + low;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fromhexstr(unsigned char *dstBinary, const char *srcHex, size_t bytes)
|
||||||
|
{
|
||||||
|
return (fromhex(dstBinary, srcHex, bytes) == bytes && srcHex[bytes * 2] == '\0') ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
int extractDid(unsigned char *packet,int *ofs,char *did)
|
int extractDid(unsigned char *packet,int *ofs,char *did)
|
||||||
{
|
{
|
||||||
@ -91,67 +121,47 @@ int stowDid(unsigned char *packet,int *ofs,char *did)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int extractSid(unsigned char *packet,int *ofs,char *sid)
|
int extractSid(unsigned char *packet, int *ofs,char *sid)
|
||||||
{
|
{
|
||||||
int i=0;
|
(void) tohex(sid, packet + *ofs, SID_SIZE);
|
||||||
int d=0;
|
*ofs += SID_SIZE;
|
||||||
for(i=0;i<SID_SIZE;i++)
|
|
||||||
{
|
|
||||||
sid[d++]=hexdigit[packet[*ofs]>>4];
|
|
||||||
sid[d++]=hexdigit[packet[*ofs]&0xf];
|
|
||||||
(*ofs)++;
|
|
||||||
}
|
|
||||||
sid[d]=0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int validateSid(const char *sid)
|
int validateSid(const char *sid)
|
||||||
{
|
{
|
||||||
if (!sid) {
|
if (!sid) {
|
||||||
WHY("SID == NULL");
|
WHY("invalid SID == NULL");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (strcasecmp(sid, "broadcast") == 0)
|
||||||
|
return 1;
|
||||||
|
const char *s = sid;
|
||||||
|
const char *e = sid + SID_STRLEN;
|
||||||
|
while (s != e && isxdigit(*s))
|
||||||
|
++s;
|
||||||
|
if (s != e) {
|
||||||
|
if (*s)
|
||||||
|
WHYF("invalid SID, contains non-hex character 0x%02x at offset %d", *s, s - sid);
|
||||||
|
else
|
||||||
|
WHYF("invalid SID, too short (strlen %d)", s - sid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (*s) {
|
||||||
|
WHYF("invalid SID, too long");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!strcasecmp(sid,"broadcast")) return 1;
|
|
||||||
size_t n = strlen(sid);
|
|
||||||
if (n != SID_STRLEN)
|
|
||||||
{ WHYF("Invalid SID (strlen is %u, should be %u)", n, SID_STRLEN); return 0; }
|
|
||||||
const char *s;
|
|
||||||
for (s = sid; *s; ++s)
|
|
||||||
if (hexvalue(*s) == -1)
|
|
||||||
{ WHY("SID contains non-hex character"); return 0; }
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stowSid(unsigned char *packet, int ofs, const char *sid)
|
int stowSid(unsigned char *packet, int ofs, const char *sid)
|
||||||
{
|
{
|
||||||
|
if (debug & DEBUG_PACKETFORMATS)
|
||||||
int i;
|
printf("stowing SID \"%s\"\n", sid);
|
||||||
if (debug&DEBUG_PACKETFORMATS)
|
if (strcasecmp(sid,"broadcast") == 0)
|
||||||
printf("Stowing SID \"%s\"\n", sid);
|
memset(packet + ofs, 0xff, SID_SIZE);
|
||||||
if (!validateSid(sid))
|
else if (fromhex(packet + ofs, sid, SID_SIZE) != SID_SIZE || sid[SID_STRLEN] != '\0')
|
||||||
return WHY("Invalid SID passed in");
|
return WHY("invalid SID");
|
||||||
if (!strcasecmp(sid,"broadcast"))
|
|
||||||
for(i=0;i<32;i++) packet[ofs++]=0xff;
|
|
||||||
else
|
|
||||||
for(i = 0; i != SID_SIZE; ++i) {
|
|
||||||
packet[ofs] = hexvalue(sid[i<<1]) << 4;
|
|
||||||
packet[ofs++] |= hexvalue(sid[(i<<1)+1]);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int stowBytes(unsigned char *packet, const char *in,int count)
|
|
||||||
{
|
|
||||||
int ofs=0;
|
|
||||||
if (strlen(in)!=(count*2))
|
|
||||||
return WHY("Input string is wrong length");
|
|
||||||
int i;
|
|
||||||
for(i = 0; i != count; ++i) {
|
|
||||||
if(hexvalue(in[i<<1])<0) return WHYF("Non-hex char at position %d",i<<1);
|
|
||||||
if(hexvalue(in[(i<<1)+1])<0) return WHYF("Non-hex char at position %d",(i<<1)+1);
|
|
||||||
packet[ofs] = hexvalue(in[i<<1]) << 4;
|
|
||||||
packet[ofs++] |= hexvalue(in[(i<<1)+1]);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,10 +175,10 @@ char *str_toupper_inplace(char *str)
|
|||||||
|
|
||||||
int hexvalue(unsigned char c)
|
int hexvalue(unsigned char c)
|
||||||
{
|
{
|
||||||
if (c>='0'&&c<='9') return c-'0';
|
if (c >= '0' && c <= '9') return c - '0';
|
||||||
if (c>='A'&&c<='F') return c-'A'+10;
|
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||||
if (c>='a'&&c<='f') return c-'a'+10;
|
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||||
return WHY("Invalid hex digit in SID");
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int packetGetID(unsigned char *packet,int len,char *did,char *sid)
|
int packetGetID(unsigned char *packet,int len,char *did,char *sid)
|
||||||
|
@ -1314,7 +1314,7 @@ unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp,unsigned char *sid)
|
int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp, const unsigned char *sid)
|
||||||
{
|
{
|
||||||
if (keyring_sanitise_position(k,cn,in,kp)) return 0;
|
if (keyring_sanitise_position(k,cn,in,kp)) return 0;
|
||||||
|
|
||||||
|
23
rhizome.c
23
rhizome.c
@ -136,18 +136,17 @@ int rhizome_manifest_check_sanity(rhizome_manifest *m_in)
|
|||||||
by joining the parent group.
|
by joining the parent group.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int rhizome_manifest_bind_id(rhizome_manifest *m_in,const char *author)
|
int rhizome_manifest_bind_id(rhizome_manifest *m_in, const unsigned char *authorSid)
|
||||||
{
|
{
|
||||||
rhizome_manifest_createid(m_in);
|
rhizome_manifest_createid(m_in);
|
||||||
|
|
||||||
/* The ID is implicit in transit, but we need to store it in the file, so that reimporting
|
/* The ID is implicit in transit, but we need to store it in the file, so that reimporting
|
||||||
manifests on receiver nodes works easily. We might implement something that strips the id
|
manifests on receiver nodes works easily. We might implement something that strips the id
|
||||||
variable out of the manifest when sending it, or some other scheme to avoid sending all the
|
variable out of the manifest when sending it, or some other scheme to avoid sending all the
|
||||||
extra bytes. */
|
extra bytes. */
|
||||||
char id[crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES*2+1];
|
char id[RHIZOME_MANIFEST_ID_STRLEN + 1];
|
||||||
rhizome_bytes_to_hex_upper(m_in->cryptoSignPublic, id, crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES);
|
rhizome_bytes_to_hex_upper(m_in->cryptoSignPublic, id, RHIZOME_MANIFEST_ID_BYTES);
|
||||||
rhizome_manifest_set(m_in, "id", id);
|
rhizome_manifest_set(m_in, "id", id);
|
||||||
if (author&&author[0]) {
|
if (authorSid) {
|
||||||
/* Set the BK using the provided authorship information.
|
/* Set the BK using the provided authorship information.
|
||||||
Serval Security Framework defines BK as being:
|
Serval Security Framework defines BK as being:
|
||||||
BK = privateKey XOR sha512(RS##BID), where BID = cryptoSignPublic,
|
BK = privateKey XOR sha512(RS##BID), where BID = cryptoSignPublic,
|
||||||
@ -156,9 +155,9 @@ int rhizome_manifest_bind_id(rhizome_manifest *m_in,const char *author)
|
|||||||
privateKey = BK XOR sha512(RS##BID), so the same function can be used
|
privateKey = BK XOR sha512(RS##BID), so the same function can be used
|
||||||
to encrypt and decrypt the BK field. */
|
to encrypt and decrypt the BK field. */
|
||||||
unsigned char bkbytes[RHIZOME_BUNDLE_KEY_BYTES];
|
unsigned char bkbytes[RHIZOME_BUNDLE_KEY_BYTES];
|
||||||
if (rhizome_bk_xor(author, m_in->cryptoSignPublic, m_in->cryptoSignSecret, bkbytes) == 0) {
|
if (rhizome_bk_xor(authorSid, m_in->cryptoSignPublic, m_in->cryptoSignSecret, bkbytes) == 0) {
|
||||||
char bkhex[RHIZOME_BUNDLE_KEY_STRLEN + 1];
|
char bkhex[RHIZOME_BUNDLE_KEY_STRLEN + 1];
|
||||||
rhizome_bytes_to_hex_upper(bkbytes, bkhex, RHIZOME_BUNDLE_KEY_BYTES);
|
(void) tohex(bkhex, bkbytes, RHIZOME_BUNDLE_KEY_BYTES);
|
||||||
if (debug&DEBUG_RHIZOME) DEBUGF("set BK=%s", bkhex);
|
if (debug&DEBUG_RHIZOME) DEBUGF("set BK=%s", bkhex);
|
||||||
rhizome_manifest_set(m_in, "BK", bkhex);
|
rhizome_manifest_set(m_in, "BK", bkhex);
|
||||||
} else {
|
} else {
|
||||||
@ -353,16 +352,6 @@ int rhizome_bundle_push_update(char *id,long long version,unsigned char *data,in
|
|||||||
return WHY("Not implemented");
|
return WHY("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the uppercase hex digit for a given nybble value 0..15.
|
|
||||||
*/
|
|
||||||
char nybltochar_upper(int nybl)
|
|
||||||
{
|
|
||||||
if (nybl<0) return '?';
|
|
||||||
if (nybl>15) return '?';
|
|
||||||
if (nybl<10) return '0'+nybl;
|
|
||||||
return 'A'+nybl-10;
|
|
||||||
}
|
|
||||||
|
|
||||||
int chartonybl(int c)
|
int chartonybl(int c)
|
||||||
{
|
{
|
||||||
if (c>='A'&&c<='F') return 0x0a+(c-'A');
|
if (c>='A'&&c<='F') return 0x0a+(c-'A');
|
||||||
|
@ -234,7 +234,7 @@ int rhizome_manifest_check_sanity(rhizome_manifest *m_in);
|
|||||||
int rhizome_manifest_check_file(rhizome_manifest *m_in);
|
int rhizome_manifest_check_file(rhizome_manifest *m_in);
|
||||||
int rhizome_manifest_check_duplicate(rhizome_manifest *m_in,rhizome_manifest **m_out);
|
int rhizome_manifest_check_duplicate(rhizome_manifest *m_in,rhizome_manifest **m_out);
|
||||||
|
|
||||||
int rhizome_manifest_bind_id(rhizome_manifest *m_in,const char *author);
|
int rhizome_manifest_bind_id(rhizome_manifest *m_in, const unsigned char *authorSid);
|
||||||
int rhizome_manifest_bind_file(rhizome_manifest *m_in,const char *filename,int encryptP);
|
int rhizome_manifest_bind_file(rhizome_manifest *m_in,const char *filename,int encryptP);
|
||||||
int rhizome_manifest_finalise(rhizome_manifest *m);
|
int rhizome_manifest_finalise(rhizome_manifest *m);
|
||||||
int rhizome_add_manifest(rhizome_manifest *m_in,int ttl);
|
int rhizome_add_manifest(rhizome_manifest *m_in,int ttl);
|
||||||
@ -242,7 +242,7 @@ int rhizome_add_manifest(rhizome_manifest *m_in,int ttl);
|
|||||||
void rhizome_bytes_to_hex_upper(unsigned const char *in, char *out, int byteCount);
|
void rhizome_bytes_to_hex_upper(unsigned const char *in, char *out, int byteCount);
|
||||||
int rhizome_hex_to_bytes(const char *in,unsigned char *out,int hexChars);
|
int rhizome_hex_to_bytes(const char *in,unsigned char *out,int hexChars);
|
||||||
int rhizome_find_privatekey(rhizome_manifest *m);
|
int rhizome_find_privatekey(rhizome_manifest *m);
|
||||||
rhizome_signature *rhizome_sign_hash(rhizome_manifest *m,const char *author);
|
rhizome_signature *rhizome_sign_hash(rhizome_manifest *m, const unsigned char *authorSid);
|
||||||
int rhizome_server_free_http_request(rhizome_http_request *r);
|
int rhizome_server_free_http_request(rhizome_http_request *r);
|
||||||
int rhizome_server_close_http_request(int i);
|
int rhizome_server_close_http_request(int i);
|
||||||
int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r);
|
int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r);
|
||||||
@ -261,7 +261,6 @@ int rhizome_update_file_priority(const char *fileid);
|
|||||||
int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found,
|
int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found,
|
||||||
int checkVersionP);
|
int checkVersionP);
|
||||||
int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar);
|
int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar);
|
||||||
char nybltochar_upper(int n);
|
|
||||||
int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peerip, int *manifest_kept);
|
int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peerip, int *manifest_kept);
|
||||||
int rhizome_list_manifests(const char *service, const char *sender_sid, const char *recipient_sid, int limit, int offset);
|
int rhizome_list_manifests(const char *service, const char *sender_sid, const char *recipient_sid, int limit, int offset);
|
||||||
int rhizome_retrieve_manifest(const char *manifestid, rhizome_manifest **mp);
|
int rhizome_retrieve_manifest(const char *manifestid, rhizome_manifest **mp);
|
||||||
@ -275,12 +274,12 @@ int rhizome_fetching_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
|
|||||||
int rhizome_manifest_version_cache_lookup(rhizome_manifest *m);
|
int rhizome_manifest_version_cache_lookup(rhizome_manifest *m);
|
||||||
int rhizome_manifest_version_cache_store(rhizome_manifest *m);
|
int rhizome_manifest_version_cache_store(rhizome_manifest *m);
|
||||||
int monitor_announce_bundle(rhizome_manifest *m);
|
int monitor_announce_bundle(rhizome_manifest *m);
|
||||||
int rhizome_bk_xor(const char *author,
|
int rhizome_bk_xor(const unsigned char *authorSid, // binary
|
||||||
unsigned char bid[crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES],
|
unsigned char bid[crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES],
|
||||||
unsigned char bkin[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES],
|
unsigned char bkin[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES],
|
||||||
unsigned char bkout[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES]);
|
unsigned char bkout[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES]);
|
||||||
unsigned char *rhizome_bundle_shared_secret(rhizome_manifest *m);
|
unsigned char *rhizome_bundle_shared_secret(rhizome_manifest *m);
|
||||||
int rhizome_extract_privatekey(rhizome_manifest *m,const char *authorHex);
|
int rhizome_extract_privatekey(rhizome_manifest *m, const unsigned char *authorSid);
|
||||||
int rhizome_verify_bundle_privatekey(rhizome_manifest *m);
|
int rhizome_verify_bundle_privatekey(rhizome_manifest *m);
|
||||||
int rhizome_queue_ignore_manifest(rhizome_manifest *m,
|
int rhizome_queue_ignore_manifest(rhizome_manifest *m,
|
||||||
struct sockaddr_in *peerip,int timeout);
|
struct sockaddr_in *peerip,int timeout);
|
||||||
|
@ -471,15 +471,7 @@ int rhizome_manifest_pack_variables(rhizome_manifest *m)
|
|||||||
int rhizome_manifest_selfsign(rhizome_manifest *m)
|
int rhizome_manifest_selfsign(rhizome_manifest *m)
|
||||||
{
|
{
|
||||||
if (!m->haveSecret) return WHY("Need private key to sign manifest");
|
if (!m->haveSecret) return WHY("Need private key to sign manifest");
|
||||||
|
rhizome_signature *sig = rhizome_sign_hash(m, m->cryptoSignSecret);
|
||||||
/* XXX we have to pass it in as hex, but then we just turn it into bytes
|
|
||||||
anyway. */
|
|
||||||
char secret[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES*2+1];
|
|
||||||
rhizome_bytes_to_hex_upper(m->cryptoSignSecret,secret,
|
|
||||||
crypto_sign_edwards25519sha512batch_SECRETKEYBYTES);
|
|
||||||
|
|
||||||
rhizome_signature *sig=rhizome_sign_hash(m,secret);
|
|
||||||
|
|
||||||
if (!sig) return WHY("rhizome_sign_hash() failed.");
|
if (!sig) return WHY("rhizome_sign_hash() failed.");
|
||||||
|
|
||||||
/* Append signature to end of manifest data */
|
/* Append signature to end of manifest data */
|
||||||
|
@ -121,7 +121,7 @@ int rhizome_find_keypair_bytes(unsigned char *p,unsigned char *s) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int rhizome_bk_xor(const char *author,
|
int rhizome_bk_xor(const unsigned char *authorSid, // binary
|
||||||
unsigned char bid[crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES],
|
unsigned char bid[crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES],
|
||||||
unsigned char bkin[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES],
|
unsigned char bkin[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES],
|
||||||
unsigned char bkout[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES])
|
unsigned char bkout[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES])
|
||||||
@ -130,11 +130,9 @@ int rhizome_bk_xor(const char *author,
|
|||||||
crypto_hash_sha512_BYTES)
|
crypto_hash_sha512_BYTES)
|
||||||
return WHY("BK needs to be longer than it can be");
|
return WHY("BK needs to be longer than it can be");
|
||||||
|
|
||||||
unsigned char authorSid[SID_SIZE];
|
|
||||||
if (stowSid(authorSid,0,author)) return WHYF("stowSid(%s) failed", author);
|
|
||||||
int cn=0,in=0,kp=0;
|
int cn=0,in=0,kp=0;
|
||||||
if (!keyring_find_sid(keyring,&cn,&in,&kp,authorSid))
|
if (!keyring_find_sid(keyring,&cn,&in,&kp,authorSid))
|
||||||
return WHYF("keyring_find_sid() couldn't find %s. Have you unlocked that identity?", author);
|
return WHYF("keyring_find_sid() couldn't find %s. Have you unlocked that identity?", alloca_tohex_sid(authorSid));
|
||||||
for(kp=0;kp<keyring->contexts[cn]->identities[in]->keypair_count;kp++)
|
for(kp=0;kp<keyring->contexts[cn]->identities[in]->keypair_count;kp++)
|
||||||
if (keyring->contexts[cn]->identities[in]->keypairs[kp]->type==KEYTYPE_RHIZOME)
|
if (keyring->contexts[cn]->identities[in]->keypairs[kp]->type==KEYTYPE_RHIZOME)
|
||||||
break;
|
break;
|
||||||
@ -172,23 +170,19 @@ int rhizome_bk_xor(const char *author,
|
|||||||
the supplied SID is correct.
|
the supplied SID is correct.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
int rhizome_extract_privatekey(rhizome_manifest *m, const char *authorHex)
|
int rhizome_extract_privatekey(rhizome_manifest *m, const unsigned char *authorSid)
|
||||||
{
|
{
|
||||||
if (!authorHex) return -1; // WHY("No author SID supplied");
|
|
||||||
char *bk = rhizome_manifest_get(m, "BK", NULL, 0);
|
char *bk = rhizome_manifest_get(m, "BK", NULL, 0);
|
||||||
if (!bk) return WHY("Cannot obtain private key as manifest lacks BK field");
|
if (!bk) return WHY("missing BK field");
|
||||||
|
unsigned char bkBytes[RHIZOME_BUNDLE_KEY_BYTES];
|
||||||
unsigned char bkBytes[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES];
|
if (fromhexstr(bkBytes, bk, RHIZOME_BUNDLE_KEY_BYTES) == -1)
|
||||||
if (stowBytes(bkBytes,bk,crypto_sign_edwards25519sha512batch_SECRETKEYBYTES))
|
return WHYF("invalid BK field: %s", bk);
|
||||||
return WHY("Failed to make packed version of BK. Is it a valid hex string of the correct length?");
|
if (rhizome_bk_xor(authorSid,
|
||||||
|
|
||||||
if (rhizome_bk_xor(authorHex,
|
|
||||||
m->cryptoSignPublic,
|
m->cryptoSignPublic,
|
||||||
bkBytes,
|
bkBytes,
|
||||||
m->cryptoSignSecret))
|
m->cryptoSignSecret))
|
||||||
return WHY("rhizome_bk_xor() failed");
|
return WHY("rhizome_bk_xor() failed");
|
||||||
return rhizome_verify_bundle_privatekey(m);
|
return rhizome_verify_bundle_privatekey(m);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify the validity of the manifest's sccret key.
|
/* Verify the validity of the manifest's sccret key.
|
||||||
@ -236,14 +230,12 @@ int rhizome_verify_bundle_privatekey(rhizome_manifest *m)
|
|||||||
#endif //!ge25519
|
#endif //!ge25519
|
||||||
}
|
}
|
||||||
|
|
||||||
rhizome_signature *rhizome_sign_hash(rhizome_manifest *m,const char *author)
|
rhizome_signature *rhizome_sign_hash(rhizome_manifest *m, const unsigned char *authorSid)
|
||||||
{
|
{
|
||||||
unsigned char *hash=m->manifesthash;
|
unsigned char *hash=m->manifesthash;
|
||||||
unsigned char *publicKeyBytes=m->cryptoSignPublic;
|
unsigned char *publicKeyBytes=m->cryptoSignPublic;
|
||||||
|
|
||||||
if (!m->haveSecret)
|
if (!m->haveSecret && rhizome_extract_privatekey(m, authorSid) == -1) {
|
||||||
if (rhizome_extract_privatekey(m,author))
|
|
||||||
{
|
|
||||||
WHY("Cannot find secret key to sign manifest data.");
|
WHY("Cannot find secret key to sign manifest data.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -699,10 +699,8 @@ int rhizome_list_manifests(const char *service, const char *sender_sid, const ch
|
|||||||
const char *blob_service = rhizome_manifest_get(m, "service", NULL, 0);
|
const char *blob_service = rhizome_manifest_get(m, "service", NULL, 0);
|
||||||
if (service[0] && !(blob_service && strcasecmp(service, blob_service) == 0))
|
if (service[0] && !(blob_service && strcasecmp(service, blob_service) == 0))
|
||||||
match = 0;
|
match = 0;
|
||||||
|
|
||||||
const char *blob_sender = rhizome_manifest_get(m, "sender", NULL, 0);
|
const char *blob_sender = rhizome_manifest_get(m, "sender", NULL, 0);
|
||||||
const char *blob_recipient = rhizome_manifest_get(m, "recipient", NULL, 0);
|
const char *blob_recipient = rhizome_manifest_get(m, "recipient", NULL, 0);
|
||||||
|
|
||||||
if (match && sender_sid[0]) {
|
if (match && sender_sid[0]) {
|
||||||
if (!(blob_sender && strcasecmp(sender_sid, blob_sender) == 0))
|
if (!(blob_sender && strcasecmp(sender_sid, blob_sender) == 0))
|
||||||
match = 0;
|
match = 0;
|
||||||
@ -711,7 +709,6 @@ int rhizome_list_manifests(const char *service, const char *sender_sid, const ch
|
|||||||
if (!(blob_recipient && strcasecmp(recipient_sid, blob_recipient) == 0))
|
if (!(blob_recipient && strcasecmp(recipient_sid, blob_recipient) == 0))
|
||||||
match = 0;
|
match = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
const char *blob_name = rhizome_manifest_get(m, "name", NULL, 0);
|
const char *blob_name = rhizome_manifest_get(m, "name", NULL, 0);
|
||||||
long long blob_date = rhizome_manifest_get_ll(m, "date");
|
long long blob_date = rhizome_manifest_get_ll(m, "date");
|
||||||
@ -938,10 +935,7 @@ int rhizome_store_file(rhizome_manifest *m,const unsigned char *key)
|
|||||||
|
|
||||||
void rhizome_bytes_to_hex_upper(unsigned const char *in, char *out, int byteCount)
|
void rhizome_bytes_to_hex_upper(unsigned const char *in, char *out, int byteCount)
|
||||||
{
|
{
|
||||||
int i=0;
|
(void) tohex(out, in, byteCount);
|
||||||
for(i = 0; i != byteCount * 2 ; ++i)
|
|
||||||
out[i] = nybltochar_upper((in[i >> 1] >> (4 - 4 * (i & 1))) & 0xf);
|
|
||||||
out[i] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int rhizome_update_file_priority(const char *fileid)
|
int rhizome_update_file_priority(const char *fileid)
|
||||||
|
12
serval.h
12
serval.h
@ -256,7 +256,7 @@ int keyring_set_did(keyring_identity *id,char *did,char *name);
|
|||||||
int keyring_sanitise_position(keyring_file *k,int *cn,int *in,int *kp);
|
int keyring_sanitise_position(keyring_file *k,int *cn,int *in,int *kp);
|
||||||
int keyring_next_identity(keyring_file *k,int *cn,int *in,int *kp);
|
int keyring_next_identity(keyring_file *k,int *cn,int *in,int *kp);
|
||||||
int keyring_find_did(keyring_file *k,int *cn,int *in,int *kp,char *did);
|
int keyring_find_did(keyring_file *k,int *cn,int *in,int *kp,char *did);
|
||||||
int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp,unsigned char *sid);
|
int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp, const unsigned char *sid);
|
||||||
unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid,
|
unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid,
|
||||||
unsigned char **sas_public);
|
unsigned char **sas_public);
|
||||||
unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid);
|
unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid);
|
||||||
@ -385,8 +385,6 @@ extern struct mphlr_variable vars[];
|
|||||||
#define ACTION_PAD 0xfe
|
#define ACTION_PAD 0xfe
|
||||||
#define ACTION_EOT 0xff
|
#define ACTION_EOT 0xff
|
||||||
|
|
||||||
extern int hexdigit[16];
|
|
||||||
|
|
||||||
/* Make sure we have space to put bytes of the packet as we go along */
|
/* Make sure we have space to put bytes of the packet as we go along */
|
||||||
#define CHECK_PACKET_LEN(B) {if (((*packet_len)+(B))>=packet_maxlen) { return WHY("Packet composition ran out of space."); } }
|
#define CHECK_PACKET_LEN(B) {if (((*packet_len)+(B))>=packet_maxlen) { return WHY("Packet composition ran out of space."); } }
|
||||||
|
|
||||||
@ -399,9 +397,12 @@ int confParseBoolean(const char *text, const char *option_name);
|
|||||||
|
|
||||||
int recvwithttl(int sock,unsigned char *buffer,int bufferlen,int *ttl,
|
int recvwithttl(int sock,unsigned char *buffer,int bufferlen,int *ttl,
|
||||||
struct sockaddr *recvaddr,unsigned int *recvaddrlen);
|
struct sockaddr *recvaddr,unsigned int *recvaddrlen);
|
||||||
|
|
||||||
|
char *tohex(char *dstHex, const unsigned char *srcBinary, size_t bytes);
|
||||||
|
size_t fromhex(unsigned char *dstBinary, const char *srcHex, size_t bytes);
|
||||||
|
int fromhexstr(unsigned char *dstBinary, const char *srcHex, size_t bytes);
|
||||||
int validateSid(const char *sid);
|
int validateSid(const char *sid);
|
||||||
int stowSid(unsigned char *packet, int ofs, const char *sid);
|
int stowSid(unsigned char *packet, int ofs, const char *sid);
|
||||||
int stowBytes(unsigned char *packet, const char *in,int count);
|
|
||||||
int stowDid(unsigned char *packet,int *ofs,char *did);
|
int stowDid(unsigned char *packet,int *ofs,char *did);
|
||||||
int isFieldZeroP(unsigned char *packet,int start,int count);
|
int isFieldZeroP(unsigned char *packet,int start,int count);
|
||||||
void srandomdev();
|
void srandomdev();
|
||||||
@ -764,6 +765,9 @@ long long debugFlagMask(const char *flagname);
|
|||||||
char *catv(const char *data, char *buf, size_t len);
|
char *catv(const char *data, char *buf, size_t len);
|
||||||
int dump(char *name,unsigned char *addr,int len);
|
int dump(char *name,unsigned char *addr,int len);
|
||||||
|
|
||||||
|
#define alloca_tohex(buf,len) tohex((char *)alloca((len)*2+1), (buf), (len))
|
||||||
|
#define alloca_tohex_sid(sid) alloca_tohex((sid), SID_SIZE)
|
||||||
|
|
||||||
const char *trimbuildpath(const char *s);
|
const char *trimbuildpath(const char *s);
|
||||||
|
|
||||||
#define LOGF(L,F,...) logMessage(L, __FILE__, __LINE__, __FUNCTION__, F, ##__VA_ARGS__)
|
#define LOGF(L,F,...) logMessage(L, __FILE__, __LINE__, __FUNCTION__, F, ##__VA_ARGS__)
|
||||||
|
@ -64,7 +64,7 @@ assert_rhizome_list() {
|
|||||||
local filename
|
local filename
|
||||||
for filename; do
|
for filename; do
|
||||||
unpack_manifest_for_grep "$filename"
|
unpack_manifest_for_grep "$filename"
|
||||||
assertStdoutGrep --matches=1 "^$re_service:$re_manifestid:.*:$re_filehash:$re_sender:$re_recipient:$re_name\$"
|
assertStdoutGrep --matches=1 "^$re_service:$re_manifestid:.*:$re_filesize:$re_filehash:$re_sender:$re_recipient:$re_name\$"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,19 +78,20 @@ assert_stdout_add_file() {
|
|||||||
assertStdoutGrep --matches=1 "^manifestid:$re_manifestid\$"
|
assertStdoutGrep --matches=1 "^manifestid:$re_manifestid\$"
|
||||||
assertStdoutGrep --matches=1 "^secret:$re_secret\$"
|
assertStdoutGrep --matches=1 "^secret:$re_secret\$"
|
||||||
assertStdoutGrep --matches=1 "^filehash:$re_filehash\$"
|
assertStdoutGrep --matches=1 "^filehash:$re_filehash\$"
|
||||||
assertStdoutGrep --matches=1 "^filesize:$re_size\$"
|
assertStdoutGrep --matches=1 "^filesize:$re_filesize\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
unpack_manifest_for_grep() {
|
unpack_manifest_for_grep() {
|
||||||
local filename="$1"
|
local filename="$1"
|
||||||
re_service="$rexp_service"
|
re_service="$rexp_service"
|
||||||
if [ -n "$filename" ]; then
|
if [ -n "$filename" ]; then
|
||||||
re_size=$(( $(cat "$filename" | wc -c) + 0 ))
|
re_filesize=$(( $(cat "$filename" | wc -c) + 0 ))
|
||||||
else
|
else
|
||||||
re_size=0
|
re_filesize=0
|
||||||
fi
|
fi
|
||||||
compute_filehash re_filehash "$filename"
|
compute_filehash re_filehash "$filename"
|
||||||
re_manifestid="$rexp_manifestid"
|
re_manifestid="$rexp_manifestid"
|
||||||
|
re_version="$rexp_version"
|
||||||
re_secret="$rexp_bundlesecret"
|
re_secret="$rexp_bundlesecret"
|
||||||
re_name=$(escape_grep_basic "${filename##*/}")
|
re_name=$(escape_grep_basic "${filename##*/}")
|
||||||
# If there is a manifest file that looks like it matches this payload
|
# If there is a manifest file that looks like it matches this payload
|
||||||
@ -98,6 +99,7 @@ unpack_manifest_for_grep() {
|
|||||||
local filehash=$(sed -n -e '/^filehash=/s///p' "$filename.manifest" 2>/dev/null)
|
local filehash=$(sed -n -e '/^filehash=/s///p' "$filename.manifest" 2>/dev/null)
|
||||||
if [ "$filehash" = "$re_filehash" ]; then
|
if [ "$filehash" = "$re_filehash" ]; then
|
||||||
re_manifestid=$(sed -n -e '/^id=/s///p' "$filename.manifest")
|
re_manifestid=$(sed -n -e '/^id=/s///p' "$filename.manifest")
|
||||||
|
re_version=$(sed -n -e '/^version=/s///p' "$filename.manifest")
|
||||||
re_service=$(sed -n -e '/^service=/s///p' "$filename.manifest")
|
re_service=$(sed -n -e '/^service=/s///p' "$filename.manifest")
|
||||||
re_service=$(escape_grep_basic "$re_service")
|
re_service=$(escape_grep_basic "$re_service")
|
||||||
re_sender=$(sed -n -e '/^sender=/s///p' "$filename.manifest")
|
re_sender=$(sed -n -e '/^sender=/s///p' "$filename.manifest")
|
||||||
@ -255,10 +257,10 @@ test_AddNonExistManifest() {
|
|||||||
assertGrep file1.manifest "^BK=$rexp_bundlekey\$"
|
assertGrep file1.manifest "^BK=$rexp_bundlekey\$"
|
||||||
assertGrep file1.manifest '^name=file1$'
|
assertGrep file1.manifest '^name=file1$'
|
||||||
assertGrep file1.manifest "^date=$rexp_date\$"
|
assertGrep file1.manifest "^date=$rexp_date\$"
|
||||||
assertGrep file1.manifest "^version=$rexp_version\$"
|
assertGrep file1.manifest "^version=$re_version\$"
|
||||||
assertGrep file1.manifest "^id=$re_manifestid\$"
|
assertGrep file1.manifest "^id=$re_manifestid\$"
|
||||||
assertGrep file1.manifest "^filehash=$re_filehash\$"
|
assertGrep file1.manifest "^filehash=$re_filehash\$"
|
||||||
assertGrep file1.manifest "^filesize=$re_size\$"
|
assertGrep file1.manifest "^filesize=$re_filesize\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_AddManifest="Add with minimal manifest file"
|
doc_AddManifest="Add with minimal manifest file"
|
||||||
@ -277,11 +279,11 @@ test_AddManifest() {
|
|||||||
assertGrep file1.manifest '^service=file$'
|
assertGrep file1.manifest '^service=file$'
|
||||||
assertGrep file1.manifest "^BK=$rexp_bundlekey\$"
|
assertGrep file1.manifest "^BK=$rexp_bundlekey\$"
|
||||||
assertGrep file1.manifest '^name=wah$'
|
assertGrep file1.manifest '^name=wah$'
|
||||||
assertGrep file1.manifest "^version=$rexp_version\$"
|
assertGrep file1.manifest "^version=$re_version\$"
|
||||||
assertGrep file1.manifest '^date=12345$'
|
assertGrep file1.manifest '^date=12345$'
|
||||||
assertGrep file1.manifest "^id=$re_manifestid\$"
|
assertGrep file1.manifest "^id=$re_manifestid\$"
|
||||||
assertGrep file1.manifest "^filehash=$re_filehash\$"
|
assertGrep file1.manifest "^filehash=$re_filehash\$"
|
||||||
assertGrep file1.manifest "^filesize=$re_size\$"
|
assertGrep file1.manifest "^filesize=$re_filesize\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_AddEmpty="Add with empty payload"
|
doc_AddEmpty="Add with empty payload"
|
||||||
@ -297,7 +299,7 @@ test_AddEmpty() {
|
|||||||
assertGrep .manifest '^service=file$'
|
assertGrep .manifest '^service=file$'
|
||||||
assertGrep .manifest "^BK=$rexp_bundlekey\$"
|
assertGrep .manifest "^BK=$rexp_bundlekey\$"
|
||||||
assertGrep .manifest '^name=$'
|
assertGrep .manifest '^name=$'
|
||||||
assertGrep .manifest "^version=$rexp_version\$"
|
assertGrep .manifest "^version=$re_version\$"
|
||||||
assertGrep .manifest "^date=$rexp_date\$"
|
assertGrep .manifest "^date=$rexp_date\$"
|
||||||
assertGrep .manifest "^id=$re_manifestid\$"
|
assertGrep .manifest "^id=$re_manifestid\$"
|
||||||
assertGrep .manifest "^filehash=$re_filehash\$"
|
assertGrep .manifest "^filehash=$re_filehash\$"
|
||||||
|
Loading…
Reference in New Issue
Block a user