You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

100 lines
3.3 KiB

#include "invite_link.h"
#include "debug_ui.h"
#include <QByteArray>
static QByteArray encodeAddresses(const QList<NodeAddr>& addrs) {
QByteArray buf;
for (const auto& a : addrs) {
buf.append(static_cast<char>(a.family));
buf.append(a.address);
buf.append(static_cast<char>((a.port >> 8) & 0xFF));
buf.append(static_cast<char>(a.port & 0xFF));
}
return buf;
}
static QList<InviteAddr> decodeAddresses(const uint8_t* data, int len,
int count) {
QList<InviteAddr> 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<const char*>(data + off), alen);
off += alen;
a.port = (static_cast<quint16>(data[off]) << 8) | data[off + 1];
off += 2;
list.append(a);
}
return list;
}
QString encodeInviteLink(const QString& channelId, const QByteArray& pubkey,
const QList<NodeAddr>& 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<char>(INVITE_LINK_VERSION));
blob.append(static_cast<char>((cid.size() >> 8) & 0xFF));
blob.append(static_cast<char>(cid.size() & 0xFF));
blob.append(cid);
blob.append(pubkey);
blob.append(static_cast<char>((addrCount >> 8) & 0xFF));
blob.append(static_cast<char>(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<const uint8_t*>(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<int>(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<const char*>(data + off), cidLen);
off += cidLen;
d.pubkey = QByteArray(reinterpret_cast<const char*>(data + off), 32);
off += 32;
int addrCount = (static_cast<int>(data[off]) << 8) | data[off + 1];
off += 2;
d.addrs = decodeAddresses(data + off, len - off, addrCount);
return d;
}