|
|
|
|
@ -123,63 +123,54 @@ static int profile_update_channel(struct UTUN_INSTANCE* inst, const char* ch, in
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: update before initialization"); return -1; |
|
|
|
|
} |
|
|
|
|
uint64_t myid = cc->my_node_id; |
|
|
|
|
char tbl[80]; peers_table_name(ch, tbl, sizeof(tbl)); |
|
|
|
|
uint8_t join_sig[64]; uint64_t join_ts = 0; |
|
|
|
|
if (topo_node_sqlite_member_get_join(cc->db, ch, myid, join_sig, &join_ts) != 0) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_CHAT, "profile: own signed member missing channel=%s", ch); return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
uint64_t local_uts = 0; |
|
|
|
|
struct profile_json profile = { .text = "{", .used = 1, .avatar = avatar }; |
|
|
|
|
if (profile_pair(&profile, "name", inst->name) < 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: display name exceeds profile limit channel=%s", ch); return -1; |
|
|
|
|
} |
|
|
|
|
{ char q[256]; snprintf(q, sizeof(q), "SELECT update_ts,userinfo FROM \"%s\" WHERE node_id=?", tbl); |
|
|
|
|
sqlite3_stmt* ps = NULL; |
|
|
|
|
if (sqlite3_prepare_v2(cc->db, q, -1, &ps, NULL) == SQLITE_OK) { |
|
|
|
|
sqlite3_bind_int64(ps, 1, (sqlite3_int64)myid); |
|
|
|
|
if (sqlite3_step(ps) == SQLITE_ROW) { |
|
|
|
|
local_uts = (uint64_t)sqlite3_column_int64(ps, 0); |
|
|
|
|
const char* old = (const char*)sqlite3_column_text(ps, 1); |
|
|
|
|
if (old && old[0] && json_flat_parse(old, profile_copy_pair, &profile) < 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: cannot preserve attributes channel=%s", ch); |
|
|
|
|
sqlite3_finalize(ps); return -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
sqlite3_finalize(ps); |
|
|
|
|
} else { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: query failed channel=%s: %s", ch, sqlite3_errmsg(cc->db)); return -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (avatar && server) { |
|
|
|
|
char id[17]; snprintf(id, sizeof(id), "%016llx", (unsigned long long)server); |
|
|
|
|
if (profile_pair(&profile, "avatar_server", id) < 0 || profile_pair(&profile, "avatar_file", file) < 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: avatar exceeds profile limit channel=%s", ch); return -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (profile.used >= MS_USERINFO_MAX) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: attributes exceed profile limit channel=%s", ch); return -1; |
|
|
|
|
} |
|
|
|
|
profile.text[profile.used++] = '}'; profile.text[profile.used] = 0; |
|
|
|
|
|
|
|
|
|
uint64_t now = (uint64_t)ntp_time_get_seconds(inst); |
|
|
|
|
uint64_t update_ts = (now > local_uts) ? now : (local_uts + 1); /* строго больше локального */ |
|
|
|
|
|
|
|
|
|
uint8_t umsg[8192]; |
|
|
|
|
int ulen = member_sync_build_update_msg(join_sig, update_ts, profile.text, umsg, (int)sizeof(umsg)); |
|
|
|
|
if (ulen < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: build_update_msg failed ch=%s", CC_ID, ch); return -1; } |
|
|
|
|
uint8_t update_sig[64]; memset(update_sig, 0, 64); |
|
|
|
|
if (sc_ed25519_sign(inst->my_ed25519_privkey, umsg, ulen, update_sig) != SC_OK) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: signature failed channel=%s", ch); return -1; |
|
|
|
|
char tbl[80]; peers_table_name(ch, tbl, sizeof(tbl)); |
|
|
|
|
uint8_t join_sig[64]; uint64_t join_ts = 0; |
|
|
|
|
if (topo_node_sqlite_member_get_join(cc->db, ch, myid, join_sig, &join_ts) != 0) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_CHAT, "profile: own signed member missing channel=%s", ch); return -1; |
|
|
|
|
} |
|
|
|
|
struct profile_json profile = { .text = "{", .used = 1, .avatar = avatar }; |
|
|
|
|
if (profile_pair(&profile, "name", inst->name) < 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: display name exceeds profile limit channel=%s", ch); return -1; |
|
|
|
|
} |
|
|
|
|
char query[256]; snprintf(query, sizeof(query), "SELECT update_ts,userinfo FROM \"%s\" WHERE node_id=?", tbl); |
|
|
|
|
sqlite3_stmt* st = NULL; |
|
|
|
|
if (sqlite3_prepare_v2(cc->db, query, -1, &st, NULL) != SQLITE_OK) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: query failed channel=%s: %s", ch, sqlite3_errmsg(cc->db)); return -1; |
|
|
|
|
} |
|
|
|
|
sqlite3_bind_int64(st, 1, (sqlite3_int64)myid); |
|
|
|
|
if (sqlite3_step(st) != SQLITE_ROW) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: cannot read own member channel=%s: %s", ch, sqlite3_errmsg(cc->db)); |
|
|
|
|
sqlite3_finalize(st); return -1; |
|
|
|
|
} |
|
|
|
|
uint64_t local_uts = (uint64_t)sqlite3_column_int64(st, 0); |
|
|
|
|
const char* old = (const char*)sqlite3_column_text(st, 1); |
|
|
|
|
if (old && old[0] && json_flat_parse(old, profile_copy_pair, &profile) < 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: cannot preserve attributes channel=%s", ch); |
|
|
|
|
sqlite3_finalize(st); return -1; |
|
|
|
|
} |
|
|
|
|
sqlite3_finalize(st); |
|
|
|
|
if (avatar && server) { |
|
|
|
|
char id[17]; snprintf(id, sizeof(id), "%016llx", (unsigned long long)server); |
|
|
|
|
if (profile_pair(&profile, "avatar_server", id) < 0 || profile_pair(&profile, "avatar_file", file) < 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: avatar exceeds profile limit channel=%s", ch); return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int r2 = member_sync_put(inst, ch, myid, inst->my_keys.public_key, |
|
|
|
|
inst->my_ed25519_pubkey, join_sig, join_ts, |
|
|
|
|
update_sig, update_ts, profile.text, NULL, NULL, 0, 0, NULL); |
|
|
|
|
if (r2 < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: member_sync_put(self) FAILED ch=%s rc=%d", CC_ID, ch, r2); return -1; } |
|
|
|
|
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: update my member ch=%s ts=%llu", CC_ID, ch, |
|
|
|
|
(unsigned long long)update_ts); |
|
|
|
|
} |
|
|
|
|
if (profile.used >= MS_USERINFO_MAX) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: attributes exceed profile limit channel=%s", ch); return -1; |
|
|
|
|
} |
|
|
|
|
profile.text[profile.used++] = '}'; profile.text[profile.used] = 0; |
|
|
|
|
uint64_t now = (uint64_t)ntp_time_get_seconds(inst); |
|
|
|
|
uint64_t update_ts = now > local_uts ? now : local_uts + 1; |
|
|
|
|
uint8_t umsg[MS_USERINFO_MAX + 73], update_sig[64]; |
|
|
|
|
int ulen = member_sync_build_update_msg(join_sig, update_ts, profile.text, umsg, sizeof(umsg)); |
|
|
|
|
if (ulen < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: cannot build signature channel=%s", ch); return -1; } |
|
|
|
|
if (sc_ed25519_sign(inst->my_ed25519_privkey, umsg, ulen, update_sig) != SC_OK) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: signature failed channel=%s", ch); return -1; |
|
|
|
|
} |
|
|
|
|
int rc = member_sync_put(inst, ch, myid, inst->my_keys.public_key, inst->my_ed25519_pubkey, join_sig, join_ts, |
|
|
|
|
update_sig, update_ts, profile.text, NULL, NULL, 0, 0, NULL); |
|
|
|
|
if (rc < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: update failed channel=%s result=%d", ch, rc); return -1; } |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: update my member ch=%s ts=%llu", CC_ID, ch, (unsigned long long)update_ts); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|