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.
@@ -125,10 +125,22 @@ const contentTypes = {
125
125
  };
126
126
  function configValidation() {
127
127
  const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
128
- if (config2["OIDC_CLIENT_ID"] && config2["OIDC_CLIENT_SECRET"] && config2["OIDC_REDIRECT_URI"] && config2["OIDC_SCOPES"] && config2["OIDC_TOKEN_ENDPOINT"] && config2["OIDC_USER_INFO_ENDPOINT"] && config2["OIDC_GRANT_TYPE"] && config2["OIDC_FAMILY_NAME_FIELD"] && config2["OIDC_GIVEN_NAME_FIELD"] && config2["OIDC_AUTHORIZATION_ENDPOINT"]) {
128
+ const requiredKeys = [
129
+ "OIDC_CLIENT_ID",
130
+ "OIDC_CLIENT_SECRET",
131
+ "OIDC_REDIRECT_URI",
132
+ "OIDC_SCOPES",
133
+ "OIDC_TOKEN_ENDPOINT",
134
+ "OIDC_USER_INFO_ENDPOINT",
135
+ "OIDC_GRANT_TYPE",
136
+ "OIDC_FAMILY_NAME_FIELD",
137
+ "OIDC_GIVEN_NAME_FIELD",
138
+ "OIDC_AUTHORIZATION_ENDPOINT"
139
+ ];
140
+ if (requiredKeys.every((key) => config2[key])) {
129
141
  return config2;
130
142
  }
131
- throw new Error("OIDC_AUTHORIZATION_ENDPOINT,OIDC_TOKEN_ENDPOINT, OIDC_USER_INFO_ENDPOINT,OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_REDIRECT_URI, and OIDC_SCOPES are required");
143
+ throw new Error(`The following configuration keys are required: ${requiredKeys.join(", ")}`);
132
144
  }
133
145
  async function oidcSignIn(ctx) {
134
146
  let { state } = ctx.query;
@@ -151,6 +163,66 @@ async function oidcSignIn(ctx) {
151
163
  ctx.set("Location", authorizationUrl);
152
164
  return ctx.send({}, 302);
153
165
  }
166
+ async function exchangeTokenAndFetchUserInfo(httpClient, config2, params) {
167
+ const response = await httpClient.post(config2.OIDC_TOKEN_ENDPOINT, params, {
168
+ headers: {
169
+ "Content-Type": "application/x-www-form-urlencoded"
170
+ }
171
+ });
172
+ let userInfoEndpointHeaders = {};
173
+ let userInfoEndpointParameters = `?access_token=${response.data.access_token}`;
174
+ if (config2.OIDC_USER_INFO_ENDPOINT_WITH_AUTH_HEADER) {
175
+ userInfoEndpointHeaders = {
176
+ headers: { Authorization: `Bearer ${response.data.access_token}` }
177
+ };
178
+ userInfoEndpointParameters = "";
179
+ }
180
+ const userInfoEndpoint = `${config2.OIDC_USER_INFO_ENDPOINT}${userInfoEndpointParameters}`;
181
+ const userResponse = await httpClient.get(userInfoEndpoint, userInfoEndpointHeaders);
182
+ return userResponse.data;
183
+ }
184
+ async function registerNewUser(userService, oauthService2, roleService2, email, userResponseData, whitelistUser, config2, ctx) {
185
+ let roles2 = [];
186
+ if (whitelistUser?.roles?.length > 0) {
187
+ roles2 = whitelistUser.roles;
188
+ } else {
189
+ const oidcRoles = await roleService2.oidcRoles();
190
+ roles2 = oidcRoles?.roles || [];
191
+ }
192
+ const defaultLocale = oauthService2.localeFindByHeader(ctx.request.headers);
193
+ const activateUser = await oauthService2.createUser(
194
+ email,
195
+ userResponseData[config2.OIDC_FAMILY_NAME_FIELD],
196
+ userResponseData[config2.OIDC_GIVEN_NAME_FIELD],
197
+ defaultLocale,
198
+ roles2
199
+ );
200
+ await oauthService2.triggerWebHook(activateUser);
201
+ return activateUser;
202
+ }
203
+ async function handleUserAuthentication(userService, oauthService2, roleService2, whitelistService2, userResponseData, config2, ctx) {
204
+ const email = String(userResponseData.email).toLowerCase();
205
+ const whitelistUser = await whitelistService2.checkWhitelistForEmail(email);
206
+ const dbUser = await userService.findOneByEmail(email);
207
+ let activateUser;
208
+ if (dbUser) {
209
+ activateUser = dbUser;
210
+ } else {
211
+ activateUser = await registerNewUser(
212
+ userService,
213
+ oauthService2,
214
+ roleService2,
215
+ email,
216
+ userResponseData,
217
+ whitelistUser,
218
+ config2,
219
+ ctx
220
+ );
221
+ }
222
+ const jwtToken = await oauthService2.generateToken(activateUser, ctx);
223
+ oauthService2.triggerSignInSuccess(activateUser);
224
+ return { activateUser, jwtToken };
225
+ }
154
226
  async function oidcSignInCallback(ctx) {
155
227
  const config2 = configValidation();
156
228
  const httpClient = axios__default.default.create();
@@ -159,77 +231,41 @@ async function oidcSignInCallback(ctx) {
159
231
  const roleService2 = strapi.plugin("strapi-plugin-oidc").service("role");
160
232
  const whitelistService2 = strapi.plugin("strapi-plugin-oidc").service("whitelist");
161
233
  if (!ctx.query.code) {
162
- return ctx.send(oauthService2.renderSignUpError(`code Not Found`));
234
+ return ctx.send(oauthService2.renderSignUpError("code Not Found"));
163
235
  }
164
236
  if (!ctx.query.state || ctx.query.state !== ctx.session.oidcState) {
165
- return ctx.send(oauthService2.renderSignUpError(`Invalid state`));
237
+ return ctx.send(oauthService2.renderSignUpError("Invalid state"));
166
238
  }
167
239
  const params = new URLSearchParams();
168
240
  params.append("code", ctx.query.code);
169
- params.append("client_id", config2["OIDC_CLIENT_ID"]);
170
- params.append("client_secret", config2["OIDC_CLIENT_SECRET"]);
171
- params.append("redirect_uri", config2["OIDC_REDIRECT_URI"]);
172
- params.append("grant_type", config2["OIDC_GRANT_TYPE"]);
241
+ params.append("client_id", config2.OIDC_CLIENT_ID);
242
+ params.append("client_secret", config2.OIDC_CLIENT_SECRET);
243
+ params.append("redirect_uri", config2.OIDC_REDIRECT_URI);
244
+ params.append("grant_type", config2.OIDC_GRANT_TYPE);
173
245
  params.append("code_verifier", ctx.session.codeVerifier);
174
246
  try {
175
- const response = await httpClient.post(config2["OIDC_TOKEN_ENDPOINT"], params, {
176
- headers: {
177
- "Content-Type": "application/x-www-form-urlencoded"
178
- }
179
- });
180
- let userInfoEndpointHeaders = {};
181
- let userInfoEndpointParameters = `?access_token=${response.data.access_token}`;
182
- if (config2["OIDC_USER_INFO_ENDPOINT_WITH_AUTH_HEADER"]) {
183
- userInfoEndpointHeaders = {
184
- headers: { Authorization: `Bearer ${response.data.access_token}` }
185
- };
186
- userInfoEndpointParameters = "";
187
- }
188
- const userInfoEndpoint = `${config2["OIDC_USER_INFO_ENDPOINT"]}${userInfoEndpointParameters}`;
189
- const userResponse = await httpClient.get(
190
- userInfoEndpoint,
191
- userInfoEndpointHeaders
247
+ const userResponseData = await exchangeTokenAndFetchUserInfo(httpClient, config2, params);
248
+ const { activateUser, jwtToken } = await handleUserAuthentication(
249
+ userService,
250
+ oauthService2,
251
+ roleService2,
252
+ whitelistService2,
253
+ userResponseData,
254
+ config2,
255
+ ctx
192
256
  );
193
- const email = userResponse.data.email;
194
- const whitelistUser = await whitelistService2.checkWhitelistForEmail(email);
195
- const dbUser = await userService.findOneByEmail(email);
196
- let activateUser;
197
- let jwtToken;
198
- if (dbUser) {
199
- activateUser = dbUser;
200
- jwtToken = await oauthService2.generateToken(dbUser, ctx);
201
- } else {
202
- let roles2 = [];
203
- if (whitelistUser && whitelistUser.roles && whitelistUser.roles.length > 0) {
204
- roles2 = whitelistUser.roles;
205
- } else {
206
- const oidcRoles = await roleService2.oidcRoles();
207
- roles2 = oidcRoles && oidcRoles["roles"] ? oidcRoles["roles"] : [];
208
- }
209
- const defaultLocale = oauthService2.localeFindByHeader(ctx.request.headers);
210
- activateUser = await oauthService2.createUser(
211
- email,
212
- userResponse.data[config2["OIDC_FAMILY_NAME_FIELD"]],
213
- userResponse.data[config2["OIDC_GIVEN_NAME_FIELD"]],
214
- defaultLocale,
215
- roles2
216
- );
217
- jwtToken = await oauthService2.generateToken(activateUser, ctx);
218
- await oauthService2.triggerWebHook(activateUser);
219
- }
220
- oauthService2.triggerSignInSuccess(activateUser);
221
257
  const nonce = node_crypto.randomUUID();
222
258
  const html = oauthService2.renderSignUpSuccess(jwtToken, activateUser, nonce);
223
259
  ctx.set("Content-Security-Policy", `script-src 'nonce-${nonce}'`);
224
260
  ctx.send(html);
225
261
  } catch (e) {
226
- console.error(e);
262
+ console.error("ERROR CAUGHT IN OIDC SIGNIN:", e);
227
263
  ctx.send(oauthService2.renderSignUpError(e.message));
228
264
  }
229
265
  }
230
266
  async function logout(ctx) {
231
267
  const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
232
- const logoutUrl = config2["OIDC_LOGOUT_URL"];
268
+ const logoutUrl = config2.OIDC_LOGOUT_URL;
233
269
  if (logoutUrl) {
234
270
  ctx.redirect(logoutUrl);
235
271
  } else {
@@ -247,10 +283,9 @@ async function find(ctx) {
247
283
  const roles2 = await roleService2.find();
248
284
  const oidcConstants = roleService2.getOidcRoles();
249
285
  for (const oidc2 of oidcConstants) {
250
- for (const role2 of roles2) {
251
- if (role2["oauth_type"] === oidc2["oauth_type"]) {
252
- oidc2["role"] = role2["roles"];
253
- }
286
+ const matchedRole = roles2.find((r) => r.oauth_type === oidc2.oauth_type);
287
+ if (matchedRole) {
288
+ oidc2.role = matchedRole.roles;
254
289
  }
255
290
  }
256
291
  ctx.send(oidcConstants);
@@ -262,7 +297,7 @@ async function update(ctx) {
262
297
  await roleService2.update(roles2);
263
298
  ctx.send({}, 204);
264
299
  } catch (e) {
265
- console.log(e);
300
+ console.error(e);
266
301
  ctx.send({}, 400);
267
302
  }
268
303
  }
@@ -281,8 +316,14 @@ async function info(ctx) {
281
316
  };
282
317
  }
283
318
  async function updateSettings(ctx) {
284
- const { useWhitelist, enforceOIDC } = ctx.request.body;
319
+ let { useWhitelist, enforceOIDC } = ctx.request.body;
285
320
  const whitelistService2 = strapi.plugin("strapi-plugin-oidc").service("whitelist");
321
+ if (useWhitelist && enforceOIDC) {
322
+ const users = await whitelistService2.getUsers();
323
+ if (users.length === 0) {
324
+ enforceOIDC = false;
325
+ }
326
+ }
286
327
  await whitelistService2.setSettings({ useWhitelist, enforceOIDC });
287
328
  ctx.body = { useWhitelist, enforceOIDC };
288
329
  }
@@ -296,12 +337,11 @@ async function publicSettings(ctx) {
296
337
  async function register(ctx) {
297
338
  const { email, roles: roles2 } = ctx.request.body;
298
339
  if (!email) {
299
- ctx.body = {
300
- message: "Please enter a valid email address"
301
- };
340
+ ctx.body = { message: "Please enter a valid email address" };
302
341
  return;
303
342
  }
304
- const emailList = Array.isArray(email) ? email : email.split(",").map((e) => e.trim()).filter((e) => e);
343
+ const rawEmails = Array.isArray(email) ? email : email.split(",");
344
+ const emailList = rawEmails.map((e) => String(e).trim().toLowerCase()).filter(Boolean);
305
345
  const existingUsers = await strapi.query("admin::user").findMany({
306
346
  where: { email: { $in: emailList } },
307
347
  populate: ["roles"]
@@ -311,8 +351,8 @@ async function register(ctx) {
311
351
  for (const singleEmail of emailList) {
312
352
  const existingUser = existingUsers.find((u) => u.email === singleEmail);
313
353
  let finalRoles = roles2;
314
- if (existingUser && existingUser.roles) {
315
- finalRoles = existingUser.roles.map((r) => r.id.toString());
354
+ if (existingUser?.roles) {
355
+ finalRoles = existingUser.roles.map((r) => String(r.id));
316
356
  matchedExistingUsersCount++;
317
357
  }
318
358
  const alreadyWhitelisted = await strapi.query("plugin::strapi-plugin-oidc.whitelists").findOne({
@@ -331,7 +371,8 @@ async function removeEmail(ctx) {
331
371
  ctx.body = {};
332
372
  }
333
373
  async function syncUsers(ctx) {
334
- const { users } = ctx.request.body;
374
+ let { users } = ctx.request.body;
375
+ users = users.map((u) => ({ ...u, email: String(u.email).toLowerCase() }));
335
376
  const whitelistService2 = strapi.plugin("strapi-plugin-oidc").service("whitelist");
336
377
  const currentUsers = await whitelistService2.getUsers();
337
378
  let matchedExistingUsersCount = 0;
@@ -349,8 +390,8 @@ async function syncUsers(ctx) {
349
390
  const existingStrapiUser = existingStrapiUsers.find((u) => u.email === user.email);
350
391
  let finalRoles = user.roles;
351
392
  const currUser = currentUsers.find((u) => u.email === user.email);
352
- if (!currUser && existingStrapiUser && existingStrapiUser.roles) {
353
- finalRoles = existingStrapiUser.roles.map((r) => r.id.toString());
393
+ if (!currUser && existingStrapiUser?.roles) {
394
+ finalRoles = existingStrapiUser.roles.map((r) => String(r.id));
354
395
  matchedExistingUsersCount++;
355
396
  }
356
397
  if (currUser) {
@@ -377,6 +418,23 @@ const controllers = {
377
418
  role,
378
419
  whitelist
379
420
  };
421
+ const rateLimitMap = /* @__PURE__ */ new Map();
422
+ const RATE_LIMIT_WINDOW = 6e4;
423
+ const MAX_REQUESTS = 20;
424
+ const rateLimitMiddleware = async (ctx, next) => {
425
+ const ip = ctx.request.ip;
426
+ const now = Date.now();
427
+ const windowStart = now - RATE_LIMIT_WINDOW;
428
+ const requestStamps = (rateLimitMap.get(ip) || []).filter((timestamp) => timestamp > windowStart);
429
+ if (requestStamps.length >= MAX_REQUESTS) {
430
+ ctx.status = 429;
431
+ ctx.body = "Too Many Requests";
432
+ return;
433
+ }
434
+ requestStamps.push(now);
435
+ rateLimitMap.set(ip, requestStamps);
436
+ await next();
437
+ };
380
438
  const routes = [
381
439
  {
382
440
  method: "GET",
@@ -396,7 +454,10 @@ const routes = [
396
454
  config: {
397
455
  policies: [
398
456
  "admin::isAuthenticatedAdmin",
399
- { name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.update"] } }
457
+ {
458
+ name: "admin::hasPermissions",
459
+ config: { actions: ["plugin::strapi-plugin-oidc.update"] }
460
+ }
400
461
  ]
401
462
  }
402
463
  },
@@ -405,7 +466,8 @@ const routes = [
405
466
  path: "/oidc",
406
467
  handler: "oidc.oidcSignIn",
407
468
  config: {
408
- auth: false
469
+ auth: false,
470
+ middlewares: [rateLimitMiddleware]
409
471
  }
410
472
  },
411
473
  {
@@ -413,7 +475,8 @@ const routes = [
413
475
  path: "/oidc/callback",
414
476
  handler: "oidc.oidcSignInCallback",
415
477
  config: {
416
- auth: false
478
+ auth: false,
479
+ middlewares: [rateLimitMiddleware]
417
480
  }
418
481
  },
419
482
  {
@@ -442,7 +505,10 @@ const routes = [
442
505
  config: {
443
506
  policies: [
444
507
  "admin::isAuthenticatedAdmin",
445
- { name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.update"] } }
508
+ {
509
+ name: "admin::hasPermissions",
510
+ config: { actions: ["plugin::strapi-plugin-oidc.update"] }
511
+ }
446
512
  ]
447
513
  }
448
514
  },
@@ -461,7 +527,10 @@ const routes = [
461
527
  config: {
462
528
  policies: [
463
529
  "admin::isAuthenticatedAdmin",
464
- { name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.update"] } }
530
+ {
531
+ name: "admin::hasPermissions",
532
+ config: { actions: ["plugin::strapi-plugin-oidc.update"] }
533
+ }
465
534
  ]
466
535
  }
467
536
  },
@@ -472,7 +541,10 @@ const routes = [
472
541
  config: {
473
542
  policies: [
474
543
  "admin::isAuthenticatedAdmin",
475
- { name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.update"] } }
544
+ {
545
+ name: "admin::hasPermissions",
546
+ config: { actions: ["plugin::strapi-plugin-oidc.update"] }
547
+ }
476
548
  ]
477
549
  }
478
550
  },
@@ -483,12 +555,132 @@ const routes = [
483
555
  config: {
484
556
  policies: [
485
557
  "admin::isAuthenticatedAdmin",
486
- { name: "admin::hasPermissions", config: { actions: ["plugin::strapi-plugin-oidc.update"] } }
558
+ {
559
+ name: "admin::hasPermissions",
560
+ config: { actions: ["plugin::strapi-plugin-oidc.update"] }
561
+ }
487
562
  ]
488
563
  }
489
564
  }
490
565
  ];
491
566
  const policies = {};
567
+ function renderHtmlTemplate(title, content) {
568
+ return `
569
+ <!doctype html>
570
+ <html lang="en">
571
+ <head>
572
+ <meta charset="utf-8">
573
+ <meta name="viewport" content="width=device-width, initial-scale=1">
574
+ <title>${title}</title>
575
+ <style>
576
+ :root {
577
+ --bg-color: #f6f6f9;
578
+ --card-bg: #ffffff;
579
+ --text-color: #32324d;
580
+ --text-muted: #666687;
581
+ --btn-bg: #4945ff;
582
+ --btn-hover: #271fe0;
583
+ --btn-text: #ffffff;
584
+ --icon-bg: #fcecea;
585
+ --icon-color: #d02b20;
586
+ --success-bg: #eafbe7;
587
+ --success-color: #328048;
588
+ --shadow: 0 1px 4px rgba(33, 33, 52, 0.1);
589
+ }
590
+ @media (prefers-color-scheme: dark) {
591
+ :root {
592
+ --bg-color: #181826;
593
+ --card-bg: #212134;
594
+ --text-color: #ffffff;
595
+ --text-muted: #a5a5ba;
596
+ --btn-bg: #4945ff;
597
+ --btn-hover: #7b79ff;
598
+ --btn-text: #ffffff;
599
+ --icon-bg: #4a2123;
600
+ --icon-color: #f23628;
601
+ --success-bg: #1c3523;
602
+ --success-color: #55ca76;
603
+ --shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
604
+ }
605
+ }
606
+ body {
607
+ margin: 0;
608
+ padding: 0;
609
+ display: flex;
610
+ justify-content: center;
611
+ align-items: center;
612
+ height: 100vh;
613
+ background-color: var(--bg-color);
614
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
615
+ color: var(--text-color);
616
+ }
617
+ .card {
618
+ background: var(--card-bg);
619
+ padding: 32px 40px;
620
+ border-radius: 8px;
621
+ box-shadow: var(--shadow);
622
+ max-width: 400px;
623
+ width: 100%;
624
+ text-align: center;
625
+ box-sizing: border-box;
626
+ }
627
+ .icon {
628
+ width: 48px;
629
+ height: 48px;
630
+ background-color: var(--icon-bg);
631
+ color: var(--icon-color);
632
+ border-radius: 50%;
633
+ display: inline-flex;
634
+ justify-content: center;
635
+ align-items: center;
636
+ margin-bottom: 24px;
637
+ }
638
+ .icon.success {
639
+ background-color: var(--success-bg);
640
+ color: var(--success-color);
641
+ }
642
+ .icon svg {
643
+ width: 24px;
644
+ height: 24px;
645
+ stroke: currentColor;
646
+ stroke-width: 2;
647
+ stroke-linecap: round;
648
+ stroke-linejoin: round;
649
+ fill: none;
650
+ }
651
+ h1 {
652
+ margin: 0 0 12px 0;
653
+ font-size: 20px;
654
+ font-weight: 600;
655
+ color: var(--text-color);
656
+ }
657
+ p {
658
+ margin: 0 0 32px 0;
659
+ font-size: 14px;
660
+ line-height: 1.5;
661
+ color: var(--text-muted);
662
+ }
663
+ .btn {
664
+ display: inline-block;
665
+ background-color: var(--btn-bg);
666
+ color: var(--btn-text);
667
+ padding: 10px 16px;
668
+ border-radius: 4px;
669
+ text-decoration: none;
670
+ font-size: 14px;
671
+ font-weight: 500;
672
+ transition: background-color 0.2s;
673
+ }
674
+ .btn:hover {
675
+ background-color: var(--btn-hover);
676
+ }
677
+ </style>
678
+ </head>
679
+ <body>
680
+ ${content}
681
+ </body>
682
+ </html>`;
683
+ }
492
684
  function oauthService({ strapi: strapi2 }) {
493
685
  return {
494
686
  async createUser(email, lastname, firstname, locale, roles2 = []) {
@@ -500,8 +692,8 @@ function oauthService({ strapi: strapi2 }) {
500
692
  }
501
693
  }
502
694
  const createdUser = await userService.create({
503
- firstname: firstname ? firstname : "unset",
504
- lastname: lastname ? lastname : "",
695
+ firstname: firstname || "unset",
696
+ lastname: lastname || "",
505
697
  email: email.toLocaleLowerCase(),
506
698
  roles: roles2,
507
699
  preferedLanguage: locale
@@ -509,8 +701,8 @@ function oauthService({ strapi: strapi2 }) {
509
701
  return await userService.register({
510
702
  registrationToken: createdUser.registrationToken,
511
703
  userInfo: {
512
- firstname: firstname ? firstname : "unset",
513
- lastname: lastname ? lastname : "user",
704
+ firstname: firstname || "unset",
705
+ lastname: lastname || "user",
514
706
  password: generator__default.default.generate({
515
707
  length: 43,
516
708
  // 256 bits (https://en.wikipedia.org/wiki/Password_strength#Random_passwords)
@@ -534,11 +726,7 @@ function oauthService({ strapi: strapi2 }) {
534
726
  return `${origin}+${alias}${domain}`;
535
727
  },
536
728
  localeFindByHeader(headers) {
537
- if (headers["accept-language"] && headers["accept-language"].includes("ja")) {
538
- return "ja";
539
- } else {
540
- return "en";
541
- }
729
+ return headers["accept-language"]?.includes("ja") ? "ja" : "en";
542
730
  },
543
731
  async triggerWebHook(user) {
544
732
  let ENTRY_CREATE;
@@ -561,7 +749,7 @@ function oauthService({ strapi: strapi2 }) {
561
749
  });
562
750
  },
563
751
  triggerSignInSuccess(user) {
564
- delete user["password"];
752
+ delete user.password;
565
753
  const eventHub = strapi2.serviceMap.get("eventHub");
566
754
  eventHub.emit("admin.auth.success", {
567
755
  user,
@@ -573,40 +761,48 @@ function oauthService({ strapi: strapi2 }) {
573
761
  const config2 = strapi2.config.get("plugin::strapi-plugin-oidc");
574
762
  const REMEMBER_ME = config2["REMEMBER_ME"];
575
763
  const isRememberMe = !!REMEMBER_ME;
576
- return `
577
- <!doctype html>
578
- <html>
579
- <head>
580
- <noscript>
581
- <h3>JavaScript must be enabled for authentication</h3>
582
- </noscript>
583
- <script nonce="${nonce}">
584
- window.addEventListener('load', function() {
585
- if(${isRememberMe}){
586
- localStorage.setItem('jwtToken', '"${jwtToken}"');
587
- }else{
588
- document.cookie = 'jwtToken=${encodeURIComponent(jwtToken)}; Path=/';
589
- }
590
- localStorage.setItem('isLoggedIn', 'true');
591
- location.href = '${strapi2.config.admin.url}'
592
- })
593
- <\/script>
594
- </head>
595
- <body>
596
- </body>
597
- </html>`;
764
+ const content = `
765
+ <noscript>
766
+ <div class="card">
767
+ <div class="icon success">
768
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check">
769
+ <path d="M20 6 9 17l-5-5"/>
770
+ </svg>
771
+ </div>
772
+ <h1>JavaScript Required</h1>
773
+ <p>JavaScript must be enabled for authentication to complete.</p>
774
+ </div>
775
+ </noscript>
776
+ <script nonce="${nonce}">
777
+ window.addEventListener('load', function() {
778
+ if(${isRememberMe}){
779
+ localStorage.setItem('jwtToken', '"${jwtToken}"');
780
+ }else{
781
+ document.cookie = 'jwtToken=${encodeURIComponent(jwtToken)}; Path=/';
782
+ }
783
+ localStorage.setItem('isLoggedIn', 'true');
784
+ location.href = '${strapi2.config.admin.url}'
785
+ })
786
+ <\/script>`;
787
+ return renderHtmlTemplate("Authenticating...", content);
598
788
  },
599
789
  // Sign In Error
600
790
  renderSignUpError(message) {
601
- return `
602
- <!doctype html>
603
- <html>
604
- <head></head>
605
- <body>
606
- <h3>Authentication failed</h3>
607
- <p>${message}</p>
608
- </body>
609
- </html>`;
791
+ const safeMessage = String(message).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
792
+ const content = `
793
+ <div class="card">
794
+ <div class="icon">
795
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-triangle-alert">
796
+ <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/>
797
+ <path d="M12 9v4"/>
798
+ <path d="M12 17h.01"/>
799
+ </svg>
800
+ </div>
801
+ <h1>Authentication Failed</h1>
802
+ <p>${safeMessage}</p>
803
+ <a href="${strapi2.config.admin.url}" class="btn">Return to Login</a>
804
+ </div>`;
805
+ return renderHtmlTemplate("Authentication Failed", content);
610
806
  },
611
807
  async generateToken(user, ctx) {
612
808
  const sessionManager = strapi2.sessionManager;
@@ -661,35 +857,35 @@ function roleService({ strapi: strapi2 }) {
661
857
  getOidcRoles() {
662
858
  return [
663
859
  {
664
- "oauth_type": this.OIDC_TYPE,
860
+ oauth_type: this.OIDC_TYPE,
665
861
  name: "OIDC"
666
862
  }
667
863
  ];
668
864
  },
669
865
  async oidcRoles() {
670
- return await strapi2.query("plugin::strapi-plugin-oidc.roles").findOne({
866
+ return strapi2.query("plugin::strapi-plugin-oidc.roles").findOne({
671
867
  where: {
672
- "oauth_type": this.OIDC_TYPE
868
+ oauth_type: this.OIDC_TYPE
673
869
  }
674
870
  });
675
871
  },
676
872
  async find() {
677
- return await strapi2.query("plugin::strapi-plugin-oidc.roles").findMany();
873
+ return strapi2.query("plugin::strapi-plugin-oidc.roles").findMany();
678
874
  },
679
875
  async update(roles2) {
680
876
  const query = strapi2.query("plugin::strapi-plugin-oidc.roles");
681
877
  await Promise.all(
682
878
  roles2.map(async (role2) => {
683
- const oidcRole = await query.findOne({ where: { "oauth_type": role2["oauth_type"] } });
879
+ const oidcRole = await query.findOne({ where: { oauth_type: role2.oauth_type } });
684
880
  if (oidcRole) {
685
881
  await query.update({
686
- where: { "oauth_type": role2["oauth_type"] },
882
+ where: { oauth_type: role2.oauth_type },
687
883
  data: { roles: role2.role }
688
884
  });
689
885
  } else {
690
886
  await query.create({
691
887
  data: {
692
- "oauth_type": role2["oauth_type"],
888
+ oauth_type: role2.oauth_type,
693
889
  roles: role2.role
694
890
  }
695
891
  });
@@ -700,53 +896,48 @@ function roleService({ strapi: strapi2 }) {
700
896
  };
701
897
  }
702
898
  function whitelistService({ strapi: strapi2 }) {
899
+ const getPluginStore = () => strapi2.store({
900
+ environment: "",
901
+ type: "plugin",
902
+ name: "strapi-plugin-oidc"
903
+ });
904
+ const getWhitelistQuery = () => strapi2.query("plugin::strapi-plugin-oidc.whitelists");
703
905
  return {
704
906
  async getSettings() {
705
- const pluginStore = strapi2.store({ type: "plugin", name: "strapi-plugin-oidc" });
706
- let settings = await pluginStore.get({ key: "settings" });
907
+ let settings = await getPluginStore().get({ key: "settings" });
707
908
  if (!settings) {
708
909
  settings = { useWhitelist: true, enforceOIDC: false };
709
- await pluginStore.set({ key: "settings", value: settings });
910
+ await getPluginStore().set({ key: "settings", value: settings });
710
911
  }
711
912
  return settings;
712
913
  },
713
914
  async setSettings(settings) {
714
- const pluginStore = strapi2.store({ type: "plugin", name: "strapi-plugin-oidc" });
715
- await pluginStore.set({ key: "settings", value: settings });
915
+ await getPluginStore().set({ key: "settings", value: settings });
716
916
  },
717
917
  async getUsers() {
718
- const query = strapi2.query("plugin::strapi-plugin-oidc.whitelists");
719
- return await query.findMany();
918
+ return getWhitelistQuery().findMany();
720
919
  },
721
920
  async registerUser(email, roles2) {
722
- const query = strapi2.query("plugin::strapi-plugin-oidc.whitelists");
723
- await query.create({
724
- data: {
725
- email,
726
- roles: roles2
727
- }
921
+ await getWhitelistQuery().create({
922
+ data: { email, roles: roles2 }
728
923
  });
729
924
  },
730
925
  async removeUser(id) {
731
- const query = strapi2.query("plugin::strapi-plugin-oidc.whitelists");
732
- await query.delete({
733
- where: {
734
- id
735
- }
926
+ await getWhitelistQuery().delete({
927
+ where: { id }
736
928
  });
737
929
  },
738
930
  async checkWhitelistForEmail(email) {
739
931
  const settings = await this.getSettings();
932
+ console.log("checkWhitelistForEmail settings:", settings);
740
933
  if (!settings.useWhitelist) {
741
934
  return null;
742
935
  }
743
- const query = strapi2.query("plugin::strapi-plugin-oidc.whitelists");
744
- const result = await query.findOne({
745
- where: {
746
- email
747
- }
936
+ const result = await getWhitelistQuery().findOne({
937
+ where: { email }
748
938
  });
749
- if (result === null) {
939
+ console.log("checkWhitelistForEmail result:", result);
940
+ if (!result) {
750
941
  throw new Error("Not present in whitelist");
751
942
  }
752
943
  return result;