Preserve precise author failure reasons and guard SQLite column allocation

This commit is contained in:
evgeny committed 2026-10-26 14:44:03 +01:00
1 parent 4b394b75e0
commit bf941bfd14
2 files changed
+30 -18

No files matched your search

+11 -5
View File
@@ -428,10 +428,13 @@ static int fb_next_channel(struct UTUN_INSTANCE* inst, const char* after, char c
/* Пересчитывает только листья, зависящие от изменённого автора/ключа пригласившего. */
int chat_feedback_member_update(struct UTUN_INSTANCE* inst, uint64_t node_id) {
if (!merkle_sync_registered(inst, MT_DATA_FEEDBACK)) return 0;
if (sqlite3_get_autocommit(inst->topo_sqlite_db)) return fb_db_error(inst, "-", "member update requires transaction");
if (sqlite3_get_autocommit(inst->topo_sqlite_db)) {
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "feedback: member update requires transaction node=%016llx",
(unsigned long long)node_id); return -1;
}
char channel[21] = "", next[21]; int scan;
while ((scan = fb_next_channel(inst, channel, next, 1)) > 0) {
memcpy(channel, next, sizeof(channel));
strcpy(channel, next);
char table[40], sql[384]; if (fb_table(inst, channel, table, NULL) < 0) return -1;
snprintf(sql, sizeof(sql), "SELECT DISTINCT f.bucket FROM %s f LEFT JOIN peers_%s p ON p.node_id=f.node_id"
" WHERE f.node_id=?1 OR p.signed_by=?1 ORDER BY f.bucket", table, channel);
@@ -448,7 +451,10 @@ int chat_feedback_member_update(struct UTUN_INSTANCE* inst, uint64_t node_id) {
buckets++;
}
int final = sqlite3_finalize(st);
if (rc != SQLITE_DONE || final != SQLITE_OK) return fb_db_error(inst, channel, "member index update");
if (rc != SQLITE_DONE || final != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "feedback: member index failed ch=%s dependency=%016llx step=%d finalize=%d",
channel, (unsigned long long)node_id, rc, final); return -1;
}
if (buckets) DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "feedback: member index updated ch=%s dependency=%016llx buckets=%u",
channel, (unsigned long long)node_id, buckets);
}
@@ -461,7 +467,7 @@ void chat_feedback_member_committed(struct UTUN_INSTANCE* inst, uint64_t node_id
if (!sqlite3_get_autocommit(inst->topo_sqlite_db)) { fb_db_error(inst, "-", "member notify before commit"); return; }
char channel[21] = "", next[21];
while (fb_next_channel(inst, channel, next, 1) > 0) {
memcpy(channel, next, sizeof(channel));
strcpy(channel, next);
/* Даже без локального feedback ключ может разрешить приём ранее отложенной страницы. */
merkle_sync_changed(inst, MT_DATA_FEEDBACK, channel);
char table[40], sql[512]; if (fb_table(inst, channel, table, NULL) < 0) return;
@@ -502,7 +508,7 @@ int chat_feedback_init(struct UTUN_INSTANCE* inst) {
return fb_db_error(inst, "-", "init begin");
char channel[21] = "", next[21]; int scan, result = 0; unsigned buckets = 0;
while ((scan = fb_next_channel(inst, channel, next, 0)) > 0) {
memcpy(channel, next, sizeof(channel));
strcpy(channel, next);
char table[40], sql[128];
if (chat_feedback_ensure_channel(inst, channel) < 0 || fb_table(inst, channel, table, NULL) < 0) { result = -1; break; }
snprintf(sql, sizeof(sql), "SELECT DISTINCT bucket FROM %s ORDER BY bucket", table);
+19 -13
View File
@@ -1344,57 +1344,63 @@ enum ms_author_status member_sync_author_key(struct UTUN_INSTANCE* inst, const c
if (rc != SQLITE_ROW) goto done;
int x_bytes = sqlite3_column_bytes(st, 0), ed_bytes = sqlite3_column_bytes(st, 1);
int tree_bytes = sqlite3_column_bytes(st, 3), join_bytes = sqlite3_column_bytes(st, 4);
if (sqlite3_errcode(db) == SQLITE_NOMEM) goto done;
if (sqlite3_errcode(db) == SQLITE_NOMEM) { rc = SQLITE_NOMEM; goto done; }
status = MS_AUTHOR_INVALID;
reason = "invalid member fields";
if (x_bytes != 32 || ed_bytes != 32 || (tree_bytes != 0 && tree_bytes != 64)
|| (join_bytes != 0 && join_bytes != 64)) goto done;
if (!tree_bytes || !join_bytes || sqlite3_column_int64(st, 5) <= 0
|| _sig_is_zero64(sqlite3_column_blob(st, 3)) || _sig_is_zero64(sqlite3_column_blob(st, 4))) {
status = MS_AUTHOR_PENDING; reason = "join or invitation pending"; goto done;
}
struct ms_member_rec member = { .node_id = author, .x25519 = sqlite3_column_blob(st, 0),
.ed25519 = sqlite3_column_blob(st, 1), .signed_by = (uint64_t)sqlite3_column_int64(st, 2),
.signature = sqlite3_column_blob(st, 3), .join_sig = sqlite3_column_blob(st, 4),
.join_ts = (uint64_t)sqlite3_column_int64(st, 5) };
if (sqlite3_errcode(db) == SQLITE_NOMEM || !member.x25519 || !member.ed25519
|| (tree_bytes && !member.signature) || (join_bytes && !member.join_sig)) {
status = MS_AUTHOR_ERROR; reason = "member column allocation"; rc = SQLITE_NOMEM; goto done;
}
if (!tree_bytes || !join_bytes || !member.join_ts
|| _sig_is_zero64(member.signature) || _sig_is_zero64(member.join_sig)) {
status = MS_AUTHOR_PENDING; reason = "join or invitation pending"; goto done;
}
reason = "node_id/X25519 mismatch";
uint64_t derived = sc_derive_node_id_from_pubkey(member.x25519);
if (!derived) { status = MS_AUTHOR_ERROR; reason = "identity digest"; goto done; }
if (!derived) { status = MS_AUTHOR_ERROR; reason = "identity digest"; rc = SC_ERR_CRYPTO; goto done; }
if (derived != author) goto done;
uint8_t trusted[32], x[32], ed[32], body[112];
reason = "trusted Ed25519 key unavailable";
int lookup = topo_node_sqlite_get_ed25519_pubkey(db, author, trusted);
if (lookup != 0) {
status = lookup == TOPO_SQLITE_LOOKUP_MISSING ? MS_AUTHOR_PENDING : MS_AUTHOR_ERROR; goto done;
status = lookup == TOPO_SQLITE_LOOKUP_MISSING ? MS_AUTHOR_PENDING : MS_AUTHOR_ERROR; rc = lookup; goto done;
}
reason = "trusted Ed25519 key mismatch";
if (memcmp(trusted, member.ed25519, 32)) goto done;
reason = "channel keys unavailable";
lookup = topo_node_sqlite_channel_get(db, channel, NULL, 0, NULL, x, ed, NULL);
if (lookup != 0) {
status = lookup == TOPO_SQLITE_LOOKUP_MISSING ? MS_AUTHOR_PENDING : MS_AUTHOR_ERROR; goto done;
status = lookup == TOPO_SQLITE_LOOKUP_MISSING ? MS_AUTHOR_PENDING : MS_AUTHOR_ERROR; rc = lookup; goto done;
}
reason = "invalid join signature";
int bytes = member_sync_build_join_msg(x, ed, author, member.x25519, member.join_ts, body, sizeof(body));
if (bytes != 112) { status = MS_AUTHOR_ERROR; reason = "join message build"; goto done; }
int signature = sc_ed25519_verify(member.ed25519, body, bytes, member.join_sig);
if (signature != SC_OK) {
status = signature == SC_ERR_AUTH_FAILED ? MS_AUTHOR_INVALID : MS_AUTHOR_ERROR; goto done;
status = signature == SC_ERR_AUTH_FAILED ? MS_AUTHOR_INVALID : MS_AUTHOR_ERROR; rc = signature; goto done;
}
reason = "invitation verification";
signature = member_sync_verify_signature(db, channel, &member);
if (signature != 1) {
status = signature == MS_VERIFY_DEFERRED ? MS_AUTHOR_PENDING
: signature == MS_VERIFY_ERROR ? MS_AUTHOR_ERROR : MS_AUTHOR_INVALID;
rc = signature;
goto done;
}
memcpy(verified_key, member.ed25519, 32); status = MS_AUTHOR_ACTIVE; reason = "verified";
done:
if (sqlite3_finalize(st) != SQLITE_OK) { status = MS_AUTHOR_ERROR; reason = "member finalize"; }
done:;
int final = sqlite3_finalize(st);
if (final != SQLITE_OK) { status = MS_AUTHOR_ERROR; reason = "member finalize"; rc = final; }
if (status == MS_AUTHOR_ACTIVE) memcpy(key, verified_key, 32);
if (status == MS_AUTHOR_ERROR) DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC,
"author verification failed ch=%s node=%016llx reason=%s rc=%d: %s",
channel, (unsigned long long)author, reason, rc, sqlite3_errmsg(db));
"author verification failed ch=%s node=%016llx reason=%s result=%d",
channel, (unsigned long long)author, reason, rc);
else if (status == MS_AUTHOR_INVALID) DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC,
"author invalid ch=%s node=%016llx reason=%s", channel, (unsigned long long)author, reason);
else if (status != MS_AUTHOR_ACTIVE) DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC,