relay: rename encrypted handshake message types
This commit is contained in:
@@ -37,23 +37,23 @@ type ChannelState = "connecting" | "handshaking" | "open" | "closed";
|
|||||||
|
|
||||||
type EncryptedChannelOptions = {
|
type EncryptedChannelOptions = {
|
||||||
/**
|
/**
|
||||||
* If set, the channel can validate repeated plaintext `{type:"hello"}`
|
* If set, the channel can validate repeated plaintext `{type:"e2ee_hello"}`
|
||||||
* messages even after it is open.
|
* messages even after it is open.
|
||||||
*
|
*
|
||||||
* This is useful for robustness when the client retries the handshake
|
* This is useful for robustness when the client retries the handshake
|
||||||
* (e.g., it didn't observe the daemon's `{type:"ready"}` yet). In that case,
|
* (e.g., it didn't observe the daemon's `{type:"e2ee_ready"}` yet). In that case,
|
||||||
* the daemon should re-send `{type:"ready"}` without changing keys.
|
* the daemon should re-send `{type:"e2ee_ready"}` without changing keys.
|
||||||
*/
|
*/
|
||||||
daemonKeyPair?: KeyPair;
|
daemonKeyPair?: KeyPair;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface HelloMessage {
|
interface E2EEHelloMessage {
|
||||||
type: "hello";
|
type: "e2ee_hello";
|
||||||
key: string;
|
key: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ReadyMessage {
|
interface E2EEReadyMessage {
|
||||||
type: "ready";
|
type: "e2ee_ready";
|
||||||
}
|
}
|
||||||
|
|
||||||
const HANDSHAKE_RETRY_MS = 1000;
|
const HANDSHAKE_RETRY_MS = 1000;
|
||||||
@@ -65,7 +65,7 @@ const MAX_PENDING_SENDS = 200;
|
|||||||
* The client:
|
* The client:
|
||||||
* 1. Receives daemon's public key via QR code
|
* 1. Receives daemon's public key via QR code
|
||||||
* 2. Generates own keypair
|
* 2. Generates own keypair
|
||||||
* 3. Sends hello with own public key
|
* 3. Sends e2ee_hello with own public key
|
||||||
* 4. Derives shared key and starts encrypted communication
|
* 4. Derives shared key and starts encrypted communication
|
||||||
*/
|
*/
|
||||||
export async function createClientChannel(
|
export async function createClientChannel(
|
||||||
@@ -79,9 +79,9 @@ export async function createClientChannel(
|
|||||||
|
|
||||||
const channel = new EncryptedChannel(transport, sharedKey, events);
|
const channel = new EncryptedChannel(transport, sharedKey, events);
|
||||||
|
|
||||||
// Send hello with our public key
|
// Send e2ee_hello with our public key
|
||||||
const ourPublicKeyB64 = exportPublicKey(keyPair.publicKey);
|
const ourPublicKeyB64 = exportPublicKey(keyPair.publicKey);
|
||||||
const hello: HelloMessage = { type: "hello", key: ourPublicKeyB64 };
|
const hello: E2EEHelloMessage = { type: "e2ee_hello", key: ourPublicKeyB64 };
|
||||||
const helloText = JSON.stringify(hello);
|
const helloText = JSON.stringify(hello);
|
||||||
|
|
||||||
let retry: ReturnType<typeof setInterval> | null = null;
|
let retry: ReturnType<typeof setInterval> | null = null;
|
||||||
@@ -129,7 +129,7 @@ export async function createClientChannel(
|
|||||||
*
|
*
|
||||||
* The daemon:
|
* The daemon:
|
||||||
* 1. Has pre-generated keypair (public key was in QR)
|
* 1. Has pre-generated keypair (public key was in QR)
|
||||||
* 2. Waits for client's hello with their public key
|
* 2. Waits for client's e2ee_hello with their public key
|
||||||
* 3. Derives shared key and starts encrypted communication
|
* 3. Derives shared key and starts encrypted communication
|
||||||
*/
|
*/
|
||||||
export async function createDaemonChannel(
|
export async function createDaemonChannel(
|
||||||
@@ -142,8 +142,8 @@ export async function createDaemonChannel(
|
|||||||
const shouldIgnorePostHelloPlaintext = (data: string | ArrayBuffer): boolean => {
|
const shouldIgnorePostHelloPlaintext = (data: string | ArrayBuffer): boolean => {
|
||||||
try {
|
try {
|
||||||
const text = typeof data === "string" ? data : new TextDecoder().decode(data);
|
const text = typeof data === "string" ? data : new TextDecoder().decode(data);
|
||||||
const parsed = JSON.parse(text) as Partial<HelloMessage | ReadyMessage>;
|
const parsed = JSON.parse(text) as Partial<E2EEHelloMessage | E2EEReadyMessage>;
|
||||||
return parsed.type === "hello" || parsed.type === "ready";
|
return parsed.type === "e2ee_hello" || parsed.type === "e2ee_ready";
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -154,8 +154,8 @@ export async function createDaemonChannel(
|
|||||||
const helloText =
|
const helloText =
|
||||||
typeof data === "string" ? data : new TextDecoder().decode(data);
|
typeof data === "string" ? data : new TextDecoder().decode(data);
|
||||||
|
|
||||||
const msg = JSON.parse(helloText) as HelloMessage;
|
const msg = JSON.parse(helloText) as E2EEHelloMessage;
|
||||||
if (msg.type !== "hello" || !msg.key) {
|
if (msg.type !== "e2ee_hello" || !msg.key) {
|
||||||
throw new Error("Invalid hello message");
|
throw new Error("Invalid hello message");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +171,9 @@ export async function createDaemonChannel(
|
|||||||
const sharedKey = deriveSharedKey(daemonKeyPair.secretKey, clientPublicKey);
|
const sharedKey = deriveSharedKey(daemonKeyPair.secretKey, clientPublicKey);
|
||||||
|
|
||||||
const channel = new EncryptedChannel(transport, sharedKey, events, { daemonKeyPair });
|
const channel = new EncryptedChannel(transport, sharedKey, events, { daemonKeyPair });
|
||||||
transport.send(JSON.stringify({ type: "ready" } satisfies ReadyMessage));
|
transport.send(
|
||||||
|
JSON.stringify({ type: "e2ee_ready" } satisfies E2EEReadyMessage)
|
||||||
|
);
|
||||||
|
|
||||||
channel.setState("open");
|
channel.setState("open");
|
||||||
events.onopen?.();
|
events.onopen?.();
|
||||||
@@ -240,8 +242,8 @@ export class EncryptedChannel {
|
|||||||
if (this.state === "handshaking") {
|
if (this.state === "handshaking") {
|
||||||
try {
|
try {
|
||||||
const text = typeof data === "string" ? data : new TextDecoder().decode(data);
|
const text = typeof data === "string" ? data : new TextDecoder().decode(data);
|
||||||
const msg = JSON.parse(text) as Partial<ReadyMessage>;
|
const msg = JSON.parse(text) as Partial<E2EEReadyMessage>;
|
||||||
if (msg.type === "ready") {
|
if (msg.type === "e2ee_ready") {
|
||||||
this.state = "open";
|
this.state = "open";
|
||||||
this.events.onopen?.();
|
this.events.onopen?.();
|
||||||
for (const cb of this.onOpenCallbacks) cb();
|
for (const cb of this.onOpenCallbacks) cb();
|
||||||
@@ -261,9 +263,11 @@ export class EncryptedChannel {
|
|||||||
try {
|
try {
|
||||||
const text = typeof data === "string" ? data : new TextDecoder().decode(data);
|
const text = typeof data === "string" ? data : new TextDecoder().decode(data);
|
||||||
if (text.trim().startsWith("{")) {
|
if (text.trim().startsWith("{")) {
|
||||||
const parsed = JSON.parse(text) as Partial<HelloMessage | ReadyMessage>;
|
const parsed = JSON.parse(text) as Partial<
|
||||||
|
E2EEHelloMessage | E2EEReadyMessage
|
||||||
|
>;
|
||||||
|
|
||||||
if (parsed.type === "hello" && typeof parsed.key === "string") {
|
if (parsed.type === "e2ee_hello" && typeof parsed.key === "string") {
|
||||||
if (this.options.daemonKeyPair) {
|
if (this.options.daemonKeyPair) {
|
||||||
try {
|
try {
|
||||||
const clientPublicKey = importPublicKey(parsed.key);
|
const clientPublicKey = importPublicKey(parsed.key);
|
||||||
@@ -277,7 +281,7 @@ export class EncryptedChannel {
|
|||||||
// the channel and cause decrypt failures.
|
// the channel and cause decrypt failures.
|
||||||
if (keysEqual(nextSharedKey, this.sharedKey)) {
|
if (keysEqual(nextSharedKey, this.sharedKey)) {
|
||||||
this.transport.send(
|
this.transport.send(
|
||||||
JSON.stringify({ type: "ready" } satisfies ReadyMessage)
|
JSON.stringify({ type: "e2ee_ready" } satisfies E2EEReadyMessage)
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -290,7 +294,7 @@ export class EncryptedChannel {
|
|||||||
this.sharedKey = nextSharedKey;
|
this.sharedKey = nextSharedKey;
|
||||||
this.pendingSends = [];
|
this.pendingSends = [];
|
||||||
this.transport.send(
|
this.transport.send(
|
||||||
JSON.stringify({ type: "ready" } satisfies ReadyMessage)
|
JSON.stringify({ type: "e2ee_ready" } satisfies E2EEReadyMessage)
|
||||||
);
|
);
|
||||||
this.state = "open";
|
this.state = "open";
|
||||||
await this.flushPendingSends();
|
await this.flushPendingSends();
|
||||||
@@ -302,7 +306,7 @@ export class EncryptedChannel {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.type === "ready") {
|
if (parsed.type === "e2ee_ready") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user