Thanks to visit codestin.com
Credit goes to github.com

Skip to content
4 changes: 2 additions & 2 deletions site/src/contexts/useProxyLatency.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useReducer, useState } from "react";
import { API } from "#/api/api";
import type { Region } from "#/api/typesGenerated";
import { generateRandomString } from "#/utils/random";
import { generateRandomBase64String } from "#/utils/random";

const proxyIntervalSeconds = 30; // seconds

Expand Down Expand Up @@ -133,7 +133,7 @@ export const useProxyLatency = (
// Add a random query param to the url to make sure we don't get a cached response.
// This is important in case there is some caching layer between us and the proxy.
const url = new URL(
`/latency-check?cache_bust=${generateRandomString(6)}`,
`/latency-check?cache_bust=${generateRandomBase64String(6)}`,
proxy.path_app_url,
);
acc[url.toString()] = proxy;
Expand Down
4 changes: 2 additions & 2 deletions site/src/pages/UsersPage/UsersPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { shouldShowAISeatColumn } from "#/modules/dashboard/entitlements";
import { useDashboard } from "#/modules/dashboard/useDashboard";
import { RoleSelectorDialog } from "#/modules/roles/RoleSelectorDialog";
import { pageTitle } from "#/utils/page";
import { generateRandomString } from "#/utils/random";
import { generateRandomBase64String } from "#/utils/random";
import { ResetPasswordDialog } from "./ResetPasswordDialog";
import { UsersPageView } from "./UsersPageView";

Expand Down Expand Up @@ -122,7 +122,7 @@ const UsersPage: React.FC = () => {
newPassword:
process.env.STORYBOOK === "true"
? "hello-storybook"
: generateRandomString(12),
: generateRandomBase64String(12),
});
}}
onSuspendUser={setUserToSuspend}
Expand Down
23 changes: 23 additions & 0 deletions site/src/utils/random.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { describe, expect, it } from "vitest";
import { generateConnectionSessionId } from "#/utils/random";

describe("generateConnectionSessionId", () => {
it("is 32 characters long", () => {
const id = generateConnectionSessionId();
expect(id.length).toBe(32);
});

it("outputs a hexadecimal string", () => {
const id = generateConnectionSessionId();
const hexRegex = /^[\da-f]+$/;
expect(hexRegex.test(id)).toBe(true);
});

it("generates unique values across calls", () => {
const numValues = 1000;
const ids = new Set(
Array.from({ length: numValues }, () => generateConnectionSessionId()),
);
expect(ids.size).toBe(numValues);
});
});
30 changes: 20 additions & 10 deletions site/src/utils/random.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/**
* Generate a random hexadecimal string from the specified number of bytes.
*/
const generateRandomString = (bytes: number): string => {
const byteArr = crypto.getRandomValues(new Uint8Array(bytes));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getRandomValues not getRandomBytes 👍
bytes are mapped into hex characters as a string.

return [...byteArr]
.map((byte) => byte.toString(16).padStart(2, "0"))
.join("");
};

/**
* Generate a cryptographically secure random string using the specified number
* of bytes then encode with base64.
Expand All @@ -6,14 +16,14 @@
* equal the number of randomly generated bytes.
* @see <https://developer.mozilla.org/en-US/docs/Glossary/Base64#encoded_size_increase>
*/
export const generateRandomString = (bytes: number): string => {
const byteArr = window.crypto.getRandomValues(new Uint8Array(bytes));
// The types for `map` don't seem to support mapping from one array type to
// another and `String.fromCharCode.apply` wants `number[]` so loop like this
// instead.
const strArr: string[] = [];
for (const byte of byteArr) {
strArr.push(String.fromCharCode(byte));
}
return btoa(strArr.join(""));
export const generateRandomBase64String = (bytes: number): string => {
return btoa(generateRandomString(bytes));
};

/**
* Generate a 16-byte (32-character) hexadecimal string for identifying
* workspace connection sessions.
*/
export const generateConnectionSessionId = (): string => {
return generateRandomString(16);
};
Loading