@adminforth/open-signup 1.0.0
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/.woodpecker/buildRelease.sh +13 -0
- package/.woodpecker/buildSlackNotify.sh +44 -0
- package/.woodpecker/release.yml +42 -0
- package/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/build.log +12 -0
- package/custom/SignupPage.vue +337 -0
- package/custom/SignupUnderLogin.vue +16 -0
- package/custom/tsconfig.json +19 -0
- package/dist/custom/SignupPage.vue +337 -0
- package/dist/custom/SignupUnderLogin.vue +16 -0
- package/dist/custom/tsconfig.json +19 -0
- package/dist/index.js +291 -0
- package/dist/types.js +1 -0
- package/index.ts +346 -0
- package/package.json +55 -0
- package/tsconfig.json +12 -0
- package/types.ts +68 -0
package/index.ts
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import AdminForth, { AdminForthPlugin, Filters, suggestIfTypo, AdminForthDataTypes } from "adminforth";
|
|
2
|
+
import type { IAdminForth, IHttpServer, AdminForthComponentDeclaration, AdminForthResourceColumn, AdminForthResource, BeforeLoginConfirmationFunction, HttpExtra } from "adminforth";
|
|
3
|
+
import type { PluginOptions } from './types.js';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
7
|
+
options: PluginOptions;
|
|
8
|
+
emailField: AdminForthResourceColumn;
|
|
9
|
+
passwordField: AdminForthResourceColumn;
|
|
10
|
+
authResource: AdminForthResource;
|
|
11
|
+
emailConfirmedField?: AdminForthResourceColumn;
|
|
12
|
+
|
|
13
|
+
adminforth: IAdminForth;
|
|
14
|
+
|
|
15
|
+
constructor(options: PluginOptions) {
|
|
16
|
+
super(options, import.meta.url);
|
|
17
|
+
this.options = options;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async modifyResourceConfig(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
|
|
21
|
+
super.modifyResourceConfig(adminforth, resourceConfig);
|
|
22
|
+
|
|
23
|
+
if (!this.options.emailField) {
|
|
24
|
+
throw new Error(`emailField is required and should be a name of field in auth resource`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// find field with name resourceConfig.emailField in adminforth.auth.usersResourceId and show error if it doesn't exist
|
|
28
|
+
const authResource = adminforth.config.resources.find(r => r.resourceId === adminforth.config.auth.usersResourceId);
|
|
29
|
+
if (!authResource) {
|
|
30
|
+
throw new Error(`Resource with id config.auth.usersResourceId=${adminforth.config.auth.usersResourceId} not found`);
|
|
31
|
+
}
|
|
32
|
+
this.authResource = authResource;
|
|
33
|
+
|
|
34
|
+
if (this.options.confirmEmails) {
|
|
35
|
+
if (!this.options.confirmEmails.adapter) {
|
|
36
|
+
throw new Error(`confirmEmails.adapter is required and should be a name of field in auth resource`);
|
|
37
|
+
}
|
|
38
|
+
if (!this.options.confirmEmails.emailConfirmedField) {
|
|
39
|
+
throw new Error(`confirmEmails.emailConfirmedField is required and should be a name of field in auth resource`);
|
|
40
|
+
}
|
|
41
|
+
const emailConfirmedField = this.authResource.columns.find(f => f.name === this.options.confirmEmails.emailConfirmedField);
|
|
42
|
+
if (!emailConfirmedField) {
|
|
43
|
+
const similar = suggestIfTypo(this.authResource.columns.map(f => f.name), this.options.confirmEmails.emailConfirmedField);
|
|
44
|
+
throw new Error(`Field with name ${this.options.confirmEmails.emailConfirmedField} not found in resource ${this.authResource.resourceId}.
|
|
45
|
+
${similar ? `Did you mean ${similar}?` : ''}
|
|
46
|
+
`);
|
|
47
|
+
}
|
|
48
|
+
this.emailConfirmedField = emailConfirmedField;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const emailField = authResource.columns.find(f => f.name === this.options.emailField);
|
|
52
|
+
if (!emailField) {
|
|
53
|
+
const similar = suggestIfTypo(authResource.columns.map(f => f.name), this.options.emailField);
|
|
54
|
+
|
|
55
|
+
throw new Error(`Field with name ${this.options.emailField} not found in resource ${authResource.resourceId}.
|
|
56
|
+
${similar ? `Did you mean ${similar}?` : ''}
|
|
57
|
+
`);
|
|
58
|
+
}
|
|
59
|
+
this.emailField = emailField;
|
|
60
|
+
|
|
61
|
+
if (!this.options.passwordField) {
|
|
62
|
+
throw new Error(`passwordField is required to get password constraints and should be a name of virtual field in auth resource`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const passwordField: AdminForthResourceColumn = authResource.columns.find(f => f.name === this.options.passwordField);
|
|
66
|
+
if (!passwordField) {
|
|
67
|
+
const similar = suggestIfTypo(authResource.columns.map(f => f.name), this.options.passwordField);
|
|
68
|
+
throw new Error(`Field with name ${this.options.passwordField} not found in resource ${authResource.resourceId}.
|
|
69
|
+
${similar ? `Did you mean ${similar}?` : ''}
|
|
70
|
+
`);
|
|
71
|
+
}
|
|
72
|
+
this.passwordField = passwordField;
|
|
73
|
+
|
|
74
|
+
(adminforth.config.customization.loginPageInjections.underInputs as AdminForthComponentDeclaration[]).push({
|
|
75
|
+
file: this.componentPath('SignupUnderLogin.vue'),
|
|
76
|
+
});
|
|
77
|
+
adminforth.config.customization.customPages.push({
|
|
78
|
+
path: '/signup',
|
|
79
|
+
component: {
|
|
80
|
+
file: this.componentPath('SignupPage.vue'),
|
|
81
|
+
meta: {
|
|
82
|
+
customLayout: true,
|
|
83
|
+
pluginInstanceId: this.pluginInstanceId,
|
|
84
|
+
requestEmailConfirmation: !!this.options.confirmEmails
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// for confirmation disable login if email is not confirmed
|
|
90
|
+
if (this.options.confirmEmails) {
|
|
91
|
+
if (!adminforth.config.auth.beforeLoginConfirmation) {
|
|
92
|
+
adminforth.config.auth.beforeLoginConfirmation = [];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
validateConfigAfterDiscover(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
|
|
98
|
+
if (this.options.confirmEmails) {
|
|
99
|
+
this.options.confirmEmails.adapter.validate();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if(this.options.confirmEmails){
|
|
104
|
+
const emailConfirmedColumn = this.resourceConfig.columns.find(f => f.name === this.options.confirmEmails.emailConfirmedField);
|
|
105
|
+
if (emailConfirmedColumn.type !== AdminForthDataTypes.BOOLEAN) {
|
|
106
|
+
throw new Error(`Field ${this.emailConfirmedField.name} must be of type boolean`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
instanceUniqueRepresentation(pluginOptions: any) : string {
|
|
112
|
+
// optional method to return unique string representation of plugin instance.
|
|
113
|
+
// Needed if plugin can have multiple instances on one resource
|
|
114
|
+
return `single`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async doLogin(email: string, response: any, extra: HttpExtra): Promise<{ error?: string; allowedLogin: boolean; redirectTo?: string; }> {
|
|
118
|
+
|
|
119
|
+
const username = email;
|
|
120
|
+
const userRecord = await this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
|
|
121
|
+
const adminUser = {
|
|
122
|
+
dbUser: userRecord,
|
|
123
|
+
pk: userRecord[this.authResource.columns.find((col) => col.primaryKey).name],
|
|
124
|
+
username,
|
|
125
|
+
};
|
|
126
|
+
const toReturn = { allowedLogin: true, error: '' };
|
|
127
|
+
|
|
128
|
+
await this.adminforth.restApi.processLoginCallbacks(adminUser, toReturn, response, extra);
|
|
129
|
+
if (toReturn.allowedLogin) {
|
|
130
|
+
this.adminforth.auth.setAuthCookie({
|
|
131
|
+
response,
|
|
132
|
+
username,
|
|
133
|
+
pk: userRecord[
|
|
134
|
+
this.authResource.columns.find((col) => col.primaryKey).name
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return toReturn;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
setupEndpoints(server: IHttpServer) {
|
|
144
|
+
|
|
145
|
+
server.endpoint({
|
|
146
|
+
method: 'GET',
|
|
147
|
+
path: `/plugin/${this.pluginInstanceId}/password-constraints`,
|
|
148
|
+
noAuth: true,
|
|
149
|
+
handler: async ({tr}) => {
|
|
150
|
+
return {
|
|
151
|
+
minLength: this.passwordField.minLength,
|
|
152
|
+
maxLength: this.passwordField.maxLength,
|
|
153
|
+
validation: await Promise.all(
|
|
154
|
+
this.passwordField.validation.map(async ({ regExp, message }) => ({ regExp, message: await tr(message, 'opensignup') }))
|
|
155
|
+
),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
server.endpoint({
|
|
161
|
+
method: 'POST',
|
|
162
|
+
path: `/plugin/${this.pluginInstanceId}/complete-verified-signup`,
|
|
163
|
+
noAuth: true,
|
|
164
|
+
handler: async ({ body, response, headers, query, cookies, tr, requestUrl }) => {
|
|
165
|
+
const { token, password } = body;
|
|
166
|
+
const { email } = await this.adminforth.auth.verify(token, 'tempVerifyEmailToken', false);
|
|
167
|
+
if (!email) {
|
|
168
|
+
return { error: 'Invalid token', ok: false };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if(!password) {
|
|
172
|
+
return { error: tr('Password is required', 'opensignup'), ok: false };
|
|
173
|
+
}
|
|
174
|
+
const userRecord = await this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
|
|
175
|
+
if (!userRecord) {
|
|
176
|
+
return { error: tr('User not found'), ok: false };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (userRecord[this.options.confirmEmails.emailConfirmedField]) {
|
|
180
|
+
return { error: tr('Email already confirmed'), ok: false };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
await this.adminforth.resource(this.authResource.resourceId).update(userRecord[this.authResource.columns.find((col) => col.primaryKey).name], {
|
|
184
|
+
[this.options.confirmEmails.emailConfirmedField]: true,
|
|
185
|
+
[this.options.passwordHashField]: await AdminForth.Utils.generatePasswordHash(password),
|
|
186
|
+
});
|
|
187
|
+
return await this.doLogin(email, response, { body, headers, query, cookies, requestUrl });
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
server.endpoint({
|
|
192
|
+
method: 'POST',
|
|
193
|
+
path: `/plugin/${this.pluginInstanceId}/signup`,
|
|
194
|
+
noAuth: true,
|
|
195
|
+
handler: async ({ body, response, headers, query, cookies, tr, requestUrl }) => {
|
|
196
|
+
const { email, url, password } = body;
|
|
197
|
+
const extra = { body, headers, query, cookies, requestUrl: url };
|
|
198
|
+
// validate email
|
|
199
|
+
if (this.emailField.validation) {
|
|
200
|
+
for (const { regExp, message } of this.emailField.validation) {
|
|
201
|
+
if (!new RegExp(regExp).test(email)) {
|
|
202
|
+
return { error: await tr(message, 'opensignup'), ok: false };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// validate password
|
|
208
|
+
if (!this.options.confirmEmails) {
|
|
209
|
+
if (password.length < this.passwordField.minLength) {
|
|
210
|
+
return {
|
|
211
|
+
error: await tr(`Password must be at least ${this.passwordField.minLength} characters long`, 'opensignup'),
|
|
212
|
+
ok: false
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
if (password.length > this.passwordField.maxLength) {
|
|
216
|
+
return {
|
|
217
|
+
error: await tr(`Password must be at most ${this.passwordField.maxLength} characters long`, 'opensignup'),
|
|
218
|
+
ok: false
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
if (this.passwordField.validation) {
|
|
222
|
+
for (const { regExp, message } of this.passwordField.validation) {
|
|
223
|
+
if (!new RegExp(regExp).test(password)) {
|
|
224
|
+
return { error: await tr(message, 'opensignup'), ok: false };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// This is not needed when right email validator is set on email field because
|
|
231
|
+
// it will not allow to create such email, but if user forgot to set it it might save situation
|
|
232
|
+
const normalizedEmail = email.toLowerCase(); // normalize email
|
|
233
|
+
|
|
234
|
+
// first check again if email already exists
|
|
235
|
+
const existingUser = await this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, normalizedEmail));
|
|
236
|
+
if ((!this.options.confirmEmails && existingUser) || (this.options.confirmEmails && existingUser?.[this.emailConfirmedField.name])) {
|
|
237
|
+
return { error: await tr(`Email already exists`, 'opensignup'), ok: false };
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// create user
|
|
241
|
+
if (!existingUser) {
|
|
242
|
+
if (this.options.hooks?.beforeUserSave) {
|
|
243
|
+
const hook = this.options.hooks.beforeUserSave;
|
|
244
|
+
const recordToCreate = {
|
|
245
|
+
...(this.options.defaultFieldValues || {}),
|
|
246
|
+
...(this.options.confirmEmails ? { [this.options.confirmEmails.emailConfirmedField]: false } : {}),
|
|
247
|
+
[this.emailField.name]: normalizedEmail,
|
|
248
|
+
[this.options.passwordHashField]: password ? await AdminForth.Utils.generatePasswordHash(password) : '',
|
|
249
|
+
};
|
|
250
|
+
const resp = await hook({
|
|
251
|
+
resource: this.authResource,
|
|
252
|
+
record: recordToCreate,
|
|
253
|
+
adminforth: this.adminforth,
|
|
254
|
+
extra,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
if (!resp || (!resp.ok && !resp.error)) {
|
|
258
|
+
throw new Error(`Hook beforeUserSave must return object with {ok: true} or { error: 'Error' } `);
|
|
259
|
+
}
|
|
260
|
+
if (resp.error) {
|
|
261
|
+
return { error: resp.error };
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const created = await this.adminforth.resource(this.authResource.resourceId).create({
|
|
265
|
+
...(this.options.defaultFieldValues || {}),
|
|
266
|
+
...(this.options.confirmEmails ? { [this.options.confirmEmails.emailConfirmedField]: false } : {}),
|
|
267
|
+
[this.emailField.name]: normalizedEmail,
|
|
268
|
+
[this.options.passwordHashField]: password ? await AdminForth.Utils.generatePasswordHash(password) : '',
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
if (this.options.hooks?.afterUserSave) {
|
|
272
|
+
const hook = this.options.hooks.afterUserSave;
|
|
273
|
+
const resp = await hook({
|
|
274
|
+
resource: this.authResource,
|
|
275
|
+
record: created,
|
|
276
|
+
adminforth: this.adminforth,
|
|
277
|
+
extra,
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
if (!resp || (!resp.ok && !resp.error)) {
|
|
281
|
+
throw new Error(`Hook afterUserSave must return object with {ok: true} or { error: 'Error' } `);
|
|
282
|
+
}
|
|
283
|
+
if (resp.error) {
|
|
284
|
+
return { error: resp.error };
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (!this.options.confirmEmails) {
|
|
290
|
+
const resp = await this.doLogin(email, response, { body, headers, query, cookies, requestUrl });
|
|
291
|
+
return resp;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// send confirmation email
|
|
295
|
+
|
|
296
|
+
const brandName = this.adminforth.config.customization.brandName;
|
|
297
|
+
|
|
298
|
+
const verifyToken = this.adminforth.auth.issueJWT({email, issuer: brandName }, 'tempVerifyEmailToken', '2h');
|
|
299
|
+
process.env.HEAVY_DEBUG && console.log('🐛Sending reset tok to', verifyToken);
|
|
300
|
+
const emailText = tr(`
|
|
301
|
+
Dear user,
|
|
302
|
+
Welcome to {brandName}!
|
|
303
|
+
|
|
304
|
+
To confirm your email, click the link below:\n\n
|
|
305
|
+
|
|
306
|
+
{url}?verifyToken={verifyToken}\n\n
|
|
307
|
+
|
|
308
|
+
If you didn't request this, please ignore this email.\n\n
|
|
309
|
+
Link is valid for 2 hours.\n\n
|
|
310
|
+
|
|
311
|
+
Thanks,
|
|
312
|
+
The {brandName} Team
|
|
313
|
+
|
|
314
|
+
`, 'opensignup', { brandName, url, verifyToken }
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
const emailHtml = tr(`
|
|
318
|
+
<html>
|
|
319
|
+
<head></head>
|
|
320
|
+
<body>
|
|
321
|
+
<p>Dear user,</p>
|
|
322
|
+
<p>Welcome to {brandName}!</p>
|
|
323
|
+
<p>To confirm your email, click the link below:</p>
|
|
324
|
+
<a href="{url}?token={verifyToken}">Confirm email</a>
|
|
325
|
+
<p>If you didn't request this, please ignore this email.</p>
|
|
326
|
+
<p>Link is valid for 2 hours.</p>
|
|
327
|
+
<p>Thanks,</p>
|
|
328
|
+
<p>The {brandName} Team</p>
|
|
329
|
+
</body>
|
|
330
|
+
</html>
|
|
331
|
+
`, 'opensignup', { brandName, url, verifyToken });
|
|
332
|
+
|
|
333
|
+
const emailSubject = tr(`Signup request at {brandName}`, 'opensignup', { brandName });
|
|
334
|
+
|
|
335
|
+
// send email with AWS SES this.options.providerOptions.AWS_SES
|
|
336
|
+
this.options.confirmEmails.adapter.sendEmail(this.options.confirmEmails.sendFrom, email, emailText, emailHtml, emailSubject);
|
|
337
|
+
|
|
338
|
+
return { ok: true };
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@adminforth/open-signup",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc && rsync -av --exclude 'node_modules' custom dist/",
|
|
9
|
+
"prepare": "npm link adminforth"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/devforth/adminforth-open-signup.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"adminforth",
|
|
17
|
+
"signup"
|
|
18
|
+
],
|
|
19
|
+
"author": "devforth",
|
|
20
|
+
"license": "ISC",
|
|
21
|
+
"description": "Open signup for adminforth",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@aws-sdk/client-ses": "^3.654.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^22.10.7",
|
|
27
|
+
"semantic-release": "^24.2.1",
|
|
28
|
+
"semantic-release-slack-bot": "^4.0.2",
|
|
29
|
+
"typescript": "^5.7.3"
|
|
30
|
+
},
|
|
31
|
+
"release": {
|
|
32
|
+
"plugins": [
|
|
33
|
+
"@semantic-release/commit-analyzer",
|
|
34
|
+
"@semantic-release/release-notes-generator",
|
|
35
|
+
"@semantic-release/npm",
|
|
36
|
+
"@semantic-release/github",
|
|
37
|
+
[
|
|
38
|
+
"semantic-release-slack-bot",
|
|
39
|
+
{
|
|
40
|
+
"notifyOnSuccess": true,
|
|
41
|
+
"notifyOnFail": true,
|
|
42
|
+
"slackIcon": ":package:",
|
|
43
|
+
"markdownReleaseNotes": true
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
],
|
|
47
|
+
"branches": [
|
|
48
|
+
"main",
|
|
49
|
+
{
|
|
50
|
+
"name": "next",
|
|
51
|
+
"prerelease": true
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include*/
|
|
4
|
+
"module": "node16", /* Specify what module code is generated. */
|
|
5
|
+
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
|
6
|
+
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. */
|
|
7
|
+
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
|
8
|
+
"strict": false, /* Enable all strict type-checking options. */
|
|
9
|
+
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
|
|
10
|
+
},
|
|
11
|
+
"exclude": ["node_modules", "dist", "custom"], /* Exclude files from compilation. */
|
|
12
|
+
}
|
package/types.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { EmailAdapter } from 'adminforth';
|
|
2
|
+
|
|
3
|
+
export interface PluginOptions {
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Field name in auth resource which contains email
|
|
7
|
+
*/
|
|
8
|
+
emailField: string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* To work properly, this plugin requires a virtual password field in auth resource,
|
|
12
|
+
* which will define any constraints which determine the password strength (regex, minLength).
|
|
13
|
+
* When user will enter passowrd, it will be validated against this field constraints
|
|
14
|
+
* If you don't need it in backoffice itself, you can add it and set showIn = []
|
|
15
|
+
*/
|
|
16
|
+
passwordField: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Non-virtual field name in auth resource which contains password hash
|
|
20
|
+
*/
|
|
21
|
+
passwordHashField: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Default which will be assigned to user by default
|
|
25
|
+
* e.g. can be used to set default role
|
|
26
|
+
*/
|
|
27
|
+
defaultFieldValues?: {
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* If not set user will not be asked for email confirmation (might be dangerous)
|
|
36
|
+
*/
|
|
37
|
+
confirmEmails?: {
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A boolean field in auth resource which will be set to true when email is confirmed.
|
|
41
|
+
* Must have boolean type.
|
|
42
|
+
*/
|
|
43
|
+
emailConfirmedField: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* From which email to send password reset emails
|
|
47
|
+
* e.g. no-reply@example.com
|
|
48
|
+
* Example.com must be allowed in provider to send emails
|
|
49
|
+
*/
|
|
50
|
+
sendFrom: string;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Adapter to send emails
|
|
54
|
+
*/
|
|
55
|
+
adapter: EmailAdapter;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Hooks to be executed before and after user is created
|
|
61
|
+
*/
|
|
62
|
+
hooks?: {
|
|
63
|
+
beforeUserSave?: any;
|
|
64
|
+
afterUserSave?: any;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
}
|