diff --git a/app-config-cli/src/index.ts b/app-config-cli/src/index.ts index 668eb888..66283460 100644 --- a/app-config-cli/src/index.ts +++ b/app-config-cli/src/index.ts @@ -562,7 +562,7 @@ export const cli = yargs } process.stdout.write(`\nYour app-config key was set up in ${keyDirs.keychain}\n\n`); - process.stdout.write(initialized.publicKeyArmored); + process.stdout.write(initialized.publicKey); process.stdout.write('\n'); }, ), @@ -676,10 +676,10 @@ export const cli = yargs async () => { logger.info('Creating a new trusted CI encryption key'); - const { privateKeyArmored, publicKeyArmored } = await initializeKeys(false); - await trustTeamMember(await loadKey(publicKeyArmored), await loadPrivateKeyLazy()); + const { privateKey, publicKey } = await initializeKeys(false); + await trustTeamMember(await loadKey(publicKey), await loadPrivateKeyLazy()); - process.stdout.write(`\n${publicKeyArmored}\n\n${privateKeyArmored}\n\n`); + process.stdout.write(`\n${publicKey}\n\n${privateKey}\n\n`); process.stdout.write( stripIndents` @@ -716,7 +716,7 @@ export const cli = yargs const privateKey = await loadPrivateKeyLazy(); await trustTeamMember(key, privateKey); - logger.info(`Trusted ${key.getUserIds().join(', ')}`); + logger.info(`Trusted ${key.getUserIDs().join(', ')}`); }, ), ) diff --git a/app-config-encryption/package.json b/app-config-encryption/package.json index 6919a946..07c42a9b 100644 --- a/app-config-encryption/package.json +++ b/app-config-encryption/package.json @@ -38,16 +38,16 @@ "@app-config/settings": "^2.8.7", "@app-config/utils": "^2.8.7", "@lcdev/ws-rpc": "0.4", - "@types/openpgp": "4", "common-tags": "1", "fs-extra": "7", - "openpgp": "^4.3.0", + "openpgp": "^5.9.0", "selfsigned": "2", "text-encoding-utf-8": "1", "ws": "^7.4.6" }, "devDependencies": { "@app-config/test-utils": "^2.8.7", + "@openpgp/web-stream-tools": "^0.0.13", "get-port": "5" }, "prettier": "@lcdev/prettier", diff --git a/app-config-encryption/src/encryption.test.ts b/app-config-encryption/src/encryption.test.ts index 5b17f15e..19be01e5 100644 --- a/app-config-encryption/src/encryption.test.ts +++ b/app-config-encryption/src/encryption.test.ts @@ -25,24 +25,24 @@ import { describe('User Keys', () => { it('initialize keys without passphrase', async () => { - const { privateKeyArmored, publicKeyArmored } = await initializeKeysManually({ + const { privateKey, publicKey } = await initializeKeysManually({ name: 'Tester', email: 'test@example.com', }); - await loadPublicKey(publicKeyArmored); - await loadPrivateKey(privateKeyArmored); + await loadPublicKey(publicKey); + await loadPrivateKey(privateKey); }); it('initialize keys with passphrase', async () => { - const { privateKeyArmored, publicKeyArmored } = await initializeKeysManually({ + const { privateKey, publicKey } = await initializeKeysManually({ name: 'Tester', email: 'test@example.com', passphrase: 'Secret!', }); - await loadPublicKey(publicKeyArmored); - await expect(loadPrivateKey(privateKeyArmored)).rejects.toBeInstanceOf(SecretsRequireTTYError); + await loadPublicKey(publicKey); + await expect(loadPrivateKey(privateKey)).rejects.toBeInstanceOf(SecretsRequireTTYError); }); it('initializes keys with a passphrase from stdin', async () => { @@ -52,21 +52,21 @@ describe('User Keys', () => { .then(() => send('$ecure!')) .catch(() => {}); - const { privateKeyArmored, publicKeyArmored } = await initializeKeys(); + const { privateKey, publicKey } = await initializeKeys(); - await loadPublicKey(publicKeyArmored); + await loadPublicKey(publicKey); send('$ecure!').catch(() => {}); - await loadPrivateKey(privateKeyArmored); + await loadPrivateKey(privateKey); }); }); it('initializes keys into a directory', async () => { await withTempFiles({}, async (inDir) => { const keys = { - privateKeyArmored: 'privateKeyArmored', - publicKeyArmored: 'publicKeyArmored', + privateKey: 'privateKeyArmored', + publicKey: 'publicKeyArmored', revocationCertificate: 'revocationCertificate', }; @@ -103,7 +103,7 @@ describe('User Keys', () => { }); const createKey = async () => { - const { privateKeyArmored } = await initializeKeysManually({ + const { privateKey: privateKeyArmored } = await initializeKeysManually({ name: 'Tester', email: 'test@example.com', }); @@ -230,7 +230,7 @@ describe('E2E Encrypted Repo', () => { }; expect(await initializeLocalKeys(keys, dirs)).toEqual({ - publicKeyArmored: keys.publicKeyArmored, + publicKeyArmored: keys.publicKey, }); const publicKey = await loadPublicKey(); @@ -254,8 +254,8 @@ describe('E2E Encrypted Repo', () => { email: 'teammate@example.com', }); - const teammatePublicKey = await loadPublicKey(teammateKeys.publicKeyArmored); - const teammatePrivateKey = await loadPrivateKey(teammateKeys.privateKeyArmored); + const teammatePublicKey = await loadPublicKey(teammateKeys.publicKey); + const teammatePrivateKey = await loadPrivateKey(teammateKeys.privateKey); await trustTeamMember(teammatePublicKey, privateKey); diff --git a/app-config-encryption/src/encryption.ts b/app-config-encryption/src/encryption.ts index a6e69f91..ae3c070c 100644 --- a/app-config-encryption/src/encryption.ts +++ b/app-config-encryption/src/encryption.ts @@ -2,7 +2,6 @@ import { join, resolve } from 'path'; import * as fs from 'fs-extra'; import * as pgp from 'openpgp'; import { inspect } from 'util'; -import { generateKey, encrypt, decrypt, message, crypto } from 'openpgp'; import { oneLine } from 'common-tags'; import { stringify, @@ -24,8 +23,11 @@ import { } from '@app-config/meta'; import { settingsDirectory } from '@app-config/settings'; import { connectAgentLazy, shouldUseSecretAgent } from './secret-agent'; +import * as crypto from "crypto"; -export type Key = pgp.key.Key & { keyName?: string }; +export type Key = pgp.Key & { keyName?: string }; +export type PrivateKey = pgp.PrivateKey & { keyName?: string }; +export type PublicKey = pgp.PublicKey & { keyName?: string }; export const keyDirs = { get keychain() { @@ -47,8 +49,8 @@ export const keyDirs = { }; interface UserKeys { - privateKeyArmored: string; - publicKeyArmored: string; + privateKey: string; + publicKey: string; revocationCertificate: string; } @@ -65,15 +67,15 @@ export async function initializeKeysManually(options: { logger.verbose(`Initializing a key without a passphrase for ${email}`); } - const { privateKeyArmored, publicKeyArmored, revocationCertificate } = await generateKey({ + const { privateKey, publicKey, revocationCertificate } = await pgp.generateKey({ curve: 'ed25519', - userIds: [{ name, email }], + userIDs: [{ name, email }], passphrase, }); return { - privateKeyArmored, - publicKeyArmored, + privateKey, + publicKey, revocationCertificate, }; } @@ -104,7 +106,7 @@ export async function initializeLocalKeys(keys?: UserKeys, dirs: typeof keyDirs logger.info('Initializing your encryption keys'); - const { privateKeyArmored, publicKeyArmored, revocationCertificate } = + const { privateKey, publicKey, revocationCertificate } = keys ?? (await initializeKeys()); const prevUmask = process.umask(0o077); @@ -115,8 +117,8 @@ export async function initializeLocalKeys(keys?: UserKeys, dirs: typeof keyDirs process.umask(0o177); await Promise.all([ - fs.writeFile(dirs.privateKey, privateKeyArmored), - fs.writeFile(dirs.publicKey, publicKeyArmored), + fs.writeFile(dirs.privateKey, privateKey), + fs.writeFile(dirs.publicKey, publicKey), fs.writeFile(dirs.revocationCert, revocationCertificate), ]); @@ -125,22 +127,22 @@ export async function initializeLocalKeys(keys?: UserKeys, dirs: typeof keyDirs process.umask(prevUmask); } - return { publicKeyArmored }; + return { publicKey }; } export async function deleteLocalKeys(dirs: typeof keyDirs = keyDirs) { await fs.remove(dirs.keychain); } -export async function loadKey(contents: string | Buffer): Promise { - const { err, keys } = await pgp.key.readArmored(contents); - - if (err) throw err[0]; - - return keys[0]; +export async function loadKey(contents: string | Uint8Array): Promise { + if (typeof contents === 'string') { + return await pgp.readPrivateKey({armoredKey: contents}); + } else { + return await pgp.readPrivateKey({binaryKey: contents}); + } } -export async function loadPrivateKey(override?: string | Buffer): Promise { +export async function loadPrivateKey(override?: string | Buffer): Promise { if (override === undefined) { if (process.env.APP_CONFIG_SECRETS_KEY) { // eslint-disable-next-line no-param-reassign @@ -151,7 +153,7 @@ export async function loadPrivateKey(override?: string | Buffer): Promise { } } - let key: Key; + let key: PrivateKey; if (override) { key = await loadKey(override); @@ -173,7 +175,10 @@ export async function loadPrivateKey(override?: string | Buffer): Promise { await promptUserWithRetry( { message: 'Your Passphrase', type: 'password' }, async (passphrase) => { - return key.decrypt(passphrase).then( + return pgp.decryptKey({ + privateKey: key, + passphrase + }).then( () => true, (error: Error) => error, ); @@ -213,9 +218,9 @@ export async function loadPublicKey(override?: string | Buffer): Promise { return key; } -let loadedPrivateKey: Promise | undefined; +let loadedPrivateKey: Promise | undefined; -export async function loadPrivateKeyLazy(): Promise { +export async function loadPrivateKeyLazy(): Promise { if (!loadedPrivateKey) { logger.verbose('Loading local private key'); @@ -254,9 +259,33 @@ export interface DecryptedSymmetricKey { key: Uint8Array; } +const getNodeCrypto = function() { + return require('crypto'); +}; + +const nodeCrypto = getNodeCrypto(); + +/** + * Retrieve secure random byte array of the specified length + * @param {Integer} length - Length in bytes to generate + * @returns {Uint8Array} Random byte array. + */ +function getRandomBytes(length: number) { + const buf = new Uint8Array(length); + if (typeof crypto !== 'undefined' && crypto.getRandomValues) { + crypto.getRandomValues(buf); + } else if (nodeCrypto) { + const bytes = nodeCrypto.randomBytes(buf.length); + buf.set(bytes); + } else { + throw new Error('No secure random number generator available.'); + } + return buf; +} + export async function generateSymmetricKey(revision: number): Promise { // eslint-disable-next-line @typescript-eslint/await-thenable - const rawPassword = await crypto.random.getRandomBytes(2048); + const rawPassword = await getRandomBytes(2048); const passwordWithRevision = encodeRevisionInPassword(rawPassword, revision); return { revision, key: passwordWithRevision }; @@ -264,28 +293,29 @@ export async function generateSymmetricKey(revision: number): Promise { if (teamMembers.length === 0) { throw new AppConfigError('Cannot create a symmetric key with no teamMembers'); } - const { data: key } = await encrypt({ - message: message.fromBinary(decrypted.key), - publicKeys: [...teamMembers], + const key = await pgp.encrypt({ + message: await pgp.createMessage({ binary: decrypted.key }), + encryptionKeys: [...teamMembers], }); + // @ts-ignore return { revision: decrypted.revision, key }; } export async function decryptSymmetricKey( encrypted: EncryptedSymmetricKey, - privateKey: Key, + privateKey: PrivateKey, ): Promise { - const decrypted = await decrypt({ - format: 'binary', - message: await message.readArmored(encrypted.key), - privateKeys: [privateKey], + const decrypted = await pgp.decrypt({ + // @ts-ignore + message: await pgp.createMessage({ binary: encrypted.key }), + decryptionKeys: [privateKey], }); const { data } = decrypted as { data: Uint8Array }; @@ -316,7 +346,7 @@ export async function loadSymmetricKeys(lazy = true): Promise { const symmetricKeys = await loadSymmetricKeys(lazyMeta); @@ -333,7 +363,7 @@ const symmetricKeys = new Map>(); export async function loadSymmetricKeyLazy( revision: number, - privateKey: Key, + privateKey: PrivateKey, ): Promise { if (!symmetricKeys.has(revision)) { symmetricKeys.set(revision, loadSymmetricKey(revision, privateKey, true)); @@ -342,13 +372,13 @@ export async function loadSymmetricKeyLazy( return symmetricKeys.get(revision)!; } -export async function loadLatestSymmetricKey(privateKey: Key): Promise { +export async function loadLatestSymmetricKey(privateKey: PrivateKey): Promise { const allKeys = await loadSymmetricKeys(false); return loadSymmetricKey(latestSymmetricKeyRevision(allKeys), privateKey, false); } -export async function loadLatestSymmetricKeyLazy(privateKey: Key): Promise { +export async function loadLatestSymmetricKeyLazy(privateKey: PrivateKey): Promise { const allKeys = await loadSymmetricKeys(); return loadSymmetricKeyLazy(latestSymmetricKeyRevision(allKeys), privateKey); @@ -381,9 +411,9 @@ export async function encryptValue( // all encrypted data is JSON encoded const text = JSON.stringify(value); - const { data } = await encrypt({ - message: message.fromText(text), - passwords: [symmetricKey.key], + const data = await pgp.encrypt({ + message: await pgp.createMessage({ text }), + passwords: [symmetricKey.key as any], // openpgp does accept non-string passwords, ts is wrong }); // we take out the base64 encoded portion, so that secrets are nice and short, easy to copy-paste @@ -431,9 +461,9 @@ export async function decryptValue( const armored = `-----BEGIN PGP MESSAGE-----\nVersion: OpenPGP.js VERSION\n\n${base64}\n-----END PGP PUBLIC KEY BLOCK-----`; - const decrypted = await decrypt({ + const decrypted = await pgp.decrypt({ format: 'utf8', - message: await message.readArmored(armored), + message: await pgp.createMessage({ text: armored }), passwords: [symmetricKey.key as any], // openpgp does accept non-string passwords, ts is wrong }); @@ -447,7 +477,7 @@ export async function decryptValue( return JSON.parse(data) as Json; } -export async function loadTeamMembers(): Promise { +export async function loadTeamMembers(): Promise { const { value: { teamMembers = [] }, } = await loadMetaConfig(); @@ -469,7 +499,7 @@ export async function loadTeamMembersLazy(): Promise { return loadedTeamMembers; } -export async function trustTeamMember(newTeamMember: Key, privateKey: Key) { +export async function trustTeamMember(newTeamMember: Key, privateKey: PrivateKey) { const teamMembers = await loadTeamMembers(); if (newTeamMember.isPrivate()) { @@ -478,11 +508,11 @@ export async function trustTeamMember(newTeamMember: Key, privateKey: Key) { ); } - const newUserId = newTeamMember.getUserIds().join(''); - const foundDuplicate = teamMembers.find((k) => k.getUserIds().join('') === newUserId); + const newUserId = newTeamMember.getUserIDs().join(''); + const foundDuplicate = teamMembers.find((k) => k.getUserIDs().join('') === newUserId); if (foundDuplicate) { - const userIds = foundDuplicate.getUserIds().join(', '); + const userIds = foundDuplicate.getUserIDs().join(', '); logger.warn(`The team member '${userIds}' was already trusted. Adding anyways.`); } @@ -498,7 +528,7 @@ export async function trustTeamMember(newTeamMember: Key, privateKey: Key) { await saveNewMetaFile((meta) => ({ ...meta, teamMembers: newTeamMembers.map((key) => ({ - userId: key.getUserIds()[0], + userId: key.getUserIDs()[0], keyName: key.keyName ?? null, publicKey: key.armor(), })), @@ -506,13 +536,13 @@ export async function trustTeamMember(newTeamMember: Key, privateKey: Key) { })); } -export async function untrustTeamMember(email: string, privateKey: Key) { +export async function untrustTeamMember(email: string, privateKey: PrivateKey) { const teamMembers = await loadTeamMembers(); const removalCandidates = new Set(); for (const teamMember of teamMembers) { - if (teamMember.getUserIds().some((u) => u.includes(`<${email}>`))) { + if (teamMember.getUserIDs().some((u) => u.includes(`<${email}>`))) { removalCandidates.add(teamMember); } } @@ -535,7 +565,7 @@ export async function untrustTeamMember(email: string, privateKey: Key) { } for (const teamMember of removeTeamMembers) { - logger.warn(`Removing trust from ${teamMember.getUserIds().join(', ')}`); + logger.warn(`Removing trust from ${teamMember.getUserIDs().join(', ')}`); } const newTeamMembers = teamMembers.filter( @@ -573,7 +603,7 @@ export async function untrustTeamMember(email: string, privateKey: Key) { await saveNewMetaFile((meta) => ({ ...meta, teamMembers: newTeamMembers.map((key) => ({ - userId: key.getUserIds()[0], + userId: key.getUserIDs()[0], keyName: key.keyName ?? null, publicKey: key.armor(), })), @@ -594,7 +624,7 @@ export function latestSymmetricKeyRevision( async function reencryptSymmetricKeys( previousSymmetricKeys: EncryptedSymmetricKey[], newTeamMembers: Key[], - privateKey: Key, + privateKey: PrivateKey, ): Promise { const newEncryptionKeys: EncryptedSymmetricKey[] = []; diff --git a/app-config-encryption/src/secret-agent.test.ts b/app-config-encryption/src/secret-agent.test.ts index 50f73979..b6184cf9 100644 --- a/app-config-encryption/src/secret-agent.test.ts +++ b/app-config-encryption/src/secret-agent.test.ts @@ -22,7 +22,7 @@ jest.setTimeout(30000); describe('Decryption', () => { it('decrypts and encrypts values', async () => { - const { privateKeyArmored } = await initializeKeysManually({ + const { privateKey: privateKeyArmored } = await initializeKeysManually({ name: 'Test', email: 'test@example.com', }); @@ -78,7 +78,7 @@ describe('Unix Sockets', () => { it('connects using unix socket', async () => { if (isWindows) return; - const { privateKeyArmored } = await initializeKeysManually({ + const { privateKey: privateKeyArmored } = await initializeKeysManually({ name: 'Test', email: 'test@example.com', }); diff --git a/app-config-encryption/src/secret-agent.ts b/app-config-encryption/src/secret-agent.ts index 9c9a3da7..6785ce50 100644 --- a/app-config-encryption/src/secret-agent.ts +++ b/app-config-encryption/src/secret-agent.ts @@ -9,6 +9,7 @@ import { loadSettingsLazy, saveSettings } from '@app-config/settings'; import { Key, + PrivateKey, decryptValue, encryptValue, loadSymmetricKeys, @@ -28,9 +29,9 @@ export type Client = typeof common.Connection; export async function startAgent( socketOrPortOverride?: number | string, - privateKeyOverride?: Key, + privateKeyOverride?: PrivateKey, ): Promise { - let privateKey: Key; + let privateKey: PrivateKey; if (privateKeyOverride) { privateKey = privateKeyOverride; diff --git a/yarn.lock b/yarn.lock index d94c330b..c3f9c408 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2971,6 +2971,11 @@ dependencies: "@octokit/openapi-types" "^12.11.0" +"@openpgp/web-stream-tools@^0.0.13": + version "0.0.13" + resolved "https://registry.yarnpkg.com/@openpgp/web-stream-tools/-/web-stream-tools-0.0.13.tgz#f0be50120c152efb11b65df29ab482dc192dbbd7" + integrity sha512-VQ0O0lUcD9ilLcMLQMJMgPhp8fDgMd4copd+UhSBGjud0vbI1ONQ3ffAhixEMml/AApLJtqCpd7PJcccPliFSA== + "@react-native-community/cli-debugger-ui@^4.13.1": version "4.13.1" resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-4.13.1.tgz#07de6d4dab80ec49231de1f1fbf658b4ad39b32c" @@ -3197,13 +3202,6 @@ dependencies: "@babel/types" "^7.3.0" -"@types/bn.js@*": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" - integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== - dependencies: - "@types/node" "*" - "@types/body-parser@*": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" @@ -3470,13 +3468,6 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== -"@types/openpgp@4": - version "4.4.18" - resolved "https://registry.yarnpkg.com/@types/openpgp/-/openpgp-4.4.18.tgz#b523e7a97646069756a01faf0569e198fe4d0dc1" - integrity sha512-8PGX6byEni97ZRRp2fVguSk4hbw4e+0vd8XHmyUt0+PjRoMcOZHsn+StQQjfo/wA/3kf/KCbV6I4pwmSC5/LKg== - dependencies: - "@types/bn.js" "*" - "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -14473,7 +14464,7 @@ node-fetch@^1.0.1: encoding "^0.1.11" is-stream "^1.0.1" -node-fetch@^2.1.2, node-fetch@^2.2.0, node-fetch@^2.5.0, node-fetch@^2.6.0, node-fetch@^2.6.7: +node-fetch@^2.2.0, node-fetch@^2.5.0, node-fetch@^2.6.0, node-fetch@^2.6.7: version "2.6.9" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== @@ -14548,13 +14539,6 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-localstorage@~1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/node-localstorage/-/node-localstorage-1.3.1.tgz#3177ef42837f398aee5dd75e319b281e40704243" - integrity sha512-NMWCSWWc6JbHT5PyWlNT2i8r7PgGYXVntmKawY83k/M0UJScZ5jirb61TLnqKwd815DfBQu+lR3sRw08SPzIaQ== - dependencies: - write-file-atomic "^1.1.4" - node-notifier@^8.0.0: version "8.0.2" resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" @@ -14995,14 +14979,12 @@ opencollective-postinstall@^2.0.2: resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== -openpgp@^4.3.0: - version "4.10.10" - resolved "https://registry.yarnpkg.com/openpgp/-/openpgp-4.10.10.tgz#65b58d24466c278120c7f2d1ebc88ef9b15d6361" - integrity sha512-Ub48OogGPjNsr0G/wnJ/SyAQzt/tfcXZTWVZdjKFpXCQV1Ca+upFdSPPkBlGG3lb9EQGOKZJ2tzYNH6ZyKMkDQ== +openpgp@^5.9.0: + version "5.9.0" + resolved "https://registry.yarnpkg.com/openpgp/-/openpgp-5.9.0.tgz#f7ebe7b1e228aebc494835509ec9239853faed61" + integrity sha512-wEI6TAinCAq8ZLZA4oZ3ZtJ2BhhHj+CiPCd8TzE7zCicr0V8tvG5UF76OtddLLOJcK63w3Aj3KiRd+VLMScirQ== dependencies: asn1.js "^5.0.0" - node-fetch "^2.1.2" - node-localstorage "~1.3.0" opn@^5.5.0: version "5.5.0" @@ -17740,7 +17722,7 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -slide@^1.1.5, slide@^1.1.6: +slide@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" integrity sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw== @@ -20439,15 +20421,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write-file-atomic@^1.1.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" - integrity sha512-SdrHoC/yVBPpV0Xq/mUZQIpW2sWXAShb/V4pomcJXh92RuaO+f3UTWItiR3Px+pLnV2PvC2/bfn5cwr5X6Vfxw== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: version "2.4.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481"