strapi-plugin-magic-sessionmanager 4.5.0 → 4.5.2
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/dist/_chunks/{Analytics-DmlZwyVu.mjs → Analytics--qB2cKuD.mjs} +2 -2
- package/dist/_chunks/{Analytics-B7t0WvG7.js → Analytics-DM4_UffY.js} +2 -2
- package/dist/_chunks/{App-LfsjcXXp.mjs → App-CL5q29Mi.mjs} +2 -2
- package/dist/_chunks/{App-Bir8yK_r.js → App-DF-VsbDW.js} +2 -2
- package/dist/_chunks/{License-OToijT0s.mjs → License-D9piCp34.mjs} +1 -1
- package/dist/_chunks/{License-B56Xklj2.js → License-Dmm1d3fQ.js} +1 -1
- package/dist/_chunks/{OnlineUsersWidget-Fpc0aH2z.mjs → OnlineUsersWidget-DHsthkt0.mjs} +1 -1
- package/dist/_chunks/{OnlineUsersWidget-DTEzguhS.js → OnlineUsersWidget-KchZ_ScS.js} +1 -1
- package/dist/_chunks/{Settings-CO3-iggu.js → Settings-CUNaxDWk.js} +303 -3
- package/dist/_chunks/{Settings-Bz3lPBJ6.mjs → Settings-D6ILgR9X.mjs} +303 -3
- package/dist/_chunks/{UpgradePage-TBx1l2mQ.mjs → UpgradePage-D697BVWo.mjs} +1 -1
- package/dist/_chunks/{UpgradePage-KqUN7mDh.js → UpgradePage-Dwrv7g8L.js} +1 -1
- package/dist/_chunks/{index-CKrO7KSQ.js → index-CTxGMDHr.js} +6 -6
- package/dist/_chunks/{index-DuVZXuJh.mjs → index-CwxKazpc.mjs} +6 -6
- package/dist/_chunks/{useLicense-Xzo6nyh3.mjs → useLicense-B9WW9s_d.mjs} +1 -1
- package/dist/_chunks/{useLicense-DHAFqFSZ.js → useLicense-BEbtA_Zo.js} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +150 -24
- package/dist/server/index.mjs +150 -24
- package/package.json +1 -1
|
@@ -4,8 +4,8 @@ import { useFetchClient } from "@strapi/strapi/admin";
|
|
|
4
4
|
import styled, { css, keyframes } from "styled-components";
|
|
5
5
|
import { Loader, Typography, Box, Flex, Badge } from "@strapi/design-system";
|
|
6
6
|
import { ChartBubble, Crown, User, Clock, Monitor } from "@strapi/icons";
|
|
7
|
-
import { a as pluginId } from "./index-
|
|
8
|
-
import { u as useLicense } from "./useLicense-
|
|
7
|
+
import { a as pluginId } from "./index-CwxKazpc.mjs";
|
|
8
|
+
import { u as useLicense } from "./useLicense-B9WW9s_d.mjs";
|
|
9
9
|
const theme = {
|
|
10
10
|
shadows: {
|
|
11
11
|
sm: "0 1px 3px 0 rgba(0, 0, 0, 0.1)",
|
|
@@ -6,8 +6,8 @@ const admin = require("@strapi/strapi/admin");
|
|
|
6
6
|
const styled = require("styled-components");
|
|
7
7
|
const designSystem = require("@strapi/design-system");
|
|
8
8
|
const icons = require("@strapi/icons");
|
|
9
|
-
const index = require("./index-
|
|
10
|
-
const useLicense = require("./useLicense-
|
|
9
|
+
const index = require("./index-CTxGMDHr.js");
|
|
10
|
+
const useLicense = require("./useLicense-BEbtA_Zo.js");
|
|
11
11
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
12
12
|
const styled__default = /* @__PURE__ */ _interopDefault(styled);
|
|
13
13
|
const theme = {
|
|
@@ -3,10 +3,10 @@ import { useState, useEffect } from "react";
|
|
|
3
3
|
import { useIntl } from "react-intl";
|
|
4
4
|
import { useFetchClient, useNotification, Page } from "@strapi/strapi/admin";
|
|
5
5
|
import styled, { css, keyframes } from "styled-components";
|
|
6
|
-
import { p as parseUserAgent, a as pluginId$1, g as getTranslation } from "./index-
|
|
6
|
+
import { p as parseUserAgent, a as pluginId$1, g as getTranslation } from "./index-CwxKazpc.mjs";
|
|
7
7
|
import { Modal, Flex, Box, Typography, Divider, Button, Loader, SingleSelect, SingleSelectOption, Thead, Tr, Th, Tbody, Td, Table, TextInput } from "@strapi/design-system";
|
|
8
8
|
import { Check, Information, Monitor, Server, Clock, Cross, Earth, Shield, Crown, Phone, Download, User, Eye, Trash, Search, Key } from "@strapi/icons";
|
|
9
|
-
import { u as useLicense } from "./useLicense-
|
|
9
|
+
import { u as useLicense } from "./useLicense-B9WW9s_d.mjs";
|
|
10
10
|
import { S as ShowHideButton, T as TertiaryButton, D as DangerButton, I as IconButtonPrimary, a as IconButtonWarning, b as IconButtonDanger } from "./StyledButtons-Cz8oYhmc.mjs";
|
|
11
11
|
import { useNavigate } from "react-router-dom";
|
|
12
12
|
const theme = {
|
|
@@ -5,10 +5,10 @@ const react = require("react");
|
|
|
5
5
|
const reactIntl = require("react-intl");
|
|
6
6
|
const admin = require("@strapi/strapi/admin");
|
|
7
7
|
const styled = require("styled-components");
|
|
8
|
-
const index = require("./index-
|
|
8
|
+
const index = require("./index-CTxGMDHr.js");
|
|
9
9
|
const designSystem = require("@strapi/design-system");
|
|
10
10
|
const icons = require("@strapi/icons");
|
|
11
|
-
const useLicense = require("./useLicense-
|
|
11
|
+
const useLicense = require("./useLicense-BEbtA_Zo.js");
|
|
12
12
|
const StyledButtons = require("./StyledButtons-DDuxnYz8.js");
|
|
13
13
|
const reactRouterDom = require("react-router-dom");
|
|
14
14
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
@@ -4,7 +4,7 @@ import { Loader, Box, Alert, Flex, Typography, Button, Badge, Accordion } from "
|
|
|
4
4
|
import { useFetchClient, useNotification } from "@strapi/strapi/admin";
|
|
5
5
|
import { ArrowClockwise, Duplicate, Download, User, Shield, Sparkle, ChartBubble } from "@strapi/icons";
|
|
6
6
|
import styled, { css, keyframes } from "styled-components";
|
|
7
|
-
import { a as pluginId } from "./index-
|
|
7
|
+
import { a as pluginId } from "./index-CwxKazpc.mjs";
|
|
8
8
|
const theme = {
|
|
9
9
|
borderRadius: { lg: "12px" }
|
|
10
10
|
};
|
|
@@ -6,7 +6,7 @@ const designSystem = require("@strapi/design-system");
|
|
|
6
6
|
const admin = require("@strapi/strapi/admin");
|
|
7
7
|
const icons = require("@strapi/icons");
|
|
8
8
|
const styled = require("styled-components");
|
|
9
|
-
const index = require("./index-
|
|
9
|
+
const index = require("./index-CTxGMDHr.js");
|
|
10
10
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
11
11
|
const styled__default = /* @__PURE__ */ _interopDefault(styled);
|
|
12
12
|
const theme = {
|
|
@@ -4,7 +4,7 @@ import { useIntl } from "react-intl";
|
|
|
4
4
|
import { Box, Typography, Flex, Grid } from "@strapi/design-system";
|
|
5
5
|
import { Check, Cross, Clock, User } from "@strapi/icons";
|
|
6
6
|
import { useFetchClient } from "@strapi/strapi/admin";
|
|
7
|
-
import { g as getTranslation } from "./index-
|
|
7
|
+
import { g as getTranslation } from "./index-CwxKazpc.mjs";
|
|
8
8
|
const OnlineUsersWidget = () => {
|
|
9
9
|
const { formatMessage } = useIntl();
|
|
10
10
|
const { get } = useFetchClient();
|
|
@@ -6,7 +6,7 @@ const reactIntl = require("react-intl");
|
|
|
6
6
|
const designSystem = require("@strapi/design-system");
|
|
7
7
|
const icons = require("@strapi/icons");
|
|
8
8
|
const admin = require("@strapi/strapi/admin");
|
|
9
|
-
const index = require("./index-
|
|
9
|
+
const index = require("./index-CTxGMDHr.js");
|
|
10
10
|
const OnlineUsersWidget = () => {
|
|
11
11
|
const { formatMessage } = reactIntl.useIntl();
|
|
12
12
|
const { get } = admin.useFetchClient();
|
|
@@ -7,11 +7,85 @@ const designSystem = require("@strapi/design-system");
|
|
|
7
7
|
const admin = require("@strapi/strapi/admin");
|
|
8
8
|
const icons = require("@strapi/icons");
|
|
9
9
|
const styled = require("styled-components");
|
|
10
|
-
const index = require("./index-
|
|
11
|
-
const useLicense = require("./useLicense-
|
|
10
|
+
const index = require("./index-CTxGMDHr.js");
|
|
11
|
+
const useLicense = require("./useLicense-BEbtA_Zo.js");
|
|
12
12
|
const StyledButtons = require("./StyledButtons-DDuxnYz8.js");
|
|
13
13
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
14
14
|
const styled__default = /* @__PURE__ */ _interopDefault(styled);
|
|
15
|
+
const COUNTRIES = [
|
|
16
|
+
{ code: "DE", name: "Germany", flag: "🇩🇪" },
|
|
17
|
+
{ code: "AT", name: "Austria", flag: "🇦🇹" },
|
|
18
|
+
{ code: "CH", name: "Switzerland", flag: "🇨🇭" },
|
|
19
|
+
{ code: "US", name: "United States", flag: "🇺🇸" },
|
|
20
|
+
{ code: "CA", name: "Canada", flag: "🇨🇦" },
|
|
21
|
+
{ code: "MX", name: "Mexico", flag: "🇲🇽" },
|
|
22
|
+
{ code: "GB", name: "United Kingdom", flag: "🇬🇧" },
|
|
23
|
+
{ code: "IE", name: "Ireland", flag: "🇮🇪" },
|
|
24
|
+
{ code: "FR", name: "France", flag: "🇫🇷" },
|
|
25
|
+
{ code: "IT", name: "Italy", flag: "🇮🇹" },
|
|
26
|
+
{ code: "ES", name: "Spain", flag: "🇪🇸" },
|
|
27
|
+
{ code: "PT", name: "Portugal", flag: "🇵🇹" },
|
|
28
|
+
{ code: "NL", name: "Netherlands", flag: "🇳🇱" },
|
|
29
|
+
{ code: "BE", name: "Belgium", flag: "🇧🇪" },
|
|
30
|
+
{ code: "LU", name: "Luxembourg", flag: "🇱🇺" },
|
|
31
|
+
{ code: "SE", name: "Sweden", flag: "🇸🇪" },
|
|
32
|
+
{ code: "NO", name: "Norway", flag: "🇳🇴" },
|
|
33
|
+
{ code: "DK", name: "Denmark", flag: "🇩🇰" },
|
|
34
|
+
{ code: "FI", name: "Finland", flag: "🇫🇮" },
|
|
35
|
+
{ code: "PL", name: "Poland", flag: "🇵🇱" },
|
|
36
|
+
{ code: "CZ", name: "Czech Republic", flag: "🇨🇿" },
|
|
37
|
+
{ code: "SK", name: "Slovakia", flag: "🇸🇰" },
|
|
38
|
+
{ code: "HU", name: "Hungary", flag: "🇭🇺" },
|
|
39
|
+
{ code: "RO", name: "Romania", flag: "🇷🇴" },
|
|
40
|
+
{ code: "BG", name: "Bulgaria", flag: "🇧🇬" },
|
|
41
|
+
{ code: "GR", name: "Greece", flag: "🇬🇷" },
|
|
42
|
+
{ code: "HR", name: "Croatia", flag: "🇭🇷" },
|
|
43
|
+
{ code: "SI", name: "Slovenia", flag: "🇸🇮" },
|
|
44
|
+
{ code: "EE", name: "Estonia", flag: "🇪🇪" },
|
|
45
|
+
{ code: "LV", name: "Latvia", flag: "🇱🇻" },
|
|
46
|
+
{ code: "LT", name: "Lithuania", flag: "🇱🇹" },
|
|
47
|
+
{ code: "IS", name: "Iceland", flag: "🇮🇸" },
|
|
48
|
+
{ code: "TR", name: "Turkey", flag: "🇹🇷" },
|
|
49
|
+
{ code: "RU", name: "Russia", flag: "🇷🇺" },
|
|
50
|
+
{ code: "UA", name: "Ukraine", flag: "🇺🇦" },
|
|
51
|
+
{ code: "BR", name: "Brazil", flag: "🇧🇷" },
|
|
52
|
+
{ code: "AR", name: "Argentina", flag: "🇦🇷" },
|
|
53
|
+
{ code: "CL", name: "Chile", flag: "🇨🇱" },
|
|
54
|
+
{ code: "CO", name: "Colombia", flag: "🇨🇴" },
|
|
55
|
+
{ code: "AU", name: "Australia", flag: "🇦🇺" },
|
|
56
|
+
{ code: "NZ", name: "New Zealand", flag: "🇳🇿" },
|
|
57
|
+
{ code: "JP", name: "Japan", flag: "🇯🇵" },
|
|
58
|
+
{ code: "KR", name: "South Korea", flag: "🇰🇷" },
|
|
59
|
+
{ code: "CN", name: "China", flag: "🇨🇳" },
|
|
60
|
+
{ code: "HK", name: "Hong Kong", flag: "🇭🇰" },
|
|
61
|
+
{ code: "TW", name: "Taiwan", flag: "🇹🇼" },
|
|
62
|
+
{ code: "SG", name: "Singapore", flag: "🇸🇬" },
|
|
63
|
+
{ code: "IN", name: "India", flag: "🇮🇳" },
|
|
64
|
+
{ code: "ID", name: "Indonesia", flag: "🇮🇩" },
|
|
65
|
+
{ code: "TH", name: "Thailand", flag: "🇹🇭" },
|
|
66
|
+
{ code: "VN", name: "Vietnam", flag: "🇻🇳" },
|
|
67
|
+
{ code: "PH", name: "Philippines", flag: "🇵🇭" },
|
|
68
|
+
{ code: "MY", name: "Malaysia", flag: "🇲🇾" },
|
|
69
|
+
{ code: "AE", name: "United Arab Emirates", flag: "🇦🇪" },
|
|
70
|
+
{ code: "SA", name: "Saudi Arabia", flag: "🇸🇦" },
|
|
71
|
+
{ code: "IL", name: "Israel", flag: "🇮🇱" },
|
|
72
|
+
{ code: "EG", name: "Egypt", flag: "🇪🇬" },
|
|
73
|
+
{ code: "ZA", name: "South Africa", flag: "🇿🇦" },
|
|
74
|
+
{ code: "NG", name: "Nigeria", flag: "🇳🇬" },
|
|
75
|
+
{ code: "KE", name: "Kenya", flag: "🇰🇪" },
|
|
76
|
+
{ code: "MA", name: "Morocco", flag: "🇲🇦" }
|
|
77
|
+
];
|
|
78
|
+
const normalizeCountryCode = (raw) => {
|
|
79
|
+
if (typeof raw !== "string") return null;
|
|
80
|
+
const up = raw.trim().toUpperCase();
|
|
81
|
+
if (!/^[A-Z]{2}$/.test(up)) return null;
|
|
82
|
+
return up;
|
|
83
|
+
};
|
|
84
|
+
const formatCountry = (code) => {
|
|
85
|
+
if (!code) return "";
|
|
86
|
+
const match = COUNTRIES.find((c) => c.code === code);
|
|
87
|
+
return match ? `${match.flag} ${match.name} (${match.code})` : code;
|
|
88
|
+
};
|
|
15
89
|
const theme = {
|
|
16
90
|
borderRadius: { md: "8px", lg: "12px" }
|
|
17
91
|
};
|
|
@@ -331,6 +405,167 @@ const generateSecureKey = () => {
|
|
|
331
405
|
}
|
|
332
406
|
return key;
|
|
333
407
|
};
|
|
408
|
+
const GeofencingPanel = ({ settings, handleChange, t }) => {
|
|
409
|
+
const [pendingCode, setPendingCode] = react.useState("");
|
|
410
|
+
const mode = (() => {
|
|
411
|
+
if (Array.isArray(settings.allowedCountries) && settings.allowedCountries.length > 0) {
|
|
412
|
+
return "allowlist";
|
|
413
|
+
}
|
|
414
|
+
if (Array.isArray(settings.blockedCountries) && settings.blockedCountries.length > 0) {
|
|
415
|
+
return "blocklist";
|
|
416
|
+
}
|
|
417
|
+
return "allowlist";
|
|
418
|
+
})();
|
|
419
|
+
const activeField = mode === "allowlist" ? "allowedCountries" : "blockedCountries";
|
|
420
|
+
const activeList = Array.isArray(settings[activeField]) ? settings[activeField] : [];
|
|
421
|
+
const setMode = (newMode) => {
|
|
422
|
+
if (newMode === mode) return;
|
|
423
|
+
if (newMode === "allowlist") {
|
|
424
|
+
handleChange("blockedCountries", []);
|
|
425
|
+
} else {
|
|
426
|
+
handleChange("allowedCountries", []);
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
const addCode = (raw) => {
|
|
430
|
+
const code = normalizeCountryCode(raw);
|
|
431
|
+
if (!code) return;
|
|
432
|
+
if (activeList.includes(code)) return;
|
|
433
|
+
handleChange(activeField, [...activeList, code]);
|
|
434
|
+
setPendingCode("");
|
|
435
|
+
};
|
|
436
|
+
const removeCode = (code) => {
|
|
437
|
+
handleChange(activeField, activeList.filter((c) => c !== code));
|
|
438
|
+
};
|
|
439
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 5, children: [
|
|
440
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
441
|
+
designSystem.Box,
|
|
442
|
+
{
|
|
443
|
+
padding: 3,
|
|
444
|
+
background: settings.enableGeofencing ? "success100" : "neutral100",
|
|
445
|
+
hasRadius: true,
|
|
446
|
+
style: { borderLeft: `4px solid ${settings.enableGeofencing ? "#16A34A" : "#9CA3AF"}` },
|
|
447
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
448
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
449
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", style: { display: "block", marginBottom: "4px" }, children: t("settings.geofencing.enable.title", "Enable Geofencing") }),
|
|
450
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "12px" }, children: t(
|
|
451
|
+
"settings.geofencing.enable.description",
|
|
452
|
+
"When enabled, the pre-login guard compares the caller's country against the configured list and rejects logins that do not match."
|
|
453
|
+
) })
|
|
454
|
+
] }),
|
|
455
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
456
|
+
designSystem.Toggle,
|
|
457
|
+
{
|
|
458
|
+
onLabel: "On",
|
|
459
|
+
offLabel: "Off",
|
|
460
|
+
checked: !!settings.enableGeofencing,
|
|
461
|
+
onChange: () => handleChange("enableGeofencing", !settings.enableGeofencing)
|
|
462
|
+
}
|
|
463
|
+
)
|
|
464
|
+
] })
|
|
465
|
+
}
|
|
466
|
+
) }),
|
|
467
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
468
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.geofencing.mode.title", "Mode") }),
|
|
469
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
|
|
470
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
471
|
+
designSystem.Button,
|
|
472
|
+
{
|
|
473
|
+
variant: mode === "allowlist" ? "default" : "tertiary",
|
|
474
|
+
onClick: () => setMode("allowlist"),
|
|
475
|
+
disabled: !settings.enableGeofencing,
|
|
476
|
+
children: t("settings.geofencing.mode.allowlist", "Allowlist (only selected countries)")
|
|
477
|
+
}
|
|
478
|
+
),
|
|
479
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
480
|
+
designSystem.Button,
|
|
481
|
+
{
|
|
482
|
+
variant: mode === "blocklist" ? "default" : "tertiary",
|
|
483
|
+
onClick: () => setMode("blocklist"),
|
|
484
|
+
disabled: !settings.enableGeofencing,
|
|
485
|
+
children: t("settings.geofencing.mode.blocklist", "Blocklist (block selected countries)")
|
|
486
|
+
}
|
|
487
|
+
)
|
|
488
|
+
] }),
|
|
489
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: mode === "allowlist" ? t(
|
|
490
|
+
"settings.geofencing.mode.allowlist.hint",
|
|
491
|
+
"Only countries in the list may authenticate. Empty list = no geo restriction."
|
|
492
|
+
) : t(
|
|
493
|
+
"settings.geofencing.mode.blocklist.hint",
|
|
494
|
+
"Every country EXCEPT those in the list may authenticate."
|
|
495
|
+
) })
|
|
496
|
+
] }) }),
|
|
497
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
498
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: mode === "allowlist" ? t("settings.geofencing.allowed.title", "Allowed Countries") : t("settings.geofencing.blocked.title", "Blocked Countries") }),
|
|
499
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, wrap: "wrap", style: { marginBottom: "12px", minHeight: "36px" }, children: activeList.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: t("settings.geofencing.empty", "No countries configured.") }) : activeList.map((code) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
500
|
+
designSystem.Badge,
|
|
501
|
+
{
|
|
502
|
+
onClick: settings.enableGeofencing ? () => removeCode(code) : void 0,
|
|
503
|
+
style: {
|
|
504
|
+
cursor: settings.enableGeofencing ? "pointer" : "not-allowed",
|
|
505
|
+
padding: "6px 10px",
|
|
506
|
+
background: mode === "allowlist" ? "#DCFCE7" : "#FEE2E2",
|
|
507
|
+
color: mode === "allowlist" ? "#15803D" : "#B91C1C"
|
|
508
|
+
},
|
|
509
|
+
children: [
|
|
510
|
+
formatCountry(code),
|
|
511
|
+
settings.enableGeofencing ? " ✕" : ""
|
|
512
|
+
]
|
|
513
|
+
},
|
|
514
|
+
code
|
|
515
|
+
)) }),
|
|
516
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
|
|
517
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
518
|
+
designSystem.SingleSelect,
|
|
519
|
+
{
|
|
520
|
+
disabled: !settings.enableGeofencing,
|
|
521
|
+
value: pendingCode || "",
|
|
522
|
+
onChange: (value) => {
|
|
523
|
+
setPendingCode(value);
|
|
524
|
+
if (value) addCode(value);
|
|
525
|
+
},
|
|
526
|
+
placeholder: t("settings.geofencing.pick", "Pick a country to add…"),
|
|
527
|
+
children: COUNTRIES.filter((c) => !activeList.includes(c.code)).map((c) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SingleSelectOption, { value: c.code, children: [
|
|
528
|
+
c.flag,
|
|
529
|
+
" ",
|
|
530
|
+
c.name,
|
|
531
|
+
" (",
|
|
532
|
+
c.code,
|
|
533
|
+
")"
|
|
534
|
+
] }, c.code))
|
|
535
|
+
}
|
|
536
|
+
) }),
|
|
537
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
538
|
+
designSystem.TextInput,
|
|
539
|
+
{
|
|
540
|
+
disabled: !settings.enableGeofencing,
|
|
541
|
+
placeholder: t("settings.geofencing.manual", "Or type ISO-2 (e.g. JP)"),
|
|
542
|
+
value: pendingCode.length <= 2 ? pendingCode : "",
|
|
543
|
+
onChange: (e) => setPendingCode(e.target.value.toUpperCase().slice(0, 2)),
|
|
544
|
+
style: { width: "180px" }
|
|
545
|
+
}
|
|
546
|
+
),
|
|
547
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
548
|
+
designSystem.Button,
|
|
549
|
+
{
|
|
550
|
+
disabled: !settings.enableGeofencing || !normalizeCountryCode(pendingCode),
|
|
551
|
+
onClick: () => addCode(pendingCode),
|
|
552
|
+
children: t("settings.geofencing.add", "Add")
|
|
553
|
+
}
|
|
554
|
+
)
|
|
555
|
+
] })
|
|
556
|
+
] }) }),
|
|
557
|
+
!settings.enableGeofencing && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 12, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "default", closeLabel: "", title: "", onClose: () => {
|
|
558
|
+
}, children: t(
|
|
559
|
+
"settings.geofencing.disabled",
|
|
560
|
+
"Geofencing is currently disabled. Enable it above to enforce the configured country list."
|
|
561
|
+
) }) }),
|
|
562
|
+
settings.enableGeofencing && !settings.enableGeolocation && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 12, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "warning", closeLabel: "", title: "", onClose: () => {
|
|
563
|
+
}, children: t(
|
|
564
|
+
"settings.geofencing.needsGeolocation",
|
|
565
|
+
"Geofencing requires Geolocation to be enabled (Security tab)."
|
|
566
|
+
) }) })
|
|
567
|
+
] });
|
|
568
|
+
};
|
|
334
569
|
const SettingsPage = () => {
|
|
335
570
|
const { formatMessage } = reactIntl.useIntl();
|
|
336
571
|
const { get, post, put } = admin.useFetchClient();
|
|
@@ -350,6 +585,14 @@ const SettingsPage = () => {
|
|
|
350
585
|
lastSeenRateLimit: 30,
|
|
351
586
|
retentionDays: 90,
|
|
352
587
|
maxSessionAgeDays: 30,
|
|
588
|
+
// Grace window (ms) during which a freshly-issued JWT is accepted
|
|
589
|
+
// without a matching session row. Prevents strict-session enforcement
|
|
590
|
+
// from blocking the very first request after login. 0 disables.
|
|
591
|
+
sessionCreationGraceMs: 5e3,
|
|
592
|
+
// Opt-in fast path for the periodic idle-session cleanup: single
|
|
593
|
+
// SQL UPDATE instead of batched Document-Service writes. Bypasses
|
|
594
|
+
// lifecycle hooks; required for very large installations.
|
|
595
|
+
cleanupUseDbDirect: false,
|
|
353
596
|
strictSessionEnforcement: false,
|
|
354
597
|
trustedProxies: false,
|
|
355
598
|
enableGeolocation: true,
|
|
@@ -397,7 +640,7 @@ const SettingsPage = () => {
|
|
|
397
640
|
}
|
|
398
641
|
});
|
|
399
642
|
}
|
|
400
|
-
setSettings(loadedSettings);
|
|
643
|
+
setSettings((prev) => ({ ...prev, ...loadedSettings }));
|
|
401
644
|
} else {
|
|
402
645
|
setSettings((prev) => ({ ...prev, emailTemplates: getDefaultTemplates() }));
|
|
403
646
|
}
|
|
@@ -632,6 +875,45 @@ const SettingsPage = () => {
|
|
|
632
875
|
),
|
|
633
876
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: settings.retentionDays === -1 ? t("settings.general.retention.hintNever", "Old sessions deleted after never") : t("settings.general.retention.hint", "Old sessions deleted after {days}", { days: `${settings.retentionDays} days` }) })
|
|
634
877
|
] }) }),
|
|
878
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
879
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.general.grace.title", "Post-Login Grace Period") }),
|
|
880
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
881
|
+
designSystem.SingleSelect,
|
|
882
|
+
{
|
|
883
|
+
value: String(settings.sessionCreationGraceMs ?? 5e3),
|
|
884
|
+
onChange: (value) => handleChange("sessionCreationGraceMs", parseInt(value)),
|
|
885
|
+
children: [
|
|
886
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "0", children: t("settings.general.grace.off", "Off (strict from first request)") }),
|
|
887
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "2000", children: t("settings.general.grace.2s", "2 seconds") }),
|
|
888
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "5000", children: t("settings.general.grace.5s", "5 seconds (Recommended)") }),
|
|
889
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "10000", children: t("settings.general.grace.10s", "10 seconds") }),
|
|
890
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "30000", children: t("settings.general.grace.30s", "30 seconds") })
|
|
891
|
+
]
|
|
892
|
+
}
|
|
893
|
+
),
|
|
894
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: t(
|
|
895
|
+
"settings.general.grace.hint",
|
|
896
|
+
"Accepts a freshly-issued JWT without a matching session row for this window, preventing strict-enforcement races right after login."
|
|
897
|
+
) })
|
|
898
|
+
] }) }),
|
|
899
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
900
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.general.cleanupMode.title", "Cleanup Strategy") }),
|
|
901
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
902
|
+
designSystem.SingleSelect,
|
|
903
|
+
{
|
|
904
|
+
value: settings.cleanupUseDbDirect ? "db" : "document-service",
|
|
905
|
+
onChange: (value) => handleChange("cleanupUseDbDirect", value === "db"),
|
|
906
|
+
children: [
|
|
907
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "document-service", children: t("settings.general.cleanupMode.ds", "Document Service (Recommended, safe)") }),
|
|
908
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "db", children: t("settings.general.cleanupMode.db", "Direct SQL UPDATE (large-scale)") })
|
|
909
|
+
]
|
|
910
|
+
}
|
|
911
|
+
),
|
|
912
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: t(
|
|
913
|
+
"settings.general.cleanupMode.hint",
|
|
914
|
+
"Direct SQL drains the entire idle-session backlog in one statement but bypasses lifecycle hooks. Only switch if you run >50 k active sessions."
|
|
915
|
+
) })
|
|
916
|
+
] }) }),
|
|
635
917
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 12, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, background: "danger100", style: { borderRadius: theme.borderRadius.md, border: `2px solid rgba(220, 38, 38, 0.2)` }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 3, alignItems: "flex-start", children: [
|
|
636
918
|
/* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { style: { width: "18px", height: "18px", color: "var(--colors-danger600, #DC2626)", flexShrink: 0, marginTop: "2px" } }),
|
|
637
919
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: 1 }, children: [
|
|
@@ -1012,6 +1294,24 @@ const SettingsPage = () => {
|
|
|
1012
1294
|
] }) }) })
|
|
1013
1295
|
] }) })
|
|
1014
1296
|
] }),
|
|
1297
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Accordion.Item, { value: "geofencing", children: [
|
|
1298
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Accordion.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1299
|
+
designSystem.Accordion.Trigger,
|
|
1300
|
+
{
|
|
1301
|
+
icon: icons.Shield,
|
|
1302
|
+
description: t("settings.geofencing.description", "Allow or block sign-ins by country"),
|
|
1303
|
+
children: t("settings.geofencing.title", "Geofencing")
|
|
1304
|
+
}
|
|
1305
|
+
) }),
|
|
1306
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Accordion.Content, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 6, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1307
|
+
GeofencingPanel,
|
|
1308
|
+
{
|
|
1309
|
+
settings,
|
|
1310
|
+
handleChange,
|
|
1311
|
+
t
|
|
1312
|
+
}
|
|
1313
|
+
) }) })
|
|
1314
|
+
] }),
|
|
1015
1315
|
isAdvanced && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Accordion.Item, { value: "email", children: [
|
|
1016
1316
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Accordion.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1017
1317
|
designSystem.Accordion.Trigger,
|