|
|
|
|
@ -24,6 +24,7 @@
|
|
|
|
|
#include "../src/routing_layer/etcp_router.h" |
|
|
|
|
#include "../src/transport_layer/secure_channel.h" |
|
|
|
|
#include "../src/transport_layer/etcp.h" |
|
|
|
|
#include "../src/media_delivery/file_transfer.h" |
|
|
|
|
#include "test_utils.h" |
|
|
|
|
|
|
|
|
|
#define GROUP 4242424242424243ULL |
|
|
|
|
@ -166,6 +167,48 @@ static void control(struct media_test* t, int dst, uint64_t source, uint8_t cmd,
|
|
|
|
|
inst->router_bindings.callbacks[ETCP_RT_ID_DM_MEDIA](conn, e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void cancelled(void* arg, int error) { |
|
|
|
|
int* calls = arg; |
|
|
|
|
*calls += error == -2 ? 1 : 100; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Ошибки регистрации не расходуют seq; квота проверяется до получения байтов. */ |
|
|
|
|
static int protocol_checks(struct media_test* t) { |
|
|
|
|
struct UTUN_INSTANCE* a = t->nodes[A]; |
|
|
|
|
struct UTUN_INSTANCE* m = t->nodes[M]; |
|
|
|
|
const uint8_t* desc = dm_message_media(t->body, t->body_len); |
|
|
|
|
uint8_t input[DM_MEDIA_DESC_SIZE + 1]; |
|
|
|
|
memcpy(input, desc, DM_MEDIA_DESC_SIZE); input[DM_MEDIA_DESC_SIZE] = 'x'; |
|
|
|
|
if (sqlite3_exec(a->topo_sqlite_db, "CREATE TEMP TRIGGER reject_dm_file BEFORE INSERT ON dm_files" |
|
|
|
|
" BEGIN SELECT RAISE(ABORT,'injected media registration failure'); END", NULL, NULL, NULL)) return -1; |
|
|
|
|
int rejected = dm_send(a, t->conv, "file", input, sizeof(input)) < 0; |
|
|
|
|
if (sqlite3_exec(a->topo_sqlite_db, "DROP TRIGGER reject_dm_file", NULL, NULL, NULL)) return -1; |
|
|
|
|
if (!rejected || value(a, "SELECT last_out_seq FROM dm_conversations") != 1 || |
|
|
|
|
value(a, "SELECT count(*) FROM dm_messages") != 1 || value(a, "SELECT count(*) FROM dm_outbox") != 0) return -1; |
|
|
|
|
char json[8192]; size_t len; |
|
|
|
|
if (dm_list_messages_json(a, t->conv, 200, 0, json, sizeof(json), &len) || |
|
|
|
|
!strstr(json, "\"media_status\":\"delivered\"") || !strstr(json, "\"media_path\":")) return -1; |
|
|
|
|
uint8_t request[8 + sizeof(t->body)]; |
|
|
|
|
memcpy(request, &t->ids[B], 8); memcpy(request + 8, t->body, t->body_len); |
|
|
|
|
uint8_t* metadata = (uint8_t*)dm_message_media(request + 8, t->body_len); |
|
|
|
|
metadata[0] ^= 0x80; |
|
|
|
|
uint64_t size = 2 * 1024 * 1024; |
|
|
|
|
memcpy(metadata + 16, &size, 8); |
|
|
|
|
if (sc_ed25519_sign(a->my_ed25519_privkey, request + 8, t->body_len - DM_MSG_SIG_SIZE, |
|
|
|
|
request + 8 + t->body_len - DM_MSG_SIG_SIZE) || chat_setting_set(m, "dm_media_storage_mb", "1")) return -1; |
|
|
|
|
control(t, M, t->ids[S], DM_MEDIA_STORE, request, 8 + t->body_len); |
|
|
|
|
if (value(m, "SELECT count(*) FROM dm_custody") != 0 || chat_setting_set(m, "dm_media_storage_mb", "1024")) return -1; |
|
|
|
|
char path[768]; snprintf(path, sizeof(path), "%s/cancelled.download", t->dir); |
|
|
|
|
int calls = 0; |
|
|
|
|
struct file_transfer_op* op = file_transfer_pull(t->nodes[B]->file_transfer, GROUP, t->ids[A], t->id, |
|
|
|
|
dm_media_cipher_size(FILE_BYTES), path, cancelled, &calls); |
|
|
|
|
if (!op) return -1; |
|
|
|
|
file_transfer_cancel_object(t->nodes[B]->file_transfer, t->id); |
|
|
|
|
if (calls != 1) return -1; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DM, "media protocol checks passed: SQL rollback, quota, JSON state, CM operation cancellation"); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Таймер служит heartbeat: большие криптозадачи не должны останавливать сценарий. */ |
|
|
|
|
static void tick(void* arg) { |
|
|
|
|
struct media_test* t = arg; |
|
|
|
|
@ -193,6 +236,7 @@ static void tick(void* arg) {
|
|
|
|
|
value(m, "SELECT count(*) FROM dm_custody") != 0) { failure(t, "direct transfer/custody isolation"); return; } |
|
|
|
|
uint8_t bad[DM_MEDIA_RECEIPT_SIZE]; memcpy(bad, t->receipt, sizeof(bad)); bad[56] ^= 1; |
|
|
|
|
if (!dm_media_verify_receipt(a, bad, t->body, t->body_len)) { failure(t, "forged media receipt accepted"); return; } |
|
|
|
|
if (protocol_checks(t)) { failure(t, "media protocol invariants"); return; } |
|
|
|
|
utun_instance_destroy(b); t->nodes[B] = NULL; t->phase++; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
|