From 0892edc4328340a6142f457f4f2c86ee915dbab2 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 9 Oct 2023 10:08:10 +0100 Subject: [PATCH 1/3] Use base64url encoding for the password param As base64 is fairly obviously not sensible for URLs and we were not URL encoding it so we were ending up with spaces in the URL. Also base 64 encode the password in case, as per comment. --- src/matrix-utils.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index 58f8bab5..778e4c6a 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -76,9 +76,13 @@ function waitForSync(client: MatrixClient) { function secureRandomString(entropyBytes: number): string { const key = new Uint8Array(entropyBytes); crypto.getRandomValues(key); + // encode to base64url as this value goes into URLs return btoa( key.reduce((acc, current) => acc + String.fromCharCode(current), "") - ).replace(/=*$/, ""); + ) + .replace("+", "-") + .replace("/", "_") + .replace(/=*$/, ""); } /** @@ -395,9 +399,13 @@ export function getRelativeRoomUrl( roomName?: string, password?: string ): string { + // The password shouldn't need URL encoding here (we generate URL-safe ones) but encode + // it in case it came from another client that generated a non url-safe one return `/room/#${ roomName ? "/" + roomAliasLocalpartFromRoomName(roomName) : "" - }?roomId=${roomId}${password ? "&" + PASSWORD_STRING + password : ""}`; + }?roomId=${roomId}${ + password ? "&" + PASSWORD_STRING + encodeURIComponent(password) : "" + }`; } export function getAvatarUrl( From 6faceb07cd2b1fe5d270fc76b01eb720d84c360b Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 9 Oct 2023 16:28:48 +0100 Subject: [PATCH 2/3] Log if password needed url encoding --- src/matrix-utils.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index 778e4c6a..1ed13839 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -401,11 +401,14 @@ export function getRelativeRoomUrl( ): string { // The password shouldn't need URL encoding here (we generate URL-safe ones) but encode // it in case it came from another client that generated a non url-safe one + const encodedPassword = password ? encodeURIComponent(password) : undefined; + if (password && encodedPassword !== password) { + logger.info("Encoded call password used non URL-safe chars: buggy client?"); + } + return `/room/#${ roomName ? "/" + roomAliasLocalpartFromRoomName(roomName) : "" - }?roomId=${roomId}${ - password ? "&" + PASSWORD_STRING + encodeURIComponent(password) : "" - }`; + }?roomId=${roomId}${password ? "&" + PASSWORD_STRING + encodedPassword : ""}`; } export function getAvatarUrl( From df93fb4a3f5ac5e955f15a37be668dfe6a06a110 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 9 Oct 2023 16:35:27 +0100 Subject: [PATCH 3/3] Add comment --- src/matrix-utils.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index 1ed13839..54105519 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -77,6 +77,11 @@ function secureRandomString(entropyBytes: number): string { const key = new Uint8Array(entropyBytes); crypto.getRandomValues(key); // encode to base64url as this value goes into URLs + // base64url is just base64 with thw two non-alphanum characters swapped out for + // ones that can be put in a URL without encoding. Browser JS has a native impl + // for base64 encoding but only a string (there isn't one that takes a UInt8Array + // yet) so just use the built-in one and convert, replace the chars and strip the + // padding from the end (otherwise we'd need to pull in another dependency). return btoa( key.reduce((acc, current) => acc + String.fromCharCode(current), "") )