strapi-plugin-oidc 1.0.4 → 1.0.6

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 CHANGED
@@ -2,8 +2,11 @@
2
2
  <img src="https://raw.githubusercontent.com/edmogeor/strapi-plugin-oidc/main/assets/icon.png" width="140" alt="OIDC Login for Strapi Logo"/>
3
3
  <h1>OIDC Login for Strapi</h1>
4
4
  <p>
5
+ <a href="https://www.npmjs.com/package/strapi-plugin-oidc">
6
+ <img src="https://img.shields.io/npm/v/strapi-plugin-oidc.svg" alt="npm version">
7
+ </a>
5
8
  <a href="https://github.com/edmogeor/strapi-plugin-oidc/actions/workflows/test.yml">
6
- <img src="https://github.com/edmogeor/strapi-plugin-oidc/actions/workflows/test.yml/badge.svg" alt="Tests">
9
+ <img src="https://github.com/edmogeor/strapi-plugin-oidc/actions/workflows/test.yml/badge.svg?branch=main" alt="Tests">
7
10
  </a>
8
11
  </p>
9
12
  </div>
@@ -67,13 +70,22 @@ module.exports = ({ env }) => ({
67
70
 
68
71
  Make sure to replace the placeholder values (e.g., `[Client ID from OpenID Provider]`) with the actual connection details from your chosen OIDC identity provider.
69
72
 
73
+ ## How to Login
74
+
75
+ Once configured, you can initiate the OIDC login flow by navigating to:
76
+ `http://<your-strapi-domain>/strapi-plugin-oidc/oidc`
77
+
78
+ (e.g., `http://localhost:1337/strapi-plugin-oidc/oidc` for local development).
79
+
80
+ When the **Enforce OIDC Login** option is enabled in the Admin Settings, the standard Strapi admin login page will be automatically redirected to this URL.
81
+
70
82
  ## Admin Settings
71
83
 
72
84
  Once the plugin is installed and configured, you can manage the OIDC settings from the Strapi Admin Panel under **Settings** > **OIDC Plugin**.
73
85
 
74
86
  - **Whitelist Management**: Restrict login to specific users by adding their email addresses to the whitelist. You can also whitelist entire email domains (e.g., `*@company.com`). If the whitelist is empty, any user who successfully authenticates via your OIDC provider will be able to log in and an account will be automatically created for them.
75
87
  - **Default Role Assignment**: Select the default Strapi admin role that will be assigned to newly created users when they log in for the first time via OIDC.
76
- - **Enforce OIDC Login**: When enabled, the default Strapi email and password login form will be disabled, forcing all administrators to log in using your OIDC provider. _(Note: This option is automatically disabled and grayed out if your whitelist is empty to prevent accidentally locking everyone out of the admin panel)._
88
+ - **Enforce OIDC Login**: When enabled, the default Strapi email and password login form will be disabled and the standard login will be redirected to the OIDC login URL, forcing all administrators to log in using your OIDC provider. _(Note: This option is automatically disabled and grayed out if your whitelist is empty to prevent accidentally locking everyone out of the admin panel)._
77
89
 
78
90
  ## Credits & Changes
79
91
 
@@ -85,7 +97,9 @@ This plugin is a hard fork of the original [`strapi-plugin-sso`](https://github.
85
97
  - Redesigned the Whitelist and Role management UI (switched to native Strapi cards, added pagination, etc.).
86
98
  - Added an OIDC logout redirect URL.
87
99
  - Added an option to "Enforce OIDC login" with an admin toggle (automatically disabled if the whitelist is empty).
100
+ - Added configurable "Remember Me" duration for sessions (`REMEMBER_ME_DAYS`).
88
101
  - Migrated the testing framework to Vitest and added comprehensive test coverage for controllers and services.
89
102
  - Cleaned up dead code and unused dependencies to improve maintainability.
90
103
  - Upgraded to use newer versions of Node.js.
104
+ - Added styled success and error pages.
91
105
  - Added misc. quality of life improvements and bug fixes.
@@ -55,7 +55,7 @@ const index = {
55
55
  defaultMessage: "Configuration"
56
56
  },
57
57
  Component: async () => {
58
- return await Promise.resolve().then(() => require("./index-D_0jCOLk.js"));
58
+ return await Promise.resolve().then(() => require("./index-CLDWnBI9.js"));
59
59
  },
60
60
  permissions: [{ action: "plugin::strapi-plugin-oidc.read", subject: null }]
61
61
  }
@@ -77,24 +77,18 @@ const index = {
77
77
  if (currentPath.endsWith("/auth/login")) {
78
78
  window.location.href = "/strapi-plugin-oidc/oidc";
79
79
  }
80
- const originalPushState = window.history.pushState;
81
- window.history.pushState = function(...args) {
82
- const url = args[2];
83
- if (url && typeof url === "string" && url.endsWith("/auth/login")) {
84
- window.location.href = "/strapi-plugin-oidc/oidc";
85
- return;
86
- }
87
- return originalPushState.apply(window.history, args);
88
- };
89
- const originalReplaceState = window.history.replaceState;
90
- window.history.replaceState = function(...args) {
91
- const url = args[2];
92
- if (url && typeof url === "string" && url.endsWith("/auth/login")) {
93
- window.location.href = "/strapi-plugin-oidc/oidc";
94
- return;
95
- }
96
- return originalReplaceState.apply(window.history, args);
80
+ const interceptHistory = (originalMethod) => {
81
+ return function(...args) {
82
+ const url = args[2];
83
+ if (url && typeof url === "string" && url.endsWith("/auth/login")) {
84
+ window.location.href = "/strapi-plugin-oidc/oidc";
85
+ return;
86
+ }
87
+ return originalMethod.apply(window.history, args);
88
+ };
97
89
  };
90
+ window.history.pushState = interceptHistory(window.history.pushState);
91
+ window.history.replaceState = interceptHistory(window.history.replaceState);
98
92
  }
99
93
  }
100
94
  } catch (error) {
@@ -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-C0GkDnGG.js");
10
+ const index = require("./index-BITZIRCD.js");
11
11
  const en = require("./en-jFPbEFeK.js");
12
12
  const styled = require("styled-components");
13
13
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
@@ -28,19 +28,22 @@ function Role({ oidcRoles, roles, onChangeRole }) {
28
28
  {
29
29
  withTags: true,
30
30
  placeholder: formatMessage(getTrad("roles.placeholder")),
31
- value: oidcRole["role"] ? oidcRole["role"].map((r) => r.toString()) : [],
31
+ value: oidcRole.role ? oidcRole.role.map((r) => String(r)) : [],
32
32
  onChange: (value) => {
33
33
  if (value && value.length > 0) {
34
- onChangeRole(value, oidcRole["oauth_type"]);
34
+ onChangeRole(value, oidcRole.oauth_type);
35
35
  }
36
36
  },
37
- children: roles.map((role) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.MultiSelectOption, { value: role.id.toString(), children: role.name }, role.id))
37
+ children: roles.map((role) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.MultiSelectOption, { value: String(role.id), children: role.name }, role.id))
38
38
  }
39
- ) }, oidcRole["oauth_type"])) })
39
+ ) }, oidcRole.oauth_type)) })
40
40
  ] });
41
41
  }
42
42
  const CustomTable = styled__default.default(designSystem.Table)`
43
- th, td, th span, td span {
43
+ th,
44
+ td,
45
+ th span,
46
+ td span {
44
47
  font-size: 1.3rem !important;
45
48
  }
46
49
  `;
@@ -54,7 +57,15 @@ const LocalizedDate = ({ date }) => {
54
57
  minute: "2-digit"
55
58
  }).format(new Date(date));
56
59
  };
57
- function Whitelist({ users, roles, oidcRoles = [], useWhitelist, loading, onSave, onDelete }) {
60
+ function Whitelist({
61
+ users,
62
+ roles,
63
+ oidcRoles = [],
64
+ useWhitelist,
65
+ loading,
66
+ onSave,
67
+ onDelete
68
+ }) {
58
69
  const [email, setEmail] = react.useState("");
59
70
  const [selectedRoles, setSelectedRoles] = react.useState([]);
60
71
  const [page, setPage] = react.useState(1);
@@ -65,9 +76,7 @@ function Whitelist({ users, roles, oidcRoles = [], useWhitelist, loading, onSave
65
76
  const onSaveEmail = react.useCallback(async () => {
66
77
  const emailText = email.trim();
67
78
  if (users.some((user) => user.email === emailText)) {
68
- alert(
69
- formatMessage(getTrad("whitelist.error.unique"))
70
- );
79
+ alert(formatMessage(getTrad("whitelist.error.unique")));
71
80
  } else {
72
81
  await onSave(emailText, selectedRoles);
73
82
  setEmail("");
@@ -126,61 +135,103 @@ function Whitelist({ users, roles, oidcRoles = [], useWhitelist, loading, onSave
126
135
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { style: { paddingRight: 0 }, children: " " })
127
136
  ] }) }),
128
137
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: users.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { colSpan: 5, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage(getTrad("whitelist.table.empty")) }) }) }) }) : paginatedUsers.map((user, index2) => {
129
- let userRolesNames = (user.roles || []).map((roleId) => {
130
- const r = roles.find((ro) => ro.id.toString() === roleId.toString());
138
+ const getRoleNames = (roleIds) => roleIds.map((roleId) => {
139
+ const r = roles.find((ro) => String(ro.id) === String(roleId));
131
140
  return r ? r.name : roleId;
132
141
  }).join(", ");
142
+ let userRolesNames = getRoleNames(user.roles || []);
133
143
  if (!userRolesNames) {
134
144
  const defaultRolesIds = oidcRoles.reduce((acc, oidc) => {
135
- if (oidc.role) {
136
- acc.push(...oidc.role);
137
- }
145
+ if (oidc.role) acc.push(...oidc.role);
138
146
  return acc;
139
147
  }, []);
140
- userRolesNames = defaultRolesIds.map((roleId) => {
141
- const r = roles.find((ro) => ro.id.toString() === roleId.toString());
142
- return r ? r.name : roleId;
143
- }).join(", ");
148
+ userRolesNames = getRoleNames(defaultRolesIds);
144
149
  }
145
150
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
146
151
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: index2 + 1 + (page - 1) * PAGE_SIZE }),
147
152
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: user.email }),
148
153
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: userRolesNames || "-" }),
149
154
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(LocalizedDate, { date: user.createdAt }) }),
150
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { style: { paddingRight: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", onClick: (e) => e.stopPropagation(), style: { width: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Root, { children: [
151
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.IconButton, { label: formatMessage(getTrad("whitelist.delete.label")), withTooltip: false, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}) }) }),
152
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
153
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage(getTrad("whitelist.delete.title")) }),
154
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.WarningCircle, { fill: "danger600" }), children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", gap: 2, children: [
155
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", children: formatMessage(getTrad("whitelist.delete.description")) }) }),
156
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: user.email }) }),
157
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", marginTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(getTrad("whitelist.delete.note")) }) })
158
- ] }) }),
159
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
160
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, variant: "tertiary", children: formatMessage(getTrad("page.cancel")) }) }),
161
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Action, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, variant: "danger-light", onClick: () => onDelete(user.email), children: formatMessage(getTrad("page.ok")) }) })
155
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { style: { paddingRight: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(
156
+ designSystem.Flex,
157
+ {
158
+ justifyContent: "flex-end",
159
+ onClick: (e) => e.stopPropagation(),
160
+ style: { width: "100%" },
161
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Root, { children: [
162
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(
163
+ designSystem.IconButton,
164
+ {
165
+ label: formatMessage(getTrad("whitelist.delete.label")),
166
+ withTooltip: false,
167
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {})
168
+ }
169
+ ) }),
170
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
171
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage(getTrad("whitelist.delete.title")) }),
172
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.WarningCircle, { fill: "danger600" }), children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", gap: 2, children: [
173
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", children: formatMessage(getTrad("whitelist.delete.description")) }) }),
174
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: user.email }) }),
175
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", marginTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(getTrad("whitelist.delete.note")) }) })
176
+ ] }) }),
177
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
178
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, variant: "tertiary", children: formatMessage(getTrad("page.cancel")) }) }),
179
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Action, { children: /* @__PURE__ */ jsxRuntime.jsx(
180
+ designSystem.Button,
181
+ {
182
+ fullWidth: true,
183
+ variant: "danger-light",
184
+ onClick: () => onDelete(user.email),
185
+ children: formatMessage(getTrad("page.ok"))
186
+ }
187
+ ) })
188
+ ] })
189
+ ] })
162
190
  ] })
163
- ] })
164
- ] }) }) })
191
+ }
192
+ ) })
165
193
  ] }, user.email);
166
194
  }) })
167
195
  ] }),
168
196
  pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Pagination, { activePage: page, pageCount, children: [
169
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.PreviousLink, { href: "#", onClick: (e) => {
170
- e.preventDefault();
171
- setPage((p) => Math.max(1, p - 1));
172
- }, children: "Go to previous page" }),
173
- Array.from({ length: pageCount }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.PageLink, { number: i + 1, href: "#", onClick: (e) => {
174
- e.preventDefault();
175
- setPage(i + 1);
176
- }, children: [
177
- "Go to page ",
197
+ /* @__PURE__ */ jsxRuntime.jsx(
198
+ designSystem.PreviousLink,
199
+ {
200
+ href: "#",
201
+ onClick: (e) => {
202
+ e.preventDefault();
203
+ setPage((p) => Math.max(1, p - 1));
204
+ },
205
+ children: "Go to previous page"
206
+ }
207
+ ),
208
+ Array.from({ length: pageCount }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs(
209
+ designSystem.PageLink,
210
+ {
211
+ number: i + 1,
212
+ href: "#",
213
+ onClick: (e) => {
214
+ e.preventDefault();
215
+ setPage(i + 1);
216
+ },
217
+ children: [
218
+ "Go to page ",
219
+ i + 1
220
+ ]
221
+ },
178
222
  i + 1
179
- ] }, i + 1)),
180
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.NextLink, { href: "#", onClick: (e) => {
181
- e.preventDefault();
182
- setPage((p) => Math.min(pageCount, p + 1));
183
- }, children: "Go to next page" })
223
+ )),
224
+ /* @__PURE__ */ jsxRuntime.jsx(
225
+ designSystem.NextLink,
226
+ {
227
+ href: "#",
228
+ onClick: (e) => {
229
+ e.preventDefault();
230
+ setPage((p) => Math.min(pageCount, p + 1));
231
+ },
232
+ children: "Go to next page"
233
+ }
234
+ )
184
235
  ] }) }) })
185
236
  ] }) });
186
237
  }
@@ -301,9 +352,12 @@ function CustomSwitch({ checked, onChange, label, disabled }) {
301
352
  label && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", textColor: disabled ? "neutral500" : "neutral800", children: label })
302
353
  ] });
303
354
  }
304
- function HomePage$1() {
305
- const { formatMessage } = reactIntl.useIntl();
355
+ function useOidcSettings() {
356
+ const { get, put } = admin.useFetchClient();
306
357
  const [loading, setLoading] = react.useState(false);
358
+ const [showSuccess, setSuccess] = react.useState(false);
359
+ const [showError, setError] = react.useState(false);
360
+ const [showMatched, setMatched] = react.useState(0);
307
361
  const [initialOidcRoles, setInitialOIDCRoles] = react.useState([]);
308
362
  const [oidcRoles, setOIDCRoles] = react.useState([]);
309
363
  const [roles, setRoles] = react.useState([]);
@@ -313,10 +367,6 @@ function HomePage$1() {
313
367
  const [enforceOIDC, setEnforceOIDC] = react.useState(false);
314
368
  const [initialUsers, setInitialUsers] = react.useState([]);
315
369
  const [users, setUsers] = react.useState([]);
316
- const [showSuccess, setSuccess] = react.useState(false);
317
- const [showError, setError] = react.useState(false);
318
- const [showMatched, setMatched] = react.useState(0);
319
- const { get, put, post, del } = admin.useFetchClient();
320
370
  react.useEffect(() => {
321
371
  get(`/strapi-plugin-oidc/oidc-roles`).then((response) => {
322
372
  setOIDCRoles(response.data);
@@ -333,31 +383,51 @@ function HomePage$1() {
333
383
  setEnforceOIDC(response.data.enforceOIDC);
334
384
  setInitialEnforceOIDC(response.data.enforceOIDC);
335
385
  });
336
- }, [setOIDCRoles, setRoles]);
386
+ }, [get]);
337
387
  const onChangeRole = (values, oidcId) => {
338
- for (const oidcRole of oidcRoles) {
339
- if (oidcRole["oauth_type"] === oidcId) {
340
- oidcRole["role"] = values;
341
- }
388
+ const updatedRoles = oidcRoles.map(
389
+ (role) => role.oauth_type === oidcId ? { ...role, role: values } : role
390
+ );
391
+ setOIDCRoles(updatedRoles);
392
+ };
393
+ const onRegisterWhitelist = async (email, selectedRoles) => {
394
+ const newUser = { email, roles: selectedRoles, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
395
+ setUsers([...users, newUser]);
396
+ };
397
+ const onDeleteWhitelist = async (email) => {
398
+ const updatedUsers = users.filter((u) => u.email !== email);
399
+ setUsers(updatedUsers);
400
+ if (useWhitelist && updatedUsers.length === 0) {
401
+ setEnforceOIDC(false);
402
+ }
403
+ };
404
+ const onToggleWhitelist = (e) => {
405
+ const checked = e.target.checked;
406
+ setUseWhitelist(checked);
407
+ if (checked && users.length === 0) {
408
+ setEnforceOIDC(false);
342
409
  }
343
- setOIDCRoles(oidcRoles.slice());
344
410
  };
411
+ const onToggleEnforce = (e) => {
412
+ setEnforceOIDC(e.target.checked);
413
+ };
414
+ const isDirty = useWhitelist !== initialUseWhitelist || enforceOIDC !== initialEnforceOIDC || JSON.stringify(oidcRoles) !== JSON.stringify(initialOidcRoles) || JSON.stringify(users) !== JSON.stringify(initialUsers);
345
415
  const onSaveAll = async () => {
346
416
  setLoading(true);
347
417
  try {
348
418
  await put("/strapi-plugin-oidc/oidc-roles", {
349
419
  roles: oidcRoles.map((role) => ({
350
- "oauth_type": role["oauth_type"],
351
- role: role["role"]
420
+ oauth_type: role.oauth_type,
421
+ role: role.role
352
422
  }))
353
423
  });
424
+ const syncResponse = await put("/strapi-plugin-oidc/whitelist/sync", {
425
+ users: users.map((u) => ({ email: u.email, roles: u.roles }))
426
+ });
354
427
  await put("/strapi-plugin-oidc/whitelist/settings", {
355
428
  useWhitelist,
356
429
  enforceOIDC
357
430
  });
358
- const syncResponse = await put("/strapi-plugin-oidc/whitelist/sync", {
359
- users: users.map((u) => ({ email: u.email, roles: u.roles }))
360
- });
361
431
  setInitialOIDCRoles(JSON.parse(JSON.stringify(oidcRoles)));
362
432
  setInitialUseWhitelist(useWhitelist);
363
433
  setInitialEnforceOIDC(enforceOIDC);
@@ -365,43 +435,51 @@ function HomePage$1() {
365
435
  setUsers(getResponse.data.whitelistUsers);
366
436
  setInitialUsers(JSON.parse(JSON.stringify(getResponse.data.whitelistUsers)));
367
437
  });
368
- if (syncResponse.data && syncResponse.data.matchedExistingUsersCount > 0) {
438
+ if (syncResponse.data?.matchedExistingUsersCount > 0) {
369
439
  setMatched(syncResponse.data.matchedExistingUsersCount);
370
- setTimeout(() => {
371
- setMatched(0);
372
- }, 3e3);
440
+ setTimeout(() => setMatched(0), 3e3);
373
441
  } else {
374
442
  setSuccess(true);
375
- setTimeout(() => {
376
- setSuccess(false);
377
- }, 3e3);
443
+ setTimeout(() => setSuccess(false), 3e3);
378
444
  }
379
445
  } catch (e) {
380
446
  console.error(e);
381
447
  setError(true);
382
- setTimeout(() => {
383
- setError(false);
384
- }, 3e3);
448
+ setTimeout(() => setError(false), 3e3);
385
449
  } finally {
386
450
  setLoading(false);
387
451
  }
388
452
  };
389
- const onRegisterWhitelist = async (email, selectedRoles) => {
390
- const newUser = { email, roles: selectedRoles, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
391
- setUsers([...users, newUser]);
392
- };
393
- const onDeleteWhitelist = async (email) => {
394
- setUsers(users.filter((u) => u.email !== email));
395
- };
396
- const onToggleWhitelist = (e) => {
397
- const newValue = e.target.checked;
398
- setUseWhitelist(newValue);
399
- };
400
- const onToggleEnforce = (e) => {
401
- const newValue = e.target.checked;
402
- setEnforceOIDC(newValue);
453
+ return {
454
+ state: {
455
+ loading,
456
+ showSuccess,
457
+ showError,
458
+ showMatched,
459
+ oidcRoles,
460
+ roles,
461
+ useWhitelist,
462
+ enforceOIDC,
463
+ initialEnforceOIDC,
464
+ users,
465
+ isDirty
466
+ },
467
+ actions: {
468
+ setSuccess,
469
+ setError,
470
+ setMatched,
471
+ onChangeRole,
472
+ onRegisterWhitelist,
473
+ onDeleteWhitelist,
474
+ onToggleWhitelist,
475
+ onToggleEnforce,
476
+ onSaveAll
477
+ }
403
478
  };
404
- const isDirty = useWhitelist !== initialUseWhitelist || enforceOIDC !== initialEnforceOIDC || JSON.stringify(oidcRoles) !== JSON.stringify(initialOidcRoles) || JSON.stringify(users) !== JSON.stringify(initialUsers);
479
+ }
480
+ function HomePage$1() {
481
+ const { formatMessage } = reactIntl.useIntl();
482
+ const { state, actions } = useOidcSettings();
405
483
  return /* @__PURE__ */ jsxRuntime.jsxs(admin.Page.Protect, { permissions: [{ action: "plugin::strapi-plugin-oidc.read", subject: null }], children: [
406
484
  /* @__PURE__ */ jsxRuntime.jsx(
407
485
  admin.Layouts.Header,
@@ -410,18 +488,18 @@ function HomePage$1() {
410
488
  subtitle: formatMessage(getTrad("page.title"))
411
489
  }
412
490
  ),
413
- showSuccess && /* @__PURE__ */ jsxRuntime.jsx(SuccessAlertMessage, { onClose: () => setSuccess(false) }),
414
- showError && /* @__PURE__ */ jsxRuntime.jsx(ErrorAlertMessage, { onClose: () => setError(false) }),
415
- showMatched > 0 && /* @__PURE__ */ jsxRuntime.jsx(MatchedUserAlertMessage, { count: showMatched, onClose: () => setMatched(0) }),
491
+ state.showSuccess && /* @__PURE__ */ jsxRuntime.jsx(SuccessAlertMessage, { onClose: () => actions.setSuccess(false) }),
492
+ state.showError && /* @__PURE__ */ jsxRuntime.jsx(ErrorAlertMessage, { onClose: () => actions.setError(false) }),
493
+ state.showMatched > 0 && /* @__PURE__ */ jsxRuntime.jsx(MatchedUserAlertMessage, { count: state.showMatched, onClose: () => actions.setMatched(0) }),
416
494
  /* @__PURE__ */ jsxRuntime.jsx(admin.Layouts.Content, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
417
495
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { background: "neutral0", hasRadius: true, shadow: "filterShadow", padding: 6, children: [
418
496
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", tag: "h2", children: formatMessage(getTrad("roles.title")) }) }),
419
497
  /* @__PURE__ */ jsxRuntime.jsx(
420
498
  Role,
421
499
  {
422
- roles,
423
- oidcRoles,
424
- onChangeRole
500
+ roles: state.roles,
501
+ oidcRoles: state.oidcRoles,
502
+ onChangeRole: actions.onChangeRole
425
503
  }
426
504
  )
427
505
  ] }),
@@ -431,22 +509,22 @@ function HomePage$1() {
431
509
  /* @__PURE__ */ jsxRuntime.jsx(
432
510
  CustomSwitch,
433
511
  {
434
- checked: useWhitelist,
435
- onChange: onToggleWhitelist,
436
- label: useWhitelist ? formatMessage(getTrad("whitelist.toggle.enabled")) : formatMessage(getTrad("whitelist.toggle.disabled"))
512
+ checked: state.useWhitelist,
513
+ onChange: actions.onToggleWhitelist,
514
+ label: state.useWhitelist ? formatMessage(getTrad("whitelist.toggle.enabled")) : formatMessage(getTrad("whitelist.toggle.disabled"))
437
515
  }
438
516
  )
439
517
  ] }),
440
518
  /* @__PURE__ */ jsxRuntime.jsx(
441
519
  Whitelist,
442
520
  {
443
- loading,
444
- users,
445
- roles,
446
- oidcRoles,
447
- useWhitelist,
448
- onSave: onRegisterWhitelist,
449
- onDelete: onDeleteWhitelist
521
+ loading: state.loading,
522
+ users: state.users,
523
+ roles: state.roles,
524
+ oidcRoles: state.oidcRoles,
525
+ useWhitelist: state.useWhitelist,
526
+ onSave: actions.onRegisterWhitelist,
527
+ onDelete: actions.onDeleteWhitelist
450
528
  }
451
529
  )
452
530
  ] }),
@@ -456,14 +534,14 @@ function HomePage$1() {
456
534
  /* @__PURE__ */ jsxRuntime.jsx(
457
535
  CustomSwitch,
458
536
  {
459
- checked: enforceOIDC,
460
- onChange: onToggleEnforce,
461
- disabled: useWhitelist && users.length === 0,
462
- label: enforceOIDC ? formatMessage(getTrad("enforce.toggle.enabled")) : formatMessage(getTrad("enforce.toggle.disabled"))
537
+ checked: state.enforceOIDC,
538
+ onChange: actions.onToggleEnforce,
539
+ disabled: state.useWhitelist && state.users.length === 0,
540
+ label: state.enforceOIDC ? formatMessage(getTrad("enforce.toggle.enabled")) : formatMessage(getTrad("enforce.toggle.disabled"))
463
541
  }
464
542
  )
465
543
  ] }),
466
- enforceOIDC && enforceOIDC !== initialEnforceOIDC && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "danger100", padding: 3, hasRadius: true, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 3, alignItems: "center", children: [
544
+ state.enforceOIDC && state.enforceOIDC !== state.initialEnforceOIDC && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "danger100", padding: 3, hasRadius: true, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 3, alignItems: "center", children: [
467
545
  /* @__PURE__ */ jsxRuntime.jsx(icons.WarningCircle, { fill: "danger600" }),
468
546
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger600", children: formatMessage(getTrad("enforce.warning")) })
469
547
  ] }) })
@@ -472,9 +550,9 @@ function HomePage$1() {
472
550
  designSystem.Button,
473
551
  {
474
552
  size: "L",
475
- onClick: onSaveAll,
476
- disabled: !isDirty || loading,
477
- loading,
553
+ onClick: actions.onSaveAll,
554
+ disabled: !state.isDirty || state.loading,
555
+ loading: state.loading,
478
556
  children: formatMessage(getTrad("page.save"))
479
557
  }
480
558
  ) })
@@ -54,7 +54,7 @@ const index = {
54
54
  defaultMessage: "Configuration"
55
55
  },
56
56
  Component: async () => {
57
- return await import("./index-DwpTg1-J.mjs");
57
+ return await import("./index-p9ncVp1G.mjs");
58
58
  },
59
59
  permissions: [{ action: "plugin::strapi-plugin-oidc.read", subject: null }]
60
60
  }
@@ -76,24 +76,18 @@ const index = {
76
76
  if (currentPath.endsWith("/auth/login")) {
77
77
  window.location.href = "/strapi-plugin-oidc/oidc";
78
78
  }
79
- const originalPushState = window.history.pushState;
80
- window.history.pushState = function(...args) {
81
- const url = args[2];
82
- if (url && typeof url === "string" && url.endsWith("/auth/login")) {
83
- window.location.href = "/strapi-plugin-oidc/oidc";
84
- return;
85
- }
86
- return originalPushState.apply(window.history, args);
87
- };
88
- const originalReplaceState = window.history.replaceState;
89
- window.history.replaceState = function(...args) {
90
- const url = args[2];
91
- if (url && typeof url === "string" && url.endsWith("/auth/login")) {
92
- window.location.href = "/strapi-plugin-oidc/oidc";
93
- return;
94
- }
95
- return originalReplaceState.apply(window.history, args);
79
+ const interceptHistory = (originalMethod) => {
80
+ return function(...args) {
81
+ const url = args[2];
82
+ if (url && typeof url === "string" && url.endsWith("/auth/login")) {
83
+ window.location.href = "/strapi-plugin-oidc/oidc";
84
+ return;
85
+ }
86
+ return originalMethod.apply(window.history, args);
87
+ };
96
88
  };
89
+ window.history.pushState = interceptHistory(window.history.pushState);
90
+ window.history.replaceState = interceptHistory(window.history.replaceState);
97
91
  }
98
92
  }
99
93
  } catch (error) {