fix(chat): commit avatar updates before notification and validate SQL reads
This commit is contained in:
1 parent
bc41bb68b6
commit
e0598ccc22
3 files changed
+212
-108
No files matched your search
@@ -10,6 +10,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#define PEERS_JOIN_SIG_SIZE 64
|
||||
#define PEERS_JOIN_TS_SIZE 8
|
||||
@@ -984,38 +985,50 @@ done:
|
||||
return result;
|
||||
}
|
||||
|
||||
int topo_node_sqlite_channel_get_priv(sqlite3* db, const char* channel_id,
|
||||
uint8_t* ed25519_priv_out) {
|
||||
if (!db || !channel_id || !ed25519_priv_out) return -1;
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(db,
|
||||
"SELECT ed25519_privkey FROM channels WHERE channel_id=?", -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
sqlite3_bind_text(stmt, 1, channel_id, -1, SQLITE_STATIC);
|
||||
if (sqlite3_step(stmt) != SQLITE_ROW) { sqlite3_finalize(stmt); return -1; }
|
||||
const uint8_t* blob = (const uint8_t*)sqlite3_column_blob(stmt, 0);
|
||||
if (!blob || sqlite3_column_bytes(stmt, 0) < 32) { sqlite3_finalize(stmt); return -1; }
|
||||
memcpy(ed25519_priv_out, blob, 32);
|
||||
sqlite3_finalize(stmt);
|
||||
return 0;
|
||||
/* Выходные ключи публикуются только после успешного завершения SELECT. */
|
||||
static int channel_private_keys(sqlite3* db, const char* channel, uint8_t* x25519, uint8_t* ed25519) {
|
||||
if (!db || !channel || !ed25519) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "channel private keys: missing argument"); return -1;
|
||||
}
|
||||
const char* sql = x25519 ? "SELECT x25519_privkey, ed25519_privkey FROM channels WHERE channel_id=?" :
|
||||
"SELECT ed25519_privkey FROM channels WHERE channel_id=?";
|
||||
sqlite3_stmt* st = NULL; uint8_t keys[64] = {0}; int columns = x25519 ? 2 : 1, result = -1;
|
||||
const char* stage = "prepare"; int rc = sqlite3_prepare_v2(db, sql, -1, &st, NULL);
|
||||
if (rc != SQLITE_OK) goto done;
|
||||
stage = "bind"; rc = sqlite3_bind_text(st, 1, channel, -1, SQLITE_STATIC); if (rc != SQLITE_OK) goto done;
|
||||
stage = "step"; rc = sqlite3_step(st); if (rc != SQLITE_ROW) goto done;
|
||||
for (int i = 0; i < columns; i++) {
|
||||
if (sqlite3_column_type(st, i) == SQLITE_NULL) { rc = SQLITE_DONE; goto done; }
|
||||
stage = "key size/type"; rc = SQLITE_CORRUPT;
|
||||
if (sqlite3_column_type(st, i) != SQLITE_BLOB || sqlite3_column_bytes(st, i) != 32) goto done;
|
||||
const void* key = sqlite3_column_blob(st, i); if (!key) { rc = SQLITE_NOMEM; goto done; }
|
||||
memcpy(keys + i * 32, key, 32);
|
||||
}
|
||||
rc = SQLITE_OK;
|
||||
done:
|
||||
{
|
||||
int final = sqlite3_finalize(st);
|
||||
if (rc == SQLITE_OK && final == SQLITE_OK) {
|
||||
if (x25519) memcpy(x25519, keys, 32);
|
||||
memcpy(ed25519, keys + (columns - 1) * 32, 32); result = 0;
|
||||
} else if (rc == SQLITE_DONE && final == SQLITE_OK) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "channel private keys unavailable channel=%s", channel);
|
||||
} else DEBUG_ERROR(DEBUG_CATEGORY_BGP, "channel private keys channel=%s stage=%s rc=%d finalize=%d: %s",
|
||||
channel, stage, rc, final, sqlite3_errmsg(db));
|
||||
}
|
||||
OPENSSL_cleanse(keys, sizeof(keys)); return result;
|
||||
}
|
||||
|
||||
int topo_node_sqlite_channel_get_priv(sqlite3* db, const char* channel_id, uint8_t* ed25519_priv_out) {
|
||||
return channel_private_keys(db, channel_id, NULL, ed25519_priv_out);
|
||||
}
|
||||
|
||||
int topo_node_sqlite_channel_get_privs(sqlite3* db, const char* channel_id,
|
||||
uint8_t* x25519_priv_out, uint8_t* ed25519_priv_out) {
|
||||
if (!db || !channel_id || !x25519_priv_out || !ed25519_priv_out) return -1;
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(db,
|
||||
"SELECT x25519_privkey, ed25519_privkey FROM channels WHERE channel_id=?", -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
sqlite3_bind_text(stmt, 1, channel_id, -1, SQLITE_STATIC);
|
||||
if (sqlite3_step(stmt) != SQLITE_ROW) { sqlite3_finalize(stmt); return -1; }
|
||||
const uint8_t* x = (const uint8_t*)sqlite3_column_blob(stmt, 0);
|
||||
const uint8_t* e = (const uint8_t*)sqlite3_column_blob(stmt, 1);
|
||||
if (!x || sqlite3_column_bytes(stmt, 0) < 32 || !e || sqlite3_column_bytes(stmt, 1) < 32) {
|
||||
sqlite3_finalize(stmt); return -1;
|
||||
if (!x25519_priv_out) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "channel private keys: X25519 output missing"); return -1;
|
||||
}
|
||||
memcpy(x25519_priv_out, x, 32);
|
||||
memcpy(ed25519_priv_out, e, 32);
|
||||
sqlite3_finalize(stmt);
|
||||
return 0;
|
||||
return channel_private_keys(db, channel_id, x25519_priv_out, ed25519_priv_out);
|
||||
}
|
||||
|
||||
/* Импорт пары: savepoint охватывает UPDATE и его завершение, внешний commit остаётся вызывающему. */
|
||||
|
||||
@@ -122,11 +122,13 @@ int topo_node_sqlite_channel_get(sqlite3* db, const char* channel_id,
|
||||
char* name_out, int name_sz, uint64_t* owner_node_id,
|
||||
uint8_t* x25519_pub, uint8_t* ed25519_pub, uint8_t* signature);
|
||||
|
||||
/* Прочитать первые 32 байта Ed25519 privkey; 0/-1, отсутствующий/короткий ключ даёт -1. */
|
||||
/* Прочитать Ed25519 privkey ровно32 байта BLOB; 0/-1, отсутствие/повреждение/SQL-ошибка даёт -1.
|
||||
* Проверяются bind/step/finalize; при отказе выход не меняется. */
|
||||
int topo_node_sqlite_channel_get_priv(sqlite3* db, const char* channel_id,
|
||||
uint8_t* ed25519_priv_out);
|
||||
|
||||
/* Прочитать оба канальных privkey (x25519 + ed25519). Возвращает 0 если оба есть. */
|
||||
/* Прочитать оба канальных privkey (x25519 + ed25519), каждый ровно32 байта BLOB.
|
||||
* 0 — оба прочитаны, -1 — отказ с сохранением обоих выходов. Временные ключи очищаются. */
|
||||
int topo_node_sqlite_channel_get_privs(sqlite3* db, const char* channel_id,
|
||||
uint8_t* x25519_priv_out, uint8_t* ed25519_priv_out);
|
||||
|
||||
|
||||
Reference in new issue
Block a user