@adminforth/email-invite 1.2.3 → 1.2.4
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 +1 -0
- package/dist/index.js +15 -5
- package/index.ts +19 -7
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export default class EmailInvitePlugin extends AdminForthPlugin {
|
|
|
10
10
|
modifyResourceConfig(adminforth: IAdminForth, resourceConfig: AdminForthResource): Promise<void>;
|
|
11
11
|
validateConfigAfterDiscover(adminforth: IAdminForth, resourceConfig: AdminForthResource): void;
|
|
12
12
|
instanceUniqueRepresentation(pluginOptions: any): string;
|
|
13
|
+
passwordHashDigest(passwordHash: string | null | undefined): string;
|
|
13
14
|
handleUserCreation({ resource, adminUser, record, adminforth, extra }: {
|
|
14
15
|
resource: AdminForthResource;
|
|
15
16
|
adminUser: AdminUser;
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import AdminForth, { AdminForthPlugin, suggestIfTypo, Filters, afLogger } from "adminforth";
|
|
11
11
|
import { z } from "zod";
|
|
12
|
-
import { randomUUID } from "crypto";
|
|
12
|
+
import { createHash, randomUUID } from "crypto";
|
|
13
13
|
const setPasswordBodySchema = z.object({
|
|
14
14
|
token: z.string(),
|
|
15
15
|
password: z.string(),
|
|
@@ -120,6 +120,9 @@ export default class EmailInvitePlugin extends AdminForthPlugin {
|
|
|
120
120
|
instanceUniqueRepresentation(pluginOptions) {
|
|
121
121
|
return `single`;
|
|
122
122
|
}
|
|
123
|
+
passwordHashDigest(passwordHash) {
|
|
124
|
+
return createHash('sha256').update(passwordHash || '').digest('hex').slice(0, 16);
|
|
125
|
+
}
|
|
123
126
|
handleUserCreation(_a) {
|
|
124
127
|
return __awaiter(this, arguments, void 0, function* ({ resource, adminUser, record, adminforth, extra }) {
|
|
125
128
|
try {
|
|
@@ -145,15 +148,19 @@ export default class EmailInvitePlugin extends AdminForthPlugin {
|
|
|
145
148
|
var _b, _c;
|
|
146
149
|
try {
|
|
147
150
|
const email = record[this.options.emailField];
|
|
151
|
+
const newRecordId = record[this.authResource.columns.find(col => col.primaryKey).name];
|
|
148
152
|
if (!email || !/\S+@\S+\.\S+/.test(email)) {
|
|
149
153
|
console.warn('Email invite plugin: Invalid or missing email address');
|
|
150
154
|
return { ok: true }; // Don't fail user creation for email issues
|
|
151
155
|
}
|
|
152
156
|
const brandName = adminforth.config.customization.brandName || 'Admin Panel';
|
|
153
|
-
const inviteToken = adminforth.auth.issueJWT({
|
|
157
|
+
const inviteToken = adminforth.auth.issueJWT({
|
|
158
|
+
email,
|
|
159
|
+
recordId: newRecordId,
|
|
160
|
+
inviteEmail: true,
|
|
161
|
+
ph: this.passwordHashDigest(record[this.adminforth.config.auth.passwordHashField])
|
|
162
|
+
}, 'inviteUser', '7d' // 7 days validity
|
|
154
163
|
);
|
|
155
|
-
console.log('Sending invite email to:', email);
|
|
156
|
-
console.log('Generated JWT token payload:', { email, recordId, inviteEmail: true });
|
|
157
164
|
const host = ((_b = extra === null || extra === void 0 ? void 0 : extra.headers) === null || _b === void 0 ? void 0 : _b.host) || 'localhost';
|
|
158
165
|
const protocol = ((_c = extra === null || extra === void 0 ? void 0 : extra.headers) === null || _c === void 0 ? void 0 : _c['x-forwarded-proto']) || 'http';
|
|
159
166
|
const inviteUrl = `${protocol}://${host}/set-password?token=${inviteToken}`;
|
|
@@ -220,6 +227,9 @@ export default class EmailInvitePlugin extends AdminForthPlugin {
|
|
|
220
227
|
if (recordId) {
|
|
221
228
|
userRecord = yield this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.authResource.columns.find(c => c.primaryKey).name, recordId));
|
|
222
229
|
}
|
|
230
|
+
if (decoded.ph !== this.passwordHashDigest(userRecord[this.adminforth.config.auth.passwordHashField])) {
|
|
231
|
+
return { error: 'Token has already been used', ok: false };
|
|
232
|
+
}
|
|
223
233
|
if (!userRecord && email) {
|
|
224
234
|
const records = yield this.adminforth.resource(this.authResource.resourceId).list(Filters.EQ(this.options.emailField, email), 1);
|
|
225
235
|
userRecord = records.length > 0 ? records[0] : null;
|
|
@@ -227,7 +237,7 @@ export default class EmailInvitePlugin extends AdminForthPlugin {
|
|
|
227
237
|
if (!userRecord) {
|
|
228
238
|
return { error: 'User not found', ok: false };
|
|
229
239
|
}
|
|
230
|
-
if (userRecord[this.options.emailConfirmedField]) {
|
|
240
|
+
if (this.options.emailConfirmedField && userRecord[this.options.emailConfirmedField]) {
|
|
231
241
|
return { error: 'Password already set. Invitation link cannot be reused.', ok: false };
|
|
232
242
|
}
|
|
233
243
|
const userEmail = userRecord[this.options.emailField];
|
package/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import AdminForth, { AdminForthPlugin, suggestIfTypo, Filters, afLogger } from "
|
|
|
2
2
|
import type { IAdminForth, IHttpServer, AdminForthResourcePages, AdminForthResourceColumn, AdminForthDataTypes, AdminForthResource, AdminUser, HttpExtra } from "adminforth";
|
|
3
3
|
import type { PluginOptions } from './types.js';
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { randomUUID } from "crypto";
|
|
5
|
+
import { createHash, randomUUID } from "crypto";
|
|
6
6
|
|
|
7
7
|
const setPasswordBodySchema = z.object({
|
|
8
8
|
token: z.string(),
|
|
@@ -138,6 +138,11 @@ export default class EmailInvitePlugin extends AdminForthPlugin {
|
|
|
138
138
|
return `single`;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
passwordHashDigest(passwordHash: string | null | undefined): string {
|
|
142
|
+
return createHash('sha256').update(passwordHash || '').digest('hex').slice(0, 16);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
141
146
|
async handleUserCreation({ resource, adminUser, record, adminforth, extra }: {
|
|
142
147
|
resource: AdminForthResource;
|
|
143
148
|
adminUser: AdminUser;
|
|
@@ -175,6 +180,7 @@ export default class EmailInvitePlugin extends AdminForthPlugin {
|
|
|
175
180
|
}): Promise<{ok: boolean, error?: string}> {
|
|
176
181
|
try {
|
|
177
182
|
const email = record[this.options.emailField];
|
|
183
|
+
const newRecordId = record[this.authResource.columns.find(col => col.primaryKey)!.name];
|
|
178
184
|
|
|
179
185
|
if (!email || !/\S+@\S+\.\S+/.test(email)) {
|
|
180
186
|
console.warn('Email invite plugin: Invalid or missing email address');
|
|
@@ -182,16 +188,18 @@ export default class EmailInvitePlugin extends AdminForthPlugin {
|
|
|
182
188
|
}
|
|
183
189
|
|
|
184
190
|
const brandName = adminforth.config.customization.brandName || 'Admin Panel';
|
|
185
|
-
|
|
191
|
+
|
|
186
192
|
const inviteToken = adminforth.auth.issueJWT(
|
|
187
|
-
{
|
|
193
|
+
{
|
|
194
|
+
email,
|
|
195
|
+
recordId: newRecordId,
|
|
196
|
+
inviteEmail: true,
|
|
197
|
+
ph: this.passwordHashDigest(record[this.adminforth.config.auth.passwordHashField])
|
|
198
|
+
},
|
|
188
199
|
'inviteUser',
|
|
189
200
|
'7d' // 7 days validity
|
|
190
201
|
);
|
|
191
202
|
|
|
192
|
-
console.log('Sending invite email to:', email);
|
|
193
|
-
console.log('Generated JWT token payload:', { email, recordId, inviteEmail: true });
|
|
194
|
-
|
|
195
203
|
const host = extra?.headers?.host || 'localhost';
|
|
196
204
|
const protocol = extra?.headers?.['x-forwarded-proto'] || 'http';
|
|
197
205
|
const inviteUrl = `${protocol}://${host}/set-password?token=${inviteToken}`;
|
|
@@ -271,6 +279,10 @@ export default class EmailInvitePlugin extends AdminForthPlugin {
|
|
|
271
279
|
userRecord = await this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.authResource.columns.find(c => c.primaryKey).name, recordId));
|
|
272
280
|
}
|
|
273
281
|
|
|
282
|
+
if (decoded.ph !== this.passwordHashDigest(userRecord[this.adminforth.config.auth.passwordHashField])) {
|
|
283
|
+
return { error: 'Token has already been used', ok: false };
|
|
284
|
+
}
|
|
285
|
+
|
|
274
286
|
if (!userRecord && email) {
|
|
275
287
|
const records = await this.adminforth.resource(this.authResource.resourceId).list(
|
|
276
288
|
Filters.EQ(this.options.emailField, email),
|
|
@@ -282,7 +294,7 @@ export default class EmailInvitePlugin extends AdminForthPlugin {
|
|
|
282
294
|
return { error: 'User not found', ok: false };
|
|
283
295
|
}
|
|
284
296
|
|
|
285
|
-
if ( userRecord[this.options.emailConfirmedField] ) {
|
|
297
|
+
if ( this.options.emailConfirmedField && userRecord[this.options.emailConfirmedField] ) {
|
|
286
298
|
return { error: 'Password already set. Invitation link cannot be reused.', ok: false };
|
|
287
299
|
}
|
|
288
300
|
const userEmail = userRecord[this.options.emailField];
|