feat: add form to send/receive messages after handshake

This commit is contained in:
Richard Ramos 2022-12-16 15:58:21 -04:00
parent c10e2f1a88
commit 6014ac0f3a
No known key found for this signature in database
GPG Key ID: BD36D48BC9FFC88C
9 changed files with 373 additions and 364 deletions

View File

@ -7,7 +7,23 @@
</head> </head>
<body> <body>
<p>Press F12 to open the console</p> <p>Press F12 to open the console</p>
<canvas id="qrCanvas"></canvas> <p><b>Waku Status:</b> <span id="waku-status">connecting...</span></p>
<p id="handshake-span"><b>Handshake Status:</b> <span id="handshake-status">-</span></p>
<canvas id="qr-canvas"></canvas>
<a href="#" id="qr-url" style="display: none" target="_blank">Click here to simulate QR code being scanned</a>
<div id="chat-area" style="display: none">
<label for="nick-input">Your nickname</label>
<input id="nick-input" placeholder="Choose a nickname" type="text" />
<label for="text-input">Message text</label>
<input id="text-input" placeholder="Type your message here" type="text" />
<button id="send-btn" type="button" disabled>Send message using Light Push</button>
<span id="sending-status"></span>
<h4 class="mu1">Messages</h4>
<div id="messages"></div>
</div>
<script src="./index.js"></script> <script src="./index.js"></script>
</body> </body>
</html> </html>

View File

@ -1,11 +1,26 @@
import { createLightNode } from "js-waku/lib/create_waku"; import { createLightNode } from "js-waku/lib/create_waku";
import { utils } from "js-waku";
import { waitForRemotePeer } from "js-waku/lib/wait_for_remote_peer"; import { waitForRemotePeer } from "js-waku/lib/wait_for_remote_peer";
import { Fleet, getPredefinedBootstrapNodes } from "js-waku/lib/predefined_bootstrap_nodes";
import { PeerDiscoveryStaticPeers } from "js-waku/lib/peer_discovery_static_list";
import { Protocols } from "js-waku";
import * as noise from "@waku/noise"; import * as noise from "@waku/noise";
import protobuf from "protobufjs";
import QRCode from "qrcode"; import QRCode from "qrcode";
// TODO: Get rid of these // TODO: Get rid of these
import hexToArrayBuffer from "hex-to-array-buffer"; import hexToArrayBuffer from "hex-to-array-buffer";
import arrayBufferToHex from "array-buffer-to-hex"; import arrayBufferToHex from "array-buffer-to-hex";
import { WakuPairing } from "@waku/noise";
const messagesDiv = document.getElementById("messages");
const nicknameInput = document.getElementById("nick-input");
const textInput = document.getElementById("text-input");
const sendButton = document.getElementById("send-btn");
const sendingStatusSpan = document.getElementById("sending-status");
const chatArea = document.getElementById("chat-area");
const qrCanvas = document.getElementById("qr-canvas");
const qrUrl = document.getElementById("qr-url");
const wakuStatusSpan = document.getElementById("waku-status");
const handshakeStatusSpan = document.getElementById("handshake-status");
function getPairingInfofromUrl() { function getPairingInfofromUrl() {
const urlParts = window.location.href.split("?"); const urlParts = window.location.href.split("?");
@ -19,22 +34,7 @@ function getPairingInfofromUrl() {
return new noise.InitiatorParameters(pairingParts.join(":"), qrMessageNameTag); return new noise.InitiatorParameters(pairingParts.join(":"), qrMessageNameTag);
} }
async function confirmAuthCodeFlow(pairingObj) { function getSenderAndResponder(node) {
const authCode = await pairingObj.getAuthCode();
pairingObj.validateAuthCode(confirm("Confirm that authcode is: " + authCode));
}
async function main() {
// Starting the node
const node = await createLightNode();
await node.start();
// Dialing a node and wait until it's available
const ma =
"/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm";
await node.dial(ma, ["filter", "lightpush"]);
await waitForRemotePeer(node, ["filter", "lightpush"]);
const sender = { const sender = {
async publish(encoder, msg) { async publish(encoder, msg) {
await node.lightPush.push(encoder, msg); await node.lightPush.push(encoder, msg);
@ -42,12 +42,15 @@ async function main() {
}; };
const msgQueue = new Array(); const msgQueue = new Array();
const receiver = { const subscriptions = new Map();
const intervals = new Map();
const responder = {
async subscribe(decoder) { async subscribe(decoder) {
await node.filter.subscribe([decoder], (wakuMessage) => { const subscription = await node.filter.subscribe([decoder], (wakuMessage) => {
msgQueue.push(wakuMessage); msgQueue.push(wakuMessage);
// TODO: remove subscription once handshake ends?
}); });
subscriptions.set(decoder.contentTopic, subscription);
}, },
async nextMessage(contentTopic) { async nextMessage(contentTopic) {
if (msgQueue.length != 0) { if (msgQueue.length != 0) {
@ -67,89 +70,219 @@ async function main() {
} }
} }
}, 100); }, 100);
intervals.set(contentTopic, interval);
}); });
}, },
async stop(contentTopic) {
if (intervals.has(contentTopic)) {
clearInterval(intervals.get(contentTopic));
intervals.delete(contentTopic);
}
if (subscriptions.has(contentTopic)) {
await subscriptions.get(contentTopic)();
subscriptions.delete(contentTopic);
} else {
console.log("Subscriptipon doesnt exist")
}
},
}; };
const myStaticKey = noise.generateX25519KeyPair(); return [sender, responder];
}
const pairingParameters = getPairingInfofromUrl(); async function confirmAuthCodeFlow(pairingObj) {
if (pairingParameters) { const authCode = await pairingObj.getAuthCode();
console.log("Initiator"); pairingObj.validateAuthCode(confirm("Confirm that authcode is: " + authCode));
}
const pairingObj = new noise.WakuPairing(sender, receiver, myStaticKey, pairingParameters); async function hideQR() {
const pExecute = pairingObj.execute(120000); // timeout after 2m qrCanvas.remove();
qrUrl.remove();
}
confirmAuthCodeFlow(pairingObj); async function disableUI() {
hideQR();
try { chatArea.remove();
console.log("executing handshake..."); }
const codecs = await pExecute;
alert("Handshake completed!"); // Function to update the fields to guide the user by disabling buttons.
// TODO: enable a form so users can send messages const updateFields = () => {
} catch (err) { const readyToSend = nicknameInput.value !== "";
alert(err); textInput.disabled = !readyToSend;
sendButton.disabled = !readyToSend;
};
// Protobuf
const ProtoChatMessage = new protobuf.Type("ChatMessage")
.add(new protobuf.Field("timestamp", 1, "uint64"))
.add(new protobuf.Field("nick", 2, "string"))
.add(new protobuf.Field("text", 3, "bytes"));
let messages = [];
const updateMessages = () => {
messagesDiv.innerHTML = "<ul>";
messages.forEach((msg) => {
messagesDiv.innerHTML += `<li>${msg}</li>`;
});
messagesDiv.innerHTML += "</ul>";
};
const onMessage = (wakuMessage) => {
const { timestamp, nick, text } = ProtoChatMessage.decode(wakuMessage.payload);
const time = new Date();
time.setTime(Number(timestamp) * 1000);
messages.push(`(${nick}) <strong>${utils.bytesToUtf8(text)}</strong> <i>[${time.toISOString()}]</i>`);
updateMessages();
};
async function main() {
// Starting the node
const node = await createLightNode({
libp2p: {
peerDiscovery: [new PeerDiscoveryStaticPeers(getPredefinedBootstrapNodes(Fleet.Test))],
},
});
try {
await node.start();
await waitForRemotePeer(node, [Protocols.Filter, Protocols.LightPush]);
wakuStatusSpan.innerHTML = "connected";
const [sender, responder] = getSenderAndResponder(node);
const myStaticKey = noise.generateX25519KeyPair();
const pairingParameters = getPairingInfofromUrl();
const initiator = pairingParameters ? true : false;
let encoder;
let decoder;
if (initiator) {
console.log("Initiator");
qrCanvas.remove(); // Initiator does not require a QR code
const pairingObj = new noise.WakuPairing(sender, responder, myStaticKey, pairingParameters);
const pExecute = pairingObj.execute(120000); // timeout after 2m
confirmAuthCodeFlow(pairingObj);
try {
handshakeStatusSpan.innerHTML = "executing handshake...";
[encoder, decoder] = await pExecute;
handshakeStatusSpan.innerHTML = "handshake completed!";
} catch (err) {
handshakeStatusSpan.innerHTML = err.message;
disableUI();
console.error(err);
}
/*
// The information needs to be backed up to decrypt messages sent with
// codecs generated with the handshake. The `handshakeResult` variable
// contains private information that needs to be stored safely
const contentTopic = pairingObj.contentTopic;
const handshakeResult = pairingObj.getHandshakeResult();
// To restore the codecs for decrypting older messages, or continuing an existing
// session, use this:
[encoder, decoder] = WakuPairing.getSecureCodec(contentTopic, handshakeResult);
*/
} else {
console.log("Responder");
const pairingObj = new noise.WakuPairing(sender, responder, myStaticKey, new noise.ResponderParameters());
const pExecute = pairingObj.execute(120000); // timeout after 2m
confirmAuthCodeFlow(pairingObj);
const pInfo = pairingObj.getPairingInfo();
// Data to encode in the QR code. The qrMessageNametag too to the QR string (separated by )
const qrString = arrayBufferToHex(pInfo.qrMessageNameTag) + ":" + pInfo.qrCode;
const qrURLString = window.location.href + "?" + encodeURIComponent(qrString);
handshakeStatusSpan.innerHTML = "generating QR code...";
console.log("Generating QR...");
QRCode.toCanvas(qrCanvas, qrURLString, (err) => {
if (err) {
handshakeStatusSpan.innerHTML = err.message;
disableUI();
console.error(err);
} else {
handshakeStatusSpan.innerHTML = "waiting for handshake to start";
qrUrl.href = qrURLString;
qrUrl.style.display = "block";
}
});
try {
handshakeStatusSpan.innerHTML = "executing handshake...";
[encoder, decoder] = await pExecute;
handshakeStatusSpan.innerHTML = "handshake completed!";
hideQR();
} catch (err) {
handshakeStatusSpan.innerHTML = err.message;
disableUI();
console.error(err);
}
/*
// The information needs to be backed up to decrypt messages sent with
// codecs generated with the handshake. The `handshakeResult` variable
// contains private information that needs to be stored safely
const contentTopic = pairingObj.contentTopic;
const handshakeResult = pairingObj.getHandshakeResult();
// To restore the codecs for decrypting older messages, or continuing an existing
// session, use this:
[encoder, decoder] = WakuPairing.getSecureCodec(contentTopic, handshakeResult);
*/
} }
// The information needs to be backed up to decrypt messages sent with nicknameInput.onchange = updateFields;
// codecs generated with the handshake nicknameInput.onblur = updateFields;
const contentTopic = pairingObj.contentTopic;
const handshakeResult = pairingObj.getHandshakeResult();
// This information should not be printed, it's done sendButton.onclick = async () => {
// to see the information in the dev console const text = utils.utf8ToBytes(textInput.value);
console.log("HandshakeResult", handshakeResult); const timestamp = new Date();
const msg = ProtoChatMessage.create({
text,
nick: nicknameInput.value,
timestamp: Math.floor(timestamp.valueOf() / 1000),
});
const payload = ProtoChatMessage.encode(msg).finish();
sendingStatusSpan.innerText = "sending...";
await node.lightPush.push(encoder, { payload, timestamp });
sendingStatusSpan.innerText = "sent!";
// To restore the codecs: onMessage({ payload });
const codecs = WakuPairing.getSecureCodec(contentTopic, handshakeResult);
} else {
console.log("Receiver");
const pairingObj = new noise.WakuPairing(sender, receiver, myStaticKey, new noise.ReceiverParameters()); textInput.value = null;
const pExecute = pairingObj.execute(120000); // timeout after 2m setTimeout(() => {
sendingStatusSpan.innerText = "";
}, 5000);
};
confirmAuthCodeFlow(pairingObj); await node.filter.subscribe([decoder], onMessage);
const pInfo = pairingObj.getPairingInfo(); chatArea.style.display = "block";
} catch (err) {
// Data to encode in the QR code. The qrMessageNametag too to the QR string (separated by ) wakuStatusSpan.innerHTML = err.message;
const qrString = arrayBufferToHex(pInfo.qrMessageNameTag) + ":" + pInfo.qrCode; disableUI();
const qrURL = window.location.href + "?" + encodeURIComponent(qrString); return;
console.log("Generating QR...");
QRCode.toCanvas(document.getElementById("qrCanvas"), qrURL, (error) => {
if (error) console.error(error);
});
// Auto open page - TODO: remove this
window.setTimeout(() => {
alert("Automatically opening new page to simulate QR code being scanned");
window.open(qrURL);
}, 1000);
try {
console.log("executing handshake...");
const codecs = await pExecute;
alert("Handshake completed!");
// TODO: enable a form so users can send messages
} catch (err) {
// TODO: hide QR
// TODO: display message indicating pairing is not valid
// TODO: handle timeout
alert(err);
}
// The information needs to be backed up to decrypt messages sent with
// codecs generated with the handshake
const contentTopic = pairingObj.contentTopic;
const handshakeResult = pairingObj.getHandshakeResult();
// This information should not be printed, it's done
// to see the information in the dev console
console.log("HandshakeResult", handshakeResult);
// To restore the codecs:
const codecs = WakuPairing.getSecureCodec(contentTopic, handshakeResult);
} }
} }
main(); main();

View File

@ -12,6 +12,7 @@
"array-buffer-to-hex": "^1.0.0", "array-buffer-to-hex": "^1.0.0",
"hex-to-array-buffer": "^2.0.0", "hex-to-array-buffer": "^2.0.0",
"js-waku": "^0.29.0-29436ea", "js-waku": "^0.29.0-29436ea",
"protobufjs": "^7.1.2",
"qrcode": "^1.5.1" "qrcode": "^1.5.1"
}, },
"devDependencies": { "devDependencies": {
@ -191,6 +192,36 @@
"npm": ">=8.7.0" "npm": ">=8.7.0"
} }
}, },
"node_modules/@chainsafe/libp2p-gossipsub/node_modules/long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
"node_modules/@chainsafe/libp2p-gossipsub/node_modules/protobufjs": {
"version": "6.11.3",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz",
"integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==",
"hasInstallScript": true,
"dependencies": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/long": "^4.0.1",
"@types/node": ">=13.7.0",
"long": "^4.0.0"
},
"bin": {
"pbjs": "bin/pbjs",
"pbts": "bin/pbts"
}
},
"node_modules/@chainsafe/libp2p-noise": { "node_modules/@chainsafe/libp2p-noise": {
"version": "8.0.2", "version": "8.0.2",
"resolved": "https://registry.npmjs.org/@chainsafe/libp2p-noise/-/libp2p-noise-8.0.2.tgz", "resolved": "https://registry.npmjs.org/@chainsafe/libp2p-noise/-/libp2p-noise-8.0.2.tgz",
@ -492,11 +523,6 @@
"npm": ">=7.0.0" "npm": ">=7.0.0"
} }
}, },
"node_modules/@libp2p/crypto/node_modules/long": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
},
"node_modules/@libp2p/crypto/node_modules/multiformats": { "node_modules/@libp2p/crypto/node_modules/multiformats": {
"version": "10.0.2", "version": "10.0.2",
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz",
@ -506,29 +532,6 @@
"npm": ">=7.0.0" "npm": ">=7.0.0"
} }
}, },
"node_modules/@libp2p/crypto/node_modules/protobufjs": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
"integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
"hasInstallScript": true,
"dependencies": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/node": ">=13.7.0",
"long": "^5.0.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/@libp2p/crypto/node_modules/protons-runtime": { "node_modules/@libp2p/crypto/node_modules/protons-runtime": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz", "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz",
@ -1213,11 +1216,6 @@
"npm": ">=7.0.0" "npm": ">=7.0.0"
} }
}, },
"node_modules/@libp2p/peer-id-factory/node_modules/long": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
},
"node_modules/@libp2p/peer-id-factory/node_modules/multiformats": { "node_modules/@libp2p/peer-id-factory/node_modules/multiformats": {
"version": "10.0.2", "version": "10.0.2",
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz",
@ -1227,29 +1225,6 @@
"npm": ">=7.0.0" "npm": ">=7.0.0"
} }
}, },
"node_modules/@libp2p/peer-id-factory/node_modules/protobufjs": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
"integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
"hasInstallScript": true,
"dependencies": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/node": ">=13.7.0",
"long": "^5.0.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/@libp2p/peer-id-factory/node_modules/protons-runtime": { "node_modules/@libp2p/peer-id-factory/node_modules/protons-runtime": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz", "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz",
@ -1347,11 +1322,6 @@
"npm": ">=7.0.0" "npm": ">=7.0.0"
} }
}, },
"node_modules/@libp2p/peer-record/node_modules/long": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
},
"node_modules/@libp2p/peer-record/node_modules/multiformats": { "node_modules/@libp2p/peer-record/node_modules/multiformats": {
"version": "10.0.2", "version": "10.0.2",
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz",
@ -1361,29 +1331,6 @@
"npm": ">=7.0.0" "npm": ">=7.0.0"
} }
}, },
"node_modules/@libp2p/peer-record/node_modules/protobufjs": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
"integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
"hasInstallScript": true,
"dependencies": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/node": ">=13.7.0",
"long": "^5.0.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/@libp2p/peer-record/node_modules/protons-runtime": { "node_modules/@libp2p/peer-record/node_modules/protons-runtime": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz", "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz",
@ -4770,9 +4717,9 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
}, },
"node_modules/long": { "node_modules/long": {
"version": "4.0.0", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
}, },
"node_modules/longbits": { "node_modules/longbits": {
"version": "1.1.0", "version": "1.1.0",
@ -5453,52 +5400,6 @@
"dev": true "dev": true
}, },
"node_modules/protobufjs": { "node_modules/protobufjs": {
"version": "6.11.3",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz",
"integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==",
"hasInstallScript": true,
"dependencies": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/long": "^4.0.1",
"@types/node": ">=13.7.0",
"long": "^4.0.0"
},
"bin": {
"pbjs": "bin/pbjs",
"pbts": "bin/pbts"
}
},
"node_modules/protons-runtime": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-3.1.0.tgz",
"integrity": "sha512-S1iSPQC0McdHKJRi0XcATBkWgwWPx46UDfrnshYDXBvGHSYqkFtn4MQ8Gatf67w7FzFtHivA+Hb0ZPq56upG8w==",
"dependencies": {
"protobufjs": "^7.0.0",
"uint8arraylist": "^2.3.2"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=7.0.0"
},
"peerDependencies": {
"uint8arraylist": "^2.3.2"
}
},
"node_modules/protons-runtime/node_modules/long": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
},
"node_modules/protons-runtime/node_modules/protobufjs": {
"version": "7.1.2", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
"integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==", "integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
@ -5521,6 +5422,22 @@
"node": ">=12.0.0" "node": ">=12.0.0"
} }
}, },
"node_modules/protons-runtime": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-3.1.0.tgz",
"integrity": "sha512-S1iSPQC0McdHKJRi0XcATBkWgwWPx46UDfrnshYDXBvGHSYqkFtn4MQ8Gatf67w7FzFtHivA+Hb0ZPq56upG8w==",
"dependencies": {
"protobufjs": "^7.0.0",
"uint8arraylist": "^2.3.2"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=7.0.0"
},
"peerDependencies": {
"uint8arraylist": "^2.3.2"
}
},
"node_modules/proxy-addr": { "node_modules/proxy-addr": {
"version": "2.0.7", "version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@ -7211,6 +7128,33 @@
"protobufjs": "^6.11.2", "protobufjs": "^6.11.2",
"uint8arraylist": "^2.3.2", "uint8arraylist": "^2.3.2",
"uint8arrays": "^3.0.0" "uint8arrays": "^3.0.0"
},
"dependencies": {
"long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
"protobufjs": {
"version": "6.11.3",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz",
"integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==",
"requires": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/long": "^4.0.1",
"@types/node": ">=13.7.0",
"long": "^4.0.0"
}
}
} }
}, },
"@chainsafe/libp2p-noise": { "@chainsafe/libp2p-noise": {
@ -7436,35 +7380,11 @@
"uint8arrays": "^4.0.2" "uint8arrays": "^4.0.2"
}, },
"dependencies": { "dependencies": {
"long": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
},
"multiformats": { "multiformats": {
"version": "10.0.2", "version": "10.0.2",
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz",
"integrity": "sha512-nJEHLFOYhO4L+aNApHhCnWqa31FyqAHv9Q77AhmwU3KsM2f1j7tuJpCk5ByZ33smzycNCpSG5klNIejIyfFx2A==" "integrity": "sha512-nJEHLFOYhO4L+aNApHhCnWqa31FyqAHv9Q77AhmwU3KsM2f1j7tuJpCk5ByZ33smzycNCpSG5klNIejIyfFx2A=="
}, },
"protobufjs": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
"integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
"requires": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/node": ">=13.7.0",
"long": "^5.0.0"
}
},
"protons-runtime": { "protons-runtime": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz", "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz",
@ -7985,35 +7905,11 @@
"uint8arrays": "^4.0.2" "uint8arrays": "^4.0.2"
}, },
"dependencies": { "dependencies": {
"long": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
},
"multiformats": { "multiformats": {
"version": "10.0.2", "version": "10.0.2",
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz",
"integrity": "sha512-nJEHLFOYhO4L+aNApHhCnWqa31FyqAHv9Q77AhmwU3KsM2f1j7tuJpCk5ByZ33smzycNCpSG5klNIejIyfFx2A==" "integrity": "sha512-nJEHLFOYhO4L+aNApHhCnWqa31FyqAHv9Q77AhmwU3KsM2f1j7tuJpCk5ByZ33smzycNCpSG5klNIejIyfFx2A=="
}, },
"protobufjs": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
"integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
"requires": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/node": ">=13.7.0",
"long": "^5.0.0"
}
},
"protons-runtime": { "protons-runtime": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz", "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz",
@ -8073,35 +7969,11 @@
"varint": "^6.0.0" "varint": "^6.0.0"
} }
}, },
"long": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
},
"multiformats": { "multiformats": {
"version": "10.0.2", "version": "10.0.2",
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-10.0.2.tgz",
"integrity": "sha512-nJEHLFOYhO4L+aNApHhCnWqa31FyqAHv9Q77AhmwU3KsM2f1j7tuJpCk5ByZ33smzycNCpSG5klNIejIyfFx2A==" "integrity": "sha512-nJEHLFOYhO4L+aNApHhCnWqa31FyqAHv9Q77AhmwU3KsM2f1j7tuJpCk5ByZ33smzycNCpSG5klNIejIyfFx2A=="
}, },
"protobufjs": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
"integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
"requires": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/node": ">=13.7.0",
"long": "^5.0.0"
}
},
"protons-runtime": { "protons-runtime": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz", "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-4.0.1.tgz",
@ -10874,9 +10746,9 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
}, },
"long": { "long": {
"version": "4.0.0", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
}, },
"longbits": { "longbits": {
"version": "1.1.0", "version": "1.1.0",
@ -11362,9 +11234,9 @@
"dev": true "dev": true
}, },
"protobufjs": { "protobufjs": {
"version": "6.11.3", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
"integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", "integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
"requires": { "requires": {
"@protobufjs/aspromise": "^1.1.2", "@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2", "@protobufjs/base64": "^1.1.2",
@ -11376,9 +11248,8 @@
"@protobufjs/path": "^1.1.2", "@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0", "@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0", "@protobufjs/utf8": "^1.1.0",
"@types/long": "^4.0.1",
"@types/node": ">=13.7.0", "@types/node": ">=13.7.0",
"long": "^4.0.0" "long": "^5.0.0"
} }
}, },
"protons-runtime": { "protons-runtime": {
@ -11388,32 +11259,6 @@
"requires": { "requires": {
"protobufjs": "^7.0.0", "protobufjs": "^7.0.0",
"uint8arraylist": "^2.3.2" "uint8arraylist": "^2.3.2"
},
"dependencies": {
"long": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
},
"protobufjs": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
"integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
"requires": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/node": ">=13.7.0",
"long": "^5.0.0"
}
}
} }
}, },
"proxy-addr": { "proxy-addr": {

View File

@ -13,6 +13,7 @@
"array-buffer-to-hex": "^1.0.0", "array-buffer-to-hex": "^1.0.0",
"hex-to-array-buffer": "^2.0.0", "hex-to-array-buffer": "^2.0.0",
"js-waku": "^0.29.0-29436ea", "js-waku": "^0.29.0-29436ea",
"protobufjs": "^7.1.2",
"qrcode": "^1.5.1" "qrcode": "^1.5.1"
}, },
"devDependencies": { "devDependencies": {

View File

@ -135,10 +135,13 @@ export class NoiseSecureTransferDecoder implements Decoder<NoiseSecureMessage> {
return; return;
} }
const payloadV2 = PayloadV2.deserialize(proto.payload); try {
const payloadV2 = PayloadV2.deserialize(proto.payload);
const decryptedPayload = this.hsResult.readMessage(payloadV2); const decryptedPayload = this.hsResult.readMessage(payloadV2);
return new NoiseSecureMessage(proto, decryptedPayload);
return new NoiseSecureMessage(proto, decryptedPayload); } catch (err) {
log("could not decode message ", err);
return;
}
} }
} }

View File

@ -13,7 +13,7 @@ import {
MessageNametagError, MessageNametagError,
StepHandshakeParameters, StepHandshakeParameters,
} from "./handshake.js"; } from "./handshake.js";
import { InitiatorParameters, Receiver, ReceiverParameters, Sender, WakuPairing } from "./pairing.js"; import { InitiatorParameters, Responder, ResponderParameters, Sender, WakuPairing } from "./pairing.js";
import { import {
EmptyPreMessage, EmptyPreMessage,
HandshakePattern, HandshakePattern,
@ -51,4 +51,4 @@ export { ChaChaPolyCipherState, NoisePublicKey };
export { MessageNametagBuffer }; export { MessageNametagBuffer };
export { NoiseHandshakeDecoder, NoiseHandshakeEncoder, NoiseSecureTransferDecoder, NoiseSecureTransferEncoder }; export { NoiseHandshakeDecoder, NoiseHandshakeEncoder, NoiseSecureTransferDecoder, NoiseSecureTransferEncoder };
export { QR }; export { QR };
export { InitiatorParameters, ReceiverParameters, Sender, Receiver, WakuPairing }; export { InitiatorParameters, ResponderParameters, Sender, Responder, WakuPairing };

View File

@ -8,7 +8,7 @@ import { equals as uint8ArrayEquals } from "uint8arrays/equals";
import { NoiseHandshakeMessage } from "./codec"; import { NoiseHandshakeMessage } from "./codec";
import { generateX25519KeyPair } from "./crypto"; import { generateX25519KeyPair } from "./crypto";
import { ReceiverParameters, WakuPairing } from "./pairing"; import { ResponderParameters, WakuPairing } from "./pairing";
import { MessageNametagBufferSize } from "./payload"; import { MessageNametagBufferSize } from "./payload";
describe("js-noise: pairing object", () => { describe("js-noise: pairing object", () => {
@ -30,7 +30,7 @@ describe("js-noise: pairing object", () => {
}, },
}; };
const decoderMap: { [key: string]: Decoder<NoiseHandshakeMessage> } = {}; const decoderMap: { [key: string]: Decoder<NoiseHandshakeMessage> } = {};
const receiver = { const responder = {
subscribe(decoder: Decoder<NoiseHandshakeMessage>): Promise<void> { subscribe(decoder: Decoder<NoiseHandshakeMessage>): Promise<void> {
return new Promise((resolve) => { return new Promise((resolve) => {
decoderMap[decoder.contentTopic] = decoder; decoderMap[decoder.contentTopic] = decoder;
@ -42,6 +42,10 @@ describe("js-noise: pairing object", () => {
const decodedMessage = await decoderMap[contentTopic].decode(msg); const decodedMessage = await decoderMap[contentTopic].decode(msg);
return decodedMessage!; return decodedMessage!;
}, },
async stop(contentTopic: string): Promise<void> {
// Do nothing. This is just a simulation
console.debug("stopping subscription to", contentTopic);
},
}; };
// ================= // =================
@ -49,15 +53,15 @@ describe("js-noise: pairing object", () => {
const bobStaticKey = generateX25519KeyPair(); const bobStaticKey = generateX25519KeyPair();
const aliceStaticKey = generateX25519KeyPair(); const aliceStaticKey = generateX25519KeyPair();
const recvParameters = new ReceiverParameters(); const recvParameters = new ResponderParameters();
const bobPairingObj = new WakuPairing(sender, receiver, bobStaticKey, recvParameters); const bobPairingObj = new WakuPairing(sender, responder, bobStaticKey, recvParameters);
const bobExecP1 = bobPairingObj.execute(); const bobExecP1 = bobPairingObj.execute();
// Confirmation is done by manually // Confirmation is done by manually
confirmAuthCodeFlow(bobPairingObj, true); confirmAuthCodeFlow(bobPairingObj, true);
const initParameters = bobPairingObj.getPairingInfo(); const initParameters = bobPairingObj.getPairingInfo();
const alicePairingObj = new WakuPairing(sender, receiver, aliceStaticKey, initParameters); const alicePairingObj = new WakuPairing(sender, responder, aliceStaticKey, initParameters);
const aliceExecP1 = alicePairingObj.execute(); const aliceExecP1 = alicePairingObj.execute();
// Confirmation is done manually // Confirmation is done manually
@ -92,8 +96,8 @@ describe("js-noise: pairing object", () => {
}); });
it("should timeout", async function () { it("should timeout", async function () {
const bobPairingObj = new WakuPairing(sender, receiver, generateX25519KeyPair(), new ReceiverParameters()); const bobPairingObj = new WakuPairing(sender, responder, generateX25519KeyPair(), new ResponderParameters());
const alicePairingObj = new WakuPairing(sender, receiver, generateX25519KeyPair(), bobPairingObj.getPairingInfo()); const alicePairingObj = new WakuPairing(sender, responder, generateX25519KeyPair(), bobPairingObj.getPairingInfo());
const bobExecP1 = bobPairingObj.execute(1000); const bobExecP1 = bobPairingObj.execute(1000);
const aliceExecP1 = alicePairingObj.execute(1000); const aliceExecP1 = alicePairingObj.execute(1000);

View File

@ -24,7 +24,7 @@ export interface Sender {
publish(encoder: Encoder, msg: Message): Promise<void>; publish(encoder: Encoder, msg: Message): Promise<void>;
} }
export interface Receiver { export interface Responder {
subscribe(decoder: Decoder<NoiseHandshakeMessage>): Promise<void>; subscribe(decoder: Decoder<NoiseHandshakeMessage>): Promise<void>;
// next message should return messages received in a content topic // next message should return messages received in a content topic
@ -32,6 +32,9 @@ export interface Receiver {
// will call pop in the queue to remove the oldest message received // will call pop in the queue to remove the oldest message received
// (it's important to maintain order of received messages) // (it's important to maintain order of received messages)
nextMessage(contentTopic: string): Promise<NoiseHandshakeMessage>; nextMessage(contentTopic: string): Promise<NoiseHandshakeMessage>;
// this should stop the subscription
stop(contentTopic: string): Promise<void>;
} }
function delay(ms: number): Promise<void> { function delay(ms: number): Promise<void> {
@ -44,7 +47,7 @@ export class InitiatorParameters {
constructor(public readonly qrCode: string, public readonly qrMessageNameTag: Uint8Array) {} constructor(public readonly qrCode: string, public readonly qrMessageNameTag: Uint8Array) {}
} }
export class ReceiverParameters { export class ResponderParameters {
constructor( constructor(
public readonly applicationName: string = "waku-noise-sessions", public readonly applicationName: string = "waku-noise-sessions",
public readonly applicationVersion: string = "0.1", public readonly applicationVersion: string = "0.1",
@ -75,9 +78,9 @@ export class WakuPairing {
constructor( constructor(
private sender: Sender, private sender: Sender,
private receiver: Receiver, private responder: Responder,
private myStaticKey: KeyPair, private myStaticKey: KeyPair,
pairingParameters: InitiatorParameters | ReceiverParameters, pairingParameters: InitiatorParameters | ResponderParameters,
private myEphemeralKey: KeyPair = generateX25519KeyPair() private myEphemeralKey: KeyPair = generateX25519KeyPair()
) { ) {
this.randomFixLenVal = randomBytes(32, rng); this.randomFixLenVal = randomBytes(32, rng);
@ -160,7 +163,7 @@ export class WakuPairing {
while (!stopLoop) { while (!stopLoop) {
try { try {
const hsMessage = await this.receiver.nextMessage(contentTopic); const hsMessage = await this.responder.nextMessage(contentTopic);
const step = this.handshake.stepHandshake({ const step = this.handshake.stepHandshake({
readPayloadV2: hsMessage.payloadV2, readPayloadV2: hsMessage.payloadV2,
messageNametag, messageNametag,
@ -181,7 +184,7 @@ export class WakuPairing {
private async initiatorHandshake(): Promise<[NoiseSecureTransferEncoder, NoiseSecureTransferDecoder]> { private async initiatorHandshake(): Promise<[NoiseSecureTransferEncoder, NoiseSecureTransferDecoder]> {
// Subscribe to the contact content topic // Subscribe to the contact content topic
const decoder = new NoiseHandshakeDecoder(this.contentTopic); const decoder = new NoiseHandshakeDecoder(this.contentTopic);
await this.receiver.subscribe(decoder); await this.responder.subscribe(decoder);
// The handshake initiator writes a Waku2 payload v2 containing the handshake message // The handshake initiator writes a Waku2 payload v2 containing the handshake message
// and the (encrypted) transport message // and the (encrypted) transport message
@ -192,7 +195,7 @@ export class WakuPairing {
}); });
// We prepare a message from initiator's payload2 // We prepare a message from initiator's payload2
// At this point wakuMsg is sent over the Waku network to receiver content topic // At this point wakuMsg is sent over the Waku network to responder content topic
let encoder = new NoiseHandshakeEncoder(this.contentTopic, hsStep); let encoder = new NoiseHandshakeEncoder(this.contentTopic, hsStep);
await this.sender.publish(encoder, {}); await this.sender.publish(encoder, {});
@ -211,12 +214,14 @@ export class WakuPairing {
// <- sB, eAsB {r} // <- sB, eAsB {r}
hsStep = await this.executeReadStepWithNextMessage(this.contentTopic, this.handshake.hs.toMessageNametag()); hsStep = await this.executeReadStepWithNextMessage(this.contentTopic, this.handshake.hs.toMessageNametag());
await this.responder.stop(this.contentTopic);
if (!this.handshake.hs.rs) throw new Error("invalid handshake state"); if (!this.handshake.hs.rs) throw new Error("invalid handshake state");
// Initiator further checks if receiver's commitment opens to receiver's static key received // Initiator further checks if responder's commitment opens to responder's static key received
const expectedReceiverCommittedStaticKey = commitPublicKey(this.handshake.hs.rs, hsStep.transportMessage); const expectedResponderCommittedStaticKey = commitPublicKey(this.handshake.hs.rs, hsStep.transportMessage);
if (!uint8ArrayEquals(expectedReceiverCommittedStaticKey, this.qr.committedStaticKey)) { if (!uint8ArrayEquals(expectedResponderCommittedStaticKey, this.qr.committedStaticKey)) {
throw new Error("expected committed static key does not match the receiver actual committed static key"); throw new Error("expected committed static key does not match the responder actual committed static key");
} }
// 3rd step // 3rd step
@ -238,10 +243,10 @@ export class WakuPairing {
return WakuPairing.getSecureCodec(this.contentTopic, this.handshakeResult); return WakuPairing.getSecureCodec(this.contentTopic, this.handshakeResult);
} }
private async receiverHandshake(): Promise<[NoiseSecureTransferEncoder, NoiseSecureTransferDecoder]> { private async responderHandshake(): Promise<[NoiseSecureTransferEncoder, NoiseSecureTransferDecoder]> {
// Subscribe to the contact content topic // Subscribe to the contact content topic
const decoder = new NoiseHandshakeDecoder(this.contentTopic); const decoder = new NoiseHandshakeDecoder(this.contentTopic);
await this.receiver.subscribe(decoder); await this.responder.subscribe(decoder);
// the received reads the initiator's payloads, and returns the (decrypted) transport message the initiator sent // the received reads the initiator's payloads, and returns the (decrypted) transport message the initiator sent
// Note that the received verifies if the received payloadV2 has the expected messageNametag set // Note that the received verifies if the received payloadV2 has the expected messageNametag set
@ -259,25 +264,27 @@ export class WakuPairing {
} }
// 2nd step // 2nd step
// <- sB, eAsB {r} // <- sB, eAsB {r}
// Receiver writes and returns a payload // Responder writes and returns a payload
hsStep = this.handshake.stepHandshake({ hsStep = this.handshake.stepHandshake({
transportMessage: this.randomFixLenVal, transportMessage: this.randomFixLenVal,
messageNametag: this.handshake.hs.toMessageNametag(), messageNametag: this.handshake.hs.toMessageNametag(),
}); });
// We prepare a Waku message from receiver's payload2 // We prepare a Waku message from responder's payload2
const encoder = new NoiseHandshakeEncoder(this.contentTopic, hsStep); const encoder = new NoiseHandshakeEncoder(this.contentTopic, hsStep);
await this.sender.publish(encoder, {}); await this.sender.publish(encoder, {});
// 3rd step // 3rd step
// -> sA, sAeB, sAsB {s} // -> sA, sAeB, sAsB {s}
// The receiver reads the initiator's payload sent by the initiator // The responder reads the initiator's payload sent by the initiator
hsStep = await this.executeReadStepWithNextMessage(this.contentTopic, this.handshake.hs.toMessageNametag()); hsStep = await this.executeReadStepWithNextMessage(this.contentTopic, this.handshake.hs.toMessageNametag());
await this.responder.stop(this.contentTopic);
if (!this.handshake.hs.rs) throw new Error("invalid handshake state"); if (!this.handshake.hs.rs) throw new Error("invalid handshake state");
// The receiver further checks if the initiator's commitment opens to the initiator's static key received // The responder further checks if the initiator's commitment opens to the initiator's static key received
const expectedInitiatorCommittedStaticKey = commitPublicKey(this.handshake.hs.rs, hsStep.transportMessage); const expectedInitiatorCommittedStaticKey = commitPublicKey(this.handshake.hs.rs, hsStep.transportMessage);
if (!uint8ArrayEquals(expectedInitiatorCommittedStaticKey, initiatorCommittedStaticKey)) { if (!uint8ArrayEquals(expectedInitiatorCommittedStaticKey, initiatorCommittedStaticKey)) {
throw new Error("expected committed static key does not match the initiator actual committed static key"); throw new Error("expected committed static key does not match the initiator actual committed static key");
@ -321,12 +328,12 @@ export class WakuPairing {
this.eventEmitter.emit("pairingTimeout"); this.eventEmitter.emit("pairingTimeout");
}, timeoutMs); }, timeoutMs);
const handshakeFn = this.initiator ? this.initiatorHandshake : this.receiverHandshake; const handshakeFn = this.initiator ? this.initiatorHandshake : this.responderHandshake;
handshakeFn handshakeFn
.bind(this)() .bind(this)()
.then( .then(
(response) => resolve(response), (response) => resolve(response),
(err) => reject(new Error(err)) (err) => reject(err)
) )
.finally(() => clearTimeout(timer)); .finally(() => clearTimeout(timer));
}); });

View File

@ -61,10 +61,10 @@ export class MessageNametagBuffer {
const index = this.buffer.findIndex((x) => uint8ArrayEquals(x, messageNametag)); const index = this.buffer.findIndex((x) => uint8ArrayEquals(x, messageNametag));
if (index == -1) { if (index == -1) {
console.error("Message nametag not found in buffer"); console.debug("Message nametag not found in buffer");
return false; return false;
} else if (index > 0) { } else if (index > 0) {
console.error( console.debug(
"Message nametag is present in buffer but is not the next expected nametag. One or more messages were probably lost" "Message nametag is present in buffer but is not the next expected nametag. One or more messages were probably lost"
); );
return false; return false;