-
-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(lib): simplified lib by externalizing crypto lib
- Loading branch information
1 parent
9522dab
commit ed223f7
Showing
38 changed files
with
730 additions
and
621 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Enclosed crypto library | ||
|
||
This package contains the natives crypto primitives used by the [Enclosed lib and project](https://enclosed.cc). It is a standalone package built to provide compatibility between different environments by exposing the same API for node:crypto and web SubtleCrypto. | ||
|
||
## Installation | ||
|
||
```bash | ||
# with npm | ||
npm install @enclosed/crypto | ||
|
||
# with yarn | ||
yarn add @enclosed/crypto | ||
|
||
# with pnpm | ||
pnpm add @enclosed/crypto | ||
``` | ||
|
||
## License | ||
|
||
This project is licensed under the Apache 2.0 License. See the [LICENSE](./LICENSE) file for more information. | ||
|
||
## Credits and Acknowledgements | ||
|
||
This project is crafted with ❤️ by [Corentin Thomasset](https://corentin.tech). |
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,14 @@ | ||
import { defineBuildConfig } from 'unbuild'; | ||
|
||
export default defineBuildConfig({ | ||
entries: [ | ||
'src/index.node', | ||
'src/index.web', | ||
], | ||
clean: true, | ||
declaration: true, | ||
sourcemap: true, | ||
rollup: { | ||
emitCJS: true, | ||
}, | ||
}); |
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,21 @@ | ||
import antfu from '@antfu/eslint-config'; | ||
|
||
export default antfu({ | ||
stylistic: { | ||
semi: true, | ||
}, | ||
|
||
rules: { | ||
// To allow export on top of files | ||
'ts/no-use-before-define': ['error', { allowNamedExports: true, functions: false }], | ||
'curly': ['error', 'all'], | ||
'vitest/consistent-test-it': ['error', { fn: 'test' }], | ||
'ts/consistent-type-definitions': ['error', 'type'], | ||
'style/brace-style': ['error', '1tbs', { allowSingleLine: false }], | ||
'unused-imports/no-unused-vars': ['error', { | ||
argsIgnorePattern: '^_', | ||
varsIgnorePattern: '^_', | ||
caughtErrorsIgnorePattern: '^_', | ||
}], | ||
}, | ||
}); |
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,93 @@ | ||
{ | ||
"name": "@enclosed/crypto", | ||
"type": "module", | ||
"version": "1.6.2", | ||
"packageManager": "[email protected]", | ||
"description": "Enclosed cross-env crypto primitives", | ||
"author": "Corentin Thomasset <[email protected]> (https://corentin.tech)", | ||
"license": "Apache-2.0", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/CorentinTh/enclosed" | ||
}, | ||
"exports": { | ||
"./package.json": "./package.json", | ||
".": { | ||
"browser": "./dist/index.web.mjs", | ||
"bun": "./dist/index.web.mjs", | ||
"deno": "./dist/index.web.mjs", | ||
"edge-light": "./dist/index.web.mjs", | ||
"edge-routine": "./dist/index.web.mjs", | ||
"netlify": "./dist/index.web.mjs", | ||
"react-native": "./dist/index.web.mjs", | ||
"wintercg": "./dist/index.web.mjs", | ||
"worker": "./dist/index.web.mjs", | ||
"workerd": "./dist/index.web.mjs", | ||
"node": { | ||
"import": { | ||
"types": "./dist/index.node.d.mts", | ||
"default": "./dist/index.node.mjs" | ||
}, | ||
"require": { | ||
"types": "./dist/index.node.d.cts", | ||
"default": "./dist/index.node.cjs" | ||
} | ||
}, | ||
"types": "./dist/index.web.d.mts", | ||
"import": { | ||
"types": "./dist/index.web.d.mts", | ||
"default": "./dist/index.web.mjs" | ||
}, | ||
"require": { | ||
"types": "./dist/index.node.d.cts", | ||
"default": "./dist/index.node.cjs" | ||
}, | ||
"default": "./dist/index.web.mjs" | ||
}, | ||
"./node": { | ||
"import": { | ||
"types": "./dist/index.node.d.mts", | ||
"default": "./dist/index.node.mjs" | ||
}, | ||
"require": { | ||
"types": "./dist/index.node.d.cts", | ||
"default": "./dist/index.node.cjs" | ||
} | ||
} | ||
}, | ||
"main": "./dist/index.node.cjs", | ||
"module": "./dist/index.web.mjs", | ||
"types": "./dist/index.web.d.ts", | ||
"files": [ | ||
"dist" | ||
], | ||
"engines": { | ||
"node": ">=22.0.0" | ||
}, | ||
"react-native": "./dist/index.web.mjs", | ||
"scripts": { | ||
"prepare": "pnpm run build", | ||
"build": "unbuild", | ||
"lint": "eslint .", | ||
"lint:fix": "eslint --fix .", | ||
"test": "pnpm run test:unit", | ||
"test:unit": "vitest run", | ||
"test:unit:watch": "vitest watch", | ||
"typecheck": "tsc --noEmit", | ||
"prepublishOnly": "pnpm run build" | ||
}, | ||
"dependencies": { | ||
"lodash-es": "^4.17.21" | ||
}, | ||
"devDependencies": { | ||
"@antfu/eslint-config": "^3.0.0", | ||
"@types/lodash-es": "^4.17.12", | ||
"@types/node": "^22.5.4", | ||
"@vitest/coverage-v8": "^2.0.5", | ||
"eslint": "^9.10.0", | ||
"tsx": "^4.17.0", | ||
"typescript": "^5.5.4", | ||
"unbuild": "^2.0.0", | ||
"vitest": "^2.0.5" | ||
} | ||
} |
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,27 @@ | ||
import type { EncryptionMethodsDefinition } from './encryption-algorithms/encryption-algorithms.types'; | ||
import { createEncryptionAlgorithmsRegistry } from './encryption-algorithms/encryption-algorithms.registry'; | ||
|
||
export { createEnclosedCryptoApi }; | ||
|
||
function createEnclosedCryptoApi({ | ||
encryptionMethodDefinitions, | ||
...api | ||
}: { | ||
generateBaseKey: () => { baseKey: Uint8Array }; | ||
deriveMasterKey: ({ baseKey, password }: { baseKey: Uint8Array; password?: string }) => Promise<{ masterKey: Uint8Array }>; | ||
base64UrlToBuffer: ({ base64Url }: { base64Url: string }) => Uint8Array; | ||
bufferToBase64Url: ({ buffer }: { buffer: Uint8Array }) => string; | ||
encryptionMethodDefinitions: { | ||
'aes-256-gcm': EncryptionMethodsDefinition; | ||
}; | ||
}) { | ||
const { encryptionAlgorithms, getDecryptionMethod, getEncryptionMethod } = createEncryptionAlgorithmsRegistry({ encryptionMethodDefinitions }); | ||
|
||
return { | ||
...api, | ||
encryptionAlgorithms, | ||
encryptionMethodDefinitions, | ||
getDecryptionMethod, | ||
getEncryptionMethod, | ||
}; | ||
} |
3 changes: 3 additions & 0 deletions
3
packages/crypto/src/encryption-algorithms/encryption-algorithms.constants.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,3 @@ | ||
export const AES_256_GCM = 'aes-256-gcm'; | ||
|
||
export const ENCRYPTION_ALGORITHMS = [AES_256_GCM] as const; |
8 changes: 8 additions & 0 deletions
8
packages/crypto/src/encryption-algorithms/encryption-algorithms.models.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,8 @@ | ||
export { defineEncryptionMethods }; | ||
|
||
function defineEncryptionMethods(args: { | ||
encryptBuffer: (args: { buffer: Uint8Array; encryptionKey: Uint8Array }) => Promise<{ encryptedString: string }>; | ||
decryptString: (args: { encryptedString: string; encryptionKey: Uint8Array }) => Promise<{ decryptedBuffer: Uint8Array }>; | ||
}) { | ||
return args; | ||
} |
81 changes: 81 additions & 0 deletions
81
packages/crypto/src/encryption-algorithms/encryption-algorithms.registry.test.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,81 @@ | ||
import type { EncryptionAlgorithmDefinitions } from './encryption-algorithms.types'; | ||
import { describe, expect, test } from 'vitest'; | ||
import { createEncryptionAlgorithmsRegistry } from './encryption-algorithms.registry'; | ||
|
||
describe('encryption-algorithms registry', () => { | ||
describe('createEncryptionAlgorithmsRegistry', () => { | ||
const dummyEncryptionAlgorithmDefinition = { | ||
encryptBuffer: async () => ({ encryptedString: '' }), | ||
decryptString: async () => ({ decryptedBuffer: new Uint8Array() }), | ||
}; | ||
|
||
describe('the encryption algorithms registry exposed methods to manage multiples encryption algorithms', () => { | ||
test('when creating the registry, it exposes the available encryption algorithms names and definition', () => { | ||
const { encryptionAlgorithms, encryptionMethodDefinitions } = createEncryptionAlgorithmsRegistry({ | ||
encryptionMethodDefinitions: { | ||
'aes-256-gcm': dummyEncryptionAlgorithmDefinition, | ||
'foo': dummyEncryptionAlgorithmDefinition, | ||
} as EncryptionAlgorithmDefinitions, | ||
}); | ||
|
||
expect(encryptionAlgorithms).to.eql(['aes-256-gcm', 'foo']); | ||
expect(encryptionMethodDefinitions).to.eql({ | ||
'aes-256-gcm': dummyEncryptionAlgorithmDefinition, | ||
'foo': dummyEncryptionAlgorithmDefinition, | ||
}); | ||
}); | ||
|
||
test('you can get the encryption method definition by its name', () => { | ||
const { getEncryptionMethod } = createEncryptionAlgorithmsRegistry({ | ||
encryptionMethodDefinitions: { | ||
'aes-256-gcm': dummyEncryptionAlgorithmDefinition, | ||
'foo': dummyEncryptionAlgorithmDefinition, | ||
} as EncryptionAlgorithmDefinitions, | ||
}); | ||
|
||
const { encryptBuffer } = getEncryptionMethod({ encryptionAlgorithm: 'aes-256-gcm' }); | ||
|
||
expect(encryptBuffer).to.be.a('function'); | ||
}); | ||
|
||
test('if the encryption method does not exist, an error is thrown', () => { | ||
const { getEncryptionMethod } = createEncryptionAlgorithmsRegistry({ | ||
encryptionMethodDefinitions: { | ||
'aes-256-gcm': dummyEncryptionAlgorithmDefinition, | ||
}, | ||
}); | ||
|
||
expect(() => getEncryptionMethod({ encryptionAlgorithm: 'foo' })).to.throw('Encryption algorithm "foo" not found'); | ||
}); | ||
|
||
test('you can get the decryption method definition by its name', () => { | ||
const { getDecryptionMethod } = createEncryptionAlgorithmsRegistry({ | ||
encryptionMethodDefinitions: { | ||
'aes-256-gcm': { | ||
encryptBuffer: async () => ({ encryptedString: 'encrypted using aes-256-gcm' }), | ||
decryptString: async () => ({ decryptedBuffer: new Uint8Array([1]) }), | ||
}, | ||
'foo': { | ||
encryptBuffer: async () => ({ encryptedString: 'encrypted using foo' }), | ||
decryptString: async () => ({ decryptedBuffer: new Uint8Array([2]) }), | ||
}, | ||
} as EncryptionAlgorithmDefinitions, | ||
}); | ||
|
||
const { decryptString } = getDecryptionMethod({ encryptionAlgorithm: 'foo' }); | ||
|
||
expect(decryptString).to.be.a('function'); | ||
}); | ||
|
||
test('if the decryption method does not exist, an error is thrown', () => { | ||
const { getDecryptionMethod } = createEncryptionAlgorithmsRegistry({ | ||
encryptionMethodDefinitions: { | ||
'aes-256-gcm': dummyEncryptionAlgorithmDefinition, | ||
}, | ||
}); | ||
|
||
expect(() => getDecryptionMethod({ encryptionAlgorithm: 'foo' })).to.throw('Decryption algorithm "foo" not found'); | ||
}); | ||
}); | ||
}); | ||
}); |
42 changes: 42 additions & 0 deletions
42
packages/crypto/src/encryption-algorithms/encryption-algorithms.registry.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,42 @@ | ||
import type { EncryptionAlgorithm, EncryptionMethodsDefinition } from './encryption-algorithms.types'; | ||
import { keys } from 'lodash-es'; | ||
|
||
export { createEncryptionAlgorithmsRegistry }; | ||
|
||
function createEncryptionAlgorithmsRegistry({ | ||
encryptionMethodDefinitions, | ||
}: { | ||
encryptionMethodDefinitions: Record<EncryptionAlgorithm, EncryptionMethodsDefinition>; | ||
}) { | ||
const encryptionAlgorithms = keys(encryptionMethodDefinitions); | ||
|
||
return { | ||
encryptionMethodDefinitions, | ||
encryptionAlgorithms, | ||
|
||
getEncryptionMethod: ({ encryptionAlgorithm }: { encryptionAlgorithm: string }) => { | ||
const encryptionMethods: EncryptionMethodsDefinition | undefined = encryptionMethodDefinitions[encryptionAlgorithm]; | ||
|
||
if (!encryptionMethods) { | ||
throw new Error(`Encryption algorithm "${encryptionAlgorithm}" not found`); | ||
} | ||
|
||
const { encryptBuffer } = encryptionMethods; | ||
|
||
return { encryptBuffer }; | ||
}, | ||
|
||
getDecryptionMethod: ({ encryptionAlgorithm }: { encryptionAlgorithm: string }) => { | ||
const encryptionMethods = encryptionMethodDefinitions[encryptionAlgorithm]; | ||
|
||
if (!encryptionMethods) { | ||
throw new Error(`Decryption algorithm "${encryptionAlgorithm}" not found`); | ||
} | ||
|
||
const { decryptString } = encryptionMethods; | ||
|
||
return { decryptString }; | ||
}, | ||
|
||
}; | ||
}; |
27 changes: 27 additions & 0 deletions
27
packages/crypto/src/encryption-algorithms/encryption-algorithms.test-utils.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,27 @@ | ||
import type { EncryptionMethodsDefinition } from './encryption-algorithms.types'; | ||
import { times } from 'lodash-es'; | ||
import { describe, expect, test } from 'vitest'; | ||
|
||
export { | ||
runCommonEncryptionAlgorithmTest, | ||
}; | ||
|
||
function runCommonEncryptionAlgorithmTest({ | ||
encryptionMethodDefinition, | ||
}: { | ||
encryptionMethodDefinition: EncryptionMethodsDefinition; | ||
}) { | ||
const { encryptBuffer, decryptString } = encryptionMethodDefinition; | ||
|
||
describe('encryptBuffer and decryptString', () => { | ||
test('an encrypted buffer can be decrypted', async () => { | ||
const encryptionKey = new Uint8Array(times(32, i => i)); | ||
const buffer = new Uint8Array([11, 22, 33, 44, 55, 66, 77, 88]); | ||
|
||
const { encryptedString } = await encryptBuffer({ buffer, encryptionKey }); | ||
const { decryptedBuffer } = await decryptString({ encryptedString, encryptionKey }); | ||
|
||
expect(decryptedBuffer).to.eql(buffer); | ||
}); | ||
}); | ||
} |
10 changes: 10 additions & 0 deletions
10
packages/crypto/src/encryption-algorithms/encryption-algorithms.types.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,10 @@ | ||
import type { ENCRYPTION_ALGORITHMS } from './encryption-algorithms.constants'; | ||
|
||
export type EncryptionMethodsDefinition = { | ||
encryptBuffer: (args: { buffer: Uint8Array; encryptionKey: Uint8Array }) => Promise<{ encryptedString: string }>; | ||
decryptString: (args: { encryptedString: string; encryptionKey: Uint8Array }) => Promise<{ decryptedBuffer: Uint8Array }>; | ||
}; | ||
|
||
export type EncryptionAlgorithm = typeof ENCRYPTION_ALGORITHMS[number]; | ||
|
||
export type EncryptionAlgorithmDefinitions = Record<EncryptionAlgorithm, EncryptionMethodsDefinition>; |
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,21 @@ | ||
import { createEnclosedCryptoApi } from './api-definition'; | ||
import * as webCryptoApi from './node/crypto.node.usecases'; | ||
import { aes256GcmEncryptionAlgorithmDefinition } from './node/encryption-algorithms/crypto.node.aes-256-gcm'; | ||
|
||
export type { EncryptionAlgorithm, EncryptionAlgorithmDefinitions, EncryptionMethodsDefinition } from './encryption-algorithms/encryption-algorithms.types'; | ||
|
||
export const { | ||
deriveMasterKey, | ||
generateBaseKey, | ||
encryptionAlgorithms, | ||
encryptionMethodDefinitions, | ||
getDecryptionMethod, | ||
getEncryptionMethod, | ||
base64UrlToBuffer, | ||
bufferToBase64Url, | ||
} = createEnclosedCryptoApi({ | ||
...webCryptoApi, | ||
encryptionMethodDefinitions: { | ||
'aes-256-gcm': aes256GcmEncryptionAlgorithmDefinition, | ||
}, | ||
}); |
Oops, something went wrong.