-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
370 additions
and
53 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
105 changes: 105 additions & 0 deletions
105
packages/backend/server/src/fundamentals/helpers/__tests__/crypto.spec.ts
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 |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { createPrivateKey, createPublicKey } from 'node:crypto'; | ||
|
||
import { Test } from '@nestjs/testing'; | ||
import ava, { TestFn } from 'ava'; | ||
import Sinon from 'sinon'; | ||
|
||
import { ConfigModule } from '../../config'; | ||
import { CryptoHelper } from '../crypto'; | ||
|
||
const test = ava as TestFn<{ | ||
crypto: CryptoHelper; | ||
}>; | ||
|
||
const key = `-----BEGIN EC PRIVATE KEY----- | ||
MHcCAQEEIEtyAJLIULkphVhqXqxk4Nr8Ggty3XLwUJWBxzAWCWTMoAoGCCqGSM49 | ||
AwEHoUQDQgAEF3U/0wIeJ3jRKXeFKqQyBKlr9F7xaAUScRrAuSP33rajm3cdfihI | ||
3JvMxVNsS2lE8PSGQrvDrJZaDo0L+Lq9Gg== | ||
-----END EC PRIVATE KEY-----`; | ||
const privateKey = createPrivateKey({ | ||
key, | ||
format: 'pem', | ||
type: 'sec1', | ||
}) | ||
.export({ | ||
type: 'pkcs8', | ||
format: 'pem', | ||
}) | ||
.toString('utf8'); | ||
|
||
const publicKey = createPublicKey({ | ||
key, | ||
format: 'pem', | ||
type: 'spki', | ||
}) | ||
.export({ | ||
format: 'pem', | ||
type: 'spki', | ||
}) | ||
.toString('utf8'); | ||
|
||
test.beforeEach(async t => { | ||
const module = await Test.createTestingModule({ | ||
imports: [ | ||
ConfigModule.forRoot({ | ||
secrets: { | ||
publicKey, | ||
privateKey, | ||
}, | ||
}), | ||
], | ||
providers: [CryptoHelper], | ||
}).compile(); | ||
|
||
t.context.crypto = module.get(CryptoHelper); | ||
}); | ||
|
||
test('should be able to sign and verify', t => { | ||
const data = 'hello world'; | ||
const signature = t.context.crypto.sign(data); | ||
t.true(t.context.crypto.verify(data, signature)); | ||
t.false(t.context.crypto.verify(data, 'fake-signature')); | ||
}); | ||
|
||
test('should be able to encrypt and decrypt', t => { | ||
const data = 'top secret'; | ||
const stub = Sinon.stub(t.context.crypto, 'randomBytes').returns( | ||
Buffer.alloc(12, 0) | ||
); | ||
|
||
const encrypted = t.context.crypto.encrypt(data); | ||
const decrypted = t.context.crypto.decrypt(encrypted); | ||
|
||
// we are using a stub to make sure the iv is always 0, | ||
// the encrypted result will always be the same | ||
t.is(encrypted, 'AAAAAAAAAAAAAAAAWUDlJRhzP+SZ3avvmLcgnou+q4E11w=='); | ||
t.is(decrypted, data); | ||
|
||
stub.restore(); | ||
}); | ||
|
||
test('should be able to get random bytes', t => { | ||
const bytes = t.context.crypto.randomBytes(); | ||
t.is(bytes.length, 12); | ||
const bytes2 = t.context.crypto.randomBytes(); | ||
|
||
t.notDeepEqual(bytes, bytes2); | ||
}); | ||
|
||
test('should be able to digest', t => { | ||
const data = 'hello world'; | ||
const hash = t.context.crypto.sha256(data).toString('base64'); | ||
t.is(hash, 'uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek='); | ||
}); | ||
|
||
test('should be able to safe compare', t => { | ||
t.true(t.context.crypto.compare('abc', 'abc')); | ||
t.false(t.context.crypto.compare('abc', 'def')); | ||
}); | ||
|
||
test('should be able to hash and verify password', async t => { | ||
const password = 'mySecurePassword'; | ||
const hash = await t.context.crypto.encryptPassword(password); | ||
t.true(await t.context.crypto.verifyPassword(password, hash)); | ||
t.false(await t.context.crypto.verifyPassword('wrong-password', hash)); | ||
}); |
Oops, something went wrong.