From 9c65c93c342c9924b328bdddaf269e94db67368b Mon Sep 17 00:00:00 2001 From: Vijay Budhram Date: Tue, 4 Jun 2024 11:15:01 -0400 Subject: [PATCH] feat(crypto): Update webpack config to use vendored crypto relier --- libs/vendored/crypto-relier/project.json | 2 +- .../src/lib/deriver/deriver-utils.ts | 36 ++++--- .../src/lib/deriver/driver-utils.spec.ts | 6 +- .../crypto-relier/src/lib/deriver/index.ts | 6 +- .../src/lib/deriver/scoped-keys.ts | 16 ++-- package.json | 1 + packages/fxa-content-server/package.json | 2 +- packages/fxa-content-server/webpack.config.js | 10 +- .../fxa-settings/config/webpack.config.js | 14 ++- packages/fxa-settings/package.json | 4 +- yarn.lock | 93 +++---------------- 11 files changed, 76 insertions(+), 114 deletions(-) diff --git a/libs/vendored/crypto-relier/project.json b/libs/vendored/crypto-relier/project.json index 84fc4ecae0..58546a79ab 100644 --- a/libs/vendored/crypto-relier/project.json +++ b/libs/vendored/crypto-relier/project.json @@ -16,7 +16,7 @@ "assets": ["libs/vendored/crypto-relier/*.md"] } }, - "test-unit": { + "test": { "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "options": { diff --git a/libs/vendored/crypto-relier/src/lib/deriver/deriver-utils.ts b/libs/vendored/crypto-relier/src/lib/deriver/deriver-utils.ts index 05ed9c5de6..893b0d211f 100644 --- a/libs/vendored/crypto-relier/src/lib/deriver/deriver-utils.ts +++ b/libs/vendored/crypto-relier/src/lib/deriver/deriver-utils.ts @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import * as jose from 'jose'; +import * as jose from 'node-jose'; /** * Scoped key deriver utilities @@ -17,28 +17,38 @@ export class DeriverUtils { * @returns {Promise} */ async encryptBundle(appPublicKeyJwk: string, bundle: string) { - const rawKey = jose.decodeJwt('.' + appPublicKeyJwk + '.'); - const key = await jose.importJWK(rawKey); + bundle = jose.util.asBuffer(bundle); + const appJwk = jose.util.base64url.decode(appPublicKeyJwk); + + const key = await jose.JWK.asKey(appJwk); // To help reliers do the right thing, we reject keys that aren't exactly as we expect. // In the future we might open up to additional key types, but for now it's better to // be strict in what we accept. - if (rawKey.kty !== 'EC') { + if (key.kty !== 'EC') { throw new Error('appJwk is not an EC key'); } - if (rawKey.crv !== 'P-256') { + if (key.get('crv') !== 'P-256') { throw new Error('appJwk is not on curve P-256'); } - if ('d' in rawKey) { + if (key.has('d', true)) { throw new Error('appJwk includes the private key'); } - - return new jose.CompactEncrypt(new TextEncoder().encode(bundle)) - .setProtectedHeader({ + const recipient = { + key: key, + header: { alg: 'ECDH-ES', - enc: 'A256GCM', - kid: rawKey.kid as any, - }) - .encrypt(key); + }, + }; + + const jwe = jose.JWE.createEncrypt( + { + format: 'compact', + contentAlg: 'A256GCM', + }, + recipient + ); + + return jwe.update(bundle).final(); } } diff --git a/libs/vendored/crypto-relier/src/lib/deriver/driver-utils.spec.ts b/libs/vendored/crypto-relier/src/lib/deriver/driver-utils.spec.ts index 23b1991651..bde5cf4c33 100644 --- a/libs/vendored/crypto-relier/src/lib/deriver/driver-utils.spec.ts +++ b/libs/vendored/crypto-relier/src/lib/deriver/driver-utils.spec.ts @@ -2,13 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import * as jose from 'jose'; +import base64url from 'base64url'; import { DeriverUtils } from './deriver-utils'; describe('DeriverUtils', () => { const deriverUtils = new DeriverUtils(); - const b64urlencode = jose.base64url.encode; + const b64urlencode = base64url.encode; const exampleScope = 'https://identity.mozilla.com/apps/notes'; const keySample = { @@ -97,7 +97,7 @@ describe('DeriverUtils', () => { ); await expect( deriverUtils.encryptBundle(appPublicKeyJwk, JSON.stringify(keySample)) - ).rejects.toThrow('Invalid JWK EC key'); + ).rejects.toThrow('invalid EC public key'); }); }); }); diff --git a/libs/vendored/crypto-relier/src/lib/deriver/index.ts b/libs/vendored/crypto-relier/src/lib/deriver/index.ts index 7c0c3c846f..2f113bef42 100644 --- a/libs/vendored/crypto-relier/src/lib/deriver/index.ts +++ b/libs/vendored/crypto-relier/src/lib/deriver/index.ts @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -export * as jose from 'jose'; +export * as jose from 'node-jose'; export * as base64url from 'base64url'; -export * as DeriverUtils from './deriver-utils'; -export * as ScopedKeys from './scoped-keys'; +export * from './deriver-utils'; +export * from './scoped-keys'; diff --git a/libs/vendored/crypto-relier/src/lib/deriver/scoped-keys.ts b/libs/vendored/crypto-relier/src/lib/deriver/scoped-keys.ts index 76785a3a87..bb14f20b9b 100644 --- a/libs/vendored/crypto-relier/src/lib/deriver/scoped-keys.ts +++ b/libs/vendored/crypto-relier/src/lib/deriver/scoped-keys.ts @@ -2,8 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { subtle } from 'crypto'; -import * as jose from 'jose'; +import base64url from 'base64url'; import HKDF from 'node-hkdf'; const KEY_LENGTH = 48; @@ -108,8 +107,8 @@ export class ScopedKeys { const k = key.slice(16, 48); const keyTimestamp = Math.round(options.keyRotationTimestamp / 1000); - scopedKey.k = jose.base64url.encode(k); - scopedKey.kid = keyTimestamp + '-' + jose.base64url.encode(kid); + scopedKey.k = base64url.encode(k); + scopedKey.kid = keyTimestamp + '-' + base64url.encode(kid); return scopedKey; } @@ -149,13 +148,16 @@ export class ScopedKeys { contextBuf, 64 ); - scopedKey.k = jose.base64url.encode(Buffer.from(key)); + scopedKey.k = base64url.encode(Buffer.from(key)); - const kHash = await subtle.digest('SHA-256', Buffer.from(inputKeyBuf)); + const kHash = await crypto.subtle.digest( + 'SHA-256', + Buffer.from(inputKeyBuf) + ); scopedKey.kid = options.keyRotationTimestamp + '-' + - jose.base64url.encode(Buffer.from(kHash.slice(0, 16))); + base64url.encode(Buffer.from(kHash.slice(0, 16))); return scopedKey; } diff --git a/package.json b/package.json index 42be803bec..719f01220b 100644 --- a/package.json +++ b/package.json @@ -274,6 +274,7 @@ "packageManager": "yarn@3.3.0", "_moduleAliases": { "@fxa/vendored/jwtool": "./dist/libs/vendored/jwtool/src/index.js", + "@fxa/vendored/crypto-relier": "./dist/libs/vendored/crypto-relier/src/index.js", "@fxa/shared/pem-jwk": "./dist/libs/shared/pem-jwk/src/index.js", "@fxa/shared/l10n": "./dist/libs/shared/l10n/src/index.js" } diff --git a/packages/fxa-content-server/package.json b/packages/fxa-content-server/package.json index a90e9e8beb..b0bf8f5c4c 100644 --- a/packages/fxa-content-server/package.json +++ b/packages/fxa-content-server/package.json @@ -50,6 +50,7 @@ "backbone.cocktail": "0.5.15", "base32-decode": "1.0.0", "body-parser": "^1.20.1", + "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "cache-loader": "^4.1.0", "chosen-js": "https://github.com/mozilla-fxa/chosen.git#3bea55b356c249ae82980c04f67ccc98ff3b28b0", @@ -70,7 +71,6 @@ "fxa-auth-client": "workspace:*", "fxa-auth-server": "workspace:*", "fxa-common-password-list": "0.0.4", - "fxa-crypto-relier": "2.7.0", "fxa-geodb": "workspace:*", "fxa-mustache-loader": "0.0.2", "fxa-pairing-channel": "1.0.2", diff --git a/packages/fxa-content-server/webpack.config.js b/packages/fxa-content-server/webpack.config.js index 3fe24b3804..49411acea5 100644 --- a/packages/fxa-content-server/webpack.config.js +++ b/packages/fxa-content-server/webpack.config.js @@ -45,6 +45,8 @@ const webpackConfig = { buffer: require.resolve('buffer/'), crypto: require.resolve('crypto-browserify'), stream: require.resolve('stream-browserify'), + 'process/browser': require.resolve('process/browser'), + zlib: require.resolve('browserify-zlib'), }, modules: [ path.resolve(__dirname, 'app/scripts'), @@ -62,8 +64,9 @@ const webpackConfig = { draggable: require.resolve('jquery-ui/ui/widgets/draggable'), duration: require.resolve('duration-js/duration'), 'fast-text-encoding': require.resolve('fast-text-encoding'), - fxaCryptoDeriver: require.resolve( - 'fxa-crypto-relier/dist/fxa-crypto-relier/fxa-crypto-deriver' + fxaCryptoDeriver: path.resolve( + __dirname, + '../../dist/libs/vendored/crypto-relier/src/lib/deriver/index.js' ), fxaPairingChannel: require.resolve( 'fxa-pairing-channel/dist/FxAccountsPairingChannel.babel.umd.js' @@ -234,6 +237,9 @@ const webpackConfig = { ], }), new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }), + new webpack.ProvidePlugin({ + process: 'process/browser', + }), ], stats: { colors: true }, diff --git a/packages/fxa-settings/config/webpack.config.js b/packages/fxa-settings/config/webpack.config.js index b96688b54d..ef78a1174f 100644 --- a/packages/fxa-settings/config/webpack.config.js +++ b/packages/fxa-settings/config/webpack.config.js @@ -73,6 +73,8 @@ const cssModuleRegex = /\.module\.css$/; const sassRegex = /\.(scss|sass)$/; const sassModuleRegex = /\.module\.(scss|sass)$/; +require('module-alias/register'); + const hasJsxRuntime = (() => { if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') { return false; @@ -328,9 +330,7 @@ module.exports = function (webpackEnv) { 'react-dom$': 'react-dom/profiling', 'scheduler/tracing': 'scheduler/tracing-profiling', }), - fxaCryptoDeriver: require.resolve( - 'fxa-crypto-relier/dist/fxa-crypto-relier/fxa-crypto-deriver' - ), + fxaCryptoDeriver: require.resolve('@fxa/vendored/crypto-relier'), ...(modules.webpackAliases || {}), }, plugins: [ @@ -355,6 +355,11 @@ module.exports = function (webpackEnv) { fallback: { fs: false, path: false, + buffer: require.resolve('buffer/'), + crypto: require.resolve('crypto-browserify'), + stream: require.resolve('stream-browserify'), + 'process/browser': require.resolve('process/browser'), + zlib: require.resolve('browserify-zlib'), }, }, module: { @@ -588,6 +593,9 @@ module.exports = function (webpackEnv) { ].filter(Boolean), }, plugins: [ + new webpack.ProvidePlugin({ + process: 'process/browser', + }), // Generates an `index.html` file with the