@nymphjs/tilmeld 1.0.0-beta.13 → 1.0.0-beta.131
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/CHANGELOG.md +604 -0
- package/README.md +21 -5
- package/dist/AbleObject.d.ts +15 -0
- package/dist/AbleObject.js +18 -6
- package/dist/AbleObject.js.map +1 -1
- package/dist/Group.d.ts +183 -19
- package/dist/Group.js +814 -440
- package/dist/Group.js.map +1 -1
- package/dist/Group.testArtifacts.d.ts +3 -0
- package/dist/Group.testArtifacts.js +120 -0
- package/dist/Group.testArtifacts.js.map +1 -0
- package/dist/Tilmeld.d.ts +241 -12
- package/dist/Tilmeld.js +725 -286
- package/dist/Tilmeld.js.map +1 -1
- package/dist/Tilmeld.types.d.ts +5 -5
- package/dist/Tilmeld.types.js +1 -2
- package/dist/User.d.ts +396 -26
- package/dist/User.js +1955 -1058
- package/dist/User.js.map +1 -1
- package/dist/User.testArtifacts.d.ts +3 -0
- package/dist/User.testArtifacts.js +175 -0
- package/dist/User.testArtifacts.js.map +1 -0
- package/dist/conf/defaults.d.ts +1 -1
- package/dist/conf/defaults.js +196 -141
- package/dist/conf/defaults.js.map +1 -1
- package/dist/conf/index.d.ts +355 -2
- package/dist/conf/index.js +2 -8
- package/dist/conf/index.js.map +1 -1
- package/dist/decorators/index.d.ts +2 -0
- package/dist/decorators/index.js +3 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/requireAbility.d.ts +10 -0
- package/dist/decorators/requireAbility.js +21 -0
- package/dist/decorators/requireAbility.js.map +1 -0
- package/dist/decorators/requireAuthentication.d.ts +8 -0
- package/dist/decorators/requireAuthentication.js +16 -0
- package/dist/decorators/requireAuthentication.js.map +1 -0
- package/dist/enforceTilmeld.d.ts +3 -0
- package/dist/enforceTilmeld.js +18 -0
- package/dist/enforceTilmeld.js.map +1 -0
- package/dist/errors/AccessControlError.d.ts +2 -1
- package/dist/errors/AccessControlError.js +3 -6
- package/dist/errors/AccessControlError.js.map +1 -1
- package/dist/errors/BadDataError.d.ts +2 -1
- package/dist/errors/BadDataError.js +3 -6
- package/dist/errors/BadDataError.js.map +1 -1
- package/dist/errors/BadEmailError.d.ts +2 -1
- package/dist/errors/BadEmailError.js +3 -6
- package/dist/errors/BadEmailError.js.map +1 -1
- package/dist/errors/BadUsernameError.d.ts +2 -1
- package/dist/errors/BadUsernameError.js +3 -6
- package/dist/errors/BadUsernameError.js.map +1 -1
- package/dist/errors/CouldNotChangeDefaultPrimaryGroupError.js +1 -5
- package/dist/errors/CouldNotChangeDefaultPrimaryGroupError.js.map +1 -1
- package/dist/errors/EmailChangeRateLimitExceededError.js +1 -5
- package/dist/errors/EmailChangeRateLimitExceededError.js.map +1 -1
- package/dist/errors/index.d.ts +6 -6
- package/dist/errors/index.js +6 -22
- package/dist/errors/index.js.map +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/index.js +17 -35
- package/dist/index.js.map +1 -1
- package/dist/testArtifacts.d.ts +23 -0
- package/dist/testArtifacts.js +1317 -0
- package/dist/testArtifacts.js.map +1 -0
- package/dist/tilmeldJoiProps.d.ts +3 -3
- package/dist/tilmeldJoiProps.js +13 -18
- package/dist/tilmeldJoiProps.js.map +1 -1
- package/jest.config.js +31 -5
- package/package.json +49 -36
- package/src/AbleObject.ts +2 -2
- package/src/Group.testArtifacts.ts +159 -0
- package/src/Group.ts +647 -241
- package/src/Tilmeld.ts +550 -315
- package/src/Tilmeld.types.ts +5 -5
- package/src/User.testArtifacts.ts +226 -0
- package/src/User.ts +1657 -637
- package/src/conf/defaults.ts +172 -109
- package/src/conf/index.ts +370 -2
- package/src/decorators/index.ts +2 -0
- package/src/decorators/requireAbility.ts +26 -0
- package/src/decorators/requireAuthentication.ts +19 -0
- package/src/enforceTilmeld.ts +20 -0
- package/src/errors/AccessControlError.ts +4 -2
- package/src/errors/BadDataError.ts +4 -2
- package/src/errors/BadEmailError.ts +4 -2
- package/src/errors/BadUsernameError.ts +4 -2
- package/src/errors/index.ts +6 -6
- package/src/index.ts +13 -10
- package/src/testArtifacts.ts +2098 -0
- package/src/tilmeldJoiProps.ts +8 -23
- package/tsconfig.json +6 -3
- package/typedoc.json +4 -0
- package/dist/Group.test.d.ts +0 -1
- package/dist/Group.test.js +0 -48
- package/dist/Group.test.js.map +0 -1
- package/dist/User.test.d.ts +0 -1
- package/dist/User.test.js +0 -51
- package/dist/User.test.js.map +0 -1
- package/dist/conf/d.d.ts +0 -55
- package/dist/conf/d.js +0 -3
- package/dist/conf/d.js.map +0 -1
- package/src/Group.test.ts +0 -58
- package/src/User.test.ts +0 -61
- package/src/conf/d.ts +0 -303
package/src/conf/defaults.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import { URL } from 'url';
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { URL, fileURLToPath } from 'node:url';
|
|
3
3
|
import jwt from 'jsonwebtoken';
|
|
4
4
|
import Email from 'email-templates';
|
|
5
5
|
import Joi from 'joi';
|
|
6
6
|
import { nanoid } from '@nymphjs/guid';
|
|
7
7
|
import { nymphJoiProps } from '@nymphjs/nymph';
|
|
8
8
|
|
|
9
|
-
import { Config } from './
|
|
10
|
-
import User from '../User';
|
|
11
|
-
import Group from '../Group';
|
|
9
|
+
import type { Config } from './index.js';
|
|
10
|
+
import User from '../User.js';
|
|
11
|
+
import Group from '../Group.js';
|
|
12
|
+
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
14
|
|
|
13
15
|
export default {
|
|
14
16
|
appName: 'My Nymph App',
|
|
@@ -18,6 +20,7 @@ export default {
|
|
|
18
20
|
setupPath: '/tilmeld',
|
|
19
21
|
createAdmin: true,
|
|
20
22
|
emailUsernames: true,
|
|
23
|
+
domainSupport: false,
|
|
21
24
|
allowRegistration: true,
|
|
22
25
|
allowUsernameChange: true,
|
|
23
26
|
enableUserSearch: false,
|
|
@@ -49,11 +52,16 @@ export default {
|
|
|
49
52
|
validEmailRegex:
|
|
50
53
|
/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
|
|
51
54
|
validEmailRegexNotice: 'Email must be a correctly formatted address.',
|
|
55
|
+
validDomainRegex:
|
|
56
|
+
/^(((?!-))(xn--|_)?[a-z0-9\-]{0,61}[a-z0-9]{1,1}\.)*(xn--)?([a-z0-9][a-z0-9\-]{0,60}|[a-z0-9\-]{1,30}\.[a-z]{2,})$/,
|
|
57
|
+
validDomainRegexNotice: 'Domain must be a correctly formatted domain name.',
|
|
58
|
+
minUsernameLength: 1,
|
|
52
59
|
maxUsernameLength: 128,
|
|
53
60
|
jwtSecret: '',
|
|
54
|
-
jwtExpire: 60 * 60 * 24 * 7 *
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
jwtExpire: 60 * 60 * 24 * 7 * 24, // 24 weeks(ish) (6 months)
|
|
62
|
+
jwtSwitchExpire: 60 * 60 * 6, // 6 hours
|
|
63
|
+
jwtRenew: 60 * 60 * 24 * 7 * 12, // 12 weeks(ish) (3 months)
|
|
64
|
+
jwtBuilder: (config, user, switchToken) => {
|
|
57
65
|
const secret = config.jwtSecret;
|
|
58
66
|
if (secret === '') {
|
|
59
67
|
throw new Error('JWT secret is not configured.');
|
|
@@ -62,12 +70,14 @@ export default {
|
|
|
62
70
|
return jwt.sign(
|
|
63
71
|
{
|
|
64
72
|
iss: config.appUrl,
|
|
65
|
-
nbf: Date.now() / 1000,
|
|
73
|
+
nbf: Math.floor(Date.now() / 1000),
|
|
74
|
+
exp:
|
|
75
|
+
Math.floor(Date.now() / 1000) +
|
|
76
|
+
(switchToken ? config.jwtSwitchExpire : config.jwtExpire),
|
|
66
77
|
guid: user.guid,
|
|
67
78
|
xsrfToken: 'TILMELDXSRF-' + nanoid(),
|
|
68
79
|
},
|
|
69
80
|
secret,
|
|
70
|
-
{ expiresIn: config.jwtExpire }
|
|
71
81
|
);
|
|
72
82
|
},
|
|
73
83
|
jwtExtract: (config, token, xsrfToken?) => {
|
|
@@ -79,14 +89,14 @@ export default {
|
|
|
79
89
|
try {
|
|
80
90
|
const payload = jwt.verify(token, secret, {
|
|
81
91
|
issuer: config.appUrl,
|
|
82
|
-
clockTolerance:
|
|
92
|
+
clockTolerance: 60,
|
|
83
93
|
});
|
|
84
94
|
|
|
85
95
|
if (typeof payload === 'string') {
|
|
86
96
|
return null;
|
|
87
97
|
}
|
|
88
98
|
|
|
89
|
-
const { guid, xsrfToken: jwtXsrfToken, exp } = payload;
|
|
99
|
+
const { guid, xsrfToken: jwtXsrfToken, exp, nbf } = payload;
|
|
90
100
|
|
|
91
101
|
if (xsrfToken != null && xsrfToken !== jwtXsrfToken) {
|
|
92
102
|
return null;
|
|
@@ -96,13 +106,19 @@ export default {
|
|
|
96
106
|
return null;
|
|
97
107
|
}
|
|
98
108
|
|
|
109
|
+
if (nbf == null) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const issued = new Date(nbf * 1000);
|
|
114
|
+
|
|
99
115
|
if (exp == null) {
|
|
100
116
|
return null;
|
|
101
117
|
}
|
|
102
118
|
|
|
103
119
|
const expire = new Date(exp * 1000);
|
|
104
120
|
|
|
105
|
-
return { guid, expire };
|
|
121
|
+
return { guid, issued, expire };
|
|
106
122
|
} catch (e: any) {
|
|
107
123
|
return null;
|
|
108
124
|
}
|
|
@@ -117,18 +133,21 @@ export default {
|
|
|
117
133
|
address: `noreply@${appUrl.hostname}`,
|
|
118
134
|
},
|
|
119
135
|
},
|
|
136
|
+
preview: {
|
|
137
|
+
openSimulator: false,
|
|
138
|
+
},
|
|
120
139
|
};
|
|
121
140
|
},
|
|
122
141
|
sendEmail: async (tilmeld, options, user) => {
|
|
123
142
|
const email = new Email(
|
|
124
|
-
await tilmeld.config.configEmail(tilmeld, options, user)
|
|
143
|
+
await tilmeld.config.configEmail(tilmeld, options, user),
|
|
125
144
|
);
|
|
126
145
|
try {
|
|
127
146
|
const result = await email.send({
|
|
128
147
|
...options,
|
|
129
148
|
template: path.join(
|
|
130
149
|
tilmeld.config.emailTemplateDir,
|
|
131
|
-
options.template ?? '.'
|
|
150
|
+
options.template ?? '.',
|
|
132
151
|
),
|
|
133
152
|
locals: {
|
|
134
153
|
// System
|
|
@@ -156,29 +175,55 @@ export default {
|
|
|
156
175
|
});
|
|
157
176
|
return !!result;
|
|
158
177
|
} catch (e: any) {
|
|
178
|
+
tilmeld.nymph.config.debugError('tilmeld', `Failed to send email: ${e}`);
|
|
159
179
|
return false;
|
|
160
180
|
}
|
|
161
181
|
},
|
|
162
182
|
userRegisteredRecipient: null,
|
|
163
|
-
|
|
183
|
+
failedLoginAttempt: (_user, _data) => {
|
|
184
|
+
// Wait 3-5 seconds to return a failure. This rate limits failed login
|
|
185
|
+
// attempts.
|
|
186
|
+
return new Promise((resolve) =>
|
|
187
|
+
setTimeout(resolve, Math.random() * 2000 + 3000),
|
|
188
|
+
);
|
|
189
|
+
},
|
|
190
|
+
validatorGroup: (tilmeld, group) => {
|
|
191
|
+
const nameFields = tilmeld.config.userFields.includes('name')
|
|
192
|
+
? {
|
|
193
|
+
name: Joi.string()
|
|
194
|
+
.trim(false)
|
|
195
|
+
.pattern(/[\x01-\x1F\x7F]/, {
|
|
196
|
+
name: 'control characters',
|
|
197
|
+
invert: true,
|
|
198
|
+
})
|
|
199
|
+
.max(512)
|
|
200
|
+
.required(),
|
|
201
|
+
}
|
|
202
|
+
: {};
|
|
203
|
+
const emailFields = tilmeld.config.userFields.includes('email')
|
|
204
|
+
? {
|
|
205
|
+
email: Joi.string()
|
|
206
|
+
.trim(false)
|
|
207
|
+
.email({ minDomainSegments: 1, tlds: false })
|
|
208
|
+
.required(),
|
|
209
|
+
}
|
|
210
|
+
: {};
|
|
211
|
+
const phoneFields = tilmeld.config.userFields.includes('phone')
|
|
212
|
+
? {
|
|
213
|
+
phone: Joi.string()
|
|
214
|
+
.trim(false)
|
|
215
|
+
.pattern(/^[0-9]+$/, 'numbers'),
|
|
216
|
+
}
|
|
217
|
+
: {};
|
|
164
218
|
Joi.attempt(
|
|
165
219
|
group.$getValidatable(),
|
|
166
220
|
Joi.object().keys({
|
|
167
221
|
...nymphJoiProps,
|
|
222
|
+
...nameFields,
|
|
223
|
+
...emailFields,
|
|
224
|
+
...phoneFields,
|
|
168
225
|
groupname: Joi.string().trim(false).required(),
|
|
169
226
|
enabled: Joi.boolean().required(),
|
|
170
|
-
email: Joi.string()
|
|
171
|
-
.trim(false)
|
|
172
|
-
.email({ minDomainSegments: 1, tlds: false })
|
|
173
|
-
.required(),
|
|
174
|
-
name: Joi.string()
|
|
175
|
-
.trim(false)
|
|
176
|
-
.pattern(/[\x01-\x1F\x7F]/, {
|
|
177
|
-
name: 'control characters',
|
|
178
|
-
invert: true,
|
|
179
|
-
})
|
|
180
|
-
.max(512)
|
|
181
|
-
.required(),
|
|
182
227
|
avatar: Joi.string()
|
|
183
228
|
.trim(false)
|
|
184
229
|
.uri()
|
|
@@ -187,9 +232,6 @@ export default {
|
|
|
187
232
|
invert: true,
|
|
188
233
|
})
|
|
189
234
|
.max(1024),
|
|
190
|
-
phone: Joi.string()
|
|
191
|
-
.trim(false)
|
|
192
|
-
.pattern(/^[0-9]+$/, 'numbers'),
|
|
193
235
|
parent: Joi.object().instance(Group),
|
|
194
236
|
user: Joi.object().instance(User),
|
|
195
237
|
abilities: Joi.array().items(
|
|
@@ -198,56 +240,110 @@ export default {
|
|
|
198
240
|
name: 'control characters',
|
|
199
241
|
invert: true,
|
|
200
242
|
})
|
|
201
|
-
.max(256)
|
|
243
|
+
.max(256),
|
|
202
244
|
),
|
|
203
245
|
defaultPrimary: Joi.boolean(),
|
|
204
246
|
defaultSecondary: Joi.boolean(),
|
|
205
247
|
unverifiedSecondary: Joi.boolean(),
|
|
206
248
|
}),
|
|
207
|
-
'Invalid Group: '
|
|
249
|
+
'Invalid Group: ',
|
|
208
250
|
);
|
|
209
251
|
},
|
|
210
|
-
validatorUser: (user) => {
|
|
252
|
+
validatorUser: (tilmeld, user) => {
|
|
253
|
+
const nameFields = tilmeld.config.userFields.includes('name')
|
|
254
|
+
? {
|
|
255
|
+
nameFirst: Joi.string()
|
|
256
|
+
.trim(false)
|
|
257
|
+
.pattern(/[\x01-\x1F\x7F]/, {
|
|
258
|
+
name: 'control characters',
|
|
259
|
+
invert: true,
|
|
260
|
+
})
|
|
261
|
+
.max(512)
|
|
262
|
+
.required(),
|
|
263
|
+
nameMiddle: Joi.string()
|
|
264
|
+
.trim(false)
|
|
265
|
+
.pattern(/[\x01-\x1F\x7F]/, {
|
|
266
|
+
name: 'control characters',
|
|
267
|
+
invert: true,
|
|
268
|
+
})
|
|
269
|
+
.max(512),
|
|
270
|
+
nameLast: Joi.string()
|
|
271
|
+
.trim(false)
|
|
272
|
+
.pattern(/[\x01-\x1F\x7F]/, {
|
|
273
|
+
name: 'control characters',
|
|
274
|
+
invert: true,
|
|
275
|
+
})
|
|
276
|
+
.max(512),
|
|
277
|
+
name: Joi.string()
|
|
278
|
+
.trim(false)
|
|
279
|
+
.pattern(/[\x01-\x1F\x7F]/, {
|
|
280
|
+
name: 'control characters',
|
|
281
|
+
invert: true,
|
|
282
|
+
})
|
|
283
|
+
.max(512)
|
|
284
|
+
.required(),
|
|
285
|
+
}
|
|
286
|
+
: {};
|
|
287
|
+
const emailFields = tilmeld.config.userFields.includes('email')
|
|
288
|
+
? {
|
|
289
|
+
email: Joi.string()
|
|
290
|
+
.trim(false)
|
|
291
|
+
.email({ minDomainSegments: 1, tlds: false })
|
|
292
|
+
.required(),
|
|
293
|
+
secret: Joi.string()
|
|
294
|
+
.trim(false)
|
|
295
|
+
.pattern(/[\x01-\x1F\x7F]/, {
|
|
296
|
+
name: 'control characters',
|
|
297
|
+
invert: true,
|
|
298
|
+
})
|
|
299
|
+
.length(21),
|
|
300
|
+
emailChangeDate: Joi.number(),
|
|
301
|
+
newEmailSecret: Joi.string()
|
|
302
|
+
.trim(false)
|
|
303
|
+
.pattern(/[\x01-\x1F\x7F]/, {
|
|
304
|
+
name: 'control characters',
|
|
305
|
+
invert: true,
|
|
306
|
+
})
|
|
307
|
+
.length(21),
|
|
308
|
+
newEmailAddress: Joi.string()
|
|
309
|
+
.trim(false)
|
|
310
|
+
.email({ minDomainSegments: 1, tlds: false }),
|
|
311
|
+
cancelEmailSecret: Joi.string()
|
|
312
|
+
.trim(false)
|
|
313
|
+
.pattern(/[\x01-\x1F\x7F]/, {
|
|
314
|
+
name: 'control characters',
|
|
315
|
+
invert: true,
|
|
316
|
+
})
|
|
317
|
+
.length(21),
|
|
318
|
+
cancelEmailAddress: Joi.string()
|
|
319
|
+
.trim(false)
|
|
320
|
+
.email({ minDomainSegments: 1, tlds: false }),
|
|
321
|
+
recoverSecret: Joi.string()
|
|
322
|
+
.trim(false)
|
|
323
|
+
.pattern(/[\x01-\x1F\x7F]/, {
|
|
324
|
+
name: 'control characters',
|
|
325
|
+
invert: true,
|
|
326
|
+
})
|
|
327
|
+
.length(10),
|
|
328
|
+
recoverSecretDate: Joi.number(),
|
|
329
|
+
}
|
|
330
|
+
: {};
|
|
331
|
+
const phoneFields = tilmeld.config.userFields.includes('phone')
|
|
332
|
+
? {
|
|
333
|
+
phone: Joi.string()
|
|
334
|
+
.trim(false)
|
|
335
|
+
.pattern(/^[0-9]+$/, 'numbers'),
|
|
336
|
+
}
|
|
337
|
+
: {};
|
|
211
338
|
Joi.attempt(
|
|
212
339
|
user.$getValidatable(),
|
|
213
340
|
Joi.object().keys({
|
|
214
341
|
...nymphJoiProps,
|
|
342
|
+
...nameFields,
|
|
343
|
+
...emailFields,
|
|
344
|
+
...phoneFields,
|
|
215
345
|
username: Joi.string().trim(false).required(),
|
|
216
346
|
enabled: Joi.boolean().required(),
|
|
217
|
-
email: Joi.string()
|
|
218
|
-
.trim(false)
|
|
219
|
-
.email({ minDomainSegments: 1, tlds: false })
|
|
220
|
-
.required(),
|
|
221
|
-
nameFirst: Joi.string()
|
|
222
|
-
.trim(false)
|
|
223
|
-
.pattern(/[\x01-\x1F\x7F]/, {
|
|
224
|
-
name: 'control characters',
|
|
225
|
-
invert: true,
|
|
226
|
-
})
|
|
227
|
-
.max(512)
|
|
228
|
-
.required(),
|
|
229
|
-
nameMiddle: Joi.string()
|
|
230
|
-
.trim(false)
|
|
231
|
-
.pattern(/[\x01-\x1F\x7F]/, {
|
|
232
|
-
name: 'control characters',
|
|
233
|
-
invert: true,
|
|
234
|
-
})
|
|
235
|
-
.max(512),
|
|
236
|
-
nameLast: Joi.string()
|
|
237
|
-
.trim(false)
|
|
238
|
-
.pattern(/[\x01-\x1F\x7F]/, {
|
|
239
|
-
name: 'control characters',
|
|
240
|
-
invert: true,
|
|
241
|
-
})
|
|
242
|
-
.max(512),
|
|
243
|
-
name: Joi.string()
|
|
244
|
-
.trim(false)
|
|
245
|
-
.pattern(/[\x01-\x1F\x7F]/, {
|
|
246
|
-
name: 'control characters',
|
|
247
|
-
invert: true,
|
|
248
|
-
})
|
|
249
|
-
.max(512)
|
|
250
|
-
.required(),
|
|
251
347
|
avatar: Joi.string()
|
|
252
348
|
.trim(false)
|
|
253
349
|
.uri()
|
|
@@ -256,9 +352,6 @@ export default {
|
|
|
256
352
|
invert: true,
|
|
257
353
|
})
|
|
258
354
|
.max(1024),
|
|
259
|
-
phone: Joi.string()
|
|
260
|
-
.trim(false)
|
|
261
|
-
.pattern(/^[0-9]+$/, 'numbers'),
|
|
262
355
|
group: Joi.object().instance(Group),
|
|
263
356
|
groups: Joi.array().items(Joi.object().instance(Group)).required(),
|
|
264
357
|
abilities: Joi.array().items(
|
|
@@ -267,49 +360,19 @@ export default {
|
|
|
267
360
|
name: 'control characters',
|
|
268
361
|
invert: true,
|
|
269
362
|
})
|
|
270
|
-
.max(256)
|
|
363
|
+
.max(256),
|
|
271
364
|
),
|
|
272
365
|
inheritAbilities: Joi.boolean(),
|
|
273
|
-
secret: Joi.string()
|
|
274
|
-
.trim(false)
|
|
275
|
-
.pattern(/[\x01-\x1F\x7F]/, {
|
|
276
|
-
name: 'control characters',
|
|
277
|
-
invert: true,
|
|
278
|
-
})
|
|
279
|
-
.length(21),
|
|
280
|
-
emailChangeDate: Joi.number(),
|
|
281
|
-
newEmailSecret: Joi.string()
|
|
282
|
-
.trim(false)
|
|
283
|
-
.pattern(/[\x01-\x1F\x7F]/, {
|
|
284
|
-
name: 'control characters',
|
|
285
|
-
invert: true,
|
|
286
|
-
})
|
|
287
|
-
.length(21),
|
|
288
|
-
newEmailAddress: Joi.string()
|
|
289
|
-
.trim(false)
|
|
290
|
-
.email({ minDomainSegments: 1, tlds: false }),
|
|
291
|
-
cancelEmailSecret: Joi.string()
|
|
292
|
-
.trim(false)
|
|
293
|
-
.pattern(/[\x01-\x1F\x7F]/, {
|
|
294
|
-
name: 'control characters',
|
|
295
|
-
invert: true,
|
|
296
|
-
})
|
|
297
|
-
.length(21),
|
|
298
|
-
cancelEmailAddress: Joi.string()
|
|
299
|
-
.trim(false)
|
|
300
|
-
.email({ minDomainSegments: 1, tlds: false }),
|
|
301
|
-
recoverSecret: Joi.string()
|
|
302
|
-
.trim(false)
|
|
303
|
-
.pattern(/[\x01-\x1F\x7F]/, {
|
|
304
|
-
name: 'control characters',
|
|
305
|
-
invert: true,
|
|
306
|
-
})
|
|
307
|
-
.length(10),
|
|
308
|
-
recoverSecretDate: Joi.number(),
|
|
309
366
|
salt: Joi.string().trim(false),
|
|
310
367
|
password: Joi.string().trim(false).required(),
|
|
368
|
+
revokeTokenDate: Joi.number(),
|
|
369
|
+
totpSecret: Joi.string()
|
|
370
|
+
.trim(false)
|
|
371
|
+
.min(24)
|
|
372
|
+
.max(40)
|
|
373
|
+
.pattern(/^[A-Z234567]+$/, 'base32 encoded unpadded'),
|
|
311
374
|
}),
|
|
312
|
-
'Invalid User: '
|
|
375
|
+
'Invalid User: ',
|
|
313
376
|
);
|
|
314
377
|
},
|
|
315
378
|
} as Config;
|