generated from 47ng/typescript-library-starter
-
-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add support for normalizing hashes (#110)
* feat(sanitize-hash): add support for sanitizing hash * feat(sanitize-hash): Add note about unique in README * feat(normalize-hash): Rename sanitize to normalize * feat(normalize-hash): Add utf8 check --------- Co-authored-by: Martijn de Voogd <[email protected]>
- Loading branch information
1 parent
edd4283
commit e10b822
Showing
8 changed files
with
166 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,43 @@ | ||
import { decoders, encoders } from '@47ng/codec' | ||
import crypto from 'node:crypto' | ||
import { HashFieldConfiguration } from 'types' | ||
import { HashFieldConfiguration, HashFieldNormalizeOptions } from './types' | ||
|
||
export function hashString( | ||
input: string, | ||
config: Omit<HashFieldConfiguration, 'sourceField'> | ||
) { | ||
const decode = decoders[config.inputEncoding] | ||
const encode = encoders[config.outputEncoding] | ||
const data = decode(input) | ||
const normalized = normalizeHashString(input, config.normalize) | ||
|
||
const data = decode(normalized) | ||
const hash = crypto.createHash(config.algorithm) | ||
hash.update(data) | ||
if (config.salt) { | ||
hash.update(decode(config.salt)) | ||
} | ||
return encode(hash.digest()) | ||
} | ||
|
||
export function normalizeHashString( | ||
input: string, | ||
options: HashFieldNormalizeOptions[] = [] | ||
) { | ||
let output = input | ||
if (options.includes(HashFieldNormalizeOptions.lowercase)) { | ||
output = output.toLowerCase() | ||
} | ||
if (options.includes(HashFieldNormalizeOptions.uppercase)) { | ||
output = output.toUpperCase() | ||
} | ||
if (options.includes(HashFieldNormalizeOptions.trim)) { | ||
output = output.trim() | ||
} | ||
if (options.includes(HashFieldNormalizeOptions.spaces)) { | ||
output = output.replace(/\s/g, '') | ||
} | ||
if (options.includes(HashFieldNormalizeOptions.diacritics)) { | ||
output = output.normalize('NFD').replace(/[\u0300-\u036f]/g, '') | ||
} | ||
return output | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -404,20 +404,53 @@ describe.each(clients)('integration ($type)', ({ client }) => { | |
} | ||
}) | ||
|
||
test("query entries with non-empty name", async () => { | ||
test('query entries with non-empty name', async () => { | ||
const fakeName = 'f@keU$er' | ||
await client.user.create({ | ||
data: { | ||
name: '', | ||
email: '[email protected]' | ||
data: { | ||
name: '', | ||
email: '[email protected]' | ||
} | ||
}); | ||
const users = await client.user.findMany(); | ||
}) | ||
const users = await client.user.findMany() | ||
// assume active user with nonempty name | ||
const activeUserCount = await client.user.count({ where: { name: { not: '' } } }) | ||
const activeUserCount = await client.user.count({ | ||
where: { name: { not: '' } } | ||
}) | ||
// use fakeName to pretend unique name | ||
const existingUsers = await client.user.findMany({ where: { name: { not: fakeName } } }) | ||
expect(activeUserCount).toBe(users.length - 1); | ||
expect(existingUsers).toEqual(users); | ||
const existingUsers = await client.user.findMany({ | ||
where: { name: { not: fakeName } } | ||
}) | ||
expect(activeUserCount).toBe(users.length - 1) | ||
expect(existingUsers).toEqual(users) | ||
}) | ||
|
||
const normalizeTestEmail = '[email protected]' | ||
|
||
test('create user with normalizeable name', async () => { | ||
const received = await client.user.create({ | ||
data: { | ||
email: normalizeTestEmail, | ||
name: ' François' | ||
} | ||
}) | ||
const dbValue = await sqlite.get({ | ||
table: 'User', | ||
where: { email: normalizeTestEmail } | ||
}) | ||
expect(received.name).toEqual(' François') // clear text in returned value | ||
expect(dbValue.name).toMatch(cloakedStringRegex) // encrypted in database | ||
}) | ||
|
||
test('query user by encrypted and hashed name field with a normalized input (with equals)', async () => { | ||
const received = await client.user.findFirst({ | ||
where: { | ||
name: { | ||
equals: 'Francois' //check for lowercase, trim and diacritics | ||
} | ||
} | ||
}) | ||
expect(received!.name).toEqual(' François') // clear text in returned value | ||
expect(received!.email).toEqual(normalizeTestEmail) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters