@adminforth/open-signup 1.3.1 → 2.0.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/index.d.ts CHANGED
@@ -10,6 +10,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
10
10
  adminforth: IAdminForth;
11
11
  constructor(options: PluginOptions);
12
12
  modifyResourceConfig(adminforth: IAdminForth, resourceConfig: AdminForthResource): Promise<void>;
13
+ getAllowedOrigins(): string[];
13
14
  validateConfigAfterDiscover(adminforth: IAdminForth, resourceConfig: AdminForthResource): void;
14
15
  instanceUniqueRepresentation(pluginOptions: any): string;
15
16
  doLogin(email: string, response: any, extra: HttpExtra): Promise<{
package/dist/index.js CHANGED
@@ -94,8 +94,27 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
94
94
  adminforth.config.auth.beforeLoginConfirmation = [];
95
95
  }
96
96
  }
97
+ const rawOrigins = this.options.expectedOrigin;
98
+ const originList = Array.isArray(rawOrigins) ? rawOrigins : [rawOrigins];
99
+ if (!rawOrigins || originList.length === 0 || originList.some(o => !o)) {
100
+ throw new Error('EmailPasswordReset: expectedOrigin is required. Set it to the admin panel origin(s) ' +
101
+ '(e.g. "https://admin.example.com") so reset links can only point to a trusted host.');
102
+ }
103
+ for (const origin of originList) {
104
+ try {
105
+ new URL(origin);
106
+ }
107
+ catch (_a) {
108
+ throw new Error(`EmailPasswordReset: expectedOrigin "${origin}" is not a valid absolute URL/origin.`);
109
+ }
110
+ }
97
111
  });
98
112
  }
113
+ getAllowedOrigins() {
114
+ const rawOrigins = this.options.expectedOrigin;
115
+ const originList = Array.isArray(rawOrigins) ? rawOrigins : [rawOrigins];
116
+ return originList.map(o => new URL(o).origin);
117
+ }
99
118
  validateConfigAfterDiscover(adminforth, resourceConfig) {
100
119
  if (this.options.confirmEmails) {
101
120
  this.options.confirmEmails.adapter.validate();
@@ -203,6 +222,18 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
203
222
  if (!this.options.confirmEmails && !password) {
204
223
  return { error: yield tr('Password is required', 'opensignup'), ok: false };
205
224
  }
225
+ let resetLink;
226
+ try {
227
+ const parsedUrl = new URL(url);
228
+ if (!this.getAllowedOrigins().includes(parsedUrl.origin)) {
229
+ return { error: 'Invalid reset url', ok: false };
230
+ }
231
+ parsedUrl.hash = '';
232
+ resetLink = parsedUrl.toString();
233
+ }
234
+ catch (_d) {
235
+ return { error: 'Invalid reset url', ok: false };
236
+ }
206
237
  const extra = { body, headers, query, cookies, requestUrl: url };
207
238
  // validate email
208
239
  if (this.emailField.validation) {
@@ -292,7 +323,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
292
323
 
293
324
  To confirm your email, click the link below:\n\n
294
325
 
295
- {url}?verifyToken={verifyToken}\n\n
326
+ {resetLink}?token={verifyToken}\n\n
296
327
 
297
328
  If you didn't request this, please ignore this email.\n\n
298
329
  Link is valid for 2 hours.\n\n
@@ -300,7 +331,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
300
331
  Thanks,
301
332
  The {brandName} Team
302
333
 
303
- `, 'opensignup', { brandName, url, verifyToken });
334
+ `, 'opensignup', { brandName, resetLink, verifyToken });
304
335
  const emailData = {
305
336
  greeting: yield tr('Dear user,', 'opensignup'),
306
337
  welcome: yield tr('Welcome to {brandName}!', 'opensignup', { brandName }),
@@ -318,7 +349,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
318
349
  <p>${emailData.greeting}</p>
319
350
  <p>${emailData.welcome}</p>
320
351
  <p>${emailData.instruction}</p>
321
- <a href="${url}?token=${verifyToken}">${emailData.linkText}</a>
352
+ <a href="${resetLink}?token=${verifyToken}">${emailData.linkText}</a>
322
353
  <p>${emailData.disclaimer}</p>
323
354
  <p>${emailData.validity}</p>
324
355
  <p>${emailData.thanks}</p>
package/dist/types.d.ts CHANGED
@@ -54,4 +54,9 @@ export interface PluginOptions extends PluginsCommonOptions {
54
54
  * Signup component order inder login button
55
55
  */
56
56
  loginPageComponentOrder?: number;
57
+ /**
58
+ * The origin(s) (scheme + host + optional port) of the admin panel that are
59
+ * allowed to appear in password reset links, e.g. "https://admin.example.com".
60
+ */
61
+ expectedOrigin: string | string[];
57
62
  }
package/index.ts CHANGED
@@ -106,6 +106,28 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
106
106
  adminforth.config.auth.beforeLoginConfirmation = [];
107
107
  }
108
108
  }
109
+
110
+ const rawOrigins = this.options.expectedOrigin;
111
+ const originList = Array.isArray(rawOrigins) ? rawOrigins : [rawOrigins];
112
+ if (!rawOrigins || originList.length === 0 || originList.some(o => !o)) {
113
+ throw new Error(
114
+ 'EmailPasswordReset: expectedOrigin is required. Set it to the admin panel origin(s) ' +
115
+ '(e.g. "https://admin.example.com") so reset links can only point to a trusted host.'
116
+ );
117
+ }
118
+ for (const origin of originList) {
119
+ try {
120
+ new URL(origin);
121
+ } catch {
122
+ throw new Error(`EmailPasswordReset: expectedOrigin "${origin}" is not a valid absolute URL/origin.`);
123
+ }
124
+ }
125
+ }
126
+
127
+ getAllowedOrigins(): string[] {
128
+ const rawOrigins = this.options.expectedOrigin;
129
+ const originList = Array.isArray(rawOrigins) ? rawOrigins : [rawOrigins];
130
+ return originList.map(o => new URL(o).origin);
109
131
  }
110
132
 
111
133
  validateConfigAfterDiscover(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
@@ -232,6 +254,19 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
232
254
  if (!this.options.confirmEmails && !password) {
233
255
  return { error: await tr('Password is required', 'opensignup'), ok: false };
234
256
  }
257
+
258
+ let resetLink: string;
259
+ try {
260
+ const parsedUrl = new URL(url);
261
+ if (!this.getAllowedOrigins().includes(parsedUrl.origin)) {
262
+ return { error: 'Invalid reset url', ok: false };
263
+ }
264
+ parsedUrl.hash = '';
265
+ resetLink = parsedUrl.toString();
266
+ } catch {
267
+ return { error: 'Invalid reset url', ok: false };
268
+ }
269
+
235
270
  const extra = { body, headers, query, cookies, requestUrl: url };
236
271
  // validate email
237
272
  if (this.emailField.validation) {
@@ -338,7 +373,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
338
373
 
339
374
  To confirm your email, click the link below:\n\n
340
375
 
341
- {url}?verifyToken={verifyToken}\n\n
376
+ {resetLink}?token={verifyToken}\n\n
342
377
 
343
378
  If you didn't request this, please ignore this email.\n\n
344
379
  Link is valid for 2 hours.\n\n
@@ -346,7 +381,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
346
381
  Thanks,
347
382
  The {brandName} Team
348
383
 
349
- `, 'opensignup', { brandName, url, verifyToken }
384
+ `, 'opensignup', { brandName, resetLink, verifyToken }
350
385
  );
351
386
 
352
387
  const emailData = {
@@ -367,7 +402,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
367
402
  <p>${emailData.greeting}</p>
368
403
  <p>${emailData.welcome}</p>
369
404
  <p>${emailData.instruction}</p>
370
- <a href="${url}?token=${verifyToken}">${emailData.linkText}</a>
405
+ <a href="${resetLink}?token=${verifyToken}">${emailData.linkText}</a>
371
406
  <p>${emailData.disclaimer}</p>
372
407
  <p>${emailData.validity}</p>
373
408
  <p>${emailData.thanks}</p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/open-signup",
3
- "version": "1.3.1",
3
+ "version": "2.0.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
package/types.ts CHANGED
@@ -70,4 +70,11 @@ export interface PluginOptions extends PluginsCommonOptions {
70
70
  * Signup component order inder login button
71
71
  */
72
72
  loginPageComponentOrder?: number;
73
+
74
+ /**
75
+ * The origin(s) (scheme + host + optional port) of the admin panel that are
76
+ * allowed to appear in password reset links, e.g. "https://admin.example.com".
77
+ */
78
+ expectedOrigin: string | string[];
79
+
73
80
  }