#include "invite_link.h" #include "debug_ui.h" #include static QByteArray encodeAddresses(const QList& addrs) { QByteArray buf; for (const auto& a : addrs) { buf.append(static_cast(a.family)); buf.append(a.address); buf.append(static_cast((a.port >> 8) & 0xFF)); buf.append(static_cast(a.port & 0xFF)); } return buf; } static QList decodeAddresses(const uint8_t* data, int len, int count) { QList list; int off = 0; for (int i = 0; i < count && off < len; i++) { if (off + 1 > len) break; InviteAddr a; a.family = data[off++]; int alen = (a.family == 4) ? 4 : 16; if (off + alen + 2 > len) break; a.address = QByteArray(reinterpret_cast(data + off), alen); off += alen; a.port = (static_cast(data[off]) << 8) | data[off + 1]; off += 2; list.append(a); } return list; } QString encodeInviteLink(const QString& channelId, const QByteArray& pubkey, const QList& addrs) { QByteArray cid = channelId.toUtf8(); if (cid.size() > 65535) { GUI_ERROR("encodeInviteLink: channelId too long (%d bytes)", cid.size()); return {}; } if (pubkey.size() != 32) { GUI_ERROR("encodeInviteLink: pubkey must be 32 bytes (got %d)", pubkey.size()); return {}; } QByteArray addrsEnc = encodeAddresses(addrs); int addrCount = addrs.size(); if (addrCount > 65535) addrCount = 65535; QByteArray blob; blob.reserve(1 + 2 + cid.size() + 32 + 2 + addrsEnc.size()); blob.append(static_cast(INVITE_LINK_VERSION)); blob.append(static_cast((cid.size() >> 8) & 0xFF)); blob.append(static_cast(cid.size() & 0xFF)); blob.append(cid); blob.append(pubkey); blob.append(static_cast((addrCount >> 8) & 0xFF)); blob.append(static_cast(addrCount & 0xFF)); blob.append(addrsEnc); return QString::fromLatin1("utun://") + QString::fromLatin1(blob.toBase64()); } InviteData decodeInviteLink(const QString& link) { InviteData d; if (!link.startsWith(QLatin1String("utun://"))) { GUI_ERROR("decodeInviteLink: invalid prefix"); return d; } QByteArray blob = QByteArray::fromBase64( link.mid(7).toLatin1()); const auto* data = reinterpret_cast(blob.constData()); int len = blob.size(); if (len < 5) { GUI_ERROR("decodeInviteLink: blob too short (%d bytes)", len); return d; } int off = 0; uint8_t ver = data[off++]; if (ver != INVITE_LINK_VERSION) { GUI_ERROR("decodeInviteLink: unsupported version %d", ver); return d; } int cidLen = (static_cast(data[off]) << 8) | data[off + 1]; off += 2; if (off + cidLen + 32 + 2 > len) { GUI_ERROR("decodeInviteLink: truncated blob"); return d; } d.channelId = QString::fromUtf8(reinterpret_cast(data + off), cidLen); off += cidLen; d.pubkey = QByteArray(reinterpret_cast(data + off), 32); off += 32; int addrCount = (static_cast(data[off]) << 8) | data[off + 1]; off += 2; d.addrs = decodeAddresses(data + off, len - off, addrCount); return d; }