-
-
Notifications
You must be signed in to change notification settings - Fork 606
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor & make base64 functions browser-safe
We had two identical sets of base64 functions in the js-sdk, both using Buffer which isn't really available in the browser unless you're using an old webpack (ie. what element-web uses). This PR: * Takes the crypto base64 file and moves it out of crypto (because we use base64 for much more than just crypto) * Makes them work in a browser without the Buffer global * Removes the other base64 functions * Changes everything to use the new common ones * Adds a comment explaining why the function is kinda ugly and how soul destroyingly awful the JS ecosystem is. * Runs the tests with both impls * Changes the test to not just test the decoder against the encoder * Adds explicit support & tests for (decoding) base64Url (I'll add an encode method later, no need for that to go in this PR too).
- Loading branch information
Showing
16 changed files
with
140 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* | ||
Copyright 2023 The Matrix.org Foundation C.I.C. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
/** | ||
* Base64 encoding and decoding utilities | ||
*/ | ||
|
||
/** | ||
* Encode a typed array of uint8 as base64. | ||
* @param uint8Array - The data to encode. | ||
* @returns The base64. | ||
*/ | ||
export function encodeBase64(uint8Array: ArrayBuffer | Uint8Array): string { | ||
// A brief note on the state of base64 encoding in Javascript. | ||
// As of 2023, there is still no common native impl between both browsers and | ||
// node. Older Webpack provides an impl for Buffer and there is a polyfill class | ||
// for it. There are also plenty of pure js impls, eg. base64-js which has 2336 | ||
// dependents at current count. Using this would probably be fine although it's | ||
// a little under-docced and run by an individual. The node impl works fine, | ||
// the browser impl works but predates Uint8Array and so only uses strings. | ||
// Right now, switching between native (or polyfilled) impls like this feels | ||
// like the least bad option, but... *shrugs*. | ||
if (typeof Buffer === "function") { | ||
return Buffer.from(uint8Array).toString("base64"); | ||
} else if (typeof btoa === "function" && uint8Array instanceof Uint8Array) { | ||
// ArrayBuffer is a node concept so the param should always be a Uint8Array on | ||
// the browser. We need to check because ArrayBuffers don't have reduce. | ||
return btoa(uint8Array.reduce((acc, current) => acc + String.fromCharCode(current), "")); | ||
} else { | ||
throw new Error("No base64 impl found!"); | ||
} | ||
} | ||
|
||
/** | ||
* Encode a typed array of uint8 as unpadded base64. | ||
* @param uint8Array - The data to encode. | ||
* @returns The unpadded base64. | ||
*/ | ||
export function encodeUnpaddedBase64(uint8Array: ArrayBuffer | Uint8Array): string { | ||
return encodeBase64(uint8Array).replace(/={1,2}$/, ""); | ||
} | ||
|
||
/** | ||
* Decode a base64 string to a typed array of uint8. | ||
* @param base64 - The base64 to decode. | ||
* @returns The decoded data. | ||
*/ | ||
export function decodeBase64(base64: string): Uint8Array { | ||
// See encodeBase64 for a short treatise on base64 en/decoding in JS | ||
if (typeof Buffer === "function") { | ||
return Buffer.from(base64, "base64"); | ||
} else if (typeof atob === "function") { | ||
const itFunc = function* (): Generator<number> { | ||
const decoded = atob( | ||
// built-in atob doesn't support base64url: convert so we support either | ||
base64.replace("-", "+").replace("_", "/"), | ||
); | ||
for (let i = 0; i < decoded.length; ++i) { | ||
yield decoded.charCodeAt(i); | ||
} | ||
}; | ||
return Uint8Array.from(itFunc()); | ||
} else { | ||
throw new Error("No base64 impl found!"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.