d9d549fd0f
* Changed identity keypair to use ed25519 * Encryption key is now x25519 based + compatibiltiy with sphinx * Pathing and import fixes * Moved all asymmetric keys to sub-module in crypto * Extracted aes to separate module * kdf module in crypto * Ability to perform diffie hellman on encryption keys * ecdsa on identity keys * Extremely rough and incomplete registration handshake * Authentication primitives * Creating new random authenticationIV * Wrapper type for the derived shared key * Removed AuthToken in favour of using SharedKey for authentication * Gateway identity keys * Registration handshake without error mapping * Gateway address in client config * Added extra key for gateway presence * Updated pemstore to work on borrows instead * Gateway client trying to perform the handshake * Gateway changes to allow for handshake and shared key * Debug trait on sharedkey * native client using updated gateway client * Slightly updated gateway API * Minor cleanup * Fixed pemstore to correctly save multiple keypairs * Gateway actually deriving shared key during handshake * Gateway sending correct mid-handshake message * Missing quotation mark in client config template * Fixed template for correct shared key serialization * Fixed gateway authentication * Fixed tests * Using correct gateway key when converting to sphinx node * "get_all_clients" takes them from gateways as opposed to providers now * cargo fmt * Renamed pemstore methods * Unused import * Encryption of forward requests between client and gateway * Updated sphinx dependency to use public revision * Sending 'error' on handshake processing error * Removed some dead code * Dead code I forgot to remove before * Extracted AckAes128Key into a struct * Slight pemstore revamp allowing for symmetric key store * ibid. * PemStorableKey for SharedKey * Introduced single location responsible for key management for client * WIP * Sphinx version update * Stop using NodeAddressBytes for two distinct and confusing purposes * Abstracting away SocketAddr from sphinx forwarding * Passing the bool for reply surbs * Attack plan for replies + encryption * Comment + removed variable binding * ReplySURB usage * Topology import in nymsphinx * Sphinx version update * Changed 'Recipient' to contain client's encryption key * Message preparation taking shape! * reply surb also containing the encryption key * Very initial message receiver * Sphinx version update * A possibly working way of receiving surbs * Fixed incorrect field name in client config template * camel casing all request arguments * Renamed and moved `MessageMode` to more appropriate file * Restored reconstruction tests * Removed dead code from chunking * Made rust examples compilable * reply SURB key storage * Replies as an InputMessage * Forgotten commented code * No retransmission processing for cover or replies * Received reply processing * Renamed client pathfinder to something more appropriate * Made HasherOutputSize public * Added key store path to config * Reply surb attaching key digest when used * Changes due to previous renaming * Removed comment * Fixed insert_encryption_key * Assigning initial value of key store path * Computing key digest with correct algorithm * Initial and presumably temporary request serialization * hacky way of introducing 'FragmentIdentifier' for replies * Moved responsibility of reply encryption, padding, etc, to message preparer * Optional recipient in try_get_valid_topology_ref * Handling new reply surbs with acks and padding * Updated go and python examples to include replies in text and binary cases * Updated rust examples + binaryserverresponse * Helpers in rust examples * And updated JS example * Moved shared key generation function to crypto crate * Cover traffic encryption! * hmac computation in crypto * Updated aes imports due to new dependencies * hkdf made more generic * crypto cleanup + algorithms in params * Clippy cleanup pass * Generating encryption+mac shared keys between client and gateway * MACs attached to forward requests to gateway * Gateway messages encrypted and mac'd * Lowered logging level * compiler warning cleanup * Some minor cleanup * Generic stream cipher * Generic shared key derivation + algorithm definitions * Project-wide AES clean-up * Comment fix * Removed commented imports * Updated comments * Fixed topology test fixture
174 lines
5.7 KiB
JavaScript
174 lines
5.7 KiB
JavaScript
var ourAddress;
|
|
var connection;
|
|
|
|
// Please note that this javascript is extremely bad, it's only purpose is to show some basic API calls, not how
|
|
// a proper application should have been written.
|
|
|
|
async function main() {
|
|
var port = '1977' // client websocket listens on 1977 by default, change if yours is different
|
|
var localClientUrl = "ws://127.0.0.1:" + port;
|
|
|
|
// Set up and handle websocket connection to our desktop client.
|
|
connection = await connectWebsocket(localClientUrl).then(function (c) {
|
|
return c;
|
|
}).catch(function (err) {
|
|
display("Websocket connection error. Is the client running with <pre>--connection-type WebSocket</pre> on port " + port + "?");
|
|
})
|
|
connection.onmessage = function (e) {
|
|
handleResponse(e);
|
|
};
|
|
|
|
sendSelfAddressRequest();
|
|
|
|
// Set up the send button
|
|
const sendButton = document.querySelector('#send-button');
|
|
sendButton.onclick = function () {
|
|
sendMessageToMixnet();
|
|
}
|
|
}
|
|
|
|
// Handle any messages that come back down the websocket.
|
|
function handleResponse(resp) {
|
|
// hacky workaround for receiving pushed 'text' messages,
|
|
// basically we can either receive proper server responses, i.e. 'error', 'send', 'selfAddress'
|
|
// or actual messages, without any framing, so they do not have 'type' field
|
|
try {
|
|
let response = JSON.parse(resp.data);
|
|
if (response.type == "error") {
|
|
displayJsonResponseWithoutReply("Server responded with error: " + response.message);
|
|
} else if (response.type == "selfAddress") {
|
|
displayJsonResponseWithoutReply(response);
|
|
ourAddress = response.address;
|
|
display("Our address is: " + ourAddress + ", we will now send messages to ourself.");
|
|
} else if (response.type == "received") {
|
|
handleReceivedTextMessage(response)
|
|
}
|
|
} catch (_) {
|
|
displayJsonResponseWithoutReply(resp.data)
|
|
}
|
|
}
|
|
|
|
|
|
function handleReceivedTextMessage(message) {
|
|
console.log("received a message!")
|
|
const text = message.message
|
|
const replySurb = message.replySurb
|
|
|
|
if (replySurb != null) {
|
|
displayJsonResponseWithReply(text, replySurb)
|
|
} else {
|
|
displayJsonResponseWithoutReply(text)
|
|
}
|
|
}
|
|
|
|
// Send a message to the mixnet.
|
|
function sendMessageToMixnet() {
|
|
const sendText = document.getElementById("sendtext").value;
|
|
const surbCheckbox = document.querySelector('#with-surb');
|
|
const attachReplySURB = surbCheckbox.checked;
|
|
|
|
const message = {
|
|
type: "send",
|
|
message: sendText,
|
|
recipient: ourAddress,
|
|
withReplySurb: attachReplySURB,
|
|
}
|
|
|
|
displayJsonResponseWithoutReply(message);
|
|
connection.send(JSON.stringify(message));
|
|
}
|
|
|
|
function sendReplyMessageToMixnet(messageContent, replySurb) {
|
|
const message = {
|
|
type: "reply",
|
|
message: messageContent,
|
|
replySurb: replySurb,
|
|
}
|
|
|
|
displayJsonResponseWithoutReply(message);
|
|
connection.send(JSON.stringify(message));
|
|
}
|
|
|
|
// Send a message to the mixnet client, asking what our own address is.
|
|
// In this simplistic demo, we'll just use our own address to send ourselves messages.
|
|
//
|
|
// In a real application, you might want to ensure that somebody else got your
|
|
// address so that they could send messages to you.
|
|
function sendSelfAddressRequest() {
|
|
var selfAddress = {
|
|
type: "selfAddress"
|
|
}
|
|
displayJsonSend(selfAddress);
|
|
connection.send(JSON.stringify(selfAddress));
|
|
}
|
|
|
|
function display(message) {
|
|
document.getElementById("output").innerHTML += "<p>" + message + "</p >";
|
|
}
|
|
|
|
function displayJsonSend(message) {
|
|
let sendDiv = document.createElement("div")
|
|
let paragraph = document.createElement("p")
|
|
paragraph.setAttribute('style', 'color: blue')
|
|
let paragraphContent = document.createTextNode("sent >>> " + JSON.stringify(message))
|
|
paragraph.appendChild(paragraphContent)
|
|
|
|
sendDiv.appendChild(paragraph)
|
|
document.getElementById("output").appendChild(sendDiv)
|
|
}
|
|
|
|
function displayJsonResponseWithoutReply(message) {
|
|
let receivedDiv = document.createElement("div")
|
|
let paragraph = document.createElement("p")
|
|
paragraph.setAttribute('style', 'color: green')
|
|
let paragraphContent = document.createTextNode("received >>> " + JSON.stringify(message) + "(NO REPLY AVAILABLE)")
|
|
paragraph.appendChild(paragraphContent)
|
|
|
|
receivedDiv.appendChild(paragraph)
|
|
document.getElementById("output").appendChild(receivedDiv)
|
|
}
|
|
|
|
function displayJsonResponseWithReply(message, replySurb) {
|
|
let replyBox = document.createElement("input")
|
|
replyBox.setAttribute('type', 'text');
|
|
replyBox.setAttribute('value', 'type your anonymous reply here!');
|
|
replyBox.setAttribute('size', 50);
|
|
|
|
let sendButton = document.createElement("button")
|
|
let buttonText = document.createTextNode("Send")
|
|
sendButton.appendChild(buttonText)
|
|
|
|
sendButton.onclick = () => {
|
|
sendReplyMessageToMixnet(replyBox.value, replySurb)
|
|
}
|
|
|
|
let receivedDiv = document.createElement("div")
|
|
let paragraph = document.createElement("p")
|
|
paragraph.setAttribute('style', 'color: green')
|
|
let paragraphContent = document.createTextNode("received >>> " + JSON.stringify(message) + "(HERE BE SURB)")
|
|
paragraph.appendChild(paragraphContent)
|
|
|
|
receivedDiv.appendChild(paragraph)
|
|
receivedDiv.appendChild(replyBox)
|
|
receivedDiv.appendChild(sendButton)
|
|
|
|
document.getElementById("output").appendChild(receivedDiv)
|
|
}
|
|
|
|
// Connect to a websocket.
|
|
function connectWebsocket(url) {
|
|
return new Promise(function (resolve, reject) {
|
|
var server = new WebSocket(url);
|
|
server.onopen = function () {
|
|
resolve(server);
|
|
};
|
|
server.onerror = function (err) {
|
|
reject(err);
|
|
};
|
|
|
|
});
|
|
}
|
|
|
|
// Start it!
|
|
main();
|