msg b64: base64-encode display prefix in d-field to avoid pipe/quote breaking parse

b64_encode/decode (URL-safe A-Za-z0-9-_) in chat_core_priv.h
on_media_registered encodes msg_data before full_data
on_msg_inserted/chat_core_attachment_download decode base_filename
android_jni_bridge decodes prefix for UI display
This commit is contained in:
evgeny committed 2026-08-03 23:02:49 +03:00
1 parent 6a02a16543
commit ea6eeae210
3 files changed
+76 -1

No files matched your search

+54
View File
@@ -16,9 +16,63 @@
#include <sqlite3.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#define CC_ID "chat_core"
/* ── Base64 encode/decode (URL-safe, used for msg "d" field prefix) ── */
static const char B64_ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
static inline int b64_decode_char(char c) {
if (c >= 'A' && c <= 'Z') return c - 'A';
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
if (c >= '0' && c <= '9') return c - '0' + 52;
if (c == '-') return 62;
if (c == '_') return 63;
return -1;
}
static inline size_t b64_encode(const uint8_t* src, size_t src_len, char* dst, size_t dst_cap) {
size_t out = 0;
for (size_t i = 0; i < src_len; i += 3) {
if (out + 4 > dst_cap) break;
uint32_t v = (uint32_t)src[i] << 16;
if (i + 1 < src_len) v |= (uint32_t)src[i + 1] << 8;
if (i + 2 < src_len) v |= (uint32_t)src[i + 2];
dst[out++] = B64_ALPHABET[(v >> 18) & 0x3F];
dst[out++] = B64_ALPHABET[(v >> 12) & 0x3F];
dst[out++] = (i + 1 < src_len) ? B64_ALPHABET[(v >> 6) & 0x3F] : '=';
dst[out++] = (i + 2 < src_len) ? B64_ALPHABET[v & 0x3F] : '=';
}
return out;
}
static inline size_t b64_decode(const char* src, size_t src_len, uint8_t* dst, size_t dst_cap) {
size_t out = 0;
int vals[4]; size_t vi = 0;
for (size_t i = 0; i < src_len && out < dst_cap; i++) {
if (src[i] == '=') break;
int v = b64_decode_char(src[i]);
if (v < 0) continue;
vals[vi++] = v;
if (vi == 4) {
dst[out++] = (uint8_t)((vals[0] << 2) | (vals[1] >> 4));
if (out < dst_cap) dst[out++] = (uint8_t)((vals[1] << 4) | (vals[2] >> 2));
if (out < dst_cap && i + 1 < src_len && src[i + 1] != '=')
dst[out++] = (uint8_t)((vals[2] << 6) | vals[3]);
vi = 0;
}
}
if (vi == 3 && out < dst_cap) {
dst[out++] = (uint8_t)((vals[0] << 2) | (vals[1] >> 4));
if (out < dst_cap) dst[out++] = (uint8_t)((vals[1] << 4) | (vals[2] >> 2));
} else if (vi == 2 && out < dst_cap) {
dst[out++] = (uint8_t)((vals[0] << 2) | (vals[1] >> 4));
}
return out;
}
/* ── Глобальное состояние (определено в chat_core.c) ── */
struct chat_core_ctx {
+9 -1
View File
@@ -116,7 +116,10 @@ static void on_media_registered(void* arg, int err, const struct media_index_res
if (!full_data) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: data alloc fail", CC_ID); u_free(mctx); return; }
size_t off = 0;
if (base_len > 0) { memcpy(full_data + off, mctx->msg_data, base_len); off += base_len; }
if (base_len > 0) {
char b64[2048]; size_t b64len = b64_encode(mctx->msg_data, base_len, b64, sizeof(b64));
memcpy(full_data + off, b64, b64len); off += b64len;
}
off += snprintf(full_data + off, fdcap - off, "|%lld|%lld|%d|",
(long long)result->file_size, (long long)result->block_size, nb);
for (int i = 0; i < 16; i++) off += snprintf(full_data + off, fdcap - off, "%02x", result->media_id[i]);
@@ -549,6 +552,9 @@ void on_msg_inserted(struct DB_SYNC_INSTANCE* si, uint64_t record_ts, const char
while (body[bfi] && body[bfi] != '|' && bfi < sizeof(base_filename) - 1)
base_filename[bfi++] = body[bfi];
base_filename[bfi] = '\0';
/* base64-decode display prefix (encoded in on_media_registered) */
uint8_t dec[256]; int dlen = (int)b64_decode(base_filename, bfi, dec, sizeof(dec));
if (dlen > 0 && dlen < (int)sizeof(base_filename)) { memcpy(base_filename, dec, (size_t)dlen); base_filename[dlen] = '\0'; }
if (bfi == 0) snprintf(base_filename, sizeof(base_filename), "file");
const uint8_t* sig_field = strstr(data, "\"sig\":\"");
@@ -630,6 +636,8 @@ void chat_core_attachment_download(const char* channel_id, int64_t msg_id) {
while (body[bfi] && body[bfi] != '|' && bfi < sizeof(base_filename) - 1)
base_filename[bfi++] = body[bfi];
base_filename[bfi] = '\0';
uint8_t dec[256]; int dlen = (int)b64_decode(base_filename, bfi, dec, sizeof(dec));
if (dlen > 0 && dlen < (int)sizeof(base_filename)) { memcpy(base_filename, dec, (size_t)dlen); base_filename[dlen] = '\0'; }
if (bfi == 0) snprintf(base_filename, sizeof(base_filename), "file");
uint8_t author_sig[64]; memcpy(author_sig, sig_blob, 64);