1 import { Router } from 'react-router-dom';
3 import { createHashHistory } from 'history';
4 import { AppGuard } from 'proton-pass-web/app/AppGuard';
5 import { AuthServiceProvider } from 'proton-pass-web/app/Auth/AuthServiceProvider';
6 import { AuthSwitchProvider } from 'proton-pass-web/app/Auth/AuthSwitchProvider';
7 import { StoreProvider } from 'proton-pass-web/app/Store/StoreProvider';
8 import { store } from 'proton-pass-web/app/Store/store';
9 import { B2BEvents } from 'proton-pass-web/lib/b2b';
10 import { core } from 'proton-pass-web/lib/core';
11 import { i18n } from 'proton-pass-web/lib/i18n';
12 import { logStore } from 'proton-pass-web/lib/logger';
13 import { monitor } from 'proton-pass-web/lib/monitor';
14 import { settings } from 'proton-pass-web/lib/settings';
15 import { spotlightProxy as spotlight } from 'proton-pass-web/lib/spotlight';
16 import { telemetry } from 'proton-pass-web/lib/telemetry';
17 import { getInitialTheme } from 'proton-pass-web/lib/theme';
23 NotificationsChildren,
24 NotificationsProvider,
26 } from '@proton/components';
27 import { Portal } from '@proton/components/components/portal';
28 import Icons from '@proton/icons/Icons';
29 import { AuthStoreProvider } from '@proton/pass/components/Core/AuthStoreProvider';
30 import { ConnectivityProvider } from '@proton/pass/components/Core/ConnectivityProvider';
31 import { Localized } from '@proton/pass/components/Core/Localized';
32 import type { PassCoreProviderProps } from '@proton/pass/components/Core/PassCoreProvider';
33 import { PassCoreProvider } from '@proton/pass/components/Core/PassCoreProvider';
34 import { PassExtensionLink } from '@proton/pass/components/Core/PassExtensionLink';
35 import { ThemeConnect } from '@proton/pass/components/Layout/Theme/ThemeConnect';
36 import { NavigationProvider } from '@proton/pass/components/Navigation/NavigationProvider';
37 import { getLocalPath } from '@proton/pass/components/Navigation/routing';
38 import { api, exposeApi } from '@proton/pass/lib/api/api';
39 import { createApi } from '@proton/pass/lib/api/factory';
40 import { createImageProxyHandler, imageResponsetoDataURL } from '@proton/pass/lib/api/images';
41 import { inferBiometricsStorageKey } from '@proton/pass/lib/auth/lock/biometrics/utils';
42 import { type AuthStore, createAuthStore, exposeAuthStore } from '@proton/pass/lib/auth/store';
43 import { exposePassCrypto } from '@proton/pass/lib/crypto';
44 import { createPassCrypto } from '@proton/pass/lib/crypto/pass-crypto';
45 import { createPassExport } from '@proton/pass/lib/export/export';
46 import { prepareImport } from '@proton/pass/lib/import/reader';
47 import { generateTOTPCode } from '@proton/pass/lib/otp/otp';
48 import { createTelemetryEvent } from '@proton/pass/lib/telemetry/event';
49 import { selectExportData } from '@proton/pass/store/selectors/export';
50 import { transferableToFile } from '@proton/pass/utils/file/transferable-file';
51 import { pipe } from '@proton/pass/utils/fp/pipe';
52 import { ping } from '@proton/shared/lib/api/tests';
53 import createSecureSessionStorage from '@proton/shared/lib/authentication/createSecureSessionStorage';
54 import sentry from '@proton/shared/lib/helpers/sentry';
56 import { PASS_CONFIG, SENTRY_CONFIG } from '../lib/env';
57 import { WelcomeScreen } from './Views/WelcomeScreen/WelcomeScreen';
58 import { isFirstLaunch } from './firstLaunch';
59 import locales from './locales';
63 const authStore = exposeAuthStore(createAuthStore(createSecureSessionStorage()));
65 exposeApi(createApi({ config: PASS_CONFIG }));
66 exposePassCrypto(createPassCrypto());
67 sentry({ config: PASS_CONFIG, sentryConfig: SENTRY_CONFIG });
69 const history = createHashHistory();
70 const imageProxy = createImageProxyHandler(api);
71 const showWelcome = isFirstLaunch();
73 export const getPassCoreProps = (): PassCoreProviderProps => ({
82 exportData: async (options) => {
83 const state = store.getState();
84 const data = selectExportData({ config: PASS_CONFIG, format: options.format })(state);
85 return transferableToFile(await createPassExport(data, options));
88 generateOTP: (payload) => (payload.type === 'uri' ? generateTOTPCode(payload.totpUri) : null),
90 getApiState: api.getState,
92 getBiometricsKey: async (store: AuthStore) => {
94 const { storageKey, version } = inferBiometricsStorageKey(store);
95 return (await window.ctxBridge?.getSecret(storageKey, version)) ?? null;
101 getDomainImage: async (domain, signal) => {
102 const url = `${PASS_CONFIG.API_URL}/core/v4/images/logo?Domain=${domain}&Size=32&Mode=light&MaxScaleUpFactor=4`;
103 const res = await imageProxy(url, signal);
104 return imageResponsetoDataURL(res);
107 getLogs: logStore.read,
108 getTheme: getInitialTheme,
110 onLink: (url) => window.open(url, '_blank'),
111 onTelemetry: pipe(createTelemetryEvent, telemetry.push),
112 onB2BEvent: B2BEvents.push,
114 openSettings: (page) =>
116 pathname: getLocalPath('settings'),
117 search: location.search,
121 prepareImport: prepareImport,
123 writeToClipboard: async (str) => window.ctxBridge?.writeToClipboard(str),
128 export const App = () => {
130 <PassCoreProvider {...getPassCoreProps()} wasm>
132 <ErrorBoundary component={<StandardErrorPage big />}>
133 <NotificationsProvider>
136 <ConnectivityProvider
137 subscribe={api.subscribe}
138 onPing={() => api({ ...ping(), unauthenticated: true })}
140 <Router history={history}>
142 <AuthStoreProvider store={authStore}>
144 <AuthServiceProvider>
148 {showWelcome ? <WelcomeScreen /> : <AppGuard />}
152 <NotificationsChildren />
155 </AuthServiceProvider>
156 </AuthSwitchProvider>
158 </NavigationProvider>
160 </ConnectivityProvider>
163 </NotificationsProvider>