diff --git a/packages/core/package.json b/packages/core/package.json index 8778fe268..fe6a62e8e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -32,6 +32,7 @@ "@logto/phrases": "^0.1.0", "@logto/schemas": "^0.1.0", "@silverhand/essentials": "^1.1.0", + "argon2": "^0.28.5", "chalk": "^4", "dayjs": "^1.10.5", "decamelize": "^5.0.0", diff --git a/packages/core/src/__mocks__/user.ts b/packages/core/src/__mocks__/user.ts index 668bc7654..7131af08d 100644 --- a/packages/core/src/__mocks__/user.ts +++ b/packages/core/src/__mocks__/user.ts @@ -9,7 +9,6 @@ export const mockUser: User = { roleNames: ['admin'], passwordEncrypted: null, passwordEncryptionMethod: null, - passwordEncryptionSalt: null, name: null, avatar: null, identities: { @@ -31,7 +30,6 @@ export const mockUserList: User[] = [ roleNames: ['admin'], passwordEncrypted: null, passwordEncryptionMethod: null, - passwordEncryptionSalt: null, name: null, avatar: null, identities: {}, @@ -47,7 +45,6 @@ export const mockUserList: User[] = [ roleNames: ['admin'], passwordEncrypted: null, passwordEncryptionMethod: null, - passwordEncryptionSalt: null, name: null, avatar: null, identities: {}, @@ -63,7 +60,6 @@ export const mockUserList: User[] = [ roleNames: ['admin'], passwordEncrypted: null, passwordEncryptionMethod: null, - passwordEncryptionSalt: null, name: null, avatar: null, identities: {}, @@ -79,7 +75,6 @@ export const mockUserList: User[] = [ roleNames: ['admin'], passwordEncrypted: null, passwordEncryptionMethod: null, - passwordEncryptionSalt: null, name: null, avatar: null, identities: {}, @@ -95,7 +90,6 @@ export const mockUserList: User[] = [ roleNames: ['admin'], passwordEncrypted: null, passwordEncryptionMethod: null, - passwordEncryptionSalt: null, name: null, avatar: null, identities: {}, diff --git a/packages/core/src/lib/user.test.ts b/packages/core/src/lib/user.test.ts index 051e144ac..c631671b1 100644 --- a/packages/core/src/lib/user.test.ts +++ b/packages/core/src/lib/user.test.ts @@ -53,12 +53,10 @@ describe('generateUserId()', () => { }); describe('encryptUserPassword()', () => { - it('generates salt, encrypted and method', () => { - const { passwordEncryptionMethod, passwordEncrypted, passwordEncryptionSalt } = - encryptUserPassword('user-id', 'password'); - expect(passwordEncryptionMethod).toEqual(UsersPasswordEncryptionMethod.SaltAndPepper); - expect(passwordEncrypted).toHaveLength(64); - expect(passwordEncryptionSalt).toHaveLength(21); + it('generates salt, encrypted and method', async () => { + const { passwordEncryptionMethod, passwordEncrypted } = await encryptUserPassword('password'); + expect(passwordEncryptionMethod).toEqual(UsersPasswordEncryptionMethod.Argon2i); + expect(passwordEncrypted).toContain('argon2'); }); }); diff --git a/packages/core/src/lib/user.ts b/packages/core/src/lib/user.ts index aa490bba5..5b397f439 100644 --- a/packages/core/src/lib/user.ts +++ b/packages/core/src/lib/user.ts @@ -1,5 +1,5 @@ import { User, UsersPasswordEncryptionMethod } from '@logto/schemas'; -import { nanoid } from 'nanoid'; +import argon2 from 'argon2'; import pRetry from 'p-retry'; import { findUserByUsername, hasUserWithId, updateUserById } from '@/queries/user'; @@ -23,24 +23,20 @@ export const generateUserId = async (retries = 500) => { retries, factor: 0 } // No need for exponential backoff ); -export const encryptUserPassword = ( - userId: string, +export const encryptUserPassword = async ( password: string -): { - passwordEncryptionSalt: string; +): Promise<{ passwordEncrypted: string; passwordEncryptionMethod: UsersPasswordEncryptionMethod; -} => { - const passwordEncryptionSalt = nanoid(); - const passwordEncryptionMethod = UsersPasswordEncryptionMethod.SaltAndPepper; - const passwordEncrypted = encryptPassword( - userId, +}> => { + const passwordEncryptionMethod = UsersPasswordEncryptionMethod.Argon2i; + const passwordEncrypted = await encryptPassword( password, - passwordEncryptionSalt, + passwordEncryptionMethod ); - return { passwordEncrypted, passwordEncryptionMethod, passwordEncryptionSalt }; + return { passwordEncrypted, passwordEncryptionMethod }; }; export const findUserByUsernameAndPassword = async ( @@ -48,18 +44,13 @@ export const findUserByUsernameAndPassword = async ( password: string ): Promise => { const user = await findUserByUsername(username); - const { id, passwordEncrypted, passwordEncryptionMethod, passwordEncryptionSalt } = user; + const { passwordEncrypted, passwordEncryptionMethod } = user; - assertThat( - passwordEncrypted && passwordEncryptionMethod && passwordEncryptionSalt, - 'session.invalid_sign_in_method' - ); + assertThat(passwordEncrypted && passwordEncryptionMethod, 'session.invalid_sign_in_method'); - assertThat( - encryptPassword(id, password, passwordEncryptionSalt, passwordEncryptionMethod) === - passwordEncrypted, - 'session.invalid_credentials' - ); + const result = await argon2.verify(passwordEncrypted, password); + + assertThat(result, 'session.invalid_credentials'); return user; }; diff --git a/packages/core/src/routes/admin-user.test.ts b/packages/core/src/routes/admin-user.test.ts index 39037d4b1..7608133cc 100644 --- a/packages/core/src/routes/admin-user.test.ts +++ b/packages/core/src/routes/admin-user.test.ts @@ -53,9 +53,8 @@ jest.mock('@/queries/user', () => ({ jest.mock('@/lib/user', () => ({ generateUserId: jest.fn(() => 'fooId'), encryptUserPassword: jest.fn(() => ({ - passwordEncryptionSalt: 'salt', passwordEncrypted: 'password', - passwordEncryptionMethod: 'saltAndPepper', + passwordEncryptionMethod: 'Argon2i', })), })); @@ -242,7 +241,7 @@ describe('adminUserRoutes', () => { const mockedUserId = 'foo'; const password = '123456'; const response = await userRequest.patch(`/users/${mockedUserId}/password`).send({ password }); - expect(encryptUserPassword).toHaveBeenCalledWith(mockedUserId, password); + expect(encryptUserPassword).toHaveBeenCalledWith(password); expect(updateUserById).toHaveBeenCalledTimes(1); expect(response.status).toEqual(200); expect(response.body).toEqual({ diff --git a/packages/core/src/routes/admin-user.ts b/packages/core/src/routes/admin-user.ts index cf62d2df4..e47f20027 100644 --- a/packages/core/src/routes/admin-user.ts +++ b/packages/core/src/routes/admin-user.ts @@ -88,15 +88,13 @@ export default function adminUserRoutes(router: T) { const id = await generateUserId(); - const { passwordEncryptionSalt, passwordEncrypted, passwordEncryptionMethod } = - encryptUserPassword(id, password); + const { passwordEncrypted, passwordEncryptionMethod } = await encryptUserPassword(password); const user = await insertUser({ id, username, passwordEncrypted, passwordEncryptionMethod, - passwordEncryptionSalt, name, }); @@ -169,13 +167,11 @@ export default function adminUserRoutes(router: T) { await findUserById(userId); - const { passwordEncryptionSalt, passwordEncrypted, passwordEncryptionMethod } = - encryptUserPassword(userId, password); + const { passwordEncrypted, passwordEncryptionMethod } = await encryptUserPassword(password); const user = await updateUserById(userId, { passwordEncrypted, passwordEncryptionMethod, - passwordEncryptionSalt, }); ctx.body = pick(user, ...userInfoSelectFields); diff --git a/packages/core/src/routes/session.test.ts b/packages/core/src/routes/session.test.ts index 3cc189a24..38a71acf5 100644 --- a/packages/core/src/routes/session.test.ts +++ b/packages/core/src/routes/session.test.ts @@ -23,10 +23,9 @@ jest.mock('@/lib/user', () => ({ return { id: 'user1' }; }, generateUserId: () => 'user1', - encryptUserPassword: (userId: string, password: string) => ({ - passwordEncrypted: userId + '_' + password + '_user1', - passwordEncryptionMethod: 'SaltAndPepper', - passwordEncryptionSalt: 'user1', + encryptUserPassword: (password: string) => ({ + passwordEncrypted: password + '_user1', + passwordEncryptionMethod: 'Argon2i', }), updateLastSignInAt: async (...args: unknown[]) => updateUserById(...args), })); @@ -490,9 +489,8 @@ describe('sessionRoutes', () => { expect.objectContaining({ id: 'user1', username: 'username', - passwordEncrypted: 'user1_password_user1', - passwordEncryptionMethod: 'SaltAndPepper', - passwordEncryptionSalt: 'user1', + passwordEncrypted: 'password_user1', + passwordEncryptionMethod: 'Argon2i', }) ); expect(response.body).toHaveProperty('redirectTo'); diff --git a/packages/core/src/routes/session.ts b/packages/core/src/routes/session.ts index 49f0b528e..3202f90cf 100644 --- a/packages/core/src/routes/session.ts +++ b/packages/core/src/routes/session.ts @@ -346,15 +346,13 @@ export default function sessionRoutes(router: T, prov const id = await generateUserId(); ctx.log(type, { userId: id }); - const { passwordEncryptionSalt, passwordEncrypted, passwordEncryptionMethod } = - encryptUserPassword(id, password); + const { passwordEncrypted, passwordEncryptionMethod } = await encryptUserPassword(password); await insertUser({ id, username, passwordEncrypted, passwordEncryptionMethod, - passwordEncryptionSalt, }); await updateLastSignInAt(id); await assignInteractionResults(ctx, provider, { login: { accountId: id } }); diff --git a/packages/core/src/utils/password.ts b/packages/core/src/utils/password.ts index c90d47639..852539bcb 100644 --- a/packages/core/src/utils/password.ts +++ b/packages/core/src/utils/password.ts @@ -1,39 +1,18 @@ -import { createHash } from 'crypto'; - import { UsersPasswordEncryptionMethod } from '@logto/schemas'; -import { repeat } from '@silverhand/essentials'; +import argon2 from 'argon2'; -import envSet from '@/env-set'; import assertThat from '@/utils/assert-that'; -export const encryptPassword = ( - id: string, +export const encryptPassword = async ( password: string, - salt: string, method: UsersPasswordEncryptionMethod -): string => { +): Promise => { assertThat( - // FIXME: // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - method === UsersPasswordEncryptionMethod.SaltAndPepper, + method === UsersPasswordEncryptionMethod.Argon2i, 'password.unsupported_encryption_method', { method } ); - const sum = [...id].reduce( - (accumulator, current) => accumulator + (current.codePointAt(0) ?? 0), - 0 - ); - const { peppers, iterationCount } = envSet.values.password; - const pepper = peppers[sum % peppers.length]; - - assertThat(pepper, 'password.pepper_not_found'); - - const result = repeat(iterationCount, password, (password) => - createHash('sha256') - .update(salt + password + pepper) - .digest('hex') - ); - - return result; + return argon2.hash(password, { timeCost: 10 }); }; diff --git a/packages/schemas/src/db-entries/custom-types.ts b/packages/schemas/src/db-entries/custom-types.ts index 80eaebc00..6f8f8da9b 100644 --- a/packages/schemas/src/db-entries/custom-types.ts +++ b/packages/schemas/src/db-entries/custom-types.ts @@ -11,5 +11,5 @@ export enum PasscodeType { ForgotPassword = 'ForgotPassword', } export enum UsersPasswordEncryptionMethod { - SaltAndPepper = 'SaltAndPepper', + Argon2i = 'Argon2i', } diff --git a/packages/schemas/src/db-entries/user.ts b/packages/schemas/src/db-entries/user.ts index 2c3f1120f..a24544e84 100644 --- a/packages/schemas/src/db-entries/user.ts +++ b/packages/schemas/src/db-entries/user.ts @@ -21,7 +21,6 @@ export type CreateUser = { primaryPhone?: string | null; passwordEncrypted?: string | null; passwordEncryptionMethod?: UsersPasswordEncryptionMethod | null; - passwordEncryptionSalt?: string | null; name?: string | null; avatar?: string | null; applicationId?: string | null; @@ -38,7 +37,6 @@ export type User = { primaryPhone: string | null; passwordEncrypted: string | null; passwordEncryptionMethod: UsersPasswordEncryptionMethod | null; - passwordEncryptionSalt: string | null; name: string | null; avatar: string | null; applicationId: string | null; @@ -55,7 +53,6 @@ const createGuard: Guard = z.object({ primaryPhone: z.string().nullable().optional(), passwordEncrypted: z.string().nullable().optional(), passwordEncryptionMethod: z.nativeEnum(UsersPasswordEncryptionMethod).nullable().optional(), - passwordEncryptionSalt: z.string().nullable().optional(), name: z.string().nullable().optional(), avatar: z.string().nullable().optional(), applicationId: z.string().nullable().optional(), @@ -75,7 +72,6 @@ export const Users: GeneratedSchema = Object.freeze({ primaryPhone: 'primary_phone', passwordEncrypted: 'password_encrypted', passwordEncryptionMethod: 'password_encryption_method', - passwordEncryptionSalt: 'password_encryption_salt', name: 'name', avatar: 'avatar', applicationId: 'application_id', @@ -91,7 +87,6 @@ export const Users: GeneratedSchema = Object.freeze({ 'primaryPhone', 'passwordEncrypted', 'passwordEncryptionMethod', - 'passwordEncryptionSalt', 'name', 'avatar', 'applicationId', diff --git a/packages/schemas/tables/users.sql b/packages/schemas/tables/users.sql index ad68cf7e4..72fd0ff7a 100644 --- a/packages/schemas/tables/users.sql +++ b/packages/schemas/tables/users.sql @@ -1,4 +1,4 @@ -create type users_password_encryption_method as enum ('SaltAndPepper'); +create type users_password_encryption_method as enum ('Argon2i'); create table users ( id varchar(12) not null, @@ -7,7 +7,6 @@ create table users ( primary_phone varchar(128) unique, password_encrypted varchar(128), password_encryption_method users_password_encryption_method, - password_encryption_salt varchar(128), name varchar(128), avatar varchar(256), application_id varchar(21) references applications(id), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c69c4ffb2..5060be6fe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -571,6 +571,7 @@ importers: '@types/node': ^16.3.1 '@types/oidc-provider': ^7.8.0 '@types/supertest': ^2.0.11 + argon2: ^0.28.5 chalk: ^4 copyfiles: ^2.4.1 dayjs: ^1.10.5 @@ -626,6 +627,7 @@ importers: '@logto/phrases': link:../phrases '@logto/schemas': link:../schemas '@silverhand/essentials': 1.1.2 + argon2: 0.28.5 chalk: 4.1.2 dayjs: 1.10.7 decamelize: 5.0.1 @@ -5282,6 +5284,24 @@ packages: react: 17.0.2 dev: true + /@mapbox/node-pre-gyp/1.0.9: + resolution: {integrity: sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==} + hasBin: true + dependencies: + detect-libc: 2.0.1 + https-proxy-agent: 5.0.0 + make-dir: 3.1.0 + node-fetch: 2.6.7 + nopt: 5.0.0 + npmlog: 5.0.1 + rimraf: 3.0.2 + semver: 7.3.7 + tar: 6.1.11 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /@mdx-js/mdx/1.6.22: resolution: {integrity: sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==} dependencies: @@ -6337,6 +6357,11 @@ packages: webcrypto-core: 1.7.3 dev: true + /@phc/format/1.0.0: + resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} + engines: {node: '>=10'} + dev: false + /@polka/url/1.0.0-next.21: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} dev: true @@ -7671,7 +7696,6 @@ packages: /abbrev/1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - dev: true /abortcontroller-polyfill/1.7.3: resolution: {integrity: sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q==} @@ -7759,7 +7783,6 @@ packages: debug: 4.3.3 transitivePeerDependencies: - supports-color - dev: true /agentkeepalive/4.2.1: resolution: {integrity: sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==} @@ -7924,7 +7947,6 @@ packages: /aproba/2.0.0: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} - dev: true /are-we-there-yet/1.1.7: resolution: {integrity: sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==} @@ -7933,6 +7955,14 @@ packages: readable-stream: 2.3.7 dev: true + /are-we-there-yet/2.0.0: + resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} + engines: {node: '>=10'} + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.0 + dev: false + /arg/4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} dev: true @@ -7941,6 +7971,19 @@ packages: resolution: {integrity: sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==} dev: true + /argon2/0.28.5: + resolution: {integrity: sha512-kGFCctzc3VWmR1aCOYjNgvoTmVF5uVBUtWlXCKKO54d1K+31zRz45KAcDIqMo2746ozv/52d25nfEekitaXP0w==} + engines: {node: '>=12.0.0'} + requiresBuild: true + dependencies: + '@mapbox/node-pre-gyp': 1.0.9 + '@phc/format': 1.0.0 + node-addon-api: 4.3.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /argparse/1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: @@ -8797,7 +8840,6 @@ packages: /chownr/2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} - dev: true /chrome-trace-event/1.0.3: resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} @@ -8980,6 +9022,11 @@ packages: /color-name/1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + /color-support/1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + dev: false + /colord/2.9.2: resolution: {integrity: sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==} dev: true @@ -9116,7 +9163,6 @@ packages: /console-control-strings/1.1.0: resolution: {integrity: sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=} - dev: true /content-disposition/0.5.2: resolution: {integrity: sha1-DPaLud318r55YcOoUXjLhdunjLQ=} @@ -9826,6 +9872,11 @@ packages: hasBin: true dev: true + /detect-libc/2.0.1: + resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==} + engines: {node: '>=8'} + dev: false + /detect-newline/3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -11194,7 +11245,6 @@ packages: engines: {node: '>= 8'} dependencies: minipass: 3.1.6 - dev: true /fs-monkey/1.0.3: resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} @@ -11202,7 +11252,6 @@ packages: /fs.realpath/1.0.0: resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} - dev: true /fsevents/2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} @@ -11232,6 +11281,21 @@ packages: wide-align: 1.1.5 dev: true + /gauge/3.0.2: + resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} + engines: {node: '>=10'} + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: false + /generic-names/4.0.0: resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} dependencies: @@ -11413,7 +11477,6 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true /global-dirs/0.1.1: resolution: {integrity: sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=} @@ -11638,7 +11701,6 @@ packages: /has-unicode/2.0.1: resolution: {integrity: sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=} - dev: true /has-yarn/2.1.0: resolution: {integrity: sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==} @@ -12026,7 +12088,6 @@ packages: debug: 4.3.3 transitivePeerDependencies: - supports-color - dev: true /human-signals/2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} @@ -12214,7 +12275,6 @@ packages: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true /inherits/2.0.1: resolution: {integrity: sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=} @@ -14104,7 +14164,6 @@ packages: engines: {node: '>=8'} dependencies: semver: 6.3.0 - dev: true /make-error/1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} @@ -14796,7 +14855,6 @@ packages: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 - dev: true /minimist-options/4.1.0: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} @@ -14869,7 +14927,6 @@ packages: engines: {node: '>=8'} dependencies: yallist: 4.0.0 - dev: true /minizlib/1.3.3: resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==} @@ -14883,7 +14940,6 @@ packages: dependencies: minipass: 3.1.6 yallist: 4.0.0 - dev: true /mkdirp-infer-owner/2.0.0: resolution: {integrity: sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw==} @@ -14905,7 +14961,6 @@ packages: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true - dev: true /modify-values/1.0.1: resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} @@ -15046,6 +15101,10 @@ packages: resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} dev: true + /node-addon-api/4.3.0: + resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} + dev: false + /node-cleanup/2.1.2: resolution: {integrity: sha1-esGavSl+Caf3KnFUXZUbUX5N3iw=} dev: true @@ -15066,7 +15125,6 @@ packages: optional: true dependencies: whatwg-url: 5.0.0 - dev: true /node-forge/1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} @@ -15166,7 +15224,6 @@ packages: hasBin: true dependencies: abbrev: 1.1.1 - dev: true /normalize-package-data/2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -15315,6 +15372,15 @@ packages: set-blocking: 2.0.0 dev: true + /npmlog/5.0.1: + resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + dependencies: + are-we-there-yet: 2.0.0 + console-control-strings: 1.1.0 + gauge: 3.0.2 + set-blocking: 2.0.0 + dev: false + /nprogress/0.2.0: resolution: {integrity: sha1-y480xTIT2JVyP8urkH6UIq28r7E=} dev: true @@ -15360,7 +15426,6 @@ packages: /object-assign/4.1.1: resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=} engines: {node: '>=0.10.0'} - dev: true /object-hash/2.2.0: resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} @@ -18004,7 +18069,6 @@ packages: hasBin: true dependencies: glob: 7.2.0 - dev: true /roarr/2.15.4: resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} @@ -18192,7 +18256,6 @@ packages: /semver/6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true - dev: true /semver/7.0.0: resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} @@ -18212,7 +18275,6 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 - dev: true /send/0.17.2: resolution: {integrity: sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==} @@ -18291,7 +18353,6 @@ packages: /set-blocking/2.0.0: resolution: {integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=} - dev: true /setimmediate/1.0.5: resolution: {integrity: sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=} @@ -19301,7 +19362,6 @@ packages: minizlib: 2.1.2 mkdirp: 1.0.4 yallist: 4.0.0 - dev: true /temp-dir/1.0.0: resolution: {integrity: sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=} @@ -19505,7 +19565,6 @@ packages: /tr46/0.0.3: resolution: {integrity: sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=} - dev: true /tr46/1.0.1: resolution: {integrity: sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=} @@ -20478,7 +20537,6 @@ packages: /webidl-conversions/3.0.1: resolution: {integrity: sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=} - dev: true /webidl-conversions/4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} @@ -20717,7 +20775,6 @@ packages: dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 - dev: true /whatwg-url/7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} @@ -20765,7 +20822,6 @@ packages: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} dependencies: string-width: 4.2.3 - dev: true /widest-line/3.1.0: resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==}