QR-Kompression: pako.deflateRaw + SDP-Dictionary statt base45
All checks were successful
Pin to IPFS / pin (push) Successful in 9s
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:
parent
f1f27e5164
commit
a7933315f3
10 changed files with 158 additions and 143 deletions
40
.tmp/Chrome Offer1 v 1 id.txt
Normal file
40
.tmp/Chrome Offer1 v 1 id.txt
Normal 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
21
.tmp/Firefox Chrome.txt
Normal 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"
|
||||||
|
}
|
||||||
43
.tmp/Firefox Offer 1 v 1 id.txt
Normal file
43
.tmp/Firefox Offer 1 v 1 id.txt
Normal 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"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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
39
app.js
|
|
@ -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 = '';
|
||||||
|
|
|
||||||
77
crypto.js
77
crypto.js
File diff suppressed because one or more lines are too long
|
|
@ -136,6 +136,7 @@
|
||||||
<p>© by neunzig.wtf · commit <a id="commit-hash" href="https://git.ziemlichoptimal.de/90wtf/randomp2p/src/commit/HASH">HASH</a></p>
|
<p>© by neunzig.wtf · 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
16
p2p.js
|
|
@ -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()) {
|
||||||
|
|
|
||||||
|
|
@ -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
2
vendor/pako.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue