Skip to content
Open
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
16 changes: 8 additions & 8 deletions assay/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion assay/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"lint-fix": "eslint --fix"
},
"dependencies": {
"@labkey/components": "7.42.1"
"@labkey/components": "7.45.2-fb-redirectGH1023.1"
},
"devDependencies": {
"@labkey/build": "9.1.5",
Expand Down
15 changes: 9 additions & 6 deletions assay/src/client/AssayTypeSelect/AssayTypeSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
AssayPickerTabs,
GENERAL_ASSAY_PROVIDER_NAME,
App as LabKeyApp,
redirect,
useServerContext,
} from '@labkey/components';

Expand Down Expand Up @@ -58,7 +59,7 @@ const AssayTypeSelect = memo(() => {
const tab = useMemo(() => ActionURL.getParameter('tab'), []);

const onCancel = useCallback(() => {
window.location.href = returnUrl || ActionURL.buildURL('project', 'begin');
redirect(returnUrl || ActionURL.buildURL('project', 'begin'));
}, [returnUrl]);

const onChange = useCallback((model: AssayPickerSelectionModel) => {
Expand All @@ -69,13 +70,15 @@ const AssayTypeSelect = memo(() => {
const { container, file, provider, tab } = assayPickerSelection;
if (tab === AssayPickerTabs.XAR_IMPORT_TAB && file) {
uploadXarFile(file, container).then(() => {
window.location.href = ActionURL.buildURL('pipeline', 'status-showList', container);
redirect(ActionURL.buildURL('pipeline', 'status-showList', container));
});
} else {
window.location.href = ActionURL.buildURL('assay', 'designer', container, {
providerName: provider ? provider.name : GENERAL_ASSAY_PROVIDER_NAME,
returnUrl,
});
redirect(
ActionURL.buildURL('assay', 'designer', container, {
providerName: provider ? provider.name : GENERAL_ASSAY_PROVIDER_NAME,
returnUrl,
})
);
}
}, [assayPickerSelection, returnUrl]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ jest.mock('@labkey/api', () => ({
},
}));

jest.mock('@labkey/components', () => ({
redirect: jest.fn(),
}));

const mockPlate: PlateTemplate = {
rowId: 1,
name: 'Test Plate',
Expand Down
12 changes: 2 additions & 10 deletions assay/src/client/PlateTemplateDesigner/PlateTemplateDesigner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
import React, { FC, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { ActionURL, Ajax, Utils } from '@labkey/api';
import { redirect } from '@labkey/components';

import { computeWarnings, PlateTemplate, Position, WellGroup } from './models';
import { StatusBar } from './components/StatusBar';
Expand Down Expand Up @@ -72,14 +73,6 @@ export function toggleCell(groups: WellGroup[], activeGroupRowId: number, row: n
});
}

export function isSameOrigin(url: string): boolean {
try {
return new URL(url, window.location.origin).origin === window.location.origin;
} catch {
return false;
}
}

export const PlateTemplateDesigner: FC = () => {
const [plate, setPlate] = useState<null | PlateTemplate>(null);
const [activeGroup, setActiveGroup] = useState<null | WellGroup>(null);
Expand Down Expand Up @@ -334,8 +327,7 @@ export const PlateTemplateDesigner: FC = () => {
const navigateAway = useCallback(() => {
isIntentionalExitRef.current = true;
const returnURL = returnURLRef.current;
window.location.href =
returnURL && isSameOrigin(returnURL) ? returnURL : ActionURL.buildURL('plate', 'plateList');
redirect(returnURL || ActionURL.buildURL('plate', 'plateList'));
}, []);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
*/
import { WellGroup } from './models';
import { assignColors, isSameOrigin, toggleCell } from './PlateTemplateDesigner';
import { assignColors, toggleCell } from './PlateTemplateDesigner';

function makeGroup(rowId: number): WellGroup {
return { rowId, type: 'SPECIMEN', name: `Group ${rowId}`, positions: [], properties: {}, allowNewGroups: false };
Expand Down Expand Up @@ -131,37 +131,3 @@ describe('toggleCell', () => {
expect(toggleCell(groups, 99, 0, 0)).toEqual(groups);
});
});

describe('isSameOrigin', () => {
// jsdom sets window.location.origin to 'http://localhost'

test('returns true for a URL on the same origin', () => {
expect(isSameOrigin('http://localhost/some/path')).toBe(true);
});

test('returns true for a root-relative URL (same origin by construction)', () => {
expect(isSameOrigin('/labkey/plate/plateList.view')).toBe(true);
});

test('returns false for a different hostname', () => {
expect(isSameOrigin('http://evil.com/path')).toBe(false);
});

test('returns false for a different scheme', () => {
expect(isSameOrigin('https://localhost/path')).toBe(false);
});

test('returns false for a different port', () => {
expect(isSameOrigin('http://localhost:8080/path')).toBe(false);
});

test('returns false for a javascript: URL (XSS guard)', () => {
expect(isSameOrigin('javascript:alert(1)')).toBe(false);
});

test('returns false for an absolute URL with an invalid host (throws during construction)', () => {
// 'http://a b' has a space in the hostname which is invalid; the URL constructor throws,
// and the catch block returns false.
expect(isSameOrigin('http://a b/path')).toBe(false);
});
});
16 changes: 8 additions & 8 deletions core/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"lint-branch-fix": "node lint.diff.mjs --currentBranch --fix"
},
"dependencies": {
"@labkey/components": "7.42.1",
"@labkey/components": "7.45.2-fb-redirectGH1023.1",
"@labkey/themes": "1.9.4"
},
"devDependencies": {
Expand Down
5 changes: 2 additions & 3 deletions core/src/client/AssayDesigner/AssayDesigner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
getWebDavUrl,
inferDomainFromFile,
LoadingSpinner,
redirect,
setDomainFields,
} from '@labkey/components';

Expand Down Expand Up @@ -136,9 +137,7 @@ class AssayDesigner extends React.Component<any, State> {

navigate(defaultUrl: string) {
this._dirty = false;
const redirectUrl = this.state.returnUrl || defaultUrl;
// TODO refactor this and other usages in platform/core/src/client to a helper safeRedirect() function from @labkey/components
window.location.href = ActionURL.buildURL('core', 'safeRedirect', undefined, { returnUrl: redirectUrl });
redirect(this.state.returnUrl || defaultUrl);
}

onCancel = (): void => {
Expand Down
4 changes: 2 additions & 2 deletions core/src/client/DataClassDesigner/DataClassDesigner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
DataClassModel,
fetchDataClass,
LoadingSpinner,
redirect,
} from '@labkey/components';

import '../DomainDesigner.scss';
Expand Down Expand Up @@ -66,8 +67,7 @@ class DataClassDesignerWrapper extends React.Component<any, State> {

navigate(defaultUrl: string) {
this._dirty = false;
const redirectUrl = ActionURL.getReturnUrl() || defaultUrl;
window.location.href = ActionURL.buildURL('core', 'safeRedirect', undefined, { returnUrl: redirectUrl });
redirect(ActionURL.getReturnUrl() || defaultUrl);
}

onCancel = () => {
Expand Down
4 changes: 2 additions & 2 deletions core/src/client/DatasetDesigner/DatasetDesigner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
DatasetModel,
fetchDatasetDesign,
LoadingSpinner,
redirect,
} from '@labkey/components';
import { ActionURL, Domain, getServerContext } from '@labkey/api';

Expand Down Expand Up @@ -66,8 +67,7 @@ class DatasetDesigner extends PureComponent<any, State> {

navigate(defaultUrl: string): void {
this._dirty = false;
const redirectUrl = ActionURL.getReturnUrl() || defaultUrl;
window.location.href = ActionURL.buildURL('core', 'safeRedirect', undefined, { returnUrl: redirectUrl });
redirect(ActionURL.getReturnUrl() || defaultUrl);
}

navigateOnComplete(model: DatasetModel): void {
Expand Down
4 changes: 2 additions & 2 deletions core/src/client/DomainDesigner/DomainDesigner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
FormButtons,
LoadingSpinner,
Modal,
redirect,
resolveErrorMessage,
saveDomain,
} from '@labkey/components';
Expand Down Expand Up @@ -161,8 +162,7 @@ class DomainDesigner extends React.PureComponent<any, Partial<IAppState>> {

navigate = (): void => {
this._dirty = false;
const redirectUrl = ActionURL.getReturnUrl() || ActionURL.buildURL('project', 'begin', getServerContext().container.path);
window.location.href = ActionURL.buildURL('core', 'safeRedirect', undefined, { returnUrl: redirectUrl });
redirect(ActionURL.getReturnUrl() || ActionURL.buildURL('project', 'begin', getServerContext().container.path));
};

renderWarningConfirm() {
Expand Down
6 changes: 3 additions & 3 deletions core/src/client/ErrorHandler/ErrorHandler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ActionURL } from '@labkey/api';

import { getErrorHeading, getImage, getInstruction, getShowDetailsBtn, getSubHeading, getViewDetails } from './ErrorType';
import { ErrorDetails } from './model';
import { withServerContext } from '@labkey/components';
import { redirect, withServerContext } from '@labkey/components';

export interface AppContext {
errorDetails: ErrorDetails;
Expand All @@ -32,7 +32,7 @@ export class ErrorHandlerImpl extends PureComponent<ErrorHandlerProps, ErrorHand
// browsers like chrome stores their homepage as first item
window.history.back();
} else {
window.location.href = ActionURL.getBaseURL(false);
redirect(ActionURL.getBaseURL(false));
}
};

Expand All @@ -41,7 +41,7 @@ export class ErrorHandlerImpl extends PureComponent<ErrorHandlerProps, ErrorHand
};

onHomeClick = (): void => {
window.location.href = ActionURL.getBaseURL(false);
redirect(ActionURL.getBaseURL(false));
}

render() {
Expand Down
4 changes: 2 additions & 2 deletions core/src/client/ErrorHandler/ErrorType.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
*/
import React, { ReactNode } from 'react';
import { imageURL, HelpLink, HELP_LINK_REFERRER } from '@labkey/components';
import { HELP_LINK_REFERRER, HelpLink, imageURL, redirect } from '@labkey/components';
import { ActionURL, Ajax, getServerContext } from '@labkey/api';

import { ErrorDetails, ErrorType } from './model';
Expand Down Expand Up @@ -161,7 +161,7 @@ const PERMISSION_DETAILS = (errorDetails: ErrorDetails) => (
returnUrl,
},
callback: () => {
window.location.href = returnUrl;
redirect(returnUrl);
},
});
}}
Expand Down
4 changes: 2 additions & 2 deletions core/src/client/IssuesListDesigner/IssuesListDesigner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
IssuesListDefDesignerPanels,
IssuesListDefModel,
LoadingSpinner,
redirect,
} from '@labkey/components';

import '../DomainDesigner.scss';
Expand Down Expand Up @@ -82,8 +83,7 @@ class IssuesListDesigner extends React.Component<{}, State> {

navigate = (defaultUrl: string) => {
this._dirty = false;
const redirectUrl = ActionURL.getReturnUrl() || defaultUrl;
window.location.href = ActionURL.buildURL('core', 'safeRedirect', undefined, { returnUrl: redirectUrl });
redirect(ActionURL.getReturnUrl() || defaultUrl);
};

onComplete = (model: IssuesListDefModel) => {
Expand Down
3 changes: 2 additions & 1 deletion core/src/client/ListDesigner/ListDesigner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
ListDesignerPanels,
ListModel,
LoadingSpinner,
redirect,
} from '@labkey/components';

import '../DomainDesigner.scss';
Expand Down Expand Up @@ -104,7 +105,7 @@ export class ListDesigner extends React.Component<Props, State> {
navigate = async (returnUrlProvider: () => Promise<string>, model?: ListModel): Promise<void> => {
this._dirty = false;
const redirectUrl = this.getReturnUrl(model) ?? (await returnUrlProvider());
window.location.href = ActionURL.buildURL('core', 'safeRedirect', undefined, { returnUrl: redirectUrl });
redirect(redirectUrl);
};

getReturnUrl = (model?: ListModel): string => {
Expand Down
Loading