strapi-plugin-oidc 1.8.3 → 1.8.5
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/README.md +22 -3
- package/dist/admin/{index-Bb9-aYb4.mjs → index-BlfNZYVU.mjs} +1 -1
- package/dist/admin/{index-Dk6TYtio.js → index-C8nfr95D.js} +1 -1
- package/dist/admin/{index-Bmg4eTYb.js → index-DDCcJt16.js} +183 -179
- package/dist/admin/{index-BqWd-Iiq.mjs → index-DRFXk_MQ.mjs} +183 -179
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +231 -219
- package/dist/server/index.mjs +232 -220
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ module.exports = ({ env }) => ({
|
|
|
48
48
|
OIDC_GROUP_FIELD: 'groups', // OIDC claim field containing group membership
|
|
49
49
|
OIDC_GROUP_ROLE_MAP: '{}', // JSON map of group names to Strapi role names
|
|
50
50
|
OIDC_REQUIRE_EMAIL_VERIFIED: true, // Reject logins when provider does not report email_verified=true (set false to disable)
|
|
51
|
-
OIDC_TRUSTED_IP_HEADER: '', // Optional:
|
|
51
|
+
OIDC_TRUSTED_IP_HEADER: '', // Optional: header set by your CDN/proxy containing the real client IP (see note below); only honoured when Koa proxy mode is enabled (see below)
|
|
52
52
|
OIDC_FORCE_SECURE_COOKIES: false, // Set true when behind a trusted HTTPS proxy that Strapi can't auto-detect
|
|
53
53
|
},
|
|
54
54
|
},
|
|
@@ -67,9 +67,28 @@ module.exports = ({ env }) => ({
|
|
|
67
67
|
|
|
68
68
|
### Client IP attribution and reverse proxies
|
|
69
69
|
|
|
70
|
-
The plugin logs client IPs for rate-limit buckets and audit logs. When Strapi runs behind a reverse proxy,
|
|
70
|
+
The plugin logs client IPs for rate-limit buckets and audit logs. When Strapi runs behind a reverse proxy, enable Koa proxy mode so Strapi trusts `X-Forwarded-For`; otherwise all IPs will be the proxy's internal address.
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
In `config/server.ts`:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
proxy: {
|
|
76
|
+
koa: true,
|
|
77
|
+
},
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Set `OIDC_TRUSTED_IP_HEADER` to the header your CDN or proxy uses to forward the real client IP. The header is only honoured when Koa proxy mode is enabled. Accepted values (all others are silently ignored):
|
|
81
|
+
|
|
82
|
+
| Header | Provider |
|
|
83
|
+
| --------------------------- | ------------------------------------------------- |
|
|
84
|
+
| `cf-connecting-ip` | Cloudflare |
|
|
85
|
+
| `true-client-ip` | Cloudflare Enterprise, Akamai |
|
|
86
|
+
| `fastly-client-ip` | Fastly |
|
|
87
|
+
| `fly-client-ip` | Fly.io |
|
|
88
|
+
| `x-nf-client-connection-ip` | Netlify |
|
|
89
|
+
| `x-real-ip` | nginx (`proxy_set_header X-Real-IP $remote_addr`) |
|
|
90
|
+
|
|
91
|
+
Only headers that CDN/proxy vendors guarantee to strip from inbound client requests are accepted, preventing IP spoofing via forged headers.
|
|
73
92
|
|
|
74
93
|
## Login
|
|
75
94
|
|
|
@@ -205,7 +205,7 @@ const index = {
|
|
|
205
205
|
defaultMessage: "Configuration"
|
|
206
206
|
},
|
|
207
207
|
Component: async () => {
|
|
208
|
-
return await import("./index-
|
|
208
|
+
return await import("./index-DRFXk_MQ.mjs");
|
|
209
209
|
},
|
|
210
210
|
permissions: [{ action: "plugin::strapi-plugin-oidc.read", subject: null }]
|
|
211
211
|
}
|
|
@@ -208,7 +208,7 @@ const index = {
|
|
|
208
208
|
defaultMessage: "Configuration"
|
|
209
209
|
},
|
|
210
210
|
Component: async () => {
|
|
211
|
-
return await Promise.resolve().then(() => require("./index-
|
|
211
|
+
return await Promise.resolve().then(() => require("./index-DDCcJt16.js"));
|
|
212
212
|
},
|
|
213
213
|
permissions: [{ action: "plugin::strapi-plugin-oidc.read", subject: null }]
|
|
214
214
|
}
|
|
@@ -7,7 +7,7 @@ const React = require("react");
|
|
|
7
7
|
const designSystem = require("@strapi/design-system");
|
|
8
8
|
const icons = require("@strapi/icons");
|
|
9
9
|
const reactIntl = require("react-intl");
|
|
10
|
-
const index = require("./index-
|
|
10
|
+
const index = require("./index-C8nfr95D.js");
|
|
11
11
|
const styled = require("styled-components");
|
|
12
12
|
const lucideReact = require("lucide-react");
|
|
13
13
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
@@ -852,7 +852,7 @@ function TablePagination({ page, pageCount, onPageChange, total }) {
|
|
|
852
852
|
] }) });
|
|
853
853
|
}
|
|
854
854
|
const PAGE_SIZE$1 = 10;
|
|
855
|
-
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
855
|
+
const EMAIL_REGEX$1 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
856
856
|
function Whitelist({
|
|
857
857
|
users,
|
|
858
858
|
useWhitelist,
|
|
@@ -893,7 +893,7 @@ function Whitelist({
|
|
|
893
893
|
if (!Array.isArray(parsed)) throw new Error();
|
|
894
894
|
const emails = parsed.filter((item) => item?.email).map(
|
|
895
895
|
(item) => String(item.email).trim().toLowerCase()
|
|
896
|
-
).filter((email2) => EMAIL_REGEX.test(email2));
|
|
896
|
+
).filter((email2) => EMAIL_REGEX$1.test(email2));
|
|
897
897
|
const count = await onImport(emails);
|
|
898
898
|
if (count === 0) {
|
|
899
899
|
toggleNotification({
|
|
@@ -935,7 +935,7 @@ function Whitelist({
|
|
|
935
935
|
type: "text",
|
|
936
936
|
disabled: loading,
|
|
937
937
|
value: email,
|
|
938
|
-
hasError: Boolean(email && !EMAIL_REGEX.test(email)),
|
|
938
|
+
hasError: Boolean(email && !EMAIL_REGEX$1.test(email)),
|
|
939
939
|
onChange: (e) => setEmail(e.currentTarget.value),
|
|
940
940
|
placeholder: formatMessage(index.getTrad("whitelist.email.placeholder")),
|
|
941
941
|
style: { fontSize: "1.4rem", lineHeight: "2.2rem" }
|
|
@@ -946,7 +946,7 @@ function Whitelist({
|
|
|
946
946
|
{
|
|
947
947
|
size: "S",
|
|
948
948
|
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
|
|
949
|
-
disabled: loading || email.trim() === "" || !EMAIL_REGEX.test(email),
|
|
949
|
+
disabled: loading || email.trim() === "" || !EMAIL_REGEX$1.test(email),
|
|
950
950
|
loading,
|
|
951
951
|
onClick: onSaveEmail,
|
|
952
952
|
children: formatMessage(index.getTrad("page.add"))
|
|
@@ -1066,6 +1066,153 @@ function Whitelist({
|
|
|
1066
1066
|
] })
|
|
1067
1067
|
] });
|
|
1068
1068
|
}
|
|
1069
|
+
const AUDIT_ACTIONS = [
|
|
1070
|
+
"login_success",
|
|
1071
|
+
"login_failure",
|
|
1072
|
+
"missing_code",
|
|
1073
|
+
"state_mismatch",
|
|
1074
|
+
"nonce_mismatch",
|
|
1075
|
+
"token_exchange_failed",
|
|
1076
|
+
"whitelist_rejected",
|
|
1077
|
+
"email_not_verified",
|
|
1078
|
+
"id_token_invalid",
|
|
1079
|
+
"logout",
|
|
1080
|
+
"session_expired",
|
|
1081
|
+
"user_created"
|
|
1082
|
+
];
|
|
1083
|
+
const IP_REGEX = /^(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}|:(?::[0-9a-fA-F]{1,4}){1,7}|::))$/;
|
|
1084
|
+
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1085
|
+
function FilterBar({
|
|
1086
|
+
filters,
|
|
1087
|
+
hasActiveFilters,
|
|
1088
|
+
onFiltersChange,
|
|
1089
|
+
onResetPage,
|
|
1090
|
+
onClear
|
|
1091
|
+
}) {
|
|
1092
|
+
const { formatMessage } = reactIntl.useIntl();
|
|
1093
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1094
|
+
designSystem.Box,
|
|
1095
|
+
{
|
|
1096
|
+
background: "neutral100",
|
|
1097
|
+
hasRadius: true,
|
|
1098
|
+
padding: 4,
|
|
1099
|
+
marginBottom: 4,
|
|
1100
|
+
borderColor: "neutral200",
|
|
1101
|
+
borderWidth: "1px",
|
|
1102
|
+
borderStyle: "solid",
|
|
1103
|
+
children: [
|
|
1104
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", marginBottom: 3, children: [
|
|
1105
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { size: "1.6rem" }) }),
|
|
1106
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h3", children: formatMessage(index.getTrad("auditlog.filters")) })
|
|
1107
|
+
] }),
|
|
1108
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, wrap: "wrap", children: [
|
|
1109
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1110
|
+
TagDateInput,
|
|
1111
|
+
{
|
|
1112
|
+
placeholder: formatMessage(index.getTrad("auditlog.filters.createdAt")),
|
|
1113
|
+
value: filters.createdAt ?? [],
|
|
1114
|
+
onChange: (selections) => {
|
|
1115
|
+
onFiltersChange((prev) => {
|
|
1116
|
+
if (selections.length === 0) {
|
|
1117
|
+
const { createdAt, ...rest } = prev;
|
|
1118
|
+
return rest;
|
|
1119
|
+
}
|
|
1120
|
+
return { ...prev, createdAt: selections };
|
|
1121
|
+
});
|
|
1122
|
+
onResetPage();
|
|
1123
|
+
},
|
|
1124
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(icons.Calendar, { width: "1.4rem", height: "1.4rem" }) })
|
|
1125
|
+
}
|
|
1126
|
+
),
|
|
1127
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1128
|
+
TagInput,
|
|
1129
|
+
{
|
|
1130
|
+
value: filters.action ?? [],
|
|
1131
|
+
onChange: (value) => onFiltersChange((prev) => ({ ...prev, action: value })),
|
|
1132
|
+
options: AUDIT_ACTIONS,
|
|
1133
|
+
placeholder: formatMessage(index.getTrad("auditlog.filters.action")),
|
|
1134
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClipboardList, { size: "1.4rem" }) })
|
|
1135
|
+
}
|
|
1136
|
+
),
|
|
1137
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1138
|
+
TagInput,
|
|
1139
|
+
{
|
|
1140
|
+
value: filters.email ?? [],
|
|
1141
|
+
onChange: (value) => onFiltersChange((prev) => ({ ...prev, email: value })),
|
|
1142
|
+
placeholder: formatMessage(index.getTrad("auditlog.filters.email")),
|
|
1143
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(icons.Mail, { width: "1.4rem", height: "1.4rem" }) }),
|
|
1144
|
+
validate: (v) => EMAIL_REGEX.test(v)
|
|
1145
|
+
}
|
|
1146
|
+
),
|
|
1147
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1148
|
+
TagInput,
|
|
1149
|
+
{
|
|
1150
|
+
value: filters.ip ?? [],
|
|
1151
|
+
onChange: (value) => onFiltersChange((prev) => ({ ...prev, ip: value })),
|
|
1152
|
+
placeholder: formatMessage(index.getTrad("auditlog.filters.ip")),
|
|
1153
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Server, { size: "1.4rem" }) }),
|
|
1154
|
+
validate: (v) => IP_REGEX.test(v)
|
|
1155
|
+
}
|
|
1156
|
+
),
|
|
1157
|
+
hasActiveFilters && /* @__PURE__ */ jsxRuntime.jsx(SizedButton, { size: "S", variant: "danger-light", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}), onClick: onClear, children: formatMessage(index.getTrad("auditlog.filters.clear")) })
|
|
1158
|
+
] })
|
|
1159
|
+
]
|
|
1160
|
+
}
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
const DETAILS_TEXT_STYLE = {
|
|
1164
|
+
display: "block",
|
|
1165
|
+
overflow: "hidden",
|
|
1166
|
+
textOverflow: "ellipsis",
|
|
1167
|
+
whiteSpace: "nowrap",
|
|
1168
|
+
maxWidth: "180px",
|
|
1169
|
+
cursor: "help"
|
|
1170
|
+
};
|
|
1171
|
+
function LogTable({ records, loading, hasActiveFilters }) {
|
|
1172
|
+
const { formatMessage } = reactIntl.useIntl();
|
|
1173
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", width: "100%" }, children: [
|
|
1174
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CustomTable, { colCount: 5, rowCount: records.length, children: [
|
|
1175
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
|
1176
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: formatMessage(index.getTrad("auditlog.table.timestamp")) }),
|
|
1177
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: formatMessage(index.getTrad("auditlog.table.action")) }),
|
|
1178
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: formatMessage(index.getTrad("auditlog.table.email")) }),
|
|
1179
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: formatMessage(index.getTrad("auditlog.table.ip")) }),
|
|
1180
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: formatMessage(index.getTrad("auditlog.table.details")) })
|
|
1181
|
+
] }) }),
|
|
1182
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tbody, { children: [
|
|
1183
|
+
records.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { colSpan: 5, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", alignItems: "center", style: { minHeight: "80px" }, children: loading ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { small: true }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: hasActiveFilters ? formatMessage(index.getTrad("auditlog.filters.empty")) : formatMessage(index.getTrad("auditlog.table.empty")) }) }) }) }),
|
|
1184
|
+
records.map((record) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { style: { opacity: loading ? 0.4 : 1, transition: "opacity 0.15s" }, children: [
|
|
1185
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: /* @__PURE__ */ jsxRuntime.jsx(LocalizedDate, { date: record.createdAt, options: { second: "2-digit" } }) }) }),
|
|
1186
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
|
|
1187
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: record.action }),
|
|
1188
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: formatMessage(index.getTrad(`auditlog.action.${record.action}`)), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1189
|
+
icons.Information,
|
|
1190
|
+
{
|
|
1191
|
+
"aria-hidden": true,
|
|
1192
|
+
style: { cursor: "help" },
|
|
1193
|
+
width: "1.4rem",
|
|
1194
|
+
height: "1.4rem",
|
|
1195
|
+
fill: "primary600"
|
|
1196
|
+
}
|
|
1197
|
+
) })
|
|
1198
|
+
] }) }),
|
|
1199
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: record.email ?? "—" }) }),
|
|
1200
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: record.ip ?? "—" }) }),
|
|
1201
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { style: { maxWidth: "200px" }, children: record.details ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: record.details, side: "top", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", style: DETAILS_TEXT_STYLE, children: record.details }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "—" }) })
|
|
1202
|
+
] }, record.id))
|
|
1203
|
+
] })
|
|
1204
|
+
] }),
|
|
1205
|
+
loading && records.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1206
|
+
designSystem.Flex,
|
|
1207
|
+
{
|
|
1208
|
+
justifyContent: "center",
|
|
1209
|
+
alignItems: "center",
|
|
1210
|
+
style: { position: "absolute", inset: 0, pointerEvents: "none" },
|
|
1211
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { small: true })
|
|
1212
|
+
}
|
|
1213
|
+
)
|
|
1214
|
+
] });
|
|
1215
|
+
}
|
|
1069
1216
|
var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
|
|
1070
1217
|
function getDefaultExportFromCjs(x) {
|
|
1071
1218
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
@@ -3607,30 +3754,6 @@ function requireLib() {
|
|
|
3607
3754
|
}
|
|
3608
3755
|
var libExports = /* @__PURE__ */ requireLib();
|
|
3609
3756
|
const qs = /* @__PURE__ */ getDefaultExportFromCjs(libExports);
|
|
3610
|
-
const AUDIT_ACTIONS = [
|
|
3611
|
-
"login_success",
|
|
3612
|
-
"login_failure",
|
|
3613
|
-
"missing_code",
|
|
3614
|
-
"state_mismatch",
|
|
3615
|
-
"nonce_mismatch",
|
|
3616
|
-
"token_exchange_failed",
|
|
3617
|
-
"whitelist_rejected",
|
|
3618
|
-
"email_not_verified",
|
|
3619
|
-
"id_token_invalid",
|
|
3620
|
-
"logout",
|
|
3621
|
-
"session_expired",
|
|
3622
|
-
"user_created"
|
|
3623
|
-
];
|
|
3624
|
-
const PAGE_SIZE = 10;
|
|
3625
|
-
const MIN_SPINNER_MS = 400;
|
|
3626
|
-
const DETAILS_TEXT_STYLE = {
|
|
3627
|
-
display: "block",
|
|
3628
|
-
overflow: "hidden",
|
|
3629
|
-
textOverflow: "ellipsis",
|
|
3630
|
-
whiteSpace: "nowrap",
|
|
3631
|
-
maxWidth: "180px",
|
|
3632
|
-
cursor: "help"
|
|
3633
|
-
};
|
|
3634
3757
|
function toWireFilters(f) {
|
|
3635
3758
|
const out = {};
|
|
3636
3759
|
if (f.action?.length) out.action = { $or: f.action.map((v) => ({ $eq: v })) };
|
|
@@ -3647,11 +3770,11 @@ function buildQueryString(params) {
|
|
|
3647
3770
|
const { filters, ...rest } = params;
|
|
3648
3771
|
return qs.stringify(
|
|
3649
3772
|
{ ...rest, filters: filters ? toWireFilters(filters) : void 0 },
|
|
3650
|
-
{
|
|
3651
|
-
encodeValuesOnly: true
|
|
3652
|
-
}
|
|
3773
|
+
{ encodeValuesOnly: true }
|
|
3653
3774
|
);
|
|
3654
3775
|
}
|
|
3776
|
+
const PAGE_SIZE = 10;
|
|
3777
|
+
const MIN_SPINNER_MS = 400;
|
|
3655
3778
|
function useDebounced(value, delay = 300) {
|
|
3656
3779
|
const [debounced, setDebounced] = React.useState(value);
|
|
3657
3780
|
React.useEffect(() => {
|
|
@@ -3660,10 +3783,8 @@ function useDebounced(value, delay = 300) {
|
|
|
3660
3783
|
}, [value, delay]);
|
|
3661
3784
|
return debounced;
|
|
3662
3785
|
}
|
|
3663
|
-
function
|
|
3664
|
-
const {
|
|
3665
|
-
const { get: get2, del } = admin.useFetchClient();
|
|
3666
|
-
const { toggleNotification } = admin.useNotification();
|
|
3786
|
+
function useAuditLogs(page, filters) {
|
|
3787
|
+
const { get: get2 } = admin.useFetchClient();
|
|
3667
3788
|
const [records, setRecords] = React.useState([]);
|
|
3668
3789
|
const [pagination, setPagination] = React.useState({
|
|
3669
3790
|
page: 1,
|
|
@@ -3671,9 +3792,7 @@ function AuditLog({ title } = {}) {
|
|
|
3671
3792
|
total: 0,
|
|
3672
3793
|
pageCount: 1
|
|
3673
3794
|
});
|
|
3674
|
-
const [page, setPage] = React.useState(1);
|
|
3675
3795
|
const [loading, setLoading] = React.useState(true);
|
|
3676
|
-
const [filters, setFilters] = React.useState({});
|
|
3677
3796
|
const fetchGenRef = React.useRef(0);
|
|
3678
3797
|
const debouncedFilters = useDebounced(filters);
|
|
3679
3798
|
const fetchLogs = React.useCallback(
|
|
@@ -3707,6 +3826,15 @@ function AuditLog({ title } = {}) {
|
|
|
3707
3826
|
React.useEffect(() => {
|
|
3708
3827
|
fetchLogs(page, debouncedFilters);
|
|
3709
3828
|
}, [fetchLogs, page, debouncedFilters]);
|
|
3829
|
+
return { records, pagination, loading };
|
|
3830
|
+
}
|
|
3831
|
+
function AuditLog({ title } = {}) {
|
|
3832
|
+
const { formatMessage } = reactIntl.useIntl();
|
|
3833
|
+
const { del } = admin.useFetchClient();
|
|
3834
|
+
const { toggleNotification } = admin.useNotification();
|
|
3835
|
+
const [page, setPage] = React.useState(1);
|
|
3836
|
+
const [filters, setFilters] = React.useState({});
|
|
3837
|
+
const { records, pagination, loading } = useAuditLogs(page, filters);
|
|
3710
3838
|
const handleClearAll = async () => {
|
|
3711
3839
|
try {
|
|
3712
3840
|
await del("/strapi-plugin-oidc/audit-logs");
|
|
@@ -3727,9 +3855,7 @@ function AuditLog({ title } = {}) {
|
|
|
3727
3855
|
try {
|
|
3728
3856
|
const cookieMatch = document.cookie.match(/(?:^|;\s*)jwtToken=([^;]+)/);
|
|
3729
3857
|
const token = cookieMatch ? decodeURIComponent(cookieMatch[1]) : "";
|
|
3730
|
-
const queryString = buildQueryString({
|
|
3731
|
-
filters
|
|
3732
|
-
});
|
|
3858
|
+
const queryString = buildQueryString({ filters });
|
|
3733
3859
|
const response = await fetch(`/strapi-plugin-oidc/audit-logs/export?${queryString}`, {
|
|
3734
3860
|
headers: { Authorization: `Bearer ${token}` }
|
|
3735
3861
|
});
|
|
@@ -3797,135 +3923,17 @@ function AuditLog({ title } = {}) {
|
|
|
3797
3923
|
)
|
|
3798
3924
|
] })
|
|
3799
3925
|
] }),
|
|
3800
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3801
|
-
|
|
3926
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3927
|
+
FilterBar,
|
|
3802
3928
|
{
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
borderWidth: "1px",
|
|
3809
|
-
borderStyle: "solid",
|
|
3810
|
-
children: [
|
|
3811
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", marginBottom: 3, children: [
|
|
3812
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { size: "1.6rem" }) }),
|
|
3813
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h3", children: formatMessage(index.getTrad("auditlog.filters")) })
|
|
3814
|
-
] }),
|
|
3815
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, wrap: "wrap", children: [
|
|
3816
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3817
|
-
TagDateInput,
|
|
3818
|
-
{
|
|
3819
|
-
placeholder: formatMessage(index.getTrad("auditlog.filters.createdAt")),
|
|
3820
|
-
value: filters.createdAt ?? [],
|
|
3821
|
-
onChange: (selections) => {
|
|
3822
|
-
setFilters((prev) => {
|
|
3823
|
-
if (selections.length === 0) {
|
|
3824
|
-
const { createdAt: _removed, ...rest } = prev;
|
|
3825
|
-
return rest;
|
|
3826
|
-
}
|
|
3827
|
-
return { ...prev, createdAt: selections };
|
|
3828
|
-
});
|
|
3829
|
-
setPage(1);
|
|
3830
|
-
},
|
|
3831
|
-
startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(icons.Calendar, { width: "1.4rem", height: "1.4rem" }) })
|
|
3832
|
-
}
|
|
3833
|
-
),
|
|
3834
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3835
|
-
TagInput,
|
|
3836
|
-
{
|
|
3837
|
-
value: filters.action ?? [],
|
|
3838
|
-
onChange: (value) => setFilters((prev) => ({ ...prev, action: value })),
|
|
3839
|
-
options: AUDIT_ACTIONS,
|
|
3840
|
-
placeholder: formatMessage(index.getTrad("auditlog.filters.action")),
|
|
3841
|
-
startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClipboardList, { size: "1.4rem" }) })
|
|
3842
|
-
}
|
|
3843
|
-
),
|
|
3844
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3845
|
-
TagInput,
|
|
3846
|
-
{
|
|
3847
|
-
value: filters.email ?? [],
|
|
3848
|
-
onChange: (value) => setFilters((prev) => ({ ...prev, email: value })),
|
|
3849
|
-
placeholder: formatMessage(index.getTrad("auditlog.filters.email")),
|
|
3850
|
-
startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(icons.Mail, { width: "1.4rem", height: "1.4rem" }) }),
|
|
3851
|
-
validate: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v)
|
|
3852
|
-
}
|
|
3853
|
-
),
|
|
3854
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3855
|
-
TagInput,
|
|
3856
|
-
{
|
|
3857
|
-
value: filters.ip ?? [],
|
|
3858
|
-
onChange: (value) => setFilters((prev) => ({ ...prev, ip: value })),
|
|
3859
|
-
placeholder: formatMessage(index.getTrad("auditlog.filters.ip")),
|
|
3860
|
-
startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Server, { size: "1.4rem" }) }),
|
|
3861
|
-
validate: (v) => /^(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}|:(?::[0-9a-fA-F]{1,4}){1,7}|::))$/.test(
|
|
3862
|
-
v
|
|
3863
|
-
)
|
|
3864
|
-
}
|
|
3865
|
-
),
|
|
3866
|
-
hasActiveFilters && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3867
|
-
SizedButton,
|
|
3868
|
-
{
|
|
3869
|
-
size: "S",
|
|
3870
|
-
variant: "danger-light",
|
|
3871
|
-
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}),
|
|
3872
|
-
onClick: clearFilters,
|
|
3873
|
-
children: formatMessage(index.getTrad("auditlog.filters.clear"))
|
|
3874
|
-
}
|
|
3875
|
-
)
|
|
3876
|
-
] })
|
|
3877
|
-
]
|
|
3929
|
+
filters,
|
|
3930
|
+
hasActiveFilters,
|
|
3931
|
+
onFiltersChange: setFilters,
|
|
3932
|
+
onResetPage: () => setPage(1),
|
|
3933
|
+
onClear: clearFilters
|
|
3878
3934
|
}
|
|
3879
3935
|
),
|
|
3880
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3881
|
-
/* @__PURE__ */ jsxRuntime.jsxs(CustomTable, { colCount: 5, rowCount: records.length, children: [
|
|
3882
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
|
3883
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: formatMessage(index.getTrad("auditlog.table.timestamp")) }),
|
|
3884
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: formatMessage(index.getTrad("auditlog.table.action")) }),
|
|
3885
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: formatMessage(index.getTrad("auditlog.table.email")) }),
|
|
3886
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: formatMessage(index.getTrad("auditlog.table.ip")) }),
|
|
3887
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: formatMessage(index.getTrad("auditlog.table.details")) })
|
|
3888
|
-
] }) }),
|
|
3889
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tbody, { children: [
|
|
3890
|
-
records.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { colSpan: 5, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", alignItems: "center", style: { minHeight: "80px" }, children: loading ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { small: true }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: hasActiveFilters ? formatMessage(index.getTrad("auditlog.filters.empty")) : formatMessage(index.getTrad("auditlog.table.empty")) }) }) }) }),
|
|
3891
|
-
records.map((record) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3892
|
-
designSystem.Tr,
|
|
3893
|
-
{
|
|
3894
|
-
style: { opacity: loading ? 0.4 : 1, transition: "opacity 0.15s" },
|
|
3895
|
-
children: [
|
|
3896
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: /* @__PURE__ */ jsxRuntime.jsx(LocalizedDate, { date: record.createdAt, options: { second: "2-digit" } }) }) }),
|
|
3897
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
|
|
3898
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: record.action }),
|
|
3899
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: formatMessage(index.getTrad(`auditlog.action.${record.action}`)), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3900
|
-
icons.Information,
|
|
3901
|
-
{
|
|
3902
|
-
"aria-hidden": true,
|
|
3903
|
-
style: { cursor: "help" },
|
|
3904
|
-
width: "1.4rem",
|
|
3905
|
-
height: "1.4rem",
|
|
3906
|
-
fill: "primary600"
|
|
3907
|
-
}
|
|
3908
|
-
) })
|
|
3909
|
-
] }) }),
|
|
3910
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: record.email ?? "—" }) }),
|
|
3911
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: record.ip ?? "—" }) }),
|
|
3912
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { style: { maxWidth: "200px" }, children: record.details ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: record.details, side: "top", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", style: DETAILS_TEXT_STYLE, children: record.details }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "—" }) })
|
|
3913
|
-
]
|
|
3914
|
-
},
|
|
3915
|
-
record.id
|
|
3916
|
-
))
|
|
3917
|
-
] })
|
|
3918
|
-
] }),
|
|
3919
|
-
loading && records.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3920
|
-
designSystem.Flex,
|
|
3921
|
-
{
|
|
3922
|
-
justifyContent: "center",
|
|
3923
|
-
alignItems: "center",
|
|
3924
|
-
style: { position: "absolute", inset: 0, pointerEvents: "none" },
|
|
3925
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { small: true })
|
|
3926
|
-
}
|
|
3927
|
-
)
|
|
3928
|
-
] }),
|
|
3936
|
+
/* @__PURE__ */ jsxRuntime.jsx(LogTable, { records, loading, hasActiveFilters }),
|
|
3929
3937
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3930
3938
|
TablePagination,
|
|
3931
3939
|
{
|
|
@@ -4059,19 +4067,15 @@ function downloadJson(basename, data) {
|
|
|
4059
4067
|
a.click();
|
|
4060
4068
|
URL.revokeObjectURL(url);
|
|
4061
4069
|
}
|
|
4070
|
+
const defaultSnapshot = {
|
|
4071
|
+
oidcRoles: [],
|
|
4072
|
+
users: [],
|
|
4073
|
+
useWhitelist: false,
|
|
4074
|
+
enforceOIDC: false
|
|
4075
|
+
};
|
|
4062
4076
|
const initialState = {
|
|
4063
|
-
current: {
|
|
4064
|
-
|
|
4065
|
-
users: [],
|
|
4066
|
-
useWhitelist: false,
|
|
4067
|
-
enforceOIDC: false
|
|
4068
|
-
},
|
|
4069
|
-
initial: {
|
|
4070
|
-
oidcRoles: [],
|
|
4071
|
-
users: [],
|
|
4072
|
-
useWhitelist: false,
|
|
4073
|
-
enforceOIDC: false
|
|
4074
|
-
},
|
|
4077
|
+
current: { ...defaultSnapshot },
|
|
4078
|
+
initial: { ...defaultSnapshot },
|
|
4075
4079
|
roles: [],
|
|
4076
4080
|
enforceOIDCConfig: null,
|
|
4077
4081
|
auditLogEnabled: true,
|