chat_join: модуль join-протокола, invite-ссылки v2, синхронизация мемберов
This commit is contained in:
1 parent
a01a4ddba4
commit
75e39d2fee
41 files changed
+2206
-471
No files matched your search
@@ -223,7 +223,7 @@ class MainActivity : ComponentActivity() {
|
||||
},
|
||||
onConnect = { data: InviteData ->
|
||||
val addrs = data.serializeAddrs()
|
||||
NativeLib.joinChannel(data.channelId, data.nodeId, data.pubkey, addrs, data.addrs.size)
|
||||
NativeLib.joinChannel(data.channelId, data.nodeId, data.joinKey, data.pubkey, addrs, data.addrs.size)
|
||||
showJoinDialog = false
|
||||
},
|
||||
onDismiss = { showJoinDialog = false }
|
||||
|
||||
@@ -386,8 +386,8 @@ class ChatRepository {
|
||||
NativeLib.photoSend(channelId, filePath, width, height)
|
||||
fun createChannel(name: String, channelId: String) = NativeLib.createChannel(name, channelId)
|
||||
fun connectNode(address: String, port: Int, pubkeyHex: String) = NativeLib.connectNode(address, port, pubkeyHex)
|
||||
fun joinChannel(channelId: Long, nodeId: Long, pubkey: ByteArray, addrs: ByteArray, addrCount: Int) =
|
||||
NativeLib.joinChannel(channelId, nodeId, pubkey, addrs, addrCount)
|
||||
fun joinChannel(channelId: Long, nodeId: Long, joinKey: Long, pubkey: ByteArray, addrs: ByteArray, addrCount: Int) =
|
||||
NativeLib.joinChannel(channelId, nodeId, joinKey, pubkey, addrs, addrCount)
|
||||
fun connectChannel(channelId: String) = NativeLib.connectChannel(channelId)
|
||||
fun connectMemberNode(channelId: String, nodeId: Long) = NativeLib.connectMemberNode(channelId, nodeId)
|
||||
fun isReady() = NativeLib.isReady()
|
||||
|
||||
@@ -29,6 +29,7 @@ data class InviteAddr(
|
||||
|
||||
data class InviteData(
|
||||
val channelId: Long,
|
||||
val joinKey: Long,
|
||||
val pubkey: ByteArray,
|
||||
val nodeId: Long,
|
||||
val addrs: List<InviteAddr>
|
||||
@@ -98,7 +99,14 @@ object InviteLink {
|
||||
}
|
||||
off += 8
|
||||
|
||||
LogManager.addLog("DEBUG", "INVITE", "decode: chId=0x%016x".format(chId))
|
||||
var joinKey = 0L
|
||||
for (i in 0 until 8) {
|
||||
if (off + i >= raw.size) return null
|
||||
joinKey = (joinKey shl 8) or (raw[off + i].toLong() and 0xFF)
|
||||
}
|
||||
off += 8
|
||||
|
||||
LogManager.addLog("DEBUG", "INVITE", "decode: chId=0x%016x joinKey=0x%016x".format(chId, joinKey))
|
||||
|
||||
var pubkey: ByteArray? = null
|
||||
val addrs = mutableListOf<InviteAddr>()
|
||||
@@ -135,7 +143,7 @@ object InviteLink {
|
||||
val pkHex = pubkey.take(8).joinToString("") { "%02x".format(it) }
|
||||
LogManager.addLog("INFO", "INVITE", "decode: ch=0x%016x node=0x%016x pk=%s... addrs=%d".format(
|
||||
chId, nodeId, pkHex, addrs.size))
|
||||
return InviteData(channelId = chId, pubkey = pubkey, nodeId = nodeId, addrs = addrs)
|
||||
return InviteData(channelId = chId, joinKey = joinKey, pubkey = pubkey, nodeId = nodeId, addrs = addrs)
|
||||
}
|
||||
|
||||
fun addrToString(addr: InviteAddr): String {
|
||||
|
||||
@@ -68,9 +68,9 @@ object NativeLib {
|
||||
fun sendMessage(channelId: String, text: String) { nativeSendMessage(channelId, text) }
|
||||
fun createChannel(name: String, channelId: String) { nativeCreateChannel(name, channelId) }
|
||||
fun connectNode(address: String, port: Int, pubkeyHex: String) { nativeConnectNode(address, port, pubkeyHex) }
|
||||
fun joinChannel(channelId: Long, nodeId: Long, pubkey: ByteArray, addrs: ByteArray, addrCount: Int) {
|
||||
fun joinChannel(channelId: Long, nodeId: Long, joinKey: Long, pubkey: ByteArray, addrs: ByteArray, addrCount: Int) {
|
||||
LogManager.addLog("INFO", "JNI", "joinChannel: calling native")
|
||||
nativeJoinChannel(channelId, nodeId, pubkey, addrs, addrCount)
|
||||
nativeJoinChannel(channelId, nodeId, joinKey, pubkey, addrs, addrCount)
|
||||
LogManager.addLog("INFO", "JNI", "joinChannel: native returned")
|
||||
}
|
||||
fun deriveNodeId(pubkey: ByteArray): Long = nativeDeriveNodeId(pubkey)
|
||||
@@ -147,7 +147,7 @@ object NativeLib {
|
||||
private external fun nativeSendMessage(channelId: String, text: String)
|
||||
private external fun nativeCreateChannel(name: String, channelId: String)
|
||||
private external fun nativeConnectNode(address: String, port: Int, pubkeyHex: String)
|
||||
private external fun nativeJoinChannel(channelId: Long, nodeId: Long, pubkey: ByteArray, addrs: ByteArray, addrCount: Int)
|
||||
private external fun nativeJoinChannel(channelId: Long, nodeId: Long, joinKey: Long, pubkey: ByteArray, addrs: ByteArray, addrCount: Int)
|
||||
private external fun nativeDeriveNodeId(pubkey: ByteArray): Long
|
||||
private external fun nativeConnectChannel(channelId: String)
|
||||
private external fun nativeConnectMemberNode(channelId: String, nodeId: Long)
|
||||
|
||||
@@ -589,11 +589,11 @@ class ChatViewModel : ViewModel() {
|
||||
r.connectNode(address, port, pubkeyHex)
|
||||
}
|
||||
|
||||
fun joinChannel(channelId: Long, nodeId: Long, pubkey: ByteArray, addrs: ByteArray, addrCount: Int) {
|
||||
fun joinChannel(channelId: Long, nodeId: Long, joinKey: Long, pubkey: ByteArray, addrs: ByteArray, addrCount: Int) {
|
||||
val r = repo
|
||||
if (r == null) { LogManager.addLog("ERROR", "VM", "joinChannel: repo is NULL"); return }
|
||||
LogManager.addLog("INFO", "VM", "joinChannel: ch=0x%016x node=0x%016x".format(channelId, nodeId))
|
||||
r.joinChannel(channelId, nodeId, pubkey, addrs, addrCount)
|
||||
r.joinChannel(channelId, nodeId, joinKey, pubkey, addrs, addrCount)
|
||||
}
|
||||
|
||||
fun startVoiceRecording() {
|
||||
|
||||
@@ -315,7 +315,7 @@ static int handle_join(int fd, int id, const char* json) {
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "join: calling chat_sync_connect_from_invite...");
|
||||
chat_sync_connect_from_invite(d.channelId, d.nodeId, d.pubkey, addrs_buf, d.addrCount, addrs_len, d.password);
|
||||
chat_sync_connect_from_invite(d.channelId, d.nodeId, d.pubkey, addrs_buf, d.addrCount, addrs_len, d.password, d.join_key);
|
||||
|
||||
char resp[512];
|
||||
snprintf(resp, sizeof(resp),
|
||||
|
||||
@@ -223,7 +223,7 @@ void utun_bridge_connect_node(const char* address, int port, const char* pubkey_
|
||||
void utun_bridge_join_channel(uint64_t channel_id, uint64_t node_id,
|
||||
const uint8_t* pubkey_bin,
|
||||
const uint8_t* addrs_data, int addr_count,
|
||||
int addrs_data_len) {
|
||||
int addrs_data_len, uint64_t join_key) {
|
||||
uint64_t real_node_id = sc_derive_node_id_from_pubkey(pubkey_bin);
|
||||
if (real_node_id != node_id)
|
||||
bridge_log(BLEV_WARN, "join: node_id Kotlin=0x%016llx != C=0x%016llx — using C value",
|
||||
@@ -235,7 +235,7 @@ void utun_bridge_join_channel(uint64_t channel_id, uint64_t node_id,
|
||||
utun_bridge_event(6, "{\"node_id\":0,\"result\":-7}"); /* CHAT_EVT_CONNECT_RESULT */
|
||||
return;
|
||||
}
|
||||
chat_sync_connect_from_invite(channel_id, real_node_id, pubkey_bin, addrs_data, addr_count, addrs_data_len, NULL);
|
||||
chat_sync_connect_from_invite(channel_id, real_node_id, pubkey_bin, addrs_data, addr_count, addrs_data_len, NULL, join_key);
|
||||
}
|
||||
|
||||
void utun_bridge_request_invite_candidates(const char* channel_id) {
|
||||
@@ -1466,7 +1466,7 @@ JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeInit(
|
||||
/* ── nativeJoinChannel ── */
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeJoinChannel(
|
||||
JNIEnv* env, jobject thiz, jlong channelId, jlong nodeId,
|
||||
JNIEnv* env, jobject thiz, jlong channelId, jlong nodeId, jlong joinKey,
|
||||
jbyteArray pubkey, jbyteArray addrsData, jint addrCount) {
|
||||
(void)thiz;
|
||||
if (!pubkey || !addrsData) {
|
||||
@@ -1483,7 +1483,7 @@ JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeJoinChannel(
|
||||
uint8_t* ad = (uint8_t*)(*env)->GetByteArrayElements(env, addrsData, NULL);
|
||||
bridge_log(BLEV_DEBUG, "nativeJoinChannel ch=%lld node=0x%llx pk=%02x%02x... addrs_sz=%d",
|
||||
(long long)channelId, (unsigned long long)nodeId, pk[0], pk[1], (int)ad_len);
|
||||
utun_bridge_join_channel((uint64_t)channelId, (uint64_t)nodeId, pk, ad, (int)addrCount, (int)ad_len);
|
||||
utun_bridge_join_channel((uint64_t)channelId, (uint64_t)nodeId, pk, ad, (int)addrCount, (int)ad_len, (uint64_t)joinKey);
|
||||
(*env)->ReleaseByteArrayElements(env, addrsData, (jbyte*)ad, JNI_ABORT);
|
||||
(*env)->ReleaseByteArrayElements(env, pubkey, (jbyte*)pk, JNI_ABORT);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ void utun_bridge_connect_node(const char* address, int port, const char* pubkey_
|
||||
void utun_bridge_join_channel(uint64_t channel_id, uint64_t node_id,
|
||||
const uint8_t* pubkey_bin,
|
||||
const uint8_t* addrs_data, int addr_count,
|
||||
int addrs_data_len);
|
||||
int addrs_data_len, uint64_t join_key);
|
||||
|
||||
/* Connect to all peers of a channel (auto-connect on select) */
|
||||
void utun_bridge_connect_channel(const char* channel_id);
|
||||
|
||||
@@ -104,6 +104,16 @@ int invite_link_decode(const char* link, size_t link_len, struct InviteDataC* ou
|
||||
for (int i = 0; i < 8; i++)
|
||||
chId = (chId << 8) | raw[off++];
|
||||
out->channelId = chId;
|
||||
|
||||
if (off + 8 > raw_len) {
|
||||
if (error_buf && error_buf_size) snprintf(error_buf, error_buf_size, "truncated at join_key");
|
||||
return -1;
|
||||
}
|
||||
uint64_t jk = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
jk = (jk << 8) | raw[off++];
|
||||
out->join_key = jk;
|
||||
|
||||
memset(out->pubkey, 0, INVITE_PUBKEY_SIZE);
|
||||
out->addrCount = 0;
|
||||
|
||||
@@ -181,6 +191,7 @@ int invite_link_encode(const struct InviteDataC* data, const char* password, cha
|
||||
memcpy(raw + pos, password, plen); pos += plen;
|
||||
}
|
||||
for (int i = 7; i >= 0; i--) raw[pos++] = (uint8_t)((data->channelId >> (i * 8)) & 0xFF);
|
||||
for (int i = 7; i >= 0; i--) raw[pos++] = (uint8_t)((data->join_key >> (i * 8)) & 0xFF);
|
||||
uint8_t pk[32]; memcpy(pk, data->pubkey, 32);
|
||||
|
||||
int ia = 0;
|
||||
|
||||
@@ -27,6 +27,7 @@ struct InviteAddrC {
|
||||
|
||||
struct InviteDataC {
|
||||
uint64_t channelId;
|
||||
uint64_t join_key; /* 64-битный ключ входа (генерируется инвайтером) */
|
||||
uint8_t pubkey[INVITE_PUBKEY_SIZE];
|
||||
uint64_t nodeId;
|
||||
uint8_t addrCount;
|
||||
|
||||
@@ -116,6 +116,17 @@ InviteData decodeInviteLink(const QString& link) {
|
||||
chId = (chId << 8) | data[off++];
|
||||
d.channelId = chId;
|
||||
|
||||
/* join_key: uint64 big-endian */
|
||||
if (off + 8 > len) {
|
||||
d.error = QStringLiteral("truncated at join_key");
|
||||
GUI_ERROR("decodeInviteLink: truncated at join_key");
|
||||
return d;
|
||||
}
|
||||
uint64_t jk = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
jk = (jk << 8) | data[off++];
|
||||
d.joinKey = jk;
|
||||
|
||||
bool firstBlock = true;
|
||||
while (off + 1 <= len) {
|
||||
uint8_t header = data[off++];
|
||||
|
||||
@@ -21,6 +21,7 @@ struct InviteAddr {
|
||||
|
||||
struct InviteData {
|
||||
uint64_t channelId = 0;
|
||||
uint64_t joinKey = 0; // 64-битный ключ входа (генерируется инвайтером)
|
||||
QByteArray pubkey;
|
||||
QList<InviteAddr> addrs;
|
||||
QString password;
|
||||
|
||||
@@ -203,7 +203,7 @@ void JoinDialog::onConnectClicked() {
|
||||
|
||||
chat_sync_connect_from_invite(d.channelId, nodeId,
|
||||
(const uint8_t*)d.pubkey.constData(),
|
||||
(const uint8_t*)addrsBuf.constData(), addrCount, addrsBuf.size(), pass);
|
||||
(const uint8_t*)addrsBuf.constData(), addrCount, addrsBuf.size(), pass, d.joinKey);
|
||||
}
|
||||
|
||||
void JoinDialog::onConnectResult(uint64_t nodeId, uint64_t channelId, int result) {
|
||||
|
||||
Reference in new issue
Block a user