Browse Source

Carry typed encrypted metadata with PM file transfers

master
evgeny 1 week ago
parent
commit
c1185b62c1
  1. 29
      src/dm/dm_media.c
  2. 6
      src/dm/dm_media.h

29
src/dm/dm_media.c

@ -43,7 +43,9 @@ struct dm_file_job {
struct file_transfer_op* transfer; struct file_transfer_op* transfer;
uint8_t id[16], key[32], hash[32]; uint8_t id[16], key[32], hash[32];
uint64_t author, size; uint64_t author, size;
char conv[64], name[256]; char conv[64];
struct attachment_info info;
int remove_source;
char input[1024], cipher[1024], plain[1024], temp[1024], output[1024]; char input[1024], cipher[1024], plain[1024], temp[1024], output[1024];
int error; int error;
}; };
@ -364,6 +366,7 @@ static void dm_file_work(void* arg) {
return; return;
} }
if (job->work == DM_FILE_PREPARE && dm_file_copy(job->input, job->plain)) return; if (job->work == DM_FILE_PREPARE && dm_file_copy(job->input, job->plain)) return;
if (job->work == DM_FILE_PREPARE && job->remove_source && dm_file_remove(job->input)) return;
FILE* in = fopen(job->work == DM_FILE_PREPARE ? job->plain : job->cipher, "rb"); FILE* in = fopen(job->work == DM_FILE_PREPARE ? job->plain : job->cipher, "rb");
FILE* out = job->work == DM_FILE_CUSTODY ? NULL : fopen(job->temp, "wb"); FILE* out = job->work == DM_FILE_CUSTODY ? NULL : fopen(job->temp, "wb");
if (!in || (job->work != DM_FILE_CUSTODY && !out)) { if (!in || (job->work != DM_FILE_CUSTODY && !out)) {
@ -420,13 +423,13 @@ static void dm_file_done(void* arg, int error) {
int custody = job->work == DM_FILE_CUSTODY; int custody = job->work == DM_FILE_CUSTODY;
if (error || job->error || media->closing) goto fail; if (error || job->error || media->closing) goto fail;
if (job->work == DM_FILE_PREPARE) { if (job->work == DM_FILE_PREPARE) {
uint8_t data[DM_MEDIA_DESC_SIZE + 256]; uint8_t data[DM_MEDIA_DESC_SIZE + ATTACHMENT_WIRE_MAX];
memcpy(data, job->id, 16); memcpy(data + 16, &job->size, 8); memcpy(data + 24, job->hash, 32); memcpy(data, job->id, 16); memcpy(data + 16, &job->size, 8); memcpy(data + 24, job->hash, 32);
size_t n = strlen(job->name); int n = attachment_encode(&job->info, data + DM_MEDIA_DESC_SIZE, ATTACHMENT_WIRE_MAX);
memcpy(data + DM_MEDIA_DESC_SIZE, job->name, n); if (n < 0) goto fail;
if (dm_send(inst, job->conv, "file", data, (uint32_t)(DM_MEDIA_DESC_SIZE + n))) goto fail; if (dm_send(inst, job->conv, "file", data, (uint32_t)(DM_MEDIA_DESC_SIZE + n))) goto fail;
DEBUG_INFO(DEBUG_CATEGORY_DM, "dm_media: prepared conv=%s bytes=%llu name=%s", job->conv, DEBUG_INFO(DEBUG_CATEGORY_DM, "dm_media: prepared conv=%s bytes=%llu name=%s", job->conv,
(unsigned long long)job->size, job->name); (unsigned long long)job->size, job->info.name);
dm_job_free(job); dm_job_free(job);
return; return;
} }
@ -566,10 +569,9 @@ static int dm_file_lookup(void* arg, uint64_t group, uint64_t peer, const uint8_
} }
/* Путь исходника копируется; caller может освободить строку после возврата. */ /* Путь исходника копируется; caller может освободить строку после возврата. */
int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path, const char* name) { int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path, const struct attachment_info* info) {
struct dm_media_state* media = inst ? inst->dm_media : NULL; struct dm_media_state* media = inst ? inst->dm_media : NULL;
if (!media || media->closing || !inst->media_async || !conv || !path || !name || !*name || strlen(name) > 255 || if (!media || media->closing || !inst->media_async || !conv || !path || attachment_validate(info) || strlen(path) >= 1024) {
strchr(name, '/') || strchr(name, '\\') || !strcmp(name, ".") || !strcmp(name, "..") || strlen(path) >= 1024) {
DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: invalid file send arguments/state"); DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: invalid file send arguments/state");
return -1; return -1;
} }
@ -579,7 +581,7 @@ int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path,
struct dm_file_job* job = u_calloc(1, sizeof(*job)); struct dm_file_job* job = u_calloc(1, sizeof(*job));
if (!job) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: preparation allocation failed"); return -1; } if (!job) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: preparation allocation failed"); return -1; }
job->media = media; job->work = DM_FILE_PREPARE; job->author = inst->node_id; job->media = media; job->work = DM_FILE_PREPARE; job->author = inst->node_id;
snprintf(job->conv, sizeof(job->conv), "%s", conv); snprintf(job->name, sizeof(job->name), "%s", name); snprintf(job->conv, sizeof(job->conv), "%s", conv); job->info = *info;
snprintf(job->input, sizeof(job->input), "%s", path); snprintf(job->input, sizeof(job->input), "%s", path);
sqlite3_stmt* st = dm_media_prepare(inst, "SELECT peer_x25519 FROM dm_conversations WHERE conv_id=?"); sqlite3_stmt* st = dm_media_prepare(inst, "SELECT peer_x25519 FROM dm_conversations WHERE conv_id=?");
if (!st) { u_free(job); return -1; } if (!st) { u_free(job); return -1; }
@ -596,7 +598,7 @@ int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path,
OPENSSL_cleanse(job->key, sizeof(job->key)); u_free(job); return -1; OPENSSL_cleanse(job->key, sizeof(job->key)); u_free(job); return -1;
} }
job->next = media->jobs; media->jobs = job; job->next = media->jobs; media->jobs = job;
DEBUG_INFO(DEBUG_CATEGORY_DM, "dm_media: preparing conv=%s name=%s", conv, name); DEBUG_INFO(DEBUG_CATEGORY_DM, "dm_media: preparing conv=%s kind=%d name=%s", conv, info->kind, info->name);
media_async_submit(inst->media_async, inst->ua, dm_file_work, job, dm_file_done, job); media_async_submit(inst->media_async, inst->ua, dm_file_work, job, dm_file_done, job);
return 0; return 0;
} }
@ -604,7 +606,12 @@ int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path,
void dm_send_file_trampoline(void* arg) { void dm_send_file_trampoline(void* arg) {
struct dm_file_req* req = arg; struct dm_file_req* req = arg;
if (!req) return; if (!req) return;
dm_send_file(req->inst, req->conv, req->path, req->name); /* Передача source во владение возможна только при принятой задаче. */
if (!dm_send_file(req->inst, req->conv, req->path, &req->info)) {
struct dm_media_state* media = req->inst->dm_media;
if (media->jobs && media->jobs->work == DM_FILE_PREPARE && !strcmp(media->jobs->input, req->path))
media->jobs->remove_source = req->remove_source;
}
u_free(req); u_free(req);
} }

6
src/dm/dm_media.h

@ -9,6 +9,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "../media_async/attachment.h"
struct UTUN_INSTANCE; struct UTUN_INSTANCE;
@ -31,12 +32,13 @@ void dm_media_quiesce(struct UTUN_INSTANCE* inst);
void dm_media_destroy(struct UTUN_INSTANCE* inst); void dm_media_destroy(struct UTUN_INSTANCE* inst);
/* Подготовить копию и enqueue file-сообщение асинхронно. 0=задача принята. */ /* Подготовить копию и enqueue file-сообщение асинхронно. 0=задача принята. */
int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path, const char* display_name); int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path, const struct attachment_info* info);
struct dm_file_req { struct dm_file_req {
struct UTUN_INSTANCE* inst; struct UTUN_INSTANCE* inst;
char conv[64]; char conv[64];
char path[1024]; char path[1024];
char name[256]; struct attachment_info info;
int remove_source; /* Только принадлежащий приложению временный файл. */
}; };
void dm_send_file_trampoline(void* arg); void dm_send_file_trampoline(void* arg);

Loading…
Cancel
Save