etcp: переупорядочить close + защита state==2 во всех API-точках; topo: правильная очистка group nodes и registry; chat/member: новый модуль member_sync; chatgui: обновления транспорта и UI
This commit is contained in:
1 parent
b2e4aadbf0
commit
7f901c01e1
38 files changed
+1275
-540
No files matched your search
@@ -1,26 +1,33 @@
|
||||
#include "memberpropsdialog.h"
|
||||
#include "../db/db_manager.h"
|
||||
#include "../transport/gui_bridge.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <cstring>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include "../../../lib/platform_compat.h"
|
||||
extern "C" {
|
||||
#include "../../../src/chat/chat_core.h"
|
||||
#include "../../../src/chat/chat_member.h"
|
||||
#include "../../../lib/mem.h"
|
||||
}
|
||||
|
||||
MemberPropsDialog::MemberPropsDialog(DbManager* db, const QString& channelId,
|
||||
quint64 nodeId, const QString& memberName,
|
||||
QWidget* parent)
|
||||
uint64_t nodeId, const QString& memberName,
|
||||
uint8_t flags, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_db(db)
|
||||
, m_channelId(channelId)
|
||||
, m_nodeId(nodeId)
|
||||
, m_flags(flags)
|
||||
{
|
||||
setWindowTitle("Member Properties");
|
||||
setMinimumWidth(340);
|
||||
setModal(true);
|
||||
|
||||
/* channel private key (for enabling admin/super checkboxes) */
|
||||
auto chs = m_db->getChannels();
|
||||
for (const auto& ch : chs) {
|
||||
if (ch.channelId == channelId) {
|
||||
@@ -29,9 +36,12 @@ MemberPropsDialog::MemberPropsDialog(DbManager* db, const QString& channelId,
|
||||
}
|
||||
}
|
||||
bool haveKey = (m_edPrivkey.size() == 32);
|
||||
bool isOwn = (m_nodeId == m_db->myNodeId());
|
||||
bool isOwn = (m_nodeId == (uint64_t)m_db->myNodeId());
|
||||
|
||||
bool isAdmin = false, isSuper = false, isStorage = false;
|
||||
bool isAdmin = (m_flags & CHAT_MEMBER_FLAG_ADMIN) != 0;
|
||||
bool isSuper = (m_flags & CHAT_MEMBER_FLAG_SUPERNODE) != 0;
|
||||
|
||||
/* load current nick and version from DB (local_nick is local-only, ver is in adm_tags) */
|
||||
QString curNick;
|
||||
m_currentVer = 0;
|
||||
if (m_db->m_db) {
|
||||
@@ -45,24 +55,13 @@ MemberPropsDialog::MemberPropsDialog(DbManager* db, const QString& channelId,
|
||||
if (sqlite3_step(st) == SQLITE_ROW) {
|
||||
const char* tags = (const char*)sqlite3_column_text(st, 0);
|
||||
if (tags) {
|
||||
const char* vp = strstr(tags, "ver=");
|
||||
if (vp) m_currentVer = atoi(vp + 4);
|
||||
if (strstr(tags, "admin=yes")) isAdmin = true;
|
||||
if (strstr(tags, "supernode=yes")) isSuper = true;
|
||||
if (strstr(tags, "storage=yes")) isStorage = true;
|
||||
const char* vp = strstr(tags, "\"ver\":\"");
|
||||
if (vp) { vp += 7; m_currentVer = atoi(vp); }
|
||||
}
|
||||
curNick = DbManager::colText(st, 1);
|
||||
}
|
||||
sqlite3_finalize(st);
|
||||
}
|
||||
QByteArray alt = QString(
|
||||
"ALTER TABLE \"%1\" ADD COLUMN adm_tags TEXT"
|
||||
).arg(tbl).toUtf8();
|
||||
sqlite3_exec(m_db->m_db, alt.constData(), nullptr, nullptr, nullptr);
|
||||
alt = QString(
|
||||
"ALTER TABLE \"%1\" ADD COLUMN adm_tags_sig BLOB"
|
||||
).arg(tbl).toUtf8();
|
||||
sqlite3_exec(m_db->m_db, alt.constData(), nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
@@ -93,7 +92,6 @@ MemberPropsDialog::MemberPropsDialog(DbManager* db, const QString& channelId,
|
||||
layout->addWidget(m_superCb);
|
||||
|
||||
m_storageCb = new QCheckBox("Storage (priority attachment keeper)", this);
|
||||
m_storageCb->setChecked(isStorage);
|
||||
m_storageCb->setEnabled(haveKey);
|
||||
layout->addWidget(m_storageCb);
|
||||
|
||||
@@ -134,10 +132,10 @@ MemberPropsDialog::MemberPropsDialog(DbManager* db, const QString& channelId,
|
||||
|
||||
void MemberPropsDialog::onSave() {
|
||||
if (!m_db->m_db) return;
|
||||
QString tbl = m_db->peersTableName(m_channelId);
|
||||
|
||||
/* local_nick — always save (unsigned, local only) */
|
||||
/* local_nick — always save local (unsigned, local only) */
|
||||
QString nick = m_nickEdit->text().trimmed();
|
||||
QString tbl = m_db->peersTableName(m_channelId);
|
||||
QByteArray nickSql = QString(
|
||||
"UPDATE \"%1\" SET local_nick=? WHERE node_id=?"
|
||||
).arg(tbl).toUtf8();
|
||||
@@ -150,49 +148,26 @@ void MemberPropsDialog::onSave() {
|
||||
sqlite3_finalize(ns);
|
||||
}
|
||||
|
||||
/* signed fields — only if key available */
|
||||
/* signed fields — через chat_member_tags_commit_trampoline */
|
||||
if (m_edPrivkey.size() != 32) { accept(); return; }
|
||||
|
||||
int ver = m_currentVer + 1;
|
||||
QString tags = QString("ver=%1").arg(ver);
|
||||
if (m_adminCb->isChecked()) tags += ",admin=yes";
|
||||
if (m_superCb->isChecked()) tags += ",supernode=yes";
|
||||
if (m_storageCb->isChecked()) tags += ",storage=yes";
|
||||
QString json;
|
||||
json += QString("{\"ver\":\"%1\"").arg(ver);
|
||||
json += QString(",\"admin\":\"%1\"").arg(m_adminCb->isChecked() ? "yes" : "no");
|
||||
json += QString(",\"supernode\":\"%1\"").arg(m_superCb->isChecked() ? "yes" : "no");
|
||||
json += QString(",\"storage\":\"%1\"").arg(m_storageCb->isChecked() ? "yes" : "no");
|
||||
json += "}";
|
||||
|
||||
QByteArray msg = tags.toUtf8();
|
||||
uint64_t le = htole64(m_nodeId);
|
||||
msg.append((const char*)&le, 8);
|
||||
struct chat_member_tags_req* req = (struct chat_member_tags_req*)
|
||||
u_calloc(1, sizeof(struct chat_member_tags_req));
|
||||
if (!req) { accept(); return; }
|
||||
|
||||
uint8_t sig[64] = {};
|
||||
EVP_PKEY* pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, nullptr,
|
||||
(const uint8_t*)m_edPrivkey.constData(), 32);
|
||||
if (pkey) {
|
||||
EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
|
||||
if (mdctx) {
|
||||
size_t siglen = 64;
|
||||
if (EVP_DigestSignInit(mdctx, nullptr, nullptr, nullptr, pkey) == 1)
|
||||
EVP_DigestSign(mdctx, sig, &siglen, (const uint8_t*)msg.constData(), msg.size());
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
}
|
||||
EVP_PKEY_free(pkey);
|
||||
}
|
||||
|
||||
QByteArray sql = QString(
|
||||
"UPDATE \"%1\" SET adm_tags=?, adm_tags_sig=?, node_type=?, storage=? WHERE node_id=?"
|
||||
).arg(tbl).toUtf8();
|
||||
sqlite3_stmt* st = nullptr;
|
||||
if (sqlite3_prepare_v2(m_db->m_db, sql.constData(), -1, &st, nullptr) == SQLITE_OK) {
|
||||
sqlite3_bind_text(st, 1, tags.isEmpty() ? nullptr : tags.toUtf8().constData(),
|
||||
-1, tags.isEmpty() ? SQLITE_STATIC : SQLITE_TRANSIENT);
|
||||
sqlite3_bind_blob(st, 2, sig, 64, SQLITE_TRANSIENT);
|
||||
int nt = m_superCb->isChecked() ? 4 : 1;
|
||||
sqlite3_bind_int(st, 3, nt);
|
||||
int stg = m_storageCb->isChecked() ? 1 : 0;
|
||||
sqlite3_bind_int(st, 4, stg);
|
||||
sqlite3_bind_int64(st, 5, (sqlite3_int64)m_nodeId);
|
||||
sqlite3_step(st);
|
||||
sqlite3_finalize(st);
|
||||
}
|
||||
QByteArray ch_id_utf8 = m_channelId.toUtf8();
|
||||
strncpy(req->ch_id, ch_id_utf8.constData(), sizeof(req->ch_id) - 1);
|
||||
req->node_id = m_nodeId;
|
||||
strncpy(req->json, json.toUtf8().constData(), sizeof(req->json) - 1);
|
||||
|
||||
gui_bridge_post_uasync_fn(chat_member_tags_commit_trampoline, req);
|
||||
accept();
|
||||
}
|
||||
Reference in new issue
Block a user