1
0
mirror of https://github.com/element-hq/element-web.git synced 2025-08-09 14:42:51 +03:00

Switch to secure random strings (#29013)

* Switch to secure random strings

Because the js-sdk methods are changing and there's no reason for these
not to use the secure versions. The dedicated upper/lower functions were
*only* used in this one case, so this should do the exact same thing with
the one exported function.

Requires https://github.com/matrix-org/matrix-js-sdk/pull/4621 (merge both together)

* Change remaining instances of randomString

which I somehow entirely missed the first time.

* Fix import order
This commit is contained in:
David Baker
2025-01-21 13:54:57 +00:00
committed by GitHub
parent 1644169ff3
commit 56eafc908e
15 changed files with 38 additions and 33 deletions

View File

@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import React from "react"; import React from "react";
import classNames from "classnames"; import classNames from "classnames";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import ToggleSwitch from "./ToggleSwitch"; import ToggleSwitch from "./ToggleSwitch";
import { Caption } from "../typography/Caption"; import { Caption } from "../typography/Caption";
@@ -36,7 +36,7 @@ interface IProps {
} }
export default class LabelledToggleSwitch extends React.PureComponent<IProps> { export default class LabelledToggleSwitch extends React.PureComponent<IProps> {
private readonly id = `mx_LabelledToggleSwitch_${randomString(12)}`; private readonly id = `mx_LabelledToggleSwitch_${secureRandomString(12)}`;
public render(): React.ReactNode { public render(): React.ReactNode {
// This is a minimal version of a SettingsFlag // This is a minimal version of a SettingsFlag

View File

@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
*/ */
import React from "react"; import React from "react";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
@@ -35,7 +35,7 @@ interface IState {
} }
export default class SettingsFlag extends React.Component<IProps, IState> { export default class SettingsFlag extends React.Component<IProps, IState> {
private readonly id = `mx_SettingsFlag_${randomString(12)}`; private readonly id = `mx_SettingsFlag_${secureRandomString(12)}`;
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);

View File

@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/ */
import React, { Ref } from "react"; import React, { Ref } from "react";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import classnames from "classnames"; import classnames from "classnames";
export enum CheckboxStyle { export enum CheckboxStyle {
@@ -33,7 +33,7 @@ export default class StyledCheckbox extends React.PureComponent<IProps, IState>
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);
// 56^10 so unlikely chance of collision. // 56^10 so unlikely chance of collision.
this.id = this.props.id || "checkbox_" + randomString(10); this.id = this.props.id || "checkbox_" + secureRandomString(10);
} }
public render(): React.ReactNode { public render(): React.ReactNode {

View File

@@ -18,7 +18,7 @@ import {
ContentHelpers, ContentHelpers,
M_BEACON, M_BEACON,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import classNames from "classnames"; import classNames from "classnames";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
@@ -81,10 +81,10 @@ const useBeaconState = (
// eg thread and main timeline, reply // eg thread and main timeline, reply
// maplibregl needs a unique id to attach the map instance to // maplibregl needs a unique id to attach the map instance to
const useUniqueId = (eventId: string): string => { const useUniqueId = (eventId: string): string => {
const [id, setId] = useState(`${eventId}_${randomString(8)}`); const [id, setId] = useState(`${eventId}_${secureRandomString(8)}`);
useEffect(() => { useEffect(() => {
setId(`${eventId}_${randomString(8)}`); setId(`${eventId}_${secureRandomString(8)}`);
}, [eventId]); }, [eventId]);
return id; return id;

View File

@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import React from "react"; import React from "react";
import { MatrixEvent, ClientEvent, ClientEventHandlerMap } from "matrix-js-sdk/src/matrix"; import { MatrixEvent, ClientEvent, ClientEventHandlerMap } from "matrix-js-sdk/src/matrix";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { Tooltip } from "@vector-im/compound-web"; import { Tooltip } from "@vector-im/compound-web";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
@@ -41,7 +41,7 @@ export default class MLocationBody extends React.Component<IBodyProps, IState> {
// multiple instances of same map might be in document // multiple instances of same map might be in document
// eg thread and main timeline, reply // eg thread and main timeline, reply
const idSuffix = `${props.mxEvent.getId()}_${randomString(8)}`; const idSuffix = `${props.mxEvent.getId()}_${secureRandomString(8)}`;
this.mapId = `mx_MLocationBody_${idSuffix}`; this.mapId = `mx_MLocationBody_${idSuffix}`;
this.reconnectedListener = createReconnectedListener(this.clearError); this.reconnectedListener = createReconnectedListener(this.clearError);

View File

@@ -18,7 +18,7 @@ import {
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { KnownMembership, Membership } from "matrix-js-sdk/src/types"; import { KnownMembership, Membership } from "matrix-js-sdk/src/types";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { CallType } from "matrix-js-sdk/src/webrtc/call"; import { CallType } from "matrix-js-sdk/src/webrtc/call";
import { NamespacedValue } from "matrix-js-sdk/src/NamespacedValue"; import { NamespacedValue } from "matrix-js-sdk/src/NamespacedValue";
import { IWidgetApiRequest } from "matrix-widget-api"; import { IWidgetApiRequest } from "matrix-widget-api";
@@ -743,7 +743,7 @@ export class ElementCall extends Call {
const url = ElementCall.generateWidgetUrl(client, roomId); const url = ElementCall.generateWidgetUrl(client, roomId);
return WidgetStore.instance.addVirtualWidget( return WidgetStore.instance.addVirtualWidget(
{ {
id: randomString(24), // So that it's globally unique id: secureRandomString(24), // So that it's globally unique
creatorUserId: client.getUserId()!, creatorUserId: client.getUserId()!,
name: "Element Call", name: "Element Call",
type: WidgetType.CALL.preferred, type: WidgetType.CALL.preferred,

View File

@@ -31,7 +31,7 @@ Please see LICENSE files in the repository root for full details.
// the frequency with which we flush to indexeddb // the frequency with which we flush to indexeddb
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { getCircularReplacer } from "../utils/JSON"; import { getCircularReplacer } from "../utils/JSON";
@@ -135,7 +135,7 @@ export class IndexedDBLogStore {
private indexedDB: IDBFactory, private indexedDB: IDBFactory,
private logger: ConsoleLogger, private logger: ConsoleLogger,
) { ) {
this.id = "instance-" + randomString(16); this.id = "instance-" + secureRandomString(16);
} }
/** /**

View File

@@ -9,12 +9,13 @@ Please see LICENSE files in the repository root for full details.
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { base32 } from "rfc4648"; import { base32 } from "rfc4648";
import { capitalize } from "lodash";
import { IWidget, IWidgetData } from "matrix-widget-api"; import { IWidget, IWidgetData } from "matrix-widget-api";
import { Room, ClientEvent, MatrixClient, RoomStateEvent, MatrixEvent } from "matrix-js-sdk/src/matrix"; import { Room, ClientEvent, MatrixClient, RoomStateEvent, MatrixEvent } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types"; import { KnownMembership } from "matrix-js-sdk/src/types";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { CallType } from "matrix-js-sdk/src/webrtc/call"; import { CallType } from "matrix-js-sdk/src/webrtc/call";
import { randomString, randomLowercaseString, randomUppercaseString } from "matrix-js-sdk/src/randomstring"; import { LOWERCASE, secureRandomString, secureRandomStringFrom } from "matrix-js-sdk/src/randomstring";
import PlatformPeg from "../PlatformPeg"; import PlatformPeg from "../PlatformPeg";
import SdkConfig from "../SdkConfig"; import SdkConfig from "../SdkConfig";
@@ -427,7 +428,10 @@ export default class WidgetUtils {
): Promise<void> { ): Promise<void> {
const domain = Jitsi.getInstance().preferredDomain; const domain = Jitsi.getInstance().preferredDomain;
const auth = (await Jitsi.getInstance().getJitsiAuth()) ?? undefined; const auth = (await Jitsi.getInstance().getJitsiAuth()) ?? undefined;
const widgetId = randomString(24); // Must be globally unique
// Must be globally unique, although predicatablity is not important, the js-sdk has functions to generate
// secure ranom strings, and speed is not important here.
const widgetId = secureRandomString(24);
let confId: string; let confId: string;
if (auth === "openidtoken-jwt") { if (auth === "openidtoken-jwt") {
@@ -437,8 +441,8 @@ export default class WidgetUtils {
// https://github.com/matrix-org/prosody-mod-auth-matrix-user-verification // https://github.com/matrix-org/prosody-mod-auth-matrix-user-verification
confId = base32.stringify(new TextEncoder().encode(roomId), { pad: false }); confId = base32.stringify(new TextEncoder().encode(roomId), { pad: false });
} else { } else {
// Create a random conference ID // Create a random conference ID (capitalised so the name looks sensible in Jitsi)
confId = `Jitsi${randomUppercaseString(1)}${randomLowercaseString(23)}`; confId = `Jitsi${capitalize(secureRandomStringFrom(24, LOWERCASE))}`;
} }
// TODO: Remove URL hacks when the mobile clients eventually support v2 widgets // TODO: Remove URL hacks when the mobile clients eventually support v2 widgets

View File

@@ -9,7 +9,7 @@ Please see LICENSE files in the repository root for full details.
import { completeAuthorizationCodeGrant, generateOidcAuthorizationUrl } from "matrix-js-sdk/src/oidc/authorize"; import { completeAuthorizationCodeGrant, generateOidcAuthorizationUrl } from "matrix-js-sdk/src/oidc/authorize";
import { QueryDict } from "matrix-js-sdk/src/utils"; import { QueryDict } from "matrix-js-sdk/src/utils";
import { OidcClientConfig } from "matrix-js-sdk/src/matrix"; import { OidcClientConfig } from "matrix-js-sdk/src/matrix";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { IdTokenClaims } from "oidc-client-ts"; import { IdTokenClaims } from "oidc-client-ts";
import { OidcClientError } from "./error"; import { OidcClientError } from "./error";
@@ -34,7 +34,7 @@ export const startOidcLogin = async (
): Promise<void> => { ): Promise<void> => {
const redirectUri = PlatformPeg.get()!.getOidcCallbackUrl().href; const redirectUri = PlatformPeg.get()!.getOidcCallbackUrl().href;
const nonce = randomString(10); const nonce = secureRandomString(10);
const prompt = isRegistration ? "create" : undefined; const prompt = isRegistration ? "create" : undefined;

View File

@@ -12,7 +12,7 @@ Please see LICENSE files in the repository root for full details.
import { MatrixClient, Room, MatrixEvent, OidcRegistrationClientMetadata } from "matrix-js-sdk/src/matrix"; import { MatrixClient, Room, MatrixEvent, OidcRegistrationClientMetadata } from "matrix-js-sdk/src/matrix";
import React from "react"; import React from "react";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import BasePlatform, { UpdateCheckStatus, UpdateStatus } from "../../BasePlatform"; import BasePlatform, { UpdateCheckStatus, UpdateStatus } from "../../BasePlatform";
@@ -93,7 +93,7 @@ export default class ElectronPlatform extends BasePlatform {
private readonly ipc = new IPCManager("ipcCall", "ipcReply"); private readonly ipc = new IPCManager("ipcCall", "ipcReply");
private readonly eventIndexManager: BaseEventIndexManager = new SeshatIndexManager(); private readonly eventIndexManager: BaseEventIndexManager = new SeshatIndexManager();
// this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile // this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile
private readonly ssoID: string = randomString(32); private readonly ssoID: string = secureRandomString(32);
public constructor() { public constructor() {
super(); super();

View File

@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import "@testing-library/jest-dom"; import "@testing-library/jest-dom";
import "blob-polyfill"; import "blob-polyfill";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { mocked } from "jest-mock"; import { mocked } from "jest-mock";
import { PredictableRandom } from "./test-utils/predictableRandom"; // https://github.com/jsdom/jsdom/issues/2555 import { PredictableRandom } from "./test-utils/predictableRandom"; // https://github.com/jsdom/jsdom/issues/2555
@@ -25,7 +25,8 @@ jest.mock("matrix-js-sdk/src/randomstring");
beforeEach(() => { beforeEach(() => {
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const mockRandom = new PredictableRandom(); const mockRandom = new PredictableRandom();
mocked(randomString).mockImplementation((len) => { // needless to say, the mock is not cryptographically secure
mocked(secureRandomString).mockImplementation((len) => {
let ret = ""; let ret = "";
for (let i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
const v = mockRandom.get() * chars.length; const v = mockRandom.get() * chars.length;

View File

@@ -18,7 +18,7 @@ import {
M_POLL_RESPONSE, M_POLL_RESPONSE,
M_TEXT, M_TEXT,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { flushPromises } from "./utilities"; import { flushPromises } from "./utilities";
@@ -67,7 +67,7 @@ export const makePollEndEvent = (
id?: string, id?: string,
): MatrixEvent => { ): MatrixEvent => {
return new MatrixEvent({ return new MatrixEvent({
event_id: id || randomString(16), event_id: id || secureRandomString(16),
room_id: roomId, room_id: roomId,
origin_server_ts: ts, origin_server_ts: ts,
type: M_POLL_END.name, type: M_POLL_END.name,
@@ -91,7 +91,7 @@ export const makePollResponseEvent = (
ts = 0, ts = 0,
): MatrixEvent => ): MatrixEvent =>
new MatrixEvent({ new MatrixEvent({
event_id: randomString(16), event_id: secureRandomString(16),
room_id: roomId, room_id: roomId,
origin_server_ts: ts, origin_server_ts: ts,
type: M_POLL_RESPONSE.name, type: M_POLL_RESPONSE.name,

View File

@@ -23,7 +23,7 @@ import {
IThreepid, IThreepid,
ThreepidMedium, ThreepidMedium,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { import {
act, act,
fireEvent, fireEvent,
@@ -287,7 +287,7 @@ describe("<Notifications />", () => {
beforeEach(async () => { beforeEach(async () => {
let i = 0; let i = 0;
mocked(randomString).mockImplementation(() => { mocked(secureRandomString).mockImplementation(() => {
return "testid_" + i++; return "testid_" + i++;
}); });

View File

@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import React from "react"; import React from "react";
import { mocked } from "jest-mock"; import { mocked } from "jest-mock";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { act, fireEvent, render, RenderResult } from "jest-matrix-react"; import { act, fireEvent, render, RenderResult } from "jest-matrix-react";
import { EventType, MatrixClient, Room, GuestAccess, HistoryVisibility, JoinRule } from "matrix-js-sdk/src/matrix"; import { EventType, MatrixClient, Room, GuestAccess, HistoryVisibility, JoinRule } from "matrix-js-sdk/src/matrix";
@@ -92,7 +92,7 @@ describe("<SpaceSettingsVisibilityTab />", () => {
beforeEach(() => { beforeEach(() => {
let i = 0; let i = 0;
mocked(randomString).mockImplementation(() => { mocked(secureRandomString).mockImplementation(() => {
return "testid_" + i++; return "testid_" + i++;
}); });

View File

@@ -49,7 +49,7 @@ describe("OIDC authorization", () => {
origin: baseUrl, origin: baseUrl,
}; };
jest.spyOn(randomStringUtils, "randomString").mockRestore(); jest.spyOn(randomStringUtils, "secureRandomString").mockRestore();
mockPlatformPeg(); mockPlatformPeg();
Object.defineProperty(window, "crypto", { Object.defineProperty(window, "crypto", {
value: { value: {