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
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; |
|
}
|
|
|