QR-Kompression: pako.deflateRaw + SDP-Dictionary statt base45
All checks were successful
Pin to IPFS / pin (push) Successful in 9s

- base45/CompressionStream entfernt, durch pako.deflateRaw + base64 ersetzt
- SDP-Dictionary aus 10 echten SDP-JSONs (Chrome+Firefox) → 97.5% Kompression
- Korrupte pako.min.js durch CDN-Version ersetzt
- Tote Altlasten entfernt: hexToBuf, _fullSDPData/getFullSDPData, CRYPTO-UPDATE.md
- Debug-Panel: QR-Click kopiert base64, Raw-Data-Click kopiert JSON
- test-pairing.html an neue pack/unpack-API angepasst
This commit is contained in:
Ole 2026-06-14 21:51:49 +02:00
parent f1f27e5164
commit a7933315f3
10 changed files with 158 additions and 143 deletions

View file

@ -0,0 +1,40 @@
Chrome:
Offer1
{
"v": 1,
"id": "21c5a474249cbbda",
"s": {
"type": "offer",
"sdp": "v=0\r\no=- 4727015153900916462 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 0.0.0.0\r\na=candidate:1600657949 1 udp 2113937151 19e60f27-7a6b-420b-b44b-80fb16b10d96.local 32922 typ host generation 0 network-cost 999\r\na=candidate:3858062446 1 udp 2113939711 5aa40abb-b5c3-46d4-8b1c-335f00f9d532.local 48316 typ host generation 0 network-cost 999\r\na=ice-ufrag:HJ3p\r\na=ice-pwd:8fF3fJMxF3Yci2HvNZOmd+6r\r\na=fingerprint:sha-256 0D:80:05:75:F9:5A:B6:CD:26:26:92:D8:04:1B:18:72:FA:AD:20:E6:AD:6F:B3:7F:F7:8D:2B:F1:36:8E:50:29\r\na=setup:actpass\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"
}
}
Answer1
{
"v": 1,
"id": "4c79fdc6b5e20f4f",
"s": {
"type": "answer",
"sdp": "v=0\r\no=- 2426412120773230660 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=application 45330 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 192.168.0.99\r\na=candidate:1040060411 1 tcp 1518214911 192.168.0.99 9 typ host tcptype active generation 0 network-id 1 network-cost 10\r\na=candidate:2271431048 1 tcp 1518283007 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 9 typ host tcptype active generation 0 network-id 2 network-cost 10\r\na=candidate:3277118319 1 udp 2122194687 192.168.0.99 45330 typ host generation 0 network-id 1 network-cost 10\r\na=candidate:2043256092 1 udp 2122262783 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 50135 typ host generation 0 network-id 2 network-cost 10\r\na=ice-ufrag:jTj4\r\na=ice-pwd:JTgImK6tSV4XrFETX4d1NeWo\r\na=fingerprint:sha-256 10:FF:A7:A1:4D:C4:E6:C8:58:80:BE:DE:89:35:64:0F:08:46:5F:62:E4:9A:26:F8:35:6F:9D:23:9E:19:0A:5B\r\na=setup:active\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"
},
"to": "21c5a474249cbbda"
}
Offer2
{
"v": 1,
"id": "ea8513afc96a66c4",
"s": {
"type": "offer",
"sdp": "v=0\r\no=- 7345681585991935661 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 0.0.0.0\r\na=candidate:3682889654 1 udp 2113937151 2fbe1617-5bef-4389-8b86-0dc8d27f01fe.local 52239 typ host generation 0 network-cost 999\r\na=candidate:2532579650 1 udp 2113939711 ba3d54c5-0b01-4df0-b677-212617ca1994.local 38447 typ host generation 0 network-cost 999\r\na=ice-ufrag:DWlh\r\na=ice-pwd:bG1hiDVlwbvtyDoC/l5edXh1\r\na=fingerprint:sha-256 DF:A7:0F:3E:00:AA:7A:CB:E9:84:65:2F:8B:9D:E8:C1:39:A7:47:C3:DE:B8:72:CF:80:4A:4A:FA:1D:C5:EB:E5\r\na=setup:actpass\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"
}
}
Answer2
{
"v": 1,
"id": "2d22b7a296f92ab9",
"s": {
"type": "answer",
"sdp": "v=0\r\no=- 628465681931269525 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=application 59397 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 192.168.0.99\r\na=candidate:811532240 1 tcp 1518214911 192.168.0.99 9 typ host tcptype active generation 0 network-id 1 network-cost 10\r\na=candidate:2328082851 1 tcp 1518283007 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 9 typ host tcptype active generation 0 network-id 2 network-cost 10\r\na=candidate:3472108356 1 udp 2122194687 192.168.0.99 59397 typ host generation 0 network-id 1 network-cost 10\r\na=candidate:1953066295 1 udp 2122262783 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 34097 typ host generation 0 network-id 2 network-cost 10\r\na=ice-ufrag:W4rw\r\na=ice-pwd:asUEGNATk7NDaiAl/qAa6lHX\r\na=fingerprint:sha-256 A8:78:40:79:2D:D9:F7:37:58:FD:1B:18:41:12:D2:2E:49:6D:1E:26:F3:6A:EC:E3:E5:9C:F7:BC:33:F6:81:79\r\na=setup:active\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"
},
"to": "ea8513afc96a66c4"
}

21
.tmp/Firefox Chrome.txt Normal file
View file

@ -0,0 +1,21 @@
Firefox <> Chrome:
Firefox Offer1
{
"v": 1,
"id": "6b6433490bb88159",
"s": {
"type": "offer",
"sdp": "v=0\r\no=mozilla...THIS_IS_SDPARTA-99.0 5855950397394494929 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 BC:D0:57:5A:7B:44:AA:CF:E0:D7:05:C2:CD:D8:C2:F9:26:D7:8D:82:D5:99:CC:54:51:A8:61:64:3C:67:53:A9\r\na=group:BUNDLE 0\r\na=msid-semantic:WMS *\r\nm=application 38115 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 192.168.0.99\r\na=candidate:0 1 UDP 2122187007 192.168.0.99 38115 typ host\r\na=candidate:1 1 UDP 2122252543 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 50751 typ host\r\na=candidate:2 1 TCP 2105458943 192.168.0.99 9 typ host tcptype active\r\na=candidate:3 1 TCP 2105524479 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=ice-pwd:e71f0120d84ac191b57936d7c2c67bbd\r\na=ice-ufrag:3391cd3b\r\na=mid:0\r\na=setup:actpass\r\na=sctp-port:5000\r\na=max-message-size:1073741823\r\n"
}
}
Chrome Answer1
{
"v": 1,
"id": "ab830b376f46683b",
"s": {
"type": "answer",
"sdp": "v=0\r\no=- 7803168747385674361 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=msid-semantic: WMS\r\nm=application 52093 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 192.168.0.99\r\na=candidate:480058806 1 tcp 1518214911 192.168.0.99 9 typ host tcptype active generation 0 network-id 1 network-cost 10\r\na=candidate:2785041349 1 tcp 1518283007 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 9 typ host tcptype active generation 0 network-id 2 network-cost 10\r\na=candidate:3795306786 1 udp 2122194687 192.168.0.99 52093 typ host generation 0 network-id 1 network-cost 10\r\na=candidate:1487572817 1 udp 2122262783 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 42761 typ host generation 0 network-id 2 network-cost 10\r\na=ice-ufrag:6Z2W\r\na=ice-pwd:mduInWDq1TEQPV0mKnVivq7l\r\na=fingerprint:sha-256 F6:A4:42:BB:8E:5F:85:CF:A1:AB:E1:E7:4E:3E:71:49:4C:FA:03:68:1B:E2:93:B6:25:09:50:B4:22:FB:5B:20\r\na=setup:active\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"
},
"to": "6b6433490bb88159"
}

View file

@ -0,0 +1,43 @@
Firefox:
Offer 1
{
"v": 1,
"id": "6b6433490bb88159",
"s": {
"type": "offer",
"sdp": "v=0\r\no=mozilla...THIS_IS_SDPARTA-99.0 5855950397394494929 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 BC:D0:57:5A:7B:44:AA:CF:E0:D7:05:C2:CD:D8:C2:F9:26:D7:8D:82:D5:99:CC:54:51:A8:61:64:3C:67:53:A9\r\na=group:BUNDLE 0\r\na=msid-semantic:WMS *\r\nm=application 38115 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 192.168.0.99\r\na=candidate:0 1 UDP 2122187007 192.168.0.99 38115 typ host\r\na=candidate:1 1 UDP 2122252543 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 50751 typ host\r\na=candidate:2 1 TCP 2105458943 192.168.0.99 9 typ host tcptype active\r\na=candidate:3 1 TCP 2105524479 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=ice-pwd:e71f0120d84ac191b57936d7c2c67bbd\r\na=ice-ufrag:3391cd3b\r\na=mid:0\r\na=setup:actpass\r\na=sctp-port:5000\r\na=max-message-size:1073741823\r\n"
}
}
Offer2
{
"v": 1,
"id": "fbb6303b01f9e18d",
"s": {
"type": "offer",
"sdp": "v=0\r\no=mozilla...THIS_IS_SDPARTA-99.0 9222699254471428255 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 19:2B:49:DB:EB:18:A6:8E:4D:EF:86:73:50:EC:AB:59:96:BB:26:EE:C4:34:D5:0B:5D:1A:2E:12:18:3B:34:E8\r\na=group:BUNDLE 0\r\na=msid-semantic:WMS *\r\nm=application 49437 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 192.168.0.99\r\na=candidate:0 1 UDP 2122187007 192.168.0.99 49437 typ host\r\na=candidate:1 1 UDP 2122252543 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 33795 typ host\r\na=candidate:2 1 TCP 2105458943 192.168.0.99 9 typ host tcptype active\r\na=candidate:3 1 TCP 2105524479 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=ice-pwd:c3415db7920f14a330919e7239e0d353\r\na=ice-ufrag:685a689c\r\na=mid:0\r\na=setup:actpass\r\na=sctp-port:5000\r\na=max-message-size:1073741823\r\n"
}
}
Answer1
{
"v": 1,
"id": "6ccd17a4b797155d",
"s": {
"type": "answer",
"sdp": "v=0\r\no=mozilla...THIS_IS_SDPARTA-99.0 1563643215392536921 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 75:EC:8B:02:86:7C:C8:04:C7:DF:B3:CE:D5:ED:5B:29:8A:2B:33:7D:B2:B0:FF:C3:3F:89:B2:14:B7:FF:98:5B\r\na=group:BUNDLE 0\r\na=msid-semantic:WMS *\r\nm=application 33301 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 192.168.0.99\r\na=candidate:0 1 UDP 2122187007 192.168.0.99 33301 typ host\r\na=candidate:1 1 UDP 2122252543 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 55772 typ host\r\na=candidate:2 1 TCP 2105458943 192.168.0.99 9 typ host tcptype active\r\na=candidate:3 1 TCP 2105524479 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=ice-pwd:126c1cb120924857d2414c3a5ef3ace9\r\na=ice-ufrag:ef47e5c9\r\na=mid:0\r\na=setup:active\r\na=sctp-port:5000\r\na=max-message-size:1073741823\r\n"
},
"to": "6b6433490bb88159"
}
Answer2
{
"v": 1,
"id": "f71f0fae072d8329",
"s": {
"type": "answer",
"sdp": "v=0\r\no=mozilla...THIS_IS_SDPARTA-99.0 7701077249990011923 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 0C:B2:E6:EC:61:95:2A:52:2C:C4:61:0B:81:FE:90:93:46:E8:1C:46:D2:0D:49:98:D2:61:02:98:48:C0:27:44\r\na=group:BUNDLE 0\r\na=msid-semantic:WMS *\r\nm=application 37049 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 192.168.0.99\r\na=candidate:0 1 UDP 2122187007 192.168.0.99 37049 typ host\r\na=candidate:1 1 UDP 2122252543 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 36699 typ host\r\na=candidate:2 1 TCP 2105458943 192.168.0.99 9 typ host tcptype active\r\na=candidate:3 1 TCP 2105524479 2a02:8108:310d:b000:66c4:ed1c:57b0:194f 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=ice-pwd:f28050b1b31bc209b3034cbd8844da15\r\na=ice-ufrag:51a0d451\r\na=mid:0\r\na=setup:active\r\na=sctp-port:5000\r\na=max-message-size:1073741823\r\n"
},
"to": "fbb6303b01f9e18d"
}

View file

@ -1,48 +0,0 @@
KONTEXT
Vanilla-ECMAScript-Projekt. Mein aktuelles Protokoll committet Geheimnisse
per H(secret) und teilt einen Schlüssel n-of-n auf. Ich ersetze das durch ein
2-von-3 Threshold-Schema: Pedersen-DKG + Threshold-ElGamal mit verifizierbarer
verteilter Entschlüsselung (Chaum-Pedersen-Beweise statt blankem Hash).
Die fertige npm-Library threshold-elgamal scheidet aus: sie funktioniert
zuverlässig nur mit threshold == Teilnehmerzahl, nicht mit 2-von-3.
AUFGABE
1. Inspiziere zuerst das Repo: finde den bestehenden Commit-/Keypart-Code,
bestimme die öffentliche Schnittstelle (welche Funktionen rufen Aufrufer
auf), und liste sie mir auf, BEVOR du etwas änderst.
2. Füge @noble/curves als Fundament hinzu (auditiert, dependency-frei).
Verifiziere die aktuelle Version aus dem npm-Registry, bevor du pinst.
KEINE selbstgebaute Feldarithmetik, KEIN eigenes BigInt-Modular-Inverse
alles über noble.
3. Implementiere mit threshold=2, parties=3 auf einer Prime-Order-Gruppe
(Ristretto255 via @noble/curves bevorzugt):
- Pedersen-VSS / Pedersen-DKG: zwei Polynome Grad 1, Koeffizienten-
Commitments C_k = g^a_k · h^b_k, h mit unbekanntem log_g(h).
- Verteilte Schlüsselerzeugung: jede Partei dealt einen Beitrag, jede
verifiziert jeden empfangenen Share gegen die Commitments.
- Threshold-ElGamal als KEM: Payload NICHT direkt mit ElGamal. Rekonstruiere
per 2 partiellen Entschlüsselungen das gemeinsame Gruppenelement, leite
daraus per HKDF-SHA256 einen 256-bit Key ab, verschlüssele das Payload mit
AES-256-GCM (WebCrypto subtle, nicht selbst gebaut).
- Jede partielle Entschlüsselung trägt einen Chaum-Pedersen-Beweis der
DL-Gleichheit; verifiziere VOR der Lagrange-Kombination.
4. Behalte die bestehende öffentliche Schnittstelle bei (gleiche Signaturen),
damit Aufrufer unverändert bleiben. Markiere den alten Code deprecated statt
ihn zu löschen.
5. Tests: (a) 2 von 3 entschlüsseln erfolgreich, (b) 1 allein scheitert,
(c) manipulierte partielle Entschlüsselung wird durch die Verifikation
abgelehnt, (d) manipulierter VSS-Share fliegt bei der DKG-Verifikation auf,
(e) echtes Payload Round-Trip.
EINSCHRÄNKUNGEN / WARNUNG
- Das ist selbstgebaute Threshold-Krypto. Setze einen unübersehbaren Kommentar
an den Kern: nicht auditiert, Komposition über noble ist ungeprüft.
- Nutze ausschließlich noble + WebCrypto für alle Primitiven. Erfinde keine
Kurven-, Hash- oder Symmetrie-Operationen selbst.
- Konstante-Zeit-Verhalten kannst du in reinem JS nicht garantieren halte das
im Kommentar fest.
- Ändere nichts an meiner Geheimnis-/Key-Persistenz, ohne vorher zu fragen.

39
app.js
View file

@ -75,6 +75,17 @@
const c = $(containerId); const c = $(containerId);
if (!c) return; if (!c) return;
c.innerHTML = ''; c.innerHTML = '';
c.dataset.qrdata = data;
c.style.cursor = 'pointer';
c.title = 'QR kopieren';
c.onclick = async () => {
try {
await navigator.clipboard.writeText(data);
const orig = c.innerHTML;
c.textContent = 'Kopiert!';
setTimeout(() => { c.innerHTML = orig; }, 1200);
} catch (e) {}
};
const size = Math.min(window.innerWidth - 64, 360); const size = Math.min(window.innerWidth - 64, 360);
qrHost = new QRCode(c, { text: data, width: size, height: size, correctLevel: QRCode.CorrectLevel.L }); qrHost = new QRCode(c, { text: data, width: size, height: size, correctLevel: QRCode.CorrectLevel.L });
} }
@ -144,8 +155,7 @@
try { try {
const raw = await detect(); const raw = await detect();
if (raw) { if (raw) {
const bytes = decode45(raw); const p = await unpack(raw);
const p = await unpack(bytes);
if (p.v === 1) { callback(p, raw); return; } if (p.v === 1) { callback(p, raw); return; }
} }
} catch (_) {} } catch (_) {}
@ -291,8 +301,19 @@
}; };
mesh.onqrupdate = d => { mesh.onqrupdate = d => {
showQR('qr-host', d); showQR('qr-host', d);
const raw = $('host-qr-raw'); if (typeof d !== 'string') {
if (raw) raw.textContent = d; const raw = $('host-qr-raw');
if (raw) raw.textContent = 'Kein String: ' + typeof d;
return;
}
unpack(d).then(obj => {
const raw = $('host-qr-raw');
if (raw) raw.textContent = JSON.stringify(obj, null, 2);
}).catch(err => {
const raw = $('host-qr-raw');
if (raw) raw.textContent = 'Fehler: ' + (err && err.stack ? err.stack : String(err));
console.error('unpack error:', err);
});
}; };
mesh.onreadyupdate = (ready, total) => { mesh.onreadyupdate = (ready, total) => {
$('btn-start-game').disabled = ready < total || total === 0; $('btn-start-game').disabled = ready < total || total === 0;
@ -331,7 +352,7 @@
if (!raw) return; if (!raw) return;
if (!mesh) return; if (!mesh) return;
try { try {
await unpack(decode45(raw)); await unpack(raw);
} catch (e) { } catch (e) {
$('host-scan-status').textContent = 'Ungültige Daten'; $('host-scan-status').textContent = 'Ungültige Daten';
return; return;
@ -357,8 +378,10 @@
mesh.onanswerready = answerData => { mesh.onanswerready = answerData => {
$('join-answer-section').hidden = false; $('join-answer-section').hidden = false;
showQR('qr-answer', answerData); showQR('qr-answer', answerData);
const raw = $('answer-raw'); unpack(answerData).then(obj => {
if (raw) raw.textContent = answerData; const raw = $('answer-raw');
if (raw) raw.textContent = JSON.stringify(obj, null, 2);
}).catch(() => {});
$('join-scan-status').textContent = 'Antwort-QR dem Host zeigen'; $('join-scan-status').textContent = 'Antwort-QR dem Host zeigen';
camStop(); camStop();
}; };
@ -394,7 +417,7 @@
if (!raw) return; if (!raw) return;
if (!mesh) { show('start'); return; } if (!mesh) { show('start'); return; }
try { try {
await unpack(decode45(raw)); await unpack(raw);
} catch (e) { return; } } catch (e) { return; }
await mesh.joinFromQR(raw); await mesh.joinFromQR(raw);
$('join-qr-paste').value = ''; $('join-qr-paste').value = '';

File diff suppressed because one or more lines are too long

View file

@ -136,6 +136,7 @@
<p>&copy; by neunzig.wtf &middot; commit <a id="commit-hash" href="https://git.ziemlichoptimal.de/90wtf/randomp2p/src/commit/HASH">HASH</a></p> <p>&copy; by neunzig.wtf &middot; commit <a id="commit-hash" href="https://git.ziemlichoptimal.de/90wtf/randomp2p/src/commit/HASH">HASH</a></p>
</footer> </footer>
<script src="vendor/simplepeer.min.js"></script> <script src="vendor/simplepeer.min.js"></script>
<script src="vendor/pako.min.js"></script>
<script src="vendor/qrcode.min.js"></script> <script src="vendor/qrcode.min.js"></script>
<script src="vendor/jsQR.js"></script> <script src="vendor/jsQR.js"></script>
<script src="crypto.js"></script> <script src="crypto.js"></script>

16
p2p.js
View file

@ -5,7 +5,6 @@ class MeshNet {
this._pendingMeshPeers = new Map(); this._pendingMeshPeers = new Map();
this._pendingPeer = null; this._pendingPeer = null;
this._currentQRData = null; this._currentQRData = null;
this._fullSDPData = null;
this.isHost = false; this.isHost = false;
this.hostPeerId = null; this.hostPeerId = null;
this.roster = []; this.roster = [];
@ -47,9 +46,7 @@ class MeshNet {
signalSent = true; signalSent = true;
this._log('SDP-Signal (Offer) empfangen'); this._log('SDP-Signal (Offer) empfangen');
const packed = await pack({ v: 1, id: this.myPeerId, s: signal }); this._currentQRData = await pack({ v: 1, id: this.myPeerId, s: signal });
this._currentQRData = encode45(packed);
this._fullSDPData = this._currentQRData;
if (this.onqrupdate) this.onqrupdate(this._currentQRData); if (this.onqrupdate) this.onqrupdate(this._currentQRData);
this._log('Offer QR erstellt'); this._log('Offer QR erstellt');
@ -81,7 +78,7 @@ class MeshNet {
return; return;
} }
try { try {
const data = await unpack(decode45(answerStr)); const data = await unpack(answerStr);
this._pendingPeer.peerId = data.id; this._pendingPeer.peerId = data.id;
this._pendingPeer.peer.signal(data.s); this._pendingPeer.peer.signal(data.s);
this._pendingPeer.signalReceived = true; this._pendingPeer.signalReceived = true;
@ -95,7 +92,7 @@ class MeshNet {
/* ─── Peer: join ─── */ /* ─── Peer: join ─── */
async joinFromQR(qrContent) { async joinFromQR(qrContent) {
const data = await unpack(decode45(qrContent)); const data = await unpack(qrContent);
const remoteId = data.id; const remoteId = data.id;
this.hostPeerId = remoteId; this.hostPeerId = remoteId;
const offer = data.s; const offer = data.s;
@ -107,8 +104,7 @@ class MeshNet {
peer.on('signal', async signal => { peer.on('signal', async signal => {
if (answerSent) return; if (answerSent) return;
answerSent = true; answerSent = true;
const packed = await pack({ v: 1, id: this.myPeerId, s: signal, to: remoteId }); const answerData = await pack({ v: 1, id: this.myPeerId, s: signal, to: remoteId });
const answerData = encode45(packed);
if (this.onanswerready) this.onanswerready(answerData); if (this.onanswerready) this.onanswerready(answerData);
this._log('Answer QR erstellt'); this._log('Answer QR erstellt');
}); });
@ -393,10 +389,6 @@ class MeshNet {
return this.names.get(peerId) || peerId.slice(0, 8); return this.names.get(peerId) || peerId.slice(0, 8);
} }
getFullSDPData() {
return this._fullSDPData;
}
destroy() { destroy() {
this._log('MeshNet wird zerstört'); this._log('MeshNet wird zerstört');
for (const peer of this.connections.values()) { for (const peer of this.connections.values()) {

View file

@ -168,19 +168,17 @@
return new Promise(r => setTimeout(r, ms)); return new Promise(r => setTimeout(r, ms));
} }
/* ─── Test: QR-Daten format (encode45/decode45 roundtrip) ─── */ /* ─── Test: pack/unpack Roundtrip ─── */
async function testQRRoundtrip() { async function testQRRoundtrip() {
const testData = { v: 1, id: 'aabbccdd', s: { type: 'offer', sdp: 'mock-sdp' } }; const testData = { v: 1, id: 'aabbccdd', s: { type: 'offer', sdp: 'mock-sdp' } };
const packed = await pack(testData); const packed = await pack(testData);
const encoded = encode45(packed); const unpacked = await unpack(packed);
const decoded = decode45(encoded);
const unpacked = await unpack(decoded);
const pass = unpacked.v === 1 && unpacked.id === 'aabbccdd' && unpacked.s.type === 'offer'; const pass = unpacked.v === 1 && unpacked.id === 'aabbccdd' && unpacked.s.type === 'offer';
return { return {
pass, pass,
detail: pass detail: pass
? `pack → encode45 → decode45 → unpack OK\nEncoded: ${encoded.slice(0, 40)}…` ? `pack → unpack OK\nBase64: ${packed.slice(0, 40)}…`
: `Roundtrip fehlgeschlagen: ${JSON.stringify(unpacked)}` : `Roundtrip fehlgeschlagen: ${JSON.stringify(unpacked)}`
}; };
} }
@ -198,7 +196,7 @@
let parsed; let parsed;
try { try {
parsed = await unpack(decode45(host._qrData)); parsed = await unpack(host._qrData);
} catch (e) { } catch (e) {
return { pass: false, detail: 'Host QR parsing failed: ' + e.message }; return { pass: false, detail: 'Host QR parsing failed: ' + e.message };
} }
@ -211,7 +209,7 @@
if (!peer._answerData) return { pass: false, detail: 'Peer Answer QR wurde nicht generiert' }; if (!peer._answerData) return { pass: false, detail: 'Peer Answer QR wurde nicht generiert' };
try { try {
parsed = await unpack(decode45(peer._answerData)); parsed = await unpack(peer._answerData);
} catch (e) { } catch (e) {
return { pass: false, detail: 'Peer Answer QR parsing failed: ' + e.message }; return { pass: false, detail: 'Peer Answer QR parsing failed: ' + e.message };
} }
@ -425,7 +423,7 @@
$('summary').style.display = 'none'; $('summary').style.display = 'none';
const tests = [ const tests = [
{ id: 't-qr-roundtrip', label: 'QR-Format: pack/encode45/decode45/unpack', fn: testQRRoundtrip }, { id: 't-qr-roundtrip', label: 'QR-Format: pack/unpack (pako+SDP dict)', fn: testQRRoundtrip },
{ id: 't-basic-pairing', label: 'Basis-Pairing: Host → QR → Peer → Answer → Feed', fn: testBasicPairing }, { id: 't-basic-pairing', label: 'Basis-Pairing: Host → QR → Peer → Answer → Feed', fn: testBasicPairing },
{ id: 't-chat-pairing', label: 'Chat via Pairing: Host ↔ Peer', fn: testChatAfterPairing }, { id: 't-chat-pairing', label: 'Chat via Pairing: Host ↔ Peer', fn: testChatAfterPairing },
{ id: 't-onchat', label: 'onchat Callback bei Chat-Empfang', fn: testOnchatCallback }, { id: 't-onchat', label: 'onchat Callback bei Chat-Empfang', fn: testOnchatCallback },

2
vendor/pako.min.js vendored Normal file

File diff suppressed because one or more lines are too long