22003: prevent redirect loop in Wb2 client-side redirect handler
[arvados.git] / services / workbench2 / src / common / redirect-to.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { getInlineFileUrl } from 'views-components/context-menu/actions/helpers';
6 import { Config } from './config';
7
8 export const REDIRECT_TO_DOWNLOAD_KEY = 'redirectToDownload';
9 export const REDIRECT_TO_PREVIEW_KEY = 'redirectToPreview';
10 export const REDIRECT_TO_KEY = 'redirectTo';
11
12 const getRedirectKeyFromUrl = (href: string): string => {
13     let params = new URL(href).searchParams;
14     switch (true) {
15         case params.has(REDIRECT_TO_DOWNLOAD_KEY):
16             return REDIRECT_TO_DOWNLOAD_KEY;
17         case params.has(REDIRECT_TO_PREVIEW_KEY):
18             return REDIRECT_TO_PREVIEW_KEY;
19         case params.has(REDIRECT_TO_KEY):
20             return REDIRECT_TO_KEY;
21         default:
22             return "";
23     }
24 }
25
26 const getRedirectKeyFromStorage = (localStorage: Storage): string => {
27     if (localStorage.getItem(REDIRECT_TO_DOWNLOAD_KEY)) {
28         return REDIRECT_TO_DOWNLOAD_KEY;
29     } else if (localStorage.getItem(REDIRECT_TO_PREVIEW_KEY)) {
30         return REDIRECT_TO_PREVIEW_KEY;
31     }
32     return "";
33 }
34
35 export const storeRedirects = () => {
36     const { location: { href }, localStorage } = window;
37     const redirectKey = getRedirectKeyFromUrl(href);
38
39     // Change old redirectTo -> redirectToPreview when storing redirect
40     const redirectStoreKey = redirectKey === REDIRECT_TO_KEY ? REDIRECT_TO_PREVIEW_KEY : redirectKey;
41
42     if (localStorage && redirectKey && redirectStoreKey) {
43         let params = new URL(href).searchParams;
44         localStorage.setItem(redirectStoreKey, params.get(redirectKey) || "");
45     }
46 };
47
48 export const handleRedirects = (token: string, config: Config) => {
49     const { localStorage } = window;
50     const { keepWebServiceUrl, keepWebInlineServiceUrl } = config;
51
52     if (localStorage) {
53         const redirectKey = getRedirectKeyFromStorage(localStorage);
54         const redirectPath = redirectKey ? localStorage.getItem(redirectKey) : '';
55         redirectKey && localStorage.removeItem(redirectKey);
56
57         if (redirectKey && redirectPath) {
58             let redirectUrl = new URL(keepWebServiceUrl);
59             // encodeURI will not touch characters such as # ? that may be
60             // delimiter in overall URL syntax
61             // Setting pathname attribute will in effect encode # and ?
62             // while leaving others minimally disturbed (useful for debugging
63             // and avoids excessive percent-encoding)
64             redirectUrl.pathname = encodeURI(redirectPath);
65             redirectUrl.searchParams.set("api_token", token);
66             let u = redirectUrl.href;
67             if (redirectKey === REDIRECT_TO_PREVIEW_KEY) {
68                 u = getInlineFileUrl(u, keepWebServiceUrl, keepWebInlineServiceUrl);
69             }
70             if (u) {
71                 window.location.href = u;
72             }
73         }
74     }
75 };