strapi-plugin-magic-sessionmanager 4.4.7 → 4.5.1
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-mFarhu5A.js → Analytics-Cp-WjeV3.js} +2 -2
- package/dist/_chunks/{Analytics-CFlATYIp.mjs → Analytics-DQyamHg6.mjs} +2 -2
- package/dist/_chunks/{App-CrdNlRlL.js → App-BvYLeEbF.js} +7 -3
- package/dist/_chunks/{App-BkFz8R3I.mjs → App-CN4bKWV9.mjs} +17 -13
- package/dist/_chunks/{License-BnbIePhc.mjs → License-Bgcm630d.mjs} +1 -1
- package/dist/_chunks/{License-BI04KWfw.js → License-DPyeZQWz.js} +1 -1
- package/dist/_chunks/{OnlineUsersWidget-D1B_2ge5.js → OnlineUsersWidget-BYnqhN3O.js} +1 -1
- package/dist/_chunks/{OnlineUsersWidget-eBwttUiU.mjs → OnlineUsersWidget-E2FA7rGi.mjs} +1 -1
- package/dist/_chunks/{Settings-Cy-6vah_.js → Settings-Bt6wy131.js} +166 -3
- package/dist/_chunks/{Settings-BfKDErt5.mjs → Settings-D9N7m11p.mjs} +167 -4
- package/dist/_chunks/{UpgradePage-B8kz6Cyz.js → UpgradePage-Bh21Lg-G.js} +1 -1
- package/dist/_chunks/{UpgradePage-2mV2iqDM.mjs → UpgradePage-DM23ZYVa.mjs} +1 -1
- package/dist/_chunks/{index-BEh2DizI.js → index-BRESWp1b.js} +12 -6
- package/dist/_chunks/{index-B0wQeSSu.mjs → index-BbbrBv3t.mjs} +12 -6
- package/dist/_chunks/{useLicense-RxDUbCoU.mjs → useLicense-Bszkymz3.mjs} +1 -1
- package/dist/_chunks/{useLicense-DFdVp_qI.js → useLicense-D_wQcoMn.js} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +13290 -8951
- package/dist/server/index.mjs +13288 -8949
- package/package.json +17 -10
|
@@ -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-BRESWp1b.js");
|
|
10
|
+
const useLicense = require("./useLicense-D_wQcoMn.js");
|
|
11
11
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
12
12
|
const styled__default = /* @__PURE__ */ _interopDefault(styled);
|
|
13
13
|
const theme = {
|
|
@@ -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-BbbrBv3t.mjs";
|
|
8
|
+
import { u as useLicense } from "./useLicense-Bszkymz3.mjs";
|
|
9
9
|
const theme = {
|
|
10
10
|
shadows: {
|
|
11
11
|
sm: "0 1px 3px 0 rgba(0, 0, 0, 0.1)",
|
|
@@ -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-BRESWp1b.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-D_wQcoMn.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 };
|
|
@@ -2025,7 +2025,11 @@ const LicenseGuard = ({ children }) => {
|
|
|
2025
2025
|
}
|
|
2026
2026
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
2027
2027
|
};
|
|
2028
|
+
const pluginId = "magic-sessionmanager";
|
|
2029
|
+
const pluginPermissions = {
|
|
2030
|
+
access: [{ action: `plugin::${pluginId}.access`, subject: null }]
|
|
2031
|
+
};
|
|
2028
2032
|
const App = () => {
|
|
2029
|
-
return /* @__PURE__ */ jsxRuntime.jsx(LicenseGuard, { children: /* @__PURE__ */ jsxRuntime.jsx(HomePage, {}) });
|
|
2033
|
+
return /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Protect, { permissions: pluginPermissions.access, children: /* @__PURE__ */ jsxRuntime.jsx(LicenseGuard, { children: /* @__PURE__ */ jsxRuntime.jsx(HomePage, {}) }) });
|
|
2030
2034
|
};
|
|
2031
2035
|
exports.default = App;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useEffect } from "react";
|
|
3
3
|
import { useIntl } from "react-intl";
|
|
4
|
-
import { useFetchClient, useNotification } from "@strapi/strapi/admin";
|
|
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, g as getTranslation } from "./index-
|
|
6
|
+
import { p as parseUserAgent, a as pluginId$1, g as getTranslation } from "./index-BbbrBv3t.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-Bszkymz3.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 = {
|
|
@@ -145,7 +145,7 @@ const SessionDetailModal = ({ session, onClose, onSessionTerminated }) => {
|
|
|
145
145
|
const fetchGeolocationData = async () => {
|
|
146
146
|
setGeoLoading(true);
|
|
147
147
|
try {
|
|
148
|
-
const { data } = await get(`/${pluginId}/geolocation/${session.ipAddress}`);
|
|
148
|
+
const { data } = await get(`/${pluginId$1}/geolocation/${session.ipAddress}`);
|
|
149
149
|
setGeoData(data.data);
|
|
150
150
|
} catch (err) {
|
|
151
151
|
console.error("[SessionDetailModal] Error fetching geolocation:", err);
|
|
@@ -185,7 +185,7 @@ const SessionDetailModal = ({ session, onClose, onSessionTerminated }) => {
|
|
|
185
185
|
}
|
|
186
186
|
setTerminating(true);
|
|
187
187
|
try {
|
|
188
|
-
await post(`/${pluginId}/sessions/${session.id}/terminate`);
|
|
188
|
+
await post(`/${pluginId$1}/sessions/${session.id}/terminate`);
|
|
189
189
|
toggleNotification({
|
|
190
190
|
type: "success",
|
|
191
191
|
message: t("notifications.success.terminated", "Session terminated successfully")
|
|
@@ -889,7 +889,7 @@ const HomePage = () => {
|
|
|
889
889
|
const fetchSessions = async () => {
|
|
890
890
|
setLoading(true);
|
|
891
891
|
try {
|
|
892
|
-
const { data } = await get(`/${pluginId}/sessions`);
|
|
892
|
+
const { data } = await get(`/${pluginId$1}/sessions`);
|
|
893
893
|
setSessions(data.data || []);
|
|
894
894
|
} catch (err) {
|
|
895
895
|
console.error("[SessionManager] Error fetching sessions:", err);
|
|
@@ -902,7 +902,7 @@ const HomePage = () => {
|
|
|
902
902
|
return;
|
|
903
903
|
}
|
|
904
904
|
try {
|
|
905
|
-
await post(`/${pluginId}/sessions/${sessionId}/terminate`);
|
|
905
|
+
await post(`/${pluginId$1}/sessions/${sessionId}/terminate`);
|
|
906
906
|
fetchSessions();
|
|
907
907
|
} catch (err) {
|
|
908
908
|
console.error("[SessionManager] Error terminating session:", err);
|
|
@@ -913,7 +913,7 @@ const HomePage = () => {
|
|
|
913
913
|
return;
|
|
914
914
|
}
|
|
915
915
|
try {
|
|
916
|
-
await del(`/${pluginId}/sessions/${sessionId}`);
|
|
916
|
+
await del(`/${pluginId$1}/sessions/${sessionId}`);
|
|
917
917
|
fetchSessions();
|
|
918
918
|
toggleNotification({
|
|
919
919
|
type: "success",
|
|
@@ -1645,7 +1645,7 @@ const LicenseGuard = ({ children }) => {
|
|
|
1645
1645
|
const checkLicenseStatus = async () => {
|
|
1646
1646
|
setIsChecking(true);
|
|
1647
1647
|
try {
|
|
1648
|
-
const response = await get(`/${pluginId}/license/status`);
|
|
1648
|
+
const response = await get(`/${pluginId$1}/license/status`);
|
|
1649
1649
|
if (response.data.valid) {
|
|
1650
1650
|
setNeedsLicense(false);
|
|
1651
1651
|
} else {
|
|
@@ -1662,7 +1662,7 @@ const LicenseGuard = ({ children }) => {
|
|
|
1662
1662
|
e.preventDefault();
|
|
1663
1663
|
setIsCreating(true);
|
|
1664
1664
|
try {
|
|
1665
|
-
const response = await post(`/${pluginId}/license/auto-create`, {});
|
|
1665
|
+
const response = await post(`/${pluginId$1}/license/auto-create`, {});
|
|
1666
1666
|
if (response.data && response.data.success) {
|
|
1667
1667
|
toggleNotification({
|
|
1668
1668
|
type: "success",
|
|
@@ -1696,7 +1696,7 @@ const LicenseGuard = ({ children }) => {
|
|
|
1696
1696
|
}
|
|
1697
1697
|
setIsCreating(true);
|
|
1698
1698
|
try {
|
|
1699
|
-
const response = await post(`/${pluginId}/license/create`, formData);
|
|
1699
|
+
const response = await post(`/${pluginId$1}/license/create`, formData);
|
|
1700
1700
|
if (response.data && response.data.success) {
|
|
1701
1701
|
toggleNotification({
|
|
1702
1702
|
type: "success",
|
|
@@ -1729,7 +1729,7 @@ const LicenseGuard = ({ children }) => {
|
|
|
1729
1729
|
}
|
|
1730
1730
|
setIsCreating(true);
|
|
1731
1731
|
try {
|
|
1732
|
-
const response = await post(`/${pluginId}/license/store-key`, {
|
|
1732
|
+
const response = await post(`/${pluginId$1}/license/store-key`, {
|
|
1733
1733
|
licenseKey: existingLicenseKey.trim(),
|
|
1734
1734
|
email: existingEmail.trim()
|
|
1735
1735
|
});
|
|
@@ -2021,8 +2021,12 @@ const LicenseGuard = ({ children }) => {
|
|
|
2021
2021
|
}
|
|
2022
2022
|
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
2023
2023
|
};
|
|
2024
|
+
const pluginId = "magic-sessionmanager";
|
|
2025
|
+
const pluginPermissions = {
|
|
2026
|
+
access: [{ action: `plugin::${pluginId}.access`, subject: null }]
|
|
2027
|
+
};
|
|
2024
2028
|
const App = () => {
|
|
2025
|
-
return /* @__PURE__ */ jsx(LicenseGuard, { children: /* @__PURE__ */ jsx(HomePage, {}) });
|
|
2029
|
+
return /* @__PURE__ */ jsx(Page.Protect, { permissions: pluginPermissions.access, children: /* @__PURE__ */ jsx(LicenseGuard, { children: /* @__PURE__ */ jsx(HomePage, {}) }) });
|
|
2026
2030
|
};
|
|
2027
2031
|
export {
|
|
2028
2032
|
App as default
|
|
@@ -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-BbbrBv3t.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-BRESWp1b.js");
|
|
10
10
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
11
11
|
const styled__default = /* @__PURE__ */ _interopDefault(styled);
|
|
12
12
|
const theme = {
|
|
@@ -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-BRESWp1b.js");
|
|
10
10
|
const OnlineUsersWidget = () => {
|
|
11
11
|
const { formatMessage } = reactIntl.useIntl();
|
|
12
12
|
const { get } = admin.useFetchClient();
|
|
@@ -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-BbbrBv3t.mjs";
|
|
8
8
|
const OnlineUsersWidget = () => {
|
|
9
9
|
const { formatMessage } = useIntl();
|
|
10
10
|
const { get } = useFetchClient();
|
|
@@ -7,8 +7,8 @@ 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-BRESWp1b.js");
|
|
11
|
+
const useLicense = require("./useLicense-D_wQcoMn.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);
|
|
@@ -349,6 +349,17 @@ const SettingsPage = () => {
|
|
|
349
349
|
cleanupInterval: 30,
|
|
350
350
|
lastSeenRateLimit: 30,
|
|
351
351
|
retentionDays: 90,
|
|
352
|
+
maxSessionAgeDays: 30,
|
|
353
|
+
// Grace window (ms) during which a freshly-issued JWT is accepted
|
|
354
|
+
// without a matching session row. Prevents strict-session enforcement
|
|
355
|
+
// from blocking the very first request after login. 0 disables.
|
|
356
|
+
sessionCreationGraceMs: 5e3,
|
|
357
|
+
// Opt-in fast path for the periodic idle-session cleanup: single
|
|
358
|
+
// SQL UPDATE instead of batched Document-Service writes. Bypasses
|
|
359
|
+
// lifecycle hooks; required for very large installations.
|
|
360
|
+
cleanupUseDbDirect: false,
|
|
361
|
+
strictSessionEnforcement: false,
|
|
362
|
+
trustedProxies: false,
|
|
352
363
|
enableGeolocation: true,
|
|
353
364
|
enableSecurityScoring: true,
|
|
354
365
|
blockSuspiciousSessions: false,
|
|
@@ -394,7 +405,7 @@ const SettingsPage = () => {
|
|
|
394
405
|
}
|
|
395
406
|
});
|
|
396
407
|
}
|
|
397
|
-
setSettings(loadedSettings);
|
|
408
|
+
setSettings((prev) => ({ ...prev, ...loadedSettings }));
|
|
398
409
|
} else {
|
|
399
410
|
setSettings((prev) => ({ ...prev, emailTemplates: getDefaultTemplates() }));
|
|
400
411
|
}
|
|
@@ -629,6 +640,45 @@ const SettingsPage = () => {
|
|
|
629
640
|
),
|
|
630
641
|
/* @__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` }) })
|
|
631
642
|
] }) }),
|
|
643
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
644
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.general.grace.title", "Post-Login Grace Period") }),
|
|
645
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
646
|
+
designSystem.SingleSelect,
|
|
647
|
+
{
|
|
648
|
+
value: String(settings.sessionCreationGraceMs ?? 5e3),
|
|
649
|
+
onChange: (value) => handleChange("sessionCreationGraceMs", parseInt(value)),
|
|
650
|
+
children: [
|
|
651
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "0", children: t("settings.general.grace.off", "Off (strict from first request)") }),
|
|
652
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "2000", children: t("settings.general.grace.2s", "2 seconds") }),
|
|
653
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "5000", children: t("settings.general.grace.5s", "5 seconds (Recommended)") }),
|
|
654
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "10000", children: t("settings.general.grace.10s", "10 seconds") }),
|
|
655
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "30000", children: t("settings.general.grace.30s", "30 seconds") })
|
|
656
|
+
]
|
|
657
|
+
}
|
|
658
|
+
),
|
|
659
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: t(
|
|
660
|
+
"settings.general.grace.hint",
|
|
661
|
+
"Accepts a freshly-issued JWT without a matching session row for this window, preventing strict-enforcement races right after login."
|
|
662
|
+
) })
|
|
663
|
+
] }) }),
|
|
664
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
665
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.general.cleanupMode.title", "Cleanup Strategy") }),
|
|
666
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
667
|
+
designSystem.SingleSelect,
|
|
668
|
+
{
|
|
669
|
+
value: settings.cleanupUseDbDirect ? "db" : "document-service",
|
|
670
|
+
onChange: (value) => handleChange("cleanupUseDbDirect", value === "db"),
|
|
671
|
+
children: [
|
|
672
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "document-service", children: t("settings.general.cleanupMode.ds", "Document Service (Recommended, safe)") }),
|
|
673
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "db", children: t("settings.general.cleanupMode.db", "Direct SQL UPDATE (large-scale)") })
|
|
674
|
+
]
|
|
675
|
+
}
|
|
676
|
+
),
|
|
677
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: t(
|
|
678
|
+
"settings.general.cleanupMode.hint",
|
|
679
|
+
"Direct SQL drains the entire idle-session backlog in one statement but bypasses lifecycle hooks. Only switch if you run >50 k active sessions."
|
|
680
|
+
) })
|
|
681
|
+
] }) }),
|
|
632
682
|
/* @__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: [
|
|
633
683
|
/* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { style: { width: "18px", height: "18px", color: "var(--colors-danger600, #DC2626)", flexShrink: 0, marginTop: "2px" } }),
|
|
634
684
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: 1 }, children: [
|
|
@@ -787,6 +837,119 @@ const SettingsPage = () => {
|
|
|
787
837
|
] })
|
|
788
838
|
}
|
|
789
839
|
),
|
|
840
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
841
|
+
designSystem.Box,
|
|
842
|
+
{
|
|
843
|
+
background: "neutral0",
|
|
844
|
+
padding: 6,
|
|
845
|
+
style: {
|
|
846
|
+
borderRadius: theme.borderRadius.lg,
|
|
847
|
+
marginBottom: "32px",
|
|
848
|
+
border: `2px solid ${settings.strictSessionEnforcement ? "rgba(220, 38, 38, 0.25)" : "rgba(2, 132, 199, 0.12)"}`,
|
|
849
|
+
background: settings.strictSessionEnforcement ? "rgba(220, 38, 38, 0.04)" : "rgba(2, 132, 199, 0.04)"
|
|
850
|
+
},
|
|
851
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 4, children: [
|
|
852
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 3, children: [
|
|
853
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.Shield, { style: { width: 24, height: 24, color: settings.strictSessionEnforcement ? "var(--colors-danger600, #DC2626)" : "var(--colors-primary600, #0284C7)" } }),
|
|
854
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", fontWeight: "bold", children: t("settings.security.enforcement.title", "Session Enforcement Policy") }),
|
|
855
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: settings.strictSessionEnforcement ? "danger100" : "neutral100", textColor: settings.strictSessionEnforcement ? "danger700" : "neutral700", children: settings.strictSessionEnforcement ? t("settings.security.enforcement.badgeStrict", "STRICT") : t("settings.security.enforcement.badgeRelaxed", "RELAXED") })
|
|
856
|
+
] }),
|
|
857
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", style: { lineHeight: 1.6 }, children: t("settings.security.enforcement.description", "Controls how aggressively JWT tokens are tied to an active session record. Strict mode rejects any token without a matching session, which is more secure but breaks tokens issued before this plugin was installed.") }),
|
|
858
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 6, children: [
|
|
859
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 12, s: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
860
|
+
ToggleCard,
|
|
861
|
+
{
|
|
862
|
+
$active: settings.strictSessionEnforcement,
|
|
863
|
+
onClick: () => handleChange("strictSessionEnforcement", !settings.strictSessionEnforcement),
|
|
864
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "row", gap: 4, style: { width: "100%" }, alignItems: "center", children: [
|
|
865
|
+
/* @__PURE__ */ jsxRuntime.jsx(GreenToggle, { $isActive: settings.strictSessionEnforcement, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
866
|
+
designSystem.Toggle,
|
|
867
|
+
{
|
|
868
|
+
checked: settings.strictSessionEnforcement,
|
|
869
|
+
onChange: () => handleChange("strictSessionEnforcement", !settings.strictSessionEnforcement)
|
|
870
|
+
}
|
|
871
|
+
) }),
|
|
872
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 1, style: { flex: 1 }, children: [
|
|
873
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
874
|
+
designSystem.Typography,
|
|
875
|
+
{
|
|
876
|
+
variant: "delta",
|
|
877
|
+
fontWeight: "bold",
|
|
878
|
+
textColor: settings.strictSessionEnforcement ? "success700" : "neutral800",
|
|
879
|
+
style: { fontSize: "15px" },
|
|
880
|
+
children: t("settings.security.enforcement.strict.title", "Strict Session Enforcement")
|
|
881
|
+
}
|
|
882
|
+
),
|
|
883
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "12px", lineHeight: "1.5" }, children: t("settings.security.enforcement.strict.description", "Reject every authenticated request that does not have a matching session record. Recommended for production.") })
|
|
884
|
+
] })
|
|
885
|
+
] })
|
|
886
|
+
}
|
|
887
|
+
) }),
|
|
888
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
889
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: [
|
|
890
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.Clock, { style: { width: 14, height: 14, verticalAlign: "middle", marginRight: 6 } }),
|
|
891
|
+
t("settings.security.enforcement.maxAge.title", "Max Session Age")
|
|
892
|
+
] }),
|
|
893
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
894
|
+
designSystem.SingleSelect,
|
|
895
|
+
{
|
|
896
|
+
value: String(settings.maxSessionAgeDays),
|
|
897
|
+
onChange: (value) => handleChange("maxSessionAgeDays", parseInt(value)),
|
|
898
|
+
children: [
|
|
899
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "1", children: t("settings.security.enforcement.maxAge.1day", "1 day (Very Strict)") }),
|
|
900
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "7", children: t("settings.security.enforcement.maxAge.7days", "7 days") }),
|
|
901
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "14", children: t("settings.security.enforcement.maxAge.14days", "14 days") }),
|
|
902
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "30", children: t("settings.security.enforcement.maxAge.30days", "30 days (Recommended)") }),
|
|
903
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "60", children: t("settings.security.enforcement.maxAge.60days", "60 days") }),
|
|
904
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "90", children: t("settings.security.enforcement.maxAge.90days", "90 days") }),
|
|
905
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "180", children: t("settings.security.enforcement.maxAge.180days", "180 days") }),
|
|
906
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "365", children: t("settings.security.enforcement.maxAge.365days", "1 year") })
|
|
907
|
+
]
|
|
908
|
+
}
|
|
909
|
+
),
|
|
910
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: t("settings.security.enforcement.maxAge.hint", "Sessions older than {days} days are automatically terminated, even if still active", { days: settings.maxSessionAgeDays }) })
|
|
911
|
+
] }) }),
|
|
912
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
913
|
+
ToggleCard,
|
|
914
|
+
{
|
|
915
|
+
$active: settings.trustedProxies,
|
|
916
|
+
onClick: () => handleChange("trustedProxies", !settings.trustedProxies),
|
|
917
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "row", gap: 4, style: { width: "100%" }, alignItems: "center", children: [
|
|
918
|
+
/* @__PURE__ */ jsxRuntime.jsx(GreenToggle, { $isActive: settings.trustedProxies, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
919
|
+
designSystem.Toggle,
|
|
920
|
+
{
|
|
921
|
+
checked: settings.trustedProxies,
|
|
922
|
+
onChange: () => handleChange("trustedProxies", !settings.trustedProxies)
|
|
923
|
+
}
|
|
924
|
+
) }),
|
|
925
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 1, style: { flex: 1 }, children: [
|
|
926
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
927
|
+
designSystem.Typography,
|
|
928
|
+
{
|
|
929
|
+
variant: "delta",
|
|
930
|
+
fontWeight: "bold",
|
|
931
|
+
textColor: settings.trustedProxies ? "success700" : "neutral800",
|
|
932
|
+
style: { fontSize: "15px" },
|
|
933
|
+
children: t("settings.security.enforcement.trustedProxies.title", "Trust Upstream Proxy")
|
|
934
|
+
}
|
|
935
|
+
),
|
|
936
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "12px", lineHeight: "1.5" }, children: t("settings.security.enforcement.trustedProxies.description", "Only enable when Strapi sits behind a trusted reverse proxy (nginx, Cloudflare). Otherwise clients can spoof X-Forwarded-For.") })
|
|
937
|
+
] })
|
|
938
|
+
] })
|
|
939
|
+
}
|
|
940
|
+
) })
|
|
941
|
+
] }),
|
|
942
|
+
!settings.strictSessionEnforcement && /* @__PURE__ */ jsxRuntime.jsx(
|
|
943
|
+
designSystem.Alert,
|
|
944
|
+
{
|
|
945
|
+
variant: "warning",
|
|
946
|
+
title: t("settings.security.enforcement.warning.title", "Running in Relaxed Mode"),
|
|
947
|
+
children: t("settings.security.enforcement.warning.body", "Tokens without a matching session record are allowed through. Manual session termination is still enforced via the token hash, but we strongly recommend enabling strict mode in production.")
|
|
948
|
+
}
|
|
949
|
+
)
|
|
950
|
+
] })
|
|
951
|
+
}
|
|
952
|
+
),
|
|
790
953
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral100", padding: 5, style: { borderRadius: theme.borderRadius.md, marginBottom: "32px" }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 4, children: [
|
|
791
954
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
792
955
|
ToggleCard,
|
|
@@ -3,10 +3,10 @@ import { useState, useEffect } from "react";
|
|
|
3
3
|
import { useIntl } from "react-intl";
|
|
4
4
|
import { Flex, Loader, Typography, Button, Box, Badge, Accordion, Grid, SingleSelect, SingleSelectOption, Divider, Alert, TextInput, Toggle, NumberInput, Checkbox, Tabs } from "@strapi/design-system";
|
|
5
5
|
import { useFetchClient, useNotification } from "@strapi/strapi/admin";
|
|
6
|
-
import { Check, Information, Cog, Trash, Shield, Code, Duplicate, Mail } from "@strapi/icons";
|
|
6
|
+
import { Check, Information, Cog, Trash, Shield, Code, Duplicate, Clock, Mail } from "@strapi/icons";
|
|
7
7
|
import styled, { css, keyframes } from "styled-components";
|
|
8
|
-
import { a as pluginId, g as getTranslation } from "./index-
|
|
9
|
-
import { u as useLicense } from "./useLicense-
|
|
8
|
+
import { a as pluginId, g as getTranslation } from "./index-BbbrBv3t.mjs";
|
|
9
|
+
import { u as useLicense } from "./useLicense-Bszkymz3.mjs";
|
|
10
10
|
import { D as DangerButton, S as ShowHideButton, G as GradientButton, C as CopyButton, T as TertiaryButton, c as SecondaryButton } from "./StyledButtons-Cz8oYhmc.mjs";
|
|
11
11
|
const theme = {
|
|
12
12
|
borderRadius: { md: "8px", lg: "12px" }
|
|
@@ -345,6 +345,17 @@ const SettingsPage = () => {
|
|
|
345
345
|
cleanupInterval: 30,
|
|
346
346
|
lastSeenRateLimit: 30,
|
|
347
347
|
retentionDays: 90,
|
|
348
|
+
maxSessionAgeDays: 30,
|
|
349
|
+
// Grace window (ms) during which a freshly-issued JWT is accepted
|
|
350
|
+
// without a matching session row. Prevents strict-session enforcement
|
|
351
|
+
// from blocking the very first request after login. 0 disables.
|
|
352
|
+
sessionCreationGraceMs: 5e3,
|
|
353
|
+
// Opt-in fast path for the periodic idle-session cleanup: single
|
|
354
|
+
// SQL UPDATE instead of batched Document-Service writes. Bypasses
|
|
355
|
+
// lifecycle hooks; required for very large installations.
|
|
356
|
+
cleanupUseDbDirect: false,
|
|
357
|
+
strictSessionEnforcement: false,
|
|
358
|
+
trustedProxies: false,
|
|
348
359
|
enableGeolocation: true,
|
|
349
360
|
enableSecurityScoring: true,
|
|
350
361
|
blockSuspiciousSessions: false,
|
|
@@ -390,7 +401,7 @@ const SettingsPage = () => {
|
|
|
390
401
|
}
|
|
391
402
|
});
|
|
392
403
|
}
|
|
393
|
-
setSettings(loadedSettings);
|
|
404
|
+
setSettings((prev) => ({ ...prev, ...loadedSettings }));
|
|
394
405
|
} else {
|
|
395
406
|
setSettings((prev) => ({ ...prev, emailTemplates: getDefaultTemplates() }));
|
|
396
407
|
}
|
|
@@ -625,6 +636,45 @@ const SettingsPage = () => {
|
|
|
625
636
|
),
|
|
626
637
|
/* @__PURE__ */ jsx(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` }) })
|
|
627
638
|
] }) }),
|
|
639
|
+
/* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
640
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.general.grace.title", "Post-Login Grace Period") }),
|
|
641
|
+
/* @__PURE__ */ jsxs(
|
|
642
|
+
SingleSelect,
|
|
643
|
+
{
|
|
644
|
+
value: String(settings.sessionCreationGraceMs ?? 5e3),
|
|
645
|
+
onChange: (value) => handleChange("sessionCreationGraceMs", parseInt(value)),
|
|
646
|
+
children: [
|
|
647
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "0", children: t("settings.general.grace.off", "Off (strict from first request)") }),
|
|
648
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "2000", children: t("settings.general.grace.2s", "2 seconds") }),
|
|
649
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "5000", children: t("settings.general.grace.5s", "5 seconds (Recommended)") }),
|
|
650
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "10000", children: t("settings.general.grace.10s", "10 seconds") }),
|
|
651
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "30000", children: t("settings.general.grace.30s", "30 seconds") })
|
|
652
|
+
]
|
|
653
|
+
}
|
|
654
|
+
),
|
|
655
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: t(
|
|
656
|
+
"settings.general.grace.hint",
|
|
657
|
+
"Accepts a freshly-issued JWT without a matching session row for this window, preventing strict-enforcement races right after login."
|
|
658
|
+
) })
|
|
659
|
+
] }) }),
|
|
660
|
+
/* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
661
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.general.cleanupMode.title", "Cleanup Strategy") }),
|
|
662
|
+
/* @__PURE__ */ jsxs(
|
|
663
|
+
SingleSelect,
|
|
664
|
+
{
|
|
665
|
+
value: settings.cleanupUseDbDirect ? "db" : "document-service",
|
|
666
|
+
onChange: (value) => handleChange("cleanupUseDbDirect", value === "db"),
|
|
667
|
+
children: [
|
|
668
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "document-service", children: t("settings.general.cleanupMode.ds", "Document Service (Recommended, safe)") }),
|
|
669
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "db", children: t("settings.general.cleanupMode.db", "Direct SQL UPDATE (large-scale)") })
|
|
670
|
+
]
|
|
671
|
+
}
|
|
672
|
+
),
|
|
673
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: t(
|
|
674
|
+
"settings.general.cleanupMode.hint",
|
|
675
|
+
"Direct SQL drains the entire idle-session backlog in one statement but bypasses lifecycle hooks. Only switch if you run >50 k active sessions."
|
|
676
|
+
) })
|
|
677
|
+
] }) }),
|
|
628
678
|
/* @__PURE__ */ jsx(Grid.Item, { col: 12, children: /* @__PURE__ */ jsx(Box, { padding: 4, background: "danger100", style: { borderRadius: theme.borderRadius.md, border: `2px solid rgba(220, 38, 38, 0.2)` }, children: /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-start", children: [
|
|
629
679
|
/* @__PURE__ */ jsx(Trash, { style: { width: "18px", height: "18px", color: "var(--colors-danger600, #DC2626)", flexShrink: 0, marginTop: "2px" } }),
|
|
630
680
|
/* @__PURE__ */ jsxs(Box, { style: { flex: 1 }, children: [
|
|
@@ -783,6 +833,119 @@ const SettingsPage = () => {
|
|
|
783
833
|
] })
|
|
784
834
|
}
|
|
785
835
|
),
|
|
836
|
+
/* @__PURE__ */ jsx(
|
|
837
|
+
Box,
|
|
838
|
+
{
|
|
839
|
+
background: "neutral0",
|
|
840
|
+
padding: 6,
|
|
841
|
+
style: {
|
|
842
|
+
borderRadius: theme.borderRadius.lg,
|
|
843
|
+
marginBottom: "32px",
|
|
844
|
+
border: `2px solid ${settings.strictSessionEnforcement ? "rgba(220, 38, 38, 0.25)" : "rgba(2, 132, 199, 0.12)"}`,
|
|
845
|
+
background: settings.strictSessionEnforcement ? "rgba(220, 38, 38, 0.04)" : "rgba(2, 132, 199, 0.04)"
|
|
846
|
+
},
|
|
847
|
+
children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 4, children: [
|
|
848
|
+
/* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, children: [
|
|
849
|
+
/* @__PURE__ */ jsx(Shield, { style: { width: 24, height: 24, color: settings.strictSessionEnforcement ? "var(--colors-danger600, #DC2626)" : "var(--colors-primary600, #0284C7)" } }),
|
|
850
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: t("settings.security.enforcement.title", "Session Enforcement Policy") }),
|
|
851
|
+
/* @__PURE__ */ jsx(Badge, { backgroundColor: settings.strictSessionEnforcement ? "danger100" : "neutral100", textColor: settings.strictSessionEnforcement ? "danger700" : "neutral700", children: settings.strictSessionEnforcement ? t("settings.security.enforcement.badgeStrict", "STRICT") : t("settings.security.enforcement.badgeRelaxed", "RELAXED") })
|
|
852
|
+
] }),
|
|
853
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", style: { lineHeight: 1.6 }, children: t("settings.security.enforcement.description", "Controls how aggressively JWT tokens are tied to an active session record. Strict mode rejects any token without a matching session, which is more secure but breaks tokens issued before this plugin was installed.") }),
|
|
854
|
+
/* @__PURE__ */ jsxs(Grid.Root, { gap: 6, children: [
|
|
855
|
+
/* @__PURE__ */ jsx(Grid.Item, { col: 12, s: 12, children: /* @__PURE__ */ jsx(
|
|
856
|
+
ToggleCard,
|
|
857
|
+
{
|
|
858
|
+
$active: settings.strictSessionEnforcement,
|
|
859
|
+
onClick: () => handleChange("strictSessionEnforcement", !settings.strictSessionEnforcement),
|
|
860
|
+
children: /* @__PURE__ */ jsxs(Flex, { direction: "row", gap: 4, style: { width: "100%" }, alignItems: "center", children: [
|
|
861
|
+
/* @__PURE__ */ jsx(GreenToggle, { $isActive: settings.strictSessionEnforcement, children: /* @__PURE__ */ jsx(
|
|
862
|
+
Toggle,
|
|
863
|
+
{
|
|
864
|
+
checked: settings.strictSessionEnforcement,
|
|
865
|
+
onChange: () => handleChange("strictSessionEnforcement", !settings.strictSessionEnforcement)
|
|
866
|
+
}
|
|
867
|
+
) }),
|
|
868
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, style: { flex: 1 }, children: [
|
|
869
|
+
/* @__PURE__ */ jsx(
|
|
870
|
+
Typography,
|
|
871
|
+
{
|
|
872
|
+
variant: "delta",
|
|
873
|
+
fontWeight: "bold",
|
|
874
|
+
textColor: settings.strictSessionEnforcement ? "success700" : "neutral800",
|
|
875
|
+
style: { fontSize: "15px" },
|
|
876
|
+
children: t("settings.security.enforcement.strict.title", "Strict Session Enforcement")
|
|
877
|
+
}
|
|
878
|
+
),
|
|
879
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "12px", lineHeight: "1.5" }, children: t("settings.security.enforcement.strict.description", "Reject every authenticated request that does not have a matching session record. Recommended for production.") })
|
|
880
|
+
] })
|
|
881
|
+
] })
|
|
882
|
+
}
|
|
883
|
+
) }),
|
|
884
|
+
/* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
885
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: [
|
|
886
|
+
/* @__PURE__ */ jsx(Clock, { style: { width: 14, height: 14, verticalAlign: "middle", marginRight: 6 } }),
|
|
887
|
+
t("settings.security.enforcement.maxAge.title", "Max Session Age")
|
|
888
|
+
] }),
|
|
889
|
+
/* @__PURE__ */ jsxs(
|
|
890
|
+
SingleSelect,
|
|
891
|
+
{
|
|
892
|
+
value: String(settings.maxSessionAgeDays),
|
|
893
|
+
onChange: (value) => handleChange("maxSessionAgeDays", parseInt(value)),
|
|
894
|
+
children: [
|
|
895
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "1", children: t("settings.security.enforcement.maxAge.1day", "1 day (Very Strict)") }),
|
|
896
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "7", children: t("settings.security.enforcement.maxAge.7days", "7 days") }),
|
|
897
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "14", children: t("settings.security.enforcement.maxAge.14days", "14 days") }),
|
|
898
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "30", children: t("settings.security.enforcement.maxAge.30days", "30 days (Recommended)") }),
|
|
899
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "60", children: t("settings.security.enforcement.maxAge.60days", "60 days") }),
|
|
900
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "90", children: t("settings.security.enforcement.maxAge.90days", "90 days") }),
|
|
901
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "180", children: t("settings.security.enforcement.maxAge.180days", "180 days") }),
|
|
902
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "365", children: t("settings.security.enforcement.maxAge.365days", "1 year") })
|
|
903
|
+
]
|
|
904
|
+
}
|
|
905
|
+
),
|
|
906
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: t("settings.security.enforcement.maxAge.hint", "Sessions older than {days} days are automatically terminated, even if still active", { days: settings.maxSessionAgeDays }) })
|
|
907
|
+
] }) }),
|
|
908
|
+
/* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsx(
|
|
909
|
+
ToggleCard,
|
|
910
|
+
{
|
|
911
|
+
$active: settings.trustedProxies,
|
|
912
|
+
onClick: () => handleChange("trustedProxies", !settings.trustedProxies),
|
|
913
|
+
children: /* @__PURE__ */ jsxs(Flex, { direction: "row", gap: 4, style: { width: "100%" }, alignItems: "center", children: [
|
|
914
|
+
/* @__PURE__ */ jsx(GreenToggle, { $isActive: settings.trustedProxies, children: /* @__PURE__ */ jsx(
|
|
915
|
+
Toggle,
|
|
916
|
+
{
|
|
917
|
+
checked: settings.trustedProxies,
|
|
918
|
+
onChange: () => handleChange("trustedProxies", !settings.trustedProxies)
|
|
919
|
+
}
|
|
920
|
+
) }),
|
|
921
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, style: { flex: 1 }, children: [
|
|
922
|
+
/* @__PURE__ */ jsx(
|
|
923
|
+
Typography,
|
|
924
|
+
{
|
|
925
|
+
variant: "delta",
|
|
926
|
+
fontWeight: "bold",
|
|
927
|
+
textColor: settings.trustedProxies ? "success700" : "neutral800",
|
|
928
|
+
style: { fontSize: "15px" },
|
|
929
|
+
children: t("settings.security.enforcement.trustedProxies.title", "Trust Upstream Proxy")
|
|
930
|
+
}
|
|
931
|
+
),
|
|
932
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "12px", lineHeight: "1.5" }, children: t("settings.security.enforcement.trustedProxies.description", "Only enable when Strapi sits behind a trusted reverse proxy (nginx, Cloudflare). Otherwise clients can spoof X-Forwarded-For.") })
|
|
933
|
+
] })
|
|
934
|
+
] })
|
|
935
|
+
}
|
|
936
|
+
) })
|
|
937
|
+
] }),
|
|
938
|
+
!settings.strictSessionEnforcement && /* @__PURE__ */ jsx(
|
|
939
|
+
Alert,
|
|
940
|
+
{
|
|
941
|
+
variant: "warning",
|
|
942
|
+
title: t("settings.security.enforcement.warning.title", "Running in Relaxed Mode"),
|
|
943
|
+
children: t("settings.security.enforcement.warning.body", "Tokens without a matching session record are allowed through. Manual session termination is still enforced via the token hash, but we strongly recommend enabling strict mode in production.")
|
|
944
|
+
}
|
|
945
|
+
)
|
|
946
|
+
] })
|
|
947
|
+
}
|
|
948
|
+
),
|
|
786
949
|
/* @__PURE__ */ jsx(Box, { background: "neutral100", padding: 5, style: { borderRadius: theme.borderRadius.md, marginBottom: "32px" }, children: /* @__PURE__ */ jsxs(Grid.Root, { gap: 4, children: [
|
|
787
950
|
/* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsx(
|
|
788
951
|
ToggleCard,
|
|
@@ -6,7 +6,7 @@ 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-
|
|
9
|
+
const index = require("./index-BRESWp1b.js");
|
|
10
10
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
11
11
|
const styled__default = /* @__PURE__ */ _interopDefault(styled);
|
|
12
12
|
const Container = styled__default.default(designSystem.Box)`
|