Skip to content
Closed
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
24 changes: 18 additions & 6 deletions browser/data-browser/src/chunks/AppPage/AppFrame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import resetCss from '../../reset.css?raw';
import { useCreateThemeVars } from '@views/PluginView/useCreateThemeVars';
import { getIntegrationProxy } from '@helpers/integrationProxy';
import { isPlatformId, ProxyConnections } from '@helpers/proxyConnections';
import { ProxyTrafficNotice } from '@components/ProxyTrafficNotice';

/** Changing installation or destination must discard source tokens and pending replies. */
export function AppFrame(props: Parameters<typeof AppFrameSession>[0]) {
Expand Down Expand Up @@ -334,12 +335,15 @@ function AppFrameSession({
)}
{connectAsk && (
<ConnectBar role='group' aria-label='Connect an account'>
<ErrorText>
This app wants to connect your{' '}
<strong>{platformName(connectAsk.platform)}</strong> account through{' '}
{getIntegrationProxy()}. The connection stays in this browser; the
app can only make requests through it.
</ErrorText>
<ConnectText>
<ErrorText>
This app wants to connect your{' '}
<strong>{platformName(connectAsk.platform)}</strong> account. The
connection stays in this browser; the app can only make requests
through it.
</ErrorText>
<ProxyTrafficNotice />
</ConnectText>
<Row gap='0.5rem'>
<Button onClick={connect}>Connect</Button>
<Button subtle onClick={cancelConnect}>
Expand Down Expand Up @@ -503,6 +507,14 @@ const ConnectBar = styled.div`
margin-bottom: 0.5rem;
`;

const ConnectText = styled.div`
display: flex;
flex-direction: column;
gap: 0.25rem;
flex: 1 1 20rem;
min-width: 0;
`;

/** Keeps the frame filling whatever is left once the bar has taken its height. */
const Wrapper = styled.div`
display: flex;
Expand Down
33 changes: 33 additions & 0 deletions browser/data-browser/src/components/ProxyTrafficNotice.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { styled } from 'styled-components';
import { useIntegrationProxy } from '@helpers/integrationProxy';
import {
PROXY_SELF_HOSTING_URL,
proxyTrafficHost,
} from '@helpers/proxyTrafficHost';
import { ExternalLink } from './ExternalLink';

/**
* Says which integration proxy carries a connection's traffic, with a link to
* running your own. Shown wherever someone connects an external service, and
* next to the proxy setting.
*/
export function ProxyTrafficNotice(): React.JSX.Element {
const host = proxyTrafficHost(useIntegrationProxy());

return (
<Notice data-testid='proxy-traffic-notice'>
This traffic goes through <strong>{host}</strong>. If you want to run your
own atomic-integration-proxy, follow the instructions here:{' '}
<ExternalLink to={PROXY_SELF_HOSTING_URL}>
self-hosting guide
</ExternalLink>
</Notice>
);
}

const Notice = styled.span`
display: block;
font-size: 0.8rem;
color: ${p => p.theme.colors.textLight};
overflow-wrap: anywhere;
`;
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from '@components/forms/InputStyles';
import { Button } from '@components/Button';
import { SettingsSection } from './SettingsSection';
import { ProxyTrafficNotice } from '@components/ProxyTrafficNotice';
import {
defaultIntegrationProxy,
setIntegrationProxy,
Expand Down Expand Up @@ -93,6 +94,7 @@ function ProxyForm({ proxy }: { proxy: string }) {
aria-describedby={error ? 'integration-proxy-error' : undefined}
/>
</InputWrapper>
<ProxyTrafficNotice />
{error && (
<ErrMessage id='integration-proxy-error' role='alert'>
{error}
Expand Down
42 changes: 42 additions & 0 deletions browser/data-browser/src/helpers/proxyTrafficHost.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { describe, expect, it } from 'vitest';
import { proxyTrafficHost } from './proxyTrafficHost';

describe('proxyTrafficHost', () => {
it('names atomic.place for the apex domain', () => {
expect(proxyTrafficHost('https://atomic.place')).toBe('atomic.place');
});

it('names atomic.place for any subdomain', () => {
expect(proxyTrafficHost('https://integrations.atomic.place')).toBe(
'atomic.place',
);
expect(proxyTrafficHost('https://a.b.atomic.place')).toBe('atomic.place');
expect(proxyTrafficHost('https://Integrations.Atomic.Place')).toBe(
'atomic.place',
);
});

it('does not mistake a lookalike for atomic.place', () => {
expect(proxyTrafficHost('https://evilatomic.place')).toBe(
'evilatomic.place',
);
expect(proxyTrafficHost('https://atomic.place.example.com')).toBe(
'atomic.place.example.com',
);
});

it('names any other host itself', () => {
expect(proxyTrafficHost('https://localthought.io')).toBe('localthought.io');
expect(proxyTrafficHost('https://proxy.example.org')).toBe(
'proxy.example.org',
);
});

it('keeps a port so a local proxy is identifiable', () => {
expect(proxyTrafficHost('http://localhost:8787')).toBe('localhost:8787');
});

it('returns the input when it is not a URL', () => {
expect(proxyTrafficHost('not a url')).toBe('not a url');
});
});
32 changes: 32 additions & 0 deletions browser/data-browser/src/helpers/proxyTrafficHost.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// @wc-ignore-file

/** How to run your own integration proxy instead of the default one. */
export const PROXY_SELF_HOSTING_URL =
'https://github.com/ontola/atomic-plugins/blob/main/integration-proxy/SELF_HOSTING.md';

const ATOMIC_PLACE = 'atomic.place';

/**
* The name to show for the integration proxy a connection's traffic goes
* through: `atomic.place` for atomic.place or any of its subdomains (so
* `integrations.atomic.place` reads as the service, not a machine), otherwise
* the proxy's own host, port included. Falls back to the input when it is not
* a URL, so a notice never hides where traffic goes.
*/
export function proxyTrafficHost(proxy: string): string {
let url: URL;

try {
url = new URL(proxy);
} catch {
return proxy;
}

const hostname = url.hostname.toLowerCase().replace(/\.$/, '');

if (hostname === ATOMIC_PLACE || hostname.endsWith(`.${ATOMIC_PLACE}`)) {
return ATOMIC_PLACE;
}

return url.host;
}
11 changes: 8 additions & 3 deletions browser/data-browser/src/locales/de.po
Original file line number Diff line number Diff line change
Expand Up @@ -9416,11 +9416,16 @@ msgstr ""
msgid "Sign in to connect an account."
msgstr ""

#. 0: ' '; 1: ' '; 2: getIntegrationProxy()
#: src/chunks/AppPage/AppFrame.tsx
msgid "This app wants to connect your{0} <0/> account through{1} {2}. The connection stays in this browser; the app can only make requests through it."
msgid "Connect an account"
msgstr ""

#. 0: ' '
#: src/chunks/AppPage/AppFrame.tsx
msgid "Connect an account"
msgid "This app wants to connect your{0} <0/> account. The connection stays in this browser; the app can only make requests through it."
msgstr ""

#. 0: ' '
#: src/components/ProxyTrafficNotice.tsx
msgid "This traffic goes through <0/>. If you want to run your own atomic-integration-proxy, follow the instructions here:{0} <1>self-hosting guide</1>"
msgstr ""
15 changes: 10 additions & 5 deletions browser/data-browser/src/locales/en.po
Original file line number Diff line number Diff line change
Expand Up @@ -9434,11 +9434,16 @@ msgstr "Finishing the connection…"
msgid "Sign in to connect an account."
msgstr "Sign in to connect an account."

#. 0: ' '; 1: ' '; 2: getIntegrationProxy()
#: src/chunks/AppPage/AppFrame.tsx
msgid "This app wants to connect your{0} <0/> account through{1} {2}. The connection stays in this browser; the app can only make requests through it."
msgstr "This app wants to connect your{0} <0/> account through{1} {2}. The connection stays in this browser; the app can only make requests through it."

#: src/chunks/AppPage/AppFrame.tsx
msgid "Connect an account"
msgstr "Connect an account"

#. 0: ' '
#: src/chunks/AppPage/AppFrame.tsx
msgid "This app wants to connect your{0} <0/> account. The connection stays in this browser; the app can only make requests through it."
msgstr "This app wants to connect your{0} <0/> account. The connection stays in this browser; the app can only make requests through it."

#. 0: ' '
#: src/components/ProxyTrafficNotice.tsx
msgid "This traffic goes through <0/>. If you want to run your own atomic-integration-proxy, follow the instructions here:{0} <1>self-hosting guide</1>"
msgstr "This traffic goes through <0/>. If you want to run your own atomic-integration-proxy, follow the instructions here:{0} <1>self-hosting guide</1>"
11 changes: 8 additions & 3 deletions browser/data-browser/src/locales/es.po
Original file line number Diff line number Diff line change
Expand Up @@ -9416,11 +9416,16 @@ msgstr ""
msgid "Sign in to connect an account."
msgstr ""

#. 0: ' '; 1: ' '; 2: getIntegrationProxy()
#: src/chunks/AppPage/AppFrame.tsx
msgid "This app wants to connect your{0} <0/> account through{1} {2}. The connection stays in this browser; the app can only make requests through it."
msgid "Connect an account"
msgstr ""

#. 0: ' '
#: src/chunks/AppPage/AppFrame.tsx
msgid "Connect an account"
msgid "This app wants to connect your{0} <0/> account. The connection stays in this browser; the app can only make requests through it."
msgstr ""

#. 0: ' '
#: src/components/ProxyTrafficNotice.tsx
msgid "This traffic goes through <0/>. If you want to run your own atomic-integration-proxy, follow the instructions here:{0} <1>self-hosting guide</1>"
msgstr ""
11 changes: 8 additions & 3 deletions browser/data-browser/src/locales/fr.po
Original file line number Diff line number Diff line change
Expand Up @@ -9416,11 +9416,16 @@ msgstr ""
msgid "Sign in to connect an account."
msgstr ""

#. 0: ' '; 1: ' '; 2: getIntegrationProxy()
#: src/chunks/AppPage/AppFrame.tsx
msgid "This app wants to connect your{0} <0/> account through{1} {2}. The connection stays in this browser; the app can only make requests through it."
msgid "Connect an account"
msgstr ""

#. 0: ' '
#: src/chunks/AppPage/AppFrame.tsx
msgid "Connect an account"
msgid "This app wants to connect your{0} <0/> account. The connection stays in this browser; the app can only make requests through it."
msgstr ""

#. 0: ' '
#: src/components/ProxyTrafficNotice.tsx
msgid "This traffic goes through <0/>. If you want to run your own atomic-integration-proxy, follow the instructions here:{0} <1>self-hosting guide</1>"
msgstr ""
Loading