1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-08-07 23:02:56 +03:00

Use a random impl with rejection sampling

This commit is contained in:
David Baker
2025-01-20 18:13:26 +00:00
parent 86494c3a96
commit 35fe7bc60a
2 changed files with 81 additions and 9 deletions

View File

@@ -24,6 +24,10 @@ import {
} from "../../src/randomstring";
describe("Random strings", () => {
afterEach(() => {
jest.restoreAllMocks();
});
it.each([8, 16, 32])("secureRandomBase64 generates %i valid base64 bytes", (n: number) => {
const randb641 = secureRandomBase64Url(n);
const randb642 = secureRandomBase64Url(n);
@@ -70,4 +74,41 @@ describe("Random strings", () => {
expect(rand1.toUpperCase()).toEqual(rand1);
},
);
it("throws if given character set less than 2 characters", () => {
expect(() => secureRandomStringFrom(8, "a")).toThrow();
});
it("throws if given character set more than 256 characters", () => {
const charSet = Array.from({ length: 257 }, (_, i) => "a").join("");
expect(() => secureRandomStringFrom(8, charSet)).toThrow();
});
it("throws if given length less than 1", () => {
expect(() => secureRandomStringFrom(0, "abc")).toThrow();
});
it("throws if given length more than 32768", () => {
expect(() => secureRandomStringFrom(32769, "abc")).toThrow();
});
it("asks for more entropy if given entropy is unusable", () => {
// This is testing the internal implementation details of the function rather
// than strictly the public API. The intention is to have some assertion that
// the rejection sampling to make the distribution even over all possible characters
// is doing what it's supposed to do.
// mock once to fill with 255 the first time: 255 should be unusable because
// we give 10 possible characters below and 256 is not evenly divisible by 10, so
// this should force it to call for more entropy.
jest.spyOn(globalThis.crypto, "getRandomValues").mockImplementationOnce((arr) => {
if (arr === null) throw new Error("Buffer is null");
new Uint8Array(arr.buffer).fill(255);
return arr;
});
secureRandomStringFrom(8, "0123456789");
expect(globalThis.crypto.getRandomValues).toHaveBeenCalledTimes(2);
});
});