@defra-fish/business-rules-lib 1.49.0-rc.0 → 1.49.0-rc.10
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra-fish/business-rules-lib",
|
|
3
|
-
"version": "1.49.0-rc.
|
|
3
|
+
"version": "1.49.0-rc.10",
|
|
4
4
|
"description": "Shared business rules for the rod licensing digital services",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"moment": "^2.29.1",
|
|
38
38
|
"uuid": "^8.3.2"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "fac8dbbd7e237e1f417c46bc4d6b138ffc035609"
|
|
41
41
|
}
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as contactValidation from './validators/contact.validators.js'
|
|
2
|
+
import * as dateValidation from './validators/date.validators.js'
|
|
2
3
|
import * as permissionValidation from './validators/permission.validators.js'
|
|
3
4
|
export * from './util/ages.js'
|
|
4
5
|
export * from './util/permissions.js'
|
|
@@ -6,5 +7,6 @@ export * from './constants.js'
|
|
|
6
7
|
|
|
7
8
|
export const validation = {
|
|
8
9
|
contact: contactValidation,
|
|
10
|
+
date: dateValidation,
|
|
9
11
|
permission: permissionValidation
|
|
10
12
|
}
|
|
@@ -5,6 +5,9 @@ import moment from 'moment'
|
|
|
5
5
|
const INVALID_DATE_ERROR_MESSAGE = '"value" must be in [YYYY-MM-DD] format'
|
|
6
6
|
|
|
7
7
|
describe('contact validators', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
jest.resetAllMocks()
|
|
10
|
+
})
|
|
8
11
|
describe('birthDateValidator', () => {
|
|
9
12
|
const validDate = moment().subtract(1, 'day')
|
|
10
13
|
|
|
@@ -128,6 +131,24 @@ describe('contact validators', () => {
|
|
|
128
131
|
'"value" must contain at least 3 alpha characters'
|
|
129
132
|
)
|
|
130
133
|
})
|
|
134
|
+
|
|
135
|
+
it.each([
|
|
136
|
+
'M̵i̵c̵h̵a̵e̵l̵',
|
|
137
|
+
'M̷i̷c̷h̷a̷e̷l̷',
|
|
138
|
+
'M͟i͟c͟h͟a͟e͟l͟',
|
|
139
|
+
'𝔐𝔦𝔠𝔥𝔞𝔢𝔩',
|
|
140
|
+
'𝕄𝕚𝕔𝕙𝕒𝕖𝕝',
|
|
141
|
+
'ןǝɐɥɔıW',
|
|
142
|
+
'Ⓜⓘⓒⓗⓐⓔⓛ',
|
|
143
|
+
'🄼🄸🄲🄷🄰🄴🄻',
|
|
144
|
+
'Mɪᴄʜᴀᴇʟ',
|
|
145
|
+
'ᴹᶦᶜʰᵃᵉˡ',
|
|
146
|
+
'𖢑𖥣𖥐𖦙𖧥𖠢ꛚ',
|
|
147
|
+
'ℳ𝒾𝒸𝒽𝒶ℯ𝓁',
|
|
148
|
+
'𝙼𝚒𝚌𝚑𝚊𝚎𝚕 '
|
|
149
|
+
])('prohibits a string with non-standard characters: %s', async c => {
|
|
150
|
+
await expect(contactValidation.createFirstNameValidator(Joi).validateAsync(c)).rejects.toThrow()
|
|
151
|
+
})
|
|
131
152
|
})
|
|
132
153
|
|
|
133
154
|
describe('lastNameValidator', () => {
|
|
@@ -229,6 +250,24 @@ describe('contact validators', () => {
|
|
|
229
250
|
'"value" must contain at least 3 alpha characters'
|
|
230
251
|
)
|
|
231
252
|
})
|
|
253
|
+
|
|
254
|
+
it.each([
|
|
255
|
+
'M̵i̵c̵h̵a̵e̵l̵',
|
|
256
|
+
'M̷i̷c̷h̷a̷e̷l̷',
|
|
257
|
+
'M͟i͟c͟h͟a͟e͟l͟',
|
|
258
|
+
'𝔐𝔦𝔠𝔥𝔞𝔢𝔩',
|
|
259
|
+
'𝕄𝕚𝕔𝕙𝕒𝕖𝕝',
|
|
260
|
+
'ןǝɐɥɔıW',
|
|
261
|
+
'Ⓜⓘⓒⓗⓐⓔⓛ',
|
|
262
|
+
'🄼🄸🄲🄷🄰🄴🄻',
|
|
263
|
+
'Mɪᴄʜᴀᴇʟ',
|
|
264
|
+
'ᴹᶦᶜʰᵃᵉˡ',
|
|
265
|
+
'𖢑𖥣𖥐𖦙𖧥𖠢ꛚ',
|
|
266
|
+
'ℳ𝒾𝒸𝒽𝒶ℯ𝓁',
|
|
267
|
+
'𝙼𝚒𝚌𝚑𝚊𝚎𝚕'
|
|
268
|
+
])('prohibits a string with non-standard characters: %s', async c => {
|
|
269
|
+
await expect(contactValidation.createLastNameValidator(Joi).validateAsync(c)).rejects.toThrow()
|
|
270
|
+
})
|
|
232
271
|
})
|
|
233
272
|
|
|
234
273
|
describe('emailValidator', () => {
|
|
@@ -241,6 +280,28 @@ describe('contact validators', () => {
|
|
|
241
280
|
'"value" must be a valid email'
|
|
242
281
|
)
|
|
243
282
|
})
|
|
283
|
+
|
|
284
|
+
it('allows a range of unicode characters from plane 1', async () => {
|
|
285
|
+
const internationStr = 'æçéñøķť@email.com'
|
|
286
|
+
await expect(contactValidation.createEmailValidator(Joi).validateAsync(internationStr)).resolves.toEqual('æçéñøķť@email.com')
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
it.each([
|
|
290
|
+
'ᵐᵢᶜₕᵃₑˡ@ᵉₘᵃᵢˡ.ᶜₒᵐ',
|
|
291
|
+
'𝓂𝒾𝒸𝒽𝒶ℯ𝓁@ℯ𝓂𝒶𝒾𝓁.𝒸ℴ𝓂',
|
|
292
|
+
'm̶i̶c̶h̶a̶e̶l̶@̶e̶m̶a̶i̶l̶.̶c̶o̶m̶',
|
|
293
|
+
'm̷i̷c̷h̷a̷e̷l̷@̷e̷m̷a̷i̷l̷.̷c̷o̷m̷',
|
|
294
|
+
'𝖒𝖎𝖈𝖍𝖆𝖊𝖑@𝖊𝖒𝖆𝖎𝖑.𝖈𝖔𝖒',
|
|
295
|
+
'm̲i̲c̲h̲a̲e̲l̲@̲e̲m̲a̲i̲l̲.̲c̲o̲m̲',
|
|
296
|
+
'ꕮꕯꖀꖾꗇꗍꝆ@ꗍꕮꗇꕯꝆ.ꖀꗞꕮ',
|
|
297
|
+
'🅼🅘🅲🅗🅰🅔🅻@🅴🅜🅰🅘🅻.🅲🅞🅼',
|
|
298
|
+
'ɯoɔ˙ןıɐɯǝ@ןǝɐɥɔıɯ',
|
|
299
|
+
'ꮇꮖꮯꮋꭺꭼꮮ@ꭼꮇꭺꮖꮮ.ꮯꮎꮇ',
|
|
300
|
+
'michael@email.com',
|
|
301
|
+
'ₘᵢcₕaₑₗ@ₑₘaᵢₗ.cₒₘ'
|
|
302
|
+
])('prohibits a string with non-standard characters: %s', async c => {
|
|
303
|
+
await expect(contactValidation.createEmailValidator(Joi).validateAsync(c)).rejects.toThrow()
|
|
304
|
+
})
|
|
244
305
|
})
|
|
245
306
|
|
|
246
307
|
describe('mobilePhoneValidator', () => {
|
|
@@ -251,6 +312,24 @@ describe('contact validators', () => {
|
|
|
251
312
|
it.each(['test', '07700 test'])('rejects the invalid number %s', async number => {
|
|
252
313
|
await expect(contactValidation.createMobilePhoneValidator(Joi).validateAsync(number)).rejects.toThrow()
|
|
253
314
|
})
|
|
315
|
+
|
|
316
|
+
it.each([
|
|
317
|
+
'𝟘𝟟𝟟𝟘𝟘 𝟡𝟘𝟘𝟘𝟠𝟠',
|
|
318
|
+
'0𝟟7𝟘0 9𝟘0𝟘8𝟠',
|
|
319
|
+
'0𝟽𝟽00 𝟿000𝟾𝟾',
|
|
320
|
+
'0̵7̵7̵0̵0̵ ̵9̵0̵0̵0̵8̵8̵',
|
|
321
|
+
'0͟7͟7͟0͟0͟ ͟9͟0͟0͟0͟8͟8͟',
|
|
322
|
+
'0̸7̸7̸0̸0̸ ̸9̸0̸0̸0̸8̸8̸',
|
|
323
|
+
'07700 900088',
|
|
324
|
+
'⁰⁷⁷⁰⁰ ⁹⁰⁰⁰⁸⁸',
|
|
325
|
+
'⓿➐➐⓿⓿ ➒⓿⓿⓿➑➑',
|
|
326
|
+
'+ㄐㄐワワㄖㄖ ㄢㄖㄖㄖ曰曰',
|
|
327
|
+
'07700👏 900088',
|
|
328
|
+
'0̐̈7̐̈7̐̈0̐̈0̐̈ ̐̈9̐̈0̐̈0̐̈0̐̈8̐̈8̐̈',
|
|
329
|
+
'+4④7⑦0⓪ ⑨0⓪0⑧8'
|
|
330
|
+
])('prohibits a string with non-standard characters: %s', async c => {
|
|
331
|
+
await expect(contactValidation.createMobilePhoneValidator(Joi).validateAsync(c)).rejects.toThrow()
|
|
332
|
+
})
|
|
254
333
|
})
|
|
255
334
|
|
|
256
335
|
describe('ukPostcodeValidator', () => {
|
|
@@ -265,33 +344,74 @@ describe('contact validators', () => {
|
|
|
265
344
|
it('expects a minimum of 1 character', async () => {
|
|
266
345
|
await expect(contactValidation.createUKPostcodeValidator(Joi).validateAsync('')).rejects.toThrow('"value" is not allowed to be empty')
|
|
267
346
|
})
|
|
347
|
+
|
|
268
348
|
it('expects a maximum of 12 characters', async () => {
|
|
269
349
|
await expect(contactValidation.createUKPostcodeValidator(Joi).validateAsync('0123456789ABC')).rejects.toThrow(
|
|
270
350
|
'"value" length must be less than or equal to 12 characters long'
|
|
271
351
|
)
|
|
272
352
|
})
|
|
353
|
+
|
|
273
354
|
it('expects postcodes to conform to the pattern used in the UK', async () => {
|
|
274
355
|
await expect(contactValidation.createUKPostcodeValidator(Joi).validateAsync('0123456789')).rejects.toThrow(
|
|
275
356
|
/fails to match the required pattern/
|
|
276
357
|
)
|
|
277
358
|
})
|
|
359
|
+
|
|
360
|
+
it.each([
|
|
361
|
+
'A⃣B⃣1⃣2⃣ 1⃣A⃣B⃣',
|
|
362
|
+
'🄐🄑⑴⑵ ⑴🄐🄑',
|
|
363
|
+
'丹乃丨己 丨丹乃',
|
|
364
|
+
'A͢B͢1͢2͢ ͢1͢A͢B͢',
|
|
365
|
+
'A⃟B⃟1⃟2⃟ 1⃟A⃟B⃟',
|
|
366
|
+
'AB12👏 1AB',
|
|
367
|
+
'🅐Ⓑ➊② ①🅐Ⓑ',
|
|
368
|
+
'𝘼𝐵𝟭𝟮 1𝘼𝘽',
|
|
369
|
+
'🅰𝙱12 1𝕬𝓑',
|
|
370
|
+
'1ᴬAᴮB¹²',
|
|
371
|
+
'ᴬᴮ¹² ¹ᴬᴮ',
|
|
372
|
+
'q∀1 21q∀',
|
|
373
|
+
'A̶B̶1̶2̶ ̶1̶A̶B̶'
|
|
374
|
+
])('prohibits a string with non-standard characters: %s', async c => {
|
|
375
|
+
await expect(contactValidation.createUKPostcodeValidator(Joi).validateAsync(c)).rejects.toThrow()
|
|
376
|
+
})
|
|
278
377
|
})
|
|
279
378
|
|
|
280
379
|
describe('overseasPostcodeValidator', () => {
|
|
281
380
|
it('converts to uppercase and trims', async () => {
|
|
282
381
|
await expect(contactValidation.createOverseasPostcodeValidator(Joi).validateAsync('a ')).resolves.toEqual('A')
|
|
283
382
|
})
|
|
383
|
+
|
|
284
384
|
it('expects a minimum of 1 character', async () => {
|
|
285
385
|
await expect(contactValidation.createOverseasPostcodeValidator(Joi).validateAsync('')).rejects.toThrow(
|
|
286
386
|
'"value" is not allowed to be empty'
|
|
287
387
|
)
|
|
288
388
|
})
|
|
389
|
+
|
|
289
390
|
it('expects a maximum of 12 characters', async () => {
|
|
290
391
|
await expect(contactValidation.createOverseasPostcodeValidator(Joi).validateAsync('123456789AAAA')).rejects.toThrow()
|
|
291
392
|
})
|
|
393
|
+
|
|
292
394
|
it('will not accept special characters', async () => {
|
|
293
395
|
await expect(contactValidation.createOverseasPostcodeValidator(Joi).validateAsync('12£4')).rejects.toThrow()
|
|
294
396
|
})
|
|
397
|
+
|
|
398
|
+
it.each([
|
|
399
|
+
'A⃣B⃣1⃣2⃣ 1⃣A⃣B⃣',
|
|
400
|
+
'🄐🄑⑴⑵ ⑴🄐🄑',
|
|
401
|
+
'丹乃丨己 丨丹乃',
|
|
402
|
+
'A͢B͢1͢2͢ ͢1͢A͢B͢',
|
|
403
|
+
'A⃟B⃟1⃟2⃟ 1⃟A⃟B⃟',
|
|
404
|
+
'AB12👏 1AB',
|
|
405
|
+
'🅐Ⓑ➊② ①🅐Ⓑ',
|
|
406
|
+
'𝘼𝐵𝟭𝟮 1𝘼𝘽',
|
|
407
|
+
'🅰𝙱12 1𝕬𝓑',
|
|
408
|
+
'1ᴬAᴮB¹²',
|
|
409
|
+
'ᴬᴮ¹² ¹ᴬᴮ',
|
|
410
|
+
'q∀1 21q∀',
|
|
411
|
+
'A̶B̶1̶2̶ ̶1̶A̶B̶'
|
|
412
|
+
])('prohibits a string with non-standard characters: %s', async c => {
|
|
413
|
+
await expect(contactValidation.createOverseasPostcodeValidator(Joi).validateAsync(c)).rejects.toThrow()
|
|
414
|
+
})
|
|
295
415
|
})
|
|
296
416
|
|
|
297
417
|
describe('premisesValidator', () => {
|
|
@@ -308,6 +428,23 @@ describe('contact validators', () => {
|
|
|
308
428
|
'"value" length must be less than or equal to 50 characters long'
|
|
309
429
|
)
|
|
310
430
|
})
|
|
431
|
+
|
|
432
|
+
it.each([
|
|
433
|
+
'15 𐝥ꗞꕷꗍ ꖀꗞꖡꖡꗇꗱꗍ',
|
|
434
|
+
'15 Rose Cottage',
|
|
435
|
+
'¹⁵ ᴿᵒˢᵉ ᶜᵒᵗᵗᵃᵍᵉ',
|
|
436
|
+
'15 ᖇᐤᔆᕪ ᐸᐤᐩᐩᐞᕐᕪ',
|
|
437
|
+
'15👏 Rose👏 Cottage',
|
|
438
|
+
'1̶5̶ ̶R̶o̶s̶e̶ ̶C̶o̶t̶t̶a̶g̶e̶',
|
|
439
|
+
'1̲5̲ ̲R̲o̲s̲e̲ ̲C̲o̲t̲t̲a̲g̲e̲',
|
|
440
|
+
'1̸5̸ ̸R̸o̸s̸e̸ ̸C̸o̸t̸t̸a̸g̸e̸',
|
|
441
|
+
'➊➎ 🅡🅞🅢🅔 🅒🅞🅣🅣🅐🅖🅔',
|
|
442
|
+
'①➎ 🅡ⓞ🅢ⓔ Ⓒ🅞ⓣ🅣ⓐ🅖ⓔ',
|
|
443
|
+
'1⑤ 𝑅𝐨𝑠ⓔ 𝒞𝓸𝘁𝕥𝒶ℊ🄴',
|
|
444
|
+
'𝟏𝟓 𝐑𝐨𝐬𝐞 𝐂𝐨𝐭𝐭𝐚𝐠𝐞'
|
|
445
|
+
])('prohibits a string with non-standard characters: %s', async c => {
|
|
446
|
+
await expect(contactValidation.createPremisesValidator(Joi).validateAsync(c)).rejects.toThrow()
|
|
447
|
+
})
|
|
311
448
|
})
|
|
312
449
|
|
|
313
450
|
describe('streetValidator', () => {
|
|
@@ -373,6 +510,13 @@ describe('contact validators', () => {
|
|
|
373
510
|
'"value" length must be less than or equal to 100 characters long'
|
|
374
511
|
)
|
|
375
512
|
})
|
|
513
|
+
|
|
514
|
+
it.each(['London', 'ᴸᵒⁿᵈᵒⁿ', '𝐋𝐨𝐧𝐝𝐨𝐧', 'ㄥL口o几n冂d口o几n', 'L⃠o⃠n⃠d⃠o⃠n⃠', '🅛🅞🅝🅓🅞🅝', 'L̸o̸n̸d̸o̸n̸', 'L̲o̲n̲d̲o̲n̲'])(
|
|
515
|
+
'prohibits a string with non-standard characters: %s',
|
|
516
|
+
async c => {
|
|
517
|
+
await expect(contactValidation.createTownValidator(Joi).validateAsync(c)).rejects.toThrow()
|
|
518
|
+
}
|
|
519
|
+
)
|
|
376
520
|
})
|
|
377
521
|
|
|
378
522
|
describe('nationalInsuranceNumberValidator', () => {
|
|
@@ -381,11 +525,28 @@ describe('contact validators', () => {
|
|
|
381
525
|
'AB 12 34 56 A'
|
|
382
526
|
)
|
|
383
527
|
})
|
|
528
|
+
|
|
384
529
|
it('Disallows invalid NI number QQ123456A', async () => {
|
|
385
530
|
await expect(contactValidation.createNationalInsuranceNumberValidator(Joi).validateAsync('QQ123456A')).rejects.toThrow()
|
|
386
531
|
})
|
|
532
|
+
|
|
387
533
|
it('Disallows invalid NI number BG123456A', async () => {
|
|
388
534
|
await expect(contactValidation.createNationalInsuranceNumberValidator(Joi).validateAsync('QQ123456A')).rejects.toThrow()
|
|
389
535
|
})
|
|
536
|
+
|
|
537
|
+
it.each([
|
|
538
|
+
'A̲B̲1̲2̲3̲4̲5̲6̲A̲',
|
|
539
|
+
'A̸B̸1̸2̸3̸4̸5̸6̸A̸',
|
|
540
|
+
'AB123456A',
|
|
541
|
+
'ᴬᴮ¹²³⁴⁵⁶ᴬ',
|
|
542
|
+
'🅐🅑①②③④⑤⑥🅐',
|
|
543
|
+
'🅐ⓑ①②③④⑤⑥ⓐ',
|
|
544
|
+
'A⃠B⃠1⃠2⃠3⃠4⃠5⃠6⃠A⃠',
|
|
545
|
+
'升A马B丨1己2ヨ3ㄐ4丂5石6刄A',
|
|
546
|
+
'✌️AB123456A✌️',
|
|
547
|
+
'𝐀𝐁𝟏𝟐𝟑𝟒𝟓𝟔𝐀'
|
|
548
|
+
])('prohibits a string with non-standard characters: %s', async c => {
|
|
549
|
+
await expect(contactValidation.createNationalInsuranceNumberValidator(Joi).validateAsync(c)).rejects.toThrow()
|
|
550
|
+
})
|
|
390
551
|
})
|
|
391
552
|
})
|
|
@@ -78,6 +78,12 @@ const createDateStringValidator = joi =>
|
|
|
78
78
|
}
|
|
79
79
|
})
|
|
80
80
|
|
|
81
|
+
const allowedUnicodeBlocks = '\\u0000-\\u024F'
|
|
82
|
+
const forbiddenCharsRegex = new RegExp(`[^${allowedUnicodeBlocks}\\s'’()-]`, 'u')
|
|
83
|
+
const forbiddenEmailRegex = new RegExp(`[^A-Za-z0-9\\s'’@._${allowedUnicodeBlocks}]`, 'u')
|
|
84
|
+
const forbiddenCharsNumbersRegex = new RegExp(`[^A-Za-z0-9\\s${allowedUnicodeBlocks}]`, 'u')
|
|
85
|
+
const forbiddenMobileRegex = /[^+()0-9\-.\s]+/g
|
|
86
|
+
|
|
81
87
|
/**
|
|
82
88
|
* Create a validator to check a contact's birth date
|
|
83
89
|
*
|
|
@@ -92,7 +98,8 @@ export const createBirthDateValidator = joi => createDateStringValidator(joi).tr
|
|
|
92
98
|
* @param {Joi.Root} joi the joi validator used by the consuming project
|
|
93
99
|
* @returns {Joi.StringSchema}
|
|
94
100
|
*/
|
|
95
|
-
export const createEmailValidator = joi =>
|
|
101
|
+
export const createEmailValidator = joi =>
|
|
102
|
+
checkCopyPasteValidator(joi, forbiddenEmailRegex).string().allowable().trim().email().max(100).lowercase().example('person@example.com')
|
|
96
103
|
|
|
97
104
|
export const mobilePhoneRegex = /^[+]*[(]?[0-9]{1,4}[)]?[-\s./0-9]*$/
|
|
98
105
|
/**
|
|
@@ -101,7 +108,10 @@ export const mobilePhoneRegex = /^[+]*[(]?[0-9]{1,4}[)]?[-\s./0-9]*$/
|
|
|
101
108
|
* @param {Joi.Root} joi the joi validator used by the consuming project
|
|
102
109
|
* @returns {Joi.StringSchema}
|
|
103
110
|
*/
|
|
104
|
-
export const createMobilePhoneValidator = joi =>
|
|
111
|
+
export const createMobilePhoneValidator = joi =>
|
|
112
|
+
checkCopyPasteValidator(joi, forbiddenMobileRegex).string().allowable().trim().pattern(mobilePhoneRegex).example('person@example.com')
|
|
113
|
+
|
|
114
|
+
const maxPremises = 50
|
|
105
115
|
|
|
106
116
|
/**
|
|
107
117
|
* Create a validator to check a contact's address premises
|
|
@@ -109,7 +119,16 @@ export const createMobilePhoneValidator = joi => joi.string().trim().pattern(mob
|
|
|
109
119
|
* @param {Joi.Root} joi the joi validator used by the consuming project
|
|
110
120
|
* @returns {Joi.StringSchema}
|
|
111
121
|
*/
|
|
112
|
-
export const createPremisesValidator = joi =>
|
|
122
|
+
export const createPremisesValidator = joi =>
|
|
123
|
+
checkCopyPasteValidator(joi, forbiddenCharsNumbersRegex)
|
|
124
|
+
.string()
|
|
125
|
+
.allowable()
|
|
126
|
+
.trim()
|
|
127
|
+
.min(1)
|
|
128
|
+
.max(maxPremises)
|
|
129
|
+
.external(toTitleCase())
|
|
130
|
+
.required()
|
|
131
|
+
.example('Example House')
|
|
113
132
|
|
|
114
133
|
/**
|
|
115
134
|
* Create a validator to check a contact's address street
|
|
@@ -134,8 +153,9 @@ export const createLocalityValidator = joi => joi.string().trim().max(100).exter
|
|
|
134
153
|
* @returns {Joi.StringSchema}
|
|
135
154
|
*/
|
|
136
155
|
export const createTownValidator = joi =>
|
|
137
|
-
joi
|
|
156
|
+
checkCopyPasteValidator(joi, forbiddenCharsRegex)
|
|
138
157
|
.string()
|
|
158
|
+
.allowable()
|
|
139
159
|
.trim()
|
|
140
160
|
.max(100)
|
|
141
161
|
.external(toTitleCase(['under', 'upon', 'in', 'on', 'cum', 'next', 'the', 'en', 'le', 'super']))
|
|
@@ -144,6 +164,7 @@ export const createTownValidator = joi =>
|
|
|
144
164
|
|
|
145
165
|
export const ukPostcodeRegex = /^([A-PR-UWYZ][0-9]{1,2}[A-HJKPSTUW]?|[A-PR-UWYZ][A-HK-Y][0-9]{1,2}[ABEHMNPRVWXY]?)\s{0,6}([0-9][A-Z]{2})$/i
|
|
146
166
|
export const overseasPostcodeRegex = /^([a-zA-Z0-9 ]{1,12})$/i
|
|
167
|
+
const maxPostcode = 12
|
|
147
168
|
|
|
148
169
|
/**
|
|
149
170
|
* Create a validator to check a contact's postcode
|
|
@@ -154,7 +175,17 @@ export const overseasPostcodeRegex = /^([a-zA-Z0-9 ]{1,12})$/i
|
|
|
154
175
|
* @returns {Joi.StringSchema}
|
|
155
176
|
*/
|
|
156
177
|
export const createUKPostcodeValidator = joi =>
|
|
157
|
-
joi
|
|
178
|
+
checkCopyPasteValidator(joi, forbiddenCharsNumbersRegex)
|
|
179
|
+
.string()
|
|
180
|
+
.allowable()
|
|
181
|
+
.trim()
|
|
182
|
+
.min(1)
|
|
183
|
+
.max(maxPostcode)
|
|
184
|
+
.required()
|
|
185
|
+
.pattern(ukPostcodeRegex)
|
|
186
|
+
.replace(ukPostcodeRegex, '$1 $2')
|
|
187
|
+
.uppercase()
|
|
188
|
+
.example('AB12 3CD')
|
|
158
189
|
|
|
159
190
|
/**
|
|
160
191
|
* Create a validator to check/format overseas postcodes
|
|
@@ -162,7 +193,15 @@ export const createUKPostcodeValidator = joi =>
|
|
|
162
193
|
* @returns {Joi.StringSchema}
|
|
163
194
|
*/
|
|
164
195
|
export const createOverseasPostcodeValidator = joi =>
|
|
165
|
-
joi
|
|
196
|
+
checkCopyPasteValidator(joi, forbiddenCharsNumbersRegex)
|
|
197
|
+
.string()
|
|
198
|
+
.allowable()
|
|
199
|
+
.trim()
|
|
200
|
+
.min(1)
|
|
201
|
+
.max(maxPostcode)
|
|
202
|
+
.uppercase()
|
|
203
|
+
.required()
|
|
204
|
+
.pattern(overseasPostcodeRegex)
|
|
166
205
|
|
|
167
206
|
const nameStringSubstitutions = [
|
|
168
207
|
/*
|
|
@@ -251,7 +290,7 @@ const createNameStringValidator = (joi, { minimumLength }) =>
|
|
|
251
290
|
return helpers.error('string.min')
|
|
252
291
|
}
|
|
253
292
|
value = standardiseName(value)
|
|
254
|
-
if (!nameStringRegex.test(value)) {
|
|
293
|
+
if (!nameStringRegex.test(value) || forbiddenCharsRegex.test(value)) {
|
|
255
294
|
return helpers.error('string.forbidden')
|
|
256
295
|
}
|
|
257
296
|
return value
|
|
@@ -302,8 +341,9 @@ const ukNINORegEx =
|
|
|
302
341
|
/^([ABCEGHJ-PRSTW-Z][ABCEGHJ-NPRSTW-Z])(?<!(?:BG|GB|KN|NK|NT|TN|ZZ))\s?([0-9]{2})\s{0,3}([0-9]{2})\s{0,3}([0-9]{2})\s{0,3}([ABCD])$/
|
|
303
342
|
|
|
304
343
|
export const createNationalInsuranceNumberValidator = joi =>
|
|
305
|
-
joi
|
|
344
|
+
checkCopyPasteValidator(joi, forbiddenCharsNumbersRegex)
|
|
306
345
|
.string()
|
|
346
|
+
.allowable()
|
|
307
347
|
.trim()
|
|
308
348
|
.uppercase()
|
|
309
349
|
.pattern(ukNINORegEx)
|
|
@@ -311,3 +351,22 @@ export const createNationalInsuranceNumberValidator = joi =>
|
|
|
311
351
|
.required()
|
|
312
352
|
.description('A UK national insurance number')
|
|
313
353
|
.example('NH 12 34 56 A')
|
|
354
|
+
|
|
355
|
+
const checkCopyPasteValidator = (joi, forbiddenRegex) =>
|
|
356
|
+
joi.extend({
|
|
357
|
+
type: 'string',
|
|
358
|
+
base: joi.string(),
|
|
359
|
+
rules: {
|
|
360
|
+
allowable: {
|
|
361
|
+
validate (value, helpers) {
|
|
362
|
+
if (forbiddenRegex.test(value)) {
|
|
363
|
+
return helpers.error('string.forbidden')
|
|
364
|
+
}
|
|
365
|
+
return value
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
messages: {
|
|
370
|
+
'string.forbidden': '{{#label}} contains forbidden characters'
|
|
371
|
+
}
|
|
372
|
+
})
|