@remit/web-client 0.0.85 → 0.0.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remit/web-client",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.86",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Remit web client, published as composable primitives — the app shell, auth shells, and runtime config. A distributor imports what it composes and bundles it.",
|
|
6
6
|
"exports": {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React-render smoke test for `TlsRootCaDownload`: it must render only when
|
|
3
|
+
* this deployment's runtime config reports TLS_MODE=internal, since every
|
|
4
|
+
* other mode either has no local root CA (acme, tailscale) or serves plain
|
|
5
|
+
* HTTP (off).
|
|
6
|
+
*/
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import { afterEach, describe, it } from "node:test";
|
|
9
|
+
import React, { createElement } from "react";
|
|
10
|
+
import { renderToString } from "react-dom/server";
|
|
11
|
+
import { TlsRootCaDownload } from "./TlsRootCaDownload";
|
|
12
|
+
|
|
13
|
+
// See MessageToolbar.render.test.ts: the SSR test loader transpiles remit-ui
|
|
14
|
+
// `.tsx` (ButtonLink, here) with the classic JSX runtime, which needs a
|
|
15
|
+
// global `React`.
|
|
16
|
+
(globalThis as { React?: typeof React }).React = React;
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
globalThis.__REMIT_CONFIG__ = undefined;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe("TlsRootCaDownload", () => {
|
|
23
|
+
it("renders the download row when tlsMode is internal", () => {
|
|
24
|
+
globalThis.__REMIT_CONFIG__ = { tlsMode: "internal" };
|
|
25
|
+
const html = renderToString(createElement(TlsRootCaDownload) as never);
|
|
26
|
+
assert.match(html, /TLS root certificate/);
|
|
27
|
+
assert.match(html, /href="\/tls-root-ca\.crt"/);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
for (const mode of ["acme", "tailscale", "off", undefined]) {
|
|
31
|
+
it(`renders nothing when tlsMode is ${mode ?? "unset (default off)"}`, () => {
|
|
32
|
+
globalThis.__REMIT_CONFIG__ = mode ? { tlsMode: mode } : {};
|
|
33
|
+
const html = renderToString(createElement(TlsRootCaDownload) as never);
|
|
34
|
+
assert.equal(html, "");
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings > Advanced, shown only for TLS_MODE=internal (deploy/vps/README.md,
|
|
3
|
+
* "TLS", has the rationale). Downloads the same root CA `remit cert` exports,
|
|
4
|
+
* served by deploy/vps/caddy/internal.caddy — reachable in-app instead of
|
|
5
|
+
* over SSH.
|
|
6
|
+
*/
|
|
7
|
+
import { ButtonLink } from "@remit/ui";
|
|
8
|
+
import { ShieldCheck } from "lucide-react";
|
|
9
|
+
import { getRuntimeConfig } from "@/runtime-config";
|
|
10
|
+
|
|
11
|
+
export function TlsRootCaDownload() {
|
|
12
|
+
if (getRuntimeConfig().tlsMode !== "internal") return null;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div className="border-t border-line pt-4 mt-4">
|
|
16
|
+
<p className="text-sm font-medium text-fg mb-1">TLS root certificate</p>
|
|
17
|
+
<p className="text-sm text-fg-muted mb-2">
|
|
18
|
+
This deployment signs its own certificate. Import it into the trust
|
|
19
|
+
store of each device you browse from, and the browser warning stops for
|
|
20
|
+
good.
|
|
21
|
+
</p>
|
|
22
|
+
<ButtonLink
|
|
23
|
+
href="/tls-root-ca.crt"
|
|
24
|
+
download
|
|
25
|
+
variant="secondary"
|
|
26
|
+
size="sm"
|
|
27
|
+
icon={<ShieldCheck className="size-3.5" />}
|
|
28
|
+
>
|
|
29
|
+
Download root certificate
|
|
30
|
+
</ButtonLink>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -7,6 +7,7 @@ import { SettingsShell } from "@remit/ui";
|
|
|
7
7
|
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
|
8
8
|
import { useState } from "react";
|
|
9
9
|
import { SelfUpdatePanel } from "@/components/settings/SelfUpdatePanel";
|
|
10
|
+
import { TlsRootCaDownload } from "@/components/settings/TlsRootCaDownload";
|
|
10
11
|
import { AppVersion } from "@/components/ui/AppVersion";
|
|
11
12
|
import { SETTINGS_ID_TO_PATH, SETTINGS_NAV_ITEMS } from "@/routes/settings";
|
|
12
13
|
|
|
@@ -49,6 +50,7 @@ function AdvancedSettings() {
|
|
|
49
50
|
Notification rules, data export, and raw sync diagnostics are coming in
|
|
50
51
|
a future release.
|
|
51
52
|
</p>
|
|
53
|
+
<TlsRootCaDownload />
|
|
52
54
|
<div className="border-t border-line pt-4 mt-4">
|
|
53
55
|
<p className="text-sm font-medium text-fg mb-1">About</p>
|
|
54
56
|
<AppVersion />
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { afterEach, describe, it } from "node:test";
|
|
3
|
+
import { getRuntimeConfig } from "./runtime-config";
|
|
4
|
+
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
globalThis.__REMIT_CONFIG__ = undefined;
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
describe("getRuntimeConfig tlsMode", () => {
|
|
10
|
+
it("defaults to off when config.js sets nothing", () => {
|
|
11
|
+
globalThis.__REMIT_CONFIG__ = {};
|
|
12
|
+
assert.equal(getRuntimeConfig().tlsMode, "off");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("passes through each recognized TLS_MODE value", () => {
|
|
16
|
+
for (const mode of ["internal", "acme", "tailscale", "off"] as const) {
|
|
17
|
+
globalThis.__REMIT_CONFIG__ = { tlsMode: mode };
|
|
18
|
+
assert.equal(getRuntimeConfig().tlsMode, mode);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("falls back to off for a value config.js never declares", () => {
|
|
23
|
+
globalThis.__REMIT_CONFIG__ = { tlsMode: "quantum" };
|
|
24
|
+
assert.equal(getRuntimeConfig().tlsMode, "off");
|
|
25
|
+
});
|
|
26
|
+
});
|
package/src/runtime-config.ts
CHANGED
|
@@ -19,6 +19,18 @@ export interface RumConfig {
|
|
|
19
19
|
region: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* The deployment's TLS termination, mirroring TLS_MODE (deploy/vps/remit.env.template).
|
|
24
|
+
* "internal" is the only mode with a locally-signed root CA worth offering for
|
|
25
|
+
* download — the others are already publicly trusted or plain HTTP.
|
|
26
|
+
*/
|
|
27
|
+
export type TlsMode = "internal" | "acme" | "tailscale" | "off";
|
|
28
|
+
|
|
29
|
+
const TLS_MODES: readonly TlsMode[] = ["internal", "acme", "tailscale", "off"];
|
|
30
|
+
|
|
31
|
+
const isTlsMode = (value: unknown): value is TlsMode =>
|
|
32
|
+
typeof value === "string" && (TLS_MODES as readonly string[]).includes(value);
|
|
33
|
+
|
|
22
34
|
export interface RemitRuntimeConfig {
|
|
23
35
|
apiUrl: string;
|
|
24
36
|
appOrigin: string;
|
|
@@ -27,6 +39,7 @@ export interface RemitRuntimeConfig {
|
|
|
27
39
|
rum: RumConfig;
|
|
28
40
|
mailboxPollIntervalSeconds?: string;
|
|
29
41
|
disableDevtools: boolean;
|
|
42
|
+
tlsMode: TlsMode;
|
|
30
43
|
}
|
|
31
44
|
|
|
32
45
|
interface RawRuntimeConfig {
|
|
@@ -37,6 +50,7 @@ interface RawRuntimeConfig {
|
|
|
37
50
|
rum?: Partial<RumConfig>;
|
|
38
51
|
mailboxPollIntervalSeconds?: string | number;
|
|
39
52
|
disableDevtools?: boolean;
|
|
53
|
+
tlsMode?: string;
|
|
40
54
|
}
|
|
41
55
|
|
|
42
56
|
declare global {
|
|
@@ -71,5 +85,6 @@ export const getRuntimeConfig = (): RemitRuntimeConfig => {
|
|
|
71
85
|
? String(raw.mailboxPollIntervalSeconds)
|
|
72
86
|
: undefined,
|
|
73
87
|
disableDevtools: raw.disableDevtools ?? false,
|
|
88
|
+
tlsMode: isTlsMode(raw.tlsMode) ? raw.tlsMode : "off",
|
|
74
89
|
};
|
|
75
90
|
};
|