Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions services/console/src/components/console/deck/DeckPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { authUser } from "../../../util/auth";
import { httpGet } from "../../../util/http";
import { NotifyKind, pageNotify } from "../../../util/notify";
import { pathname, useSearchParams } from "../../../util/url";
import { type InitValid, init_valid, validJwt } from "../../../util/valid";
import { init_valid, jwtRequiredInvalid } from "../../../util/valid";
import Deck, { type DeckConfig } from "./hand/Deck";
import DeckHeader, { type DeckHeaderConfig } from "./header/DeckHeader";

Expand Down Expand Up @@ -45,17 +45,16 @@ const DeckPanel = (props: Props) => {

const fetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
token: authUser()?.token,
};
});

const getData = async (fetcher: {
bencher_valid: InitValid;
token: string;
}) => {
const EMPTY_OBJECT = {};
if (!fetcher.bencher_valid || !validJwt(fetcher.token)) {
// Fire in parallel with WASM init; the server validates the token regardless.
if (jwtRequiredInvalid(bencher_valid(), fetcher.token)) {
return EMPTY_OBJECT;
}
return await httpGet(props.apiUrl, path(), fetcher.token)
Expand Down
13 changes: 5 additions & 8 deletions services/console/src/components/console/perf/PerfFrame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
NotifyKind,
pageNotify,
} from "../../../util/notify";
import { type InitValid, init_valid, validJwt } from "../../../util/valid";
import { init_valid, jwtRequiredInvalid } from "../../../util/valid";
import type { Theme } from "../../navbar/theme/theme";
import PerfPlot from "./plot/PerfPlot";

Expand Down Expand Up @@ -73,28 +73,25 @@ const PerfFrame = (props: Props) => {

const perfFetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
project_slug: props.project_slug(),
perfQuery: props.perfQuery(),
refresh: props.refresh(),
token: props.user?.token,
};
});
const getPerf = async (fetcher: {
bencher_valid: InitValid;
project_slug: string;
perfQuery: JsonPerfQuery;
refresh: number;
token: string;
}) => {
const EMPTY_OBJECT = {};
if (!fetcher.bencher_valid) {
return EMPTY_OBJECT;
}

// Don't even send query if there isn't at least one: branch, testbed, and benchmark
// Fire in parallel with WASM init; the server validates the token regardless.
// On the console still require a token to be present. Also don't send a query
// without at least one branch, testbed, and benchmark.
if (
(props.isConsole && !validJwt(fetcher.token)) ||
(props.isConsole && jwtRequiredInvalid(bencher_valid(), fetcher.token)) ||
props.isPlotInit() ||
!fetcher.project_slug ||
fetcher.project_slug === "undefined"
Expand Down
29 changes: 7 additions & 22 deletions services/console/src/components/console/perf/PerfPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ import { X_TOTAL_COUNT, httpGet } from "../../../util/http";
import { useSearchParams } from "../../../util/url";
import {
DEBOUNCE_DELAY,
type InitValid,
init_valid,
validJwt,
jwtRequiredInvalid,
validU32,
} from "../../../util/valid";
import { theme } from "../../navbar/theme/util";
Expand Down Expand Up @@ -595,19 +594,16 @@ const PerfPanel = (props: Props) => {
perfTab: PerfTab,
memo: T[],
fetcher: {
bencher_valid: InitValid;
project_slug: undefined | string;
param_uuids: string[];
token: string;
},
) {
const EMPTY_ARRAY: T[] = [];
if (!fetcher.bencher_valid) {
return EMPTY_ARRAY;
}

// Fire in parallel with WASM init; the server validates the token regardless.
// On the console still require a token to be present.
if (
(props.isConsole && !validJwt(fetcher.token)) ||
(props.isConsole && jwtRequiredInvalid(bencher_valid(), fetcher.token)) ||
!fetcher.project_slug ||
fetcher.project_slug === "undefined" ||
props.isEmbed === true
Expand Down Expand Up @@ -637,7 +633,6 @@ const PerfPanel = (props: Props) => {
const [branches_memo, setBranchesMemo] = createStore<JsonBranch[]>([]);
const selectedBranchesFetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
project_slug: project_slug(),
param_uuids: branches(),
token: user?.token,
Expand Down Expand Up @@ -669,7 +664,6 @@ const PerfPanel = (props: Props) => {
const [testbeds_memo, setTestbedsMemo] = createStore<JsonTestbed[]>([]);
const selectedTestbedFetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
project_slug: project_slug(),
param_uuids: testbeds(),
token: user?.token,
Expand Down Expand Up @@ -701,7 +695,6 @@ const PerfPanel = (props: Props) => {
const [benchmarks_memo, setBenchmarksMemo] = createStore<JsonBenchmark[]>([]);
const selectedBenchmarkFetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
project_slug: project_slug(),
param_uuids: benchmarks(),
token: user?.token,
Expand Down Expand Up @@ -729,7 +722,6 @@ const PerfPanel = (props: Props) => {
async function getPerfTab<T>(
perfTab: PerfTab,
fetcher: {
bencher_valid: InitValid;
project_slug: undefined | string;
per_page: number;
page: number;
Expand All @@ -742,12 +734,10 @@ const PerfPanel = (props: Props) => {
totalCount: (headers: { [X_TOTAL_COUNT]: string }) => void,
) {
const EMPTY_ARRAY: T[] = [];
if (!fetcher.bencher_valid) {
return EMPTY_ARRAY;
}

// Fire in parallel with WASM init; the server validates the token regardless.
// On the console still require a token to be present.
if (
(props.isConsole && !validJwt(fetcher.token)) ||
(props.isConsole && jwtRequiredInvalid(bencher_valid(), fetcher.token)) ||
!fetcher.project_slug ||
fetcher.project_slug === "undefined" ||
props.isEmbed === true ||
Expand Down Expand Up @@ -786,7 +776,6 @@ const PerfPanel = (props: Props) => {

const reports_fetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
project_slug: project_slug(),
per_page: reports_per_page(),
page: reports_page(),
Expand Down Expand Up @@ -853,7 +842,6 @@ const PerfPanel = (props: Props) => {

const branches_fetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
project_slug: project_slug(),
per_page: branches_per_page(),
page: branches_page(),
Expand All @@ -876,7 +864,6 @@ const PerfPanel = (props: Props) => {

const testbeds_fetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
project_slug: project_slug(),
per_page: testbeds_per_page(),
page: testbeds_page(),
Expand All @@ -899,7 +886,6 @@ const PerfPanel = (props: Props) => {

const benchmarks_fetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
project_slug: project_slug(),
per_page: benchmarks_per_page(),
page: benchmarks_page(),
Expand All @@ -924,7 +910,6 @@ const PerfPanel = (props: Props) => {

const plots_fetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
project_slug: project_slug(),
per_page: plots_per_page(),
page: plots_page(),
Expand Down
10 changes: 3 additions & 7 deletions services/console/src/components/console/plots/PinnedPlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "../../../util/auth";
import { httpGet } from "../../../util/http";
import { NotifyKind, navigateNotify } from "../../../util/notify";
import { type InitValid, init_valid, validJwt } from "../../../util/valid";
import { init_valid, jwtOptionalInvalid } from "../../../util/valid";
import Pinned from "./Pinned";

export interface Props {
Expand All @@ -26,19 +26,15 @@ const PinnedPlot = (props: Props) => {
const project_slug = createMemo(() => props.params?.project);
const plotFetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
token: user?.token,
};
});
const getPlot = async (fetcher: {
bencher_valid: InitValid;
token: string;
}) => {
const EMPTY_OBJECT = {};
if (!fetcher.bencher_valid) {
return EMPTY_OBJECT;
}
if (fetcher.token && !validJwt(fetcher.token)) {
// Fire in parallel with WASM init; the server validates the token regardless.
if (jwtOptionalInvalid(bencher_valid(), fetcher.token)) {
return EMPTY_OBJECT;
}
const path = `/v0/projects/${props.params?.project}/plots/${props.params?.plot}`;
Expand Down
19 changes: 5 additions & 14 deletions services/console/src/components/console/plots/PlotsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ import { setPageTitle } from "../../../util/resource";
import { useSearchParams } from "../../../util/url";
import {
DEBOUNCE_DELAY,
type InitValid,
init_valid,
validJwt,
jwtOptionalInvalid,
} from "../../../util/valid";
import FallbackPlots from "./FallbackPlots";
import Pinned from "./Pinned";
Expand Down Expand Up @@ -70,21 +69,17 @@ const PlotsPanel = (props: Props) => {
const project_slug = createMemo(() => params().project);
const projectFetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
project_slug: project_slug(),
token: user?.token,
};
});
const getProject = async (fetcher: {
bencher_valid: InitValid;
project_slug: string;
token: string;
}) => {
const EMPTY_OBJECT = {};
if (!fetcher.bencher_valid) {
return EMPTY_OBJECT;
}
if (fetcher.token && !validJwt(fetcher.token)) {
// Fire in parallel with WASM init; the server validates the token regardless.
if (jwtOptionalInvalid(bencher_valid(), fetcher.token)) {
return EMPTY_OBJECT;
}
const path = `/v0/projects/${fetcher.project_slug}`;
Expand All @@ -108,14 +103,12 @@ const PlotsPanel = (props: Props) => {
});
const plotsFetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
project_slug: project_slug(),
searchQuery: searchQuery(),
token: user?.token,
};
});
const getPlots = async (fetcher: {
bencher_valid: InitValid;
project_slug: string;
searchQuery: {
per_page: number;
Expand All @@ -124,10 +117,8 @@ const PlotsPanel = (props: Props) => {
token: string;
}) => {
const EMPTY_ARRAY: JsonPlot[] = [];
if (!fetcher.bencher_valid) {
return EMPTY_ARRAY;
}
if (fetcher.token && !validJwt(fetcher.token)) {
// Fire in parallel with WASM init; the server validates the token regardless.
if (jwtOptionalInvalid(bencher_valid(), fetcher.token)) {
return EMPTY_ARRAY;
}
const searchParams = new URLSearchParams();
Expand Down
8 changes: 3 additions & 5 deletions services/console/src/components/console/table/TablePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ import { NotifyKind, pageNotify } from "../../../util/notify";
import { useSearchParams } from "../../../util/url";
import {
DEBOUNCE_DELAY,
type InitValid,
init_valid,
validJwt,
jwtRequiredInvalid,
validU32,
} from "../../../util/valid";
import Pagination, { PaginationSize } from "../../site/Pagination";
Expand Down Expand Up @@ -137,7 +136,6 @@ const TablePanel = (props: Props) => {

const fetcher = createMemo(() => {
return {
bencher_valid: bencher_valid(),
searchQuery: searchQuery(),
token: authUser()?.token,
};
Expand All @@ -146,7 +144,6 @@ const TablePanel = (props: Props) => {
const [state, setState] = createSignal(TableState.LOADING);
const [totalCount, setTotalCount] = createSignal(0);
const getData = async (fetcher: {
bencher_valid: InitValid;
searchQuery: {
per_page: number;
page: number;
Expand All @@ -159,7 +156,8 @@ const TablePanel = (props: Props) => {
token: string;
}) => {
const EMPTY_ARRAY: object[] = [];
if (!fetcher.bencher_valid || !validJwt(fetcher.token)) {
// Fire in parallel with WASM init; the server validates the token regardless.
if (jwtRequiredInvalid(bencher_valid(), fetcher.token)) {
return EMPTY_ARRAY;
}
const searchParams = new URLSearchParams();
Expand Down
19 changes: 19 additions & 0 deletions services/console/src/util/valid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,25 @@ export const validJwt = (token: undefined | null | string): boolean =>
export const validOptionJwt = (token: undefined | null | string): boolean =>
validOptionString(token, (i) => i.length === 0 || is_valid_jwt(i));

// Best-effort JWT pre-checks used to gate data fetches without blocking on WASM
// init. The `validJwt` format check needs the `bencher_valid` WASM validator, so
// it is only run once that validator has loaded (`valid` truthy); until then the
// request is allowed through and the server validates the token regardless.

// Required token: returns true when the fetch should be skipped, i.e. there is no
// token, or the validator is loaded and the token is malformed.
export const jwtRequiredInvalid = (
valid: InitValid,
token: undefined | null | string,
): boolean => !token || (!!valid && !validJwt(token));

// Optional token: returns true only when a token is present, the validator is
// loaded, and the token is malformed. A missing token is allowed (public access).
export const jwtOptionalInvalid = (
valid: InitValid,
token: undefined | null | string,
): boolean => !!token && !!valid && !validJwt(token);

export const validOptionUrl = (url: undefined | null | string): boolean =>
validOptionString(url, (i) => i.length === 0 || is_valid_url(i));

Expand Down
Loading
Loading