Last active
March 2, 2022 14:44
-
-
Save dhensby/e0140ea7f4262d23b75769255562d91a to your computer and use it in GitHub Desktop.
Add an intermediate certificate to an Azure Key Vault Certificate (Node CLI)
This file contains hidden or 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
const { DefaultAzureCredential } = require('@azure/identity'); | |
const { CertificateClient } = require('@azure/keyvault-certificates'); | |
const { SecretClient } = require('@azure/keyvault-secrets'); | |
const { pkcs12, asn1, pki } = require('node-forge'); | |
const { writeFile, readFile } = require('fs').promises; | |
const [nodePath, scriptPath, vaultName, certName, pathToIntermediate, outFile] = process.argv; | |
function output(string) { | |
return new Promise((resolve, reject) => process.stdout.write(`${string}\n`, (err) => err ? reject(err) : resolve())); | |
} | |
function outputError(string) { | |
return new Promise((resolve, reject) => process.stderr.write(`${string}\n`, (err) => err ? reject(err) : resolve())); | |
} | |
/** | |
* This is a CLI tool that fetches a certificate from the KeyVault, appends the supplied | |
* intermediate certificate and then outputs the binary pfx data. | |
* | |
* This is used when a certificate is accidentally uploaded without the intermediate certificate and | |
* it needs to be re-uploaded. | |
* | |
* Users must have access to read the vault certificates and secrets. The certificate will also have | |
* to have the setting that allows the private key to be extracted. | |
*/ | |
(async () => { | |
let intermediateCert; | |
// there are no arguments supplied, so output usage | |
if (!vaultName) { | |
await output('Usage: vaultName certName pathToIntermediateCert [outFile]'); | |
process.exit(0); | |
} | |
// validate arguments | |
if (!certName) { | |
await outputError('certName argument is missing'); | |
process.exit(1); | |
} | |
if (!pathToIntermediate) { | |
await outputError('pathToIntermediate argument is missing'); | |
process.exit(1); | |
} else { | |
let intermediateFile; | |
try { | |
intermediateFile = await readFile(pathToIntermediate); | |
} catch (e) { | |
await outputError('Unable to read intermediate certificate'); | |
process.exit(2); | |
} | |
try { | |
intermediateCert = pki.certificateFromPem(intermediateFile.toString()); | |
} catch (e) { | |
await outputError('Unable to parse intermediate certificate. Must be a PEM formatted cert'); | |
process.exit(3); | |
} | |
} | |
const credential = new DefaultAzureCredential(); | |
const url = `https://${vaultName}.vault.azure.net/`; | |
const certificateClient = new CertificateClient(url, credential); | |
const secretClient = new SecretClient(url, credential); | |
const azCert = await certificateClient.getCertificate(certName).catch((e) => { | |
return outputError(`Unable to read certificate from vault: ${e.message}`).then(() => Promise.reject(e)); | |
}); | |
// the true certificate (including private key) is stored as a secret | |
const [secretName, secretVersion] = azCert.secretId.split('/').slice(-2); | |
const secret = await secretClient.getSecret(secretName, { version: secretVersion }).catch((e) => { | |
return outputError(`Unable to read certificate key from vault: ${e.message}`).then(() => Promise.reject(e)); | |
}); | |
// parse the "secret" (ie: the p12 encoded certificate that includes the private key) | |
const secretAsn1 = asn1.fromDer(Buffer.from(secret.value, 'base64').toString('binary')); | |
const p12 = pkcs12.pkcs12FromAsn1(secretAsn1); | |
const privateKey = p12.getBags({ | |
bagType: pki.oids.pkcs8ShroudedKeyBag, | |
})[pki.oids.pkcs8ShroudedKeyBag][0].key; | |
const certificates = p12.getBags({ | |
bagType: pki.oids.certBag, | |
})[pki.oids.certBag].map(({ cert }) => cert); | |
// validate if this certificate already has the intermediate certificate | |
if (certificates.length > 1) { | |
await output('Certificate appears to include chain... Validating'); | |
// the certificates should go from leaf -> intermediate with each certificate being the issuer | |
// of the previous one. This checks the certificate chain is valid. | |
for (let i = 1; i < certificates.length; i++) { | |
const child = certificates[i - 1]; | |
const parent = certificates[i]; | |
try { | |
const validChain = parent.verify(child); | |
if (!validChain) { | |
throw new Error('Could not validate chain'); | |
} | |
} catch (e) { | |
// eslint-disable-next-line no-await-in-loop | |
await outputError('Certificate includes multiple certificates, but they are not valid issuers'); | |
process.exit(5); | |
} | |
} | |
// the certificate chain is valid, now does it include the intermediate already? | |
const lastCert = certificates[certificates.length - 1]; | |
if (Buffer.from(lastCert.generateSubjectKeyIdentifier().getBytes(), 'binary').equals(Buffer.from(intermediateCert.generateSubjectKeyIdentifier().getBytes(), 'binary'))) { | |
await output('Certificate already includes intermediate. Nothing to do.'); | |
process.exit(0); | |
} else { | |
await outputError('Certificate includes a valid chain, but it does not include the current intermediate. No clear path to continue.'); | |
process.exit(6); | |
} | |
} | |
const [certificate] = certificates; | |
try { | |
// validate that the supplied intermediate certificate is the issuer of the certificate | |
const isIssuedBy = intermediateCert.verify(certificate); | |
if (!isIssuedBy) { | |
throw new Error('Unable to validate intermediate certificate was the issuer of certificate'); | |
} | |
} catch (e) { | |
await outputError('The supplied certificate does not appear to have been issued by the supplied intermediate'); | |
process.exit(6); | |
} | |
const newCert = pkcs12.toPkcs12Asn1(privateKey, [ | |
certificate, | |
intermediateCert, | |
], null); | |
const newP12 = Buffer.from(asn1.toDer(newCert).getBytes(), 'binary'); | |
// we could aim to use the `certificateClient.importCertificate()` method here, but that probably is too opinionated. | |
// instead, users should perform `node ./cert-merge.js ...args > /path/to/cert.pfx` and then upload it manually | |
if (outFile) { | |
return writeFile(outFile, newP12); | |
} | |
// NB: I've noticed this adds a new line to the end of the file when doing `node ./cert-merge.js ...args > /path/to/cert.pfx` | |
// and Azure's import is sensitive to that (understandably as it's a binary format with an ascii char at the end) | |
return new Promise((resolve, reject) => { | |
process.stdout.write(newP12, (err) => err ? reject(err) : resolve()); | |
}); | |
})().catch((err) => { | |
if (process.env.DEBUG) { | |
console.error(err); | |
} | |
process.exit(99); | |
}); |
This file contains hidden or 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
{ | |
"requires": true, | |
"lockfileVersion": 1, | |
"dependencies": { | |
"@azure/abort-controller": { | |
"version": "1.0.4", | |
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.0.4.tgz", | |
"integrity": "sha512-lNUmDRVGpanCsiUN3NWxFTdwmdFI53xwhkTFfHDGTYk46ca7Ind3nanJc+U6Zj9Tv+9nTCWRBscWEW1DyKOpTw==", | |
"requires": { | |
"tslib": "^2.0.0" | |
} | |
}, | |
"@azure/core-asynciterator-polyfill": { | |
"version": "1.0.2", | |
"resolved": "https://registry.npmjs.org/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.2.tgz", | |
"integrity": "sha512-3rkP4LnnlWawl0LZptJOdXNrT/fHp2eQMadoasa6afspXdpGrtPZuAQc2PD0cpgyuoXtUWyC3tv7xfntjGS5Dw==" | |
}, | |
"@azure/core-auth": { | |
"version": "1.3.2", | |
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.3.2.tgz", | |
"integrity": "sha512-7CU6DmCHIZp5ZPiZ9r3J17lTKMmYsm/zGvNkjArQwPkrLlZ1TZ+EUYfGgh2X31OLMVAQCTJZW4cXHJi02EbJnA==", | |
"requires": { | |
"@azure/abort-controller": "^1.0.0", | |
"tslib": "^2.2.0" | |
} | |
}, | |
"@azure/core-client": { | |
"version": "1.5.0", | |
"resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.5.0.tgz", | |
"integrity": "sha512-YNk8i9LT6YcFdFO+RRU0E4Ef+A8Y5lhXo6lz61rwbG8Uo7kSqh0YqK04OexiilM43xd6n3Y9yBhLnb1NFNI9dA==", | |
"requires": { | |
"@azure/abort-controller": "^1.0.0", | |
"@azure/core-asynciterator-polyfill": "^1.0.0", | |
"@azure/core-auth": "^1.3.0", | |
"@azure/core-rest-pipeline": "^1.5.0", | |
"@azure/core-tracing": "1.0.0-preview.13", | |
"@azure/logger": "^1.0.0", | |
"tslib": "^2.2.0" | |
} | |
}, | |
"@azure/core-http": { | |
"version": "2.2.4", | |
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-2.2.4.tgz", | |
"integrity": "sha512-QmmJmexXKtPyc3/rsZR/YTLDvMatzbzAypJmLzvlfxgz/SkgnqV/D4f6F2LsK6tBj1qhyp8BoXiOebiej0zz3A==", | |
"requires": { | |
"@azure/abort-controller": "^1.0.0", | |
"@azure/core-asynciterator-polyfill": "^1.0.0", | |
"@azure/core-auth": "^1.3.0", | |
"@azure/core-tracing": "1.0.0-preview.13", | |
"@azure/logger": "^1.0.0", | |
"@types/node-fetch": "^2.5.0", | |
"@types/tunnel": "^0.0.3", | |
"form-data": "^4.0.0", | |
"node-fetch": "^2.6.7", | |
"process": "^0.11.10", | |
"tough-cookie": "^4.0.0", | |
"tslib": "^2.2.0", | |
"tunnel": "^0.0.6", | |
"uuid": "^8.3.0", | |
"xml2js": "^0.4.19" | |
} | |
}, | |
"@azure/core-lro": { | |
"version": "2.2.3", | |
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.2.3.tgz", | |
"integrity": "sha512-UMdlR9NsqDCLTba3EUbRjfMF4gDmWvld196JmUjbz9WWhJ2XT00OR5MXeWiR+vmGT+ETiO4hHFCi2/eGO5YVtg==", | |
"requires": { | |
"@azure/abort-controller": "^1.0.0", | |
"@azure/core-tracing": "1.0.0-preview.13", | |
"@azure/logger": "^1.0.0", | |
"tslib": "^2.2.0" | |
} | |
}, | |
"@azure/core-paging": { | |
"version": "1.2.1", | |
"resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.2.1.tgz", | |
"integrity": "sha512-UtH5iMlYsvg+nQYIl4UHlvvSrsBjOlRF4fs0j7mxd3rWdAStrKYrh2durOpHs5C9yZbVhsVDaisoyaf/lL1EVA==", | |
"requires": { | |
"@azure/core-asynciterator-polyfill": "^1.0.0", | |
"tslib": "^2.2.0" | |
} | |
}, | |
"@azure/core-rest-pipeline": { | |
"version": "1.5.0", | |
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.5.0.tgz", | |
"integrity": "sha512-Lofjl3mu1TULhjxoPKY4IqXt6mC8Q+r3xMF1dOz0D/aElKfrbqtO2fts36PCClAq+DJzQM/kbnrNTf3X601I5w==", | |
"requires": { | |
"@azure/abort-controller": "^1.0.0", | |
"@azure/core-auth": "^1.3.0", | |
"@azure/core-tracing": "1.0.0-preview.13", | |
"@azure/logger": "^1.0.0", | |
"form-data": "^4.0.0", | |
"http-proxy-agent": "^4.0.1", | |
"https-proxy-agent": "^5.0.0", | |
"tslib": "^2.2.0", | |
"uuid": "^8.3.0" | |
} | |
}, | |
"@azure/core-tracing": { | |
"version": "1.0.0-preview.13", | |
"resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz", | |
"integrity": "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==", | |
"requires": { | |
"@opentelemetry/api": "^1.0.1", | |
"tslib": "^2.2.0" | |
} | |
}, | |
"@azure/core-util": { | |
"version": "1.0.0-beta.1", | |
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.0.0-beta.1.tgz", | |
"integrity": "sha512-pS6cup979/qyuyNP9chIybK2qVkJ3MarbY/bx3JcGKE6An6dRweLnsfJfU2ydqUI/B51Rjnn59ajHIhCUTwWZw==", | |
"requires": { | |
"tslib": "^2.0.0" | |
} | |
}, | |
"@azure/identity": { | |
"version": "2.0.4", | |
"resolved": "https://registry.npmjs.org/@azure/identity/-/identity-2.0.4.tgz", | |
"integrity": "sha512-ZgFubAsmo7dji63NLPaot6O7pmDfceAUPY57uphSCr0hmRj+Cakqb4SUz5SohCHFtscrhcmejRU903Fowz6iXg==", | |
"requires": { | |
"@azure/abort-controller": "^1.0.0", | |
"@azure/core-auth": "^1.3.0", | |
"@azure/core-client": "^1.4.0", | |
"@azure/core-rest-pipeline": "^1.1.0", | |
"@azure/core-tracing": "1.0.0-preview.13", | |
"@azure/core-util": "^1.0.0-beta.1", | |
"@azure/logger": "^1.0.0", | |
"@azure/msal-browser": "^2.16.0", | |
"@azure/msal-common": "^4.5.1", | |
"@azure/msal-node": "^1.3.0", | |
"events": "^3.0.0", | |
"jws": "^4.0.0", | |
"open": "^8.0.0", | |
"stoppable": "^1.1.0", | |
"tslib": "^2.2.0", | |
"uuid": "^8.3.0" | |
} | |
}, | |
"@azure/keyvault-certificates": { | |
"version": "4.3.0", | |
"resolved": "https://registry.npmjs.org/@azure/keyvault-certificates/-/keyvault-certificates-4.3.0.tgz", | |
"integrity": "sha512-wCceKxgorRupYqx8jmWkyCiBmEfOo3VXONYp4eyDhXt/MfaYf0YF5O829Ft6EFQLf6D9CQMc2maZgCMOajaeOA==", | |
"requires": { | |
"@azure/abort-controller": "^1.0.0", | |
"@azure/core-http": "^2.0.0", | |
"@azure/core-lro": "^2.0.0", | |
"@azure/core-paging": "^1.1.1", | |
"@azure/core-tracing": "1.0.0-preview.13", | |
"@azure/logger": "^1.0.0", | |
"tslib": "^2.2.0" | |
} | |
}, | |
"@azure/keyvault-secrets": { | |
"version": "4.3.0", | |
"resolved": "https://registry.npmjs.org/@azure/keyvault-secrets/-/keyvault-secrets-4.3.0.tgz", | |
"integrity": "sha512-bhdAr2Yjx+XpgfkClOufpTxcnKqDIwyOSKrbI9mJ2q5wQNb7Z1WPnPnIhjdsw1on/NRXzMaarYFNkf/MdS73FA==", | |
"requires": { | |
"@azure/abort-controller": "^1.0.0", | |
"@azure/core-http": "^2.0.0", | |
"@azure/core-lro": "^2.0.0", | |
"@azure/core-paging": "^1.1.1", | |
"@azure/core-tracing": "1.0.0-preview.13", | |
"@azure/logger": "^1.0.0", | |
"tslib": "^2.2.0" | |
} | |
}, | |
"@azure/logger": { | |
"version": "1.0.3", | |
"resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.3.tgz", | |
"integrity": "sha512-aK4s3Xxjrx3daZr3VylxejK3vG5ExXck5WOHDJ8in/k9AqlfIyFMMT1uG7u8mNjX+QRILTIn0/Xgschfh/dQ9g==", | |
"requires": { | |
"tslib": "^2.2.0" | |
} | |
}, | |
"@azure/msal-browser": { | |
"version": "2.22.0", | |
"resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-2.22.0.tgz", | |
"integrity": "sha512-ZpnbnzjYGRGHjWDPOLjSp47CQvhK927+W9avtLoNNCMudqs2dBfwj76lnJwObDE7TAKmCUueTiieglBiPb1mgQ==", | |
"requires": { | |
"@azure/msal-common": "^6.1.0" | |
}, | |
"dependencies": { | |
"@azure/msal-common": { | |
"version": "6.1.0", | |
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-6.1.0.tgz", | |
"integrity": "sha512-IGjAHttOgKDPQr0Qxx1NjABR635ZNuN7LHjxI0Y7SEA2thcaRGTccy+oaXTFabM/rZLt4F2VrPKUX4BnR9hW9g==", | |
"requires": { | |
"debug": "^4.1.1" | |
} | |
} | |
} | |
}, | |
"@azure/msal-common": { | |
"version": "4.5.1", | |
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-4.5.1.tgz", | |
"integrity": "sha512-/i5dXM+QAtO+6atYd5oHGBAx48EGSISkXNXViheliOQe+SIFMDo3gSq3lL54W0suOSAsVPws3XnTaIHlla0PIQ==", | |
"requires": { | |
"debug": "^4.1.1" | |
} | |
}, | |
"@azure/msal-node": { | |
"version": "1.6.0", | |
"resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.6.0.tgz", | |
"integrity": "sha512-RCPXVWsjqYZh7NB1pAJLn4ypHlLBulOjw5nKPLsJiaJJIXnN8kc6SMkK3S9/80DZCEBstvoRMz6zF50QZJUeOQ==", | |
"requires": { | |
"@azure/msal-common": "^6.1.0", | |
"axios": "^0.21.4", | |
"https-proxy-agent": "^5.0.0", | |
"jsonwebtoken": "^8.5.1", | |
"uuid": "^8.3.0" | |
}, | |
"dependencies": { | |
"@azure/msal-common": { | |
"version": "6.1.0", | |
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-6.1.0.tgz", | |
"integrity": "sha512-IGjAHttOgKDPQr0Qxx1NjABR635ZNuN7LHjxI0Y7SEA2thcaRGTccy+oaXTFabM/rZLt4F2VrPKUX4BnR9hW9g==", | |
"requires": { | |
"debug": "^4.1.1" | |
} | |
} | |
} | |
}, | |
"@opentelemetry/api": { | |
"version": "1.0.4", | |
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.4.tgz", | |
"integrity": "sha512-BuJuXRSJNQ3QoKA6GWWDyuLpOUck+9hAXNMCnrloc1aWVoy6Xq6t9PUV08aBZ4Lutqq2LEHM486bpZqoViScog==" | |
}, | |
"@tootallnate/once": { | |
"version": "1.1.2", | |
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", | |
"integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" | |
}, | |
"@types/node": { | |
"version": "17.0.21", | |
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", | |
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" | |
}, | |
"@types/node-fetch": { | |
"version": "2.6.1", | |
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", | |
"integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", | |
"requires": { | |
"@types/node": "*", | |
"form-data": "^3.0.0" | |
}, | |
"dependencies": { | |
"form-data": { | |
"version": "3.0.1", | |
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", | |
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", | |
"requires": { | |
"asynckit": "^0.4.0", | |
"combined-stream": "^1.0.8", | |
"mime-types": "^2.1.12" | |
} | |
} | |
} | |
}, | |
"@types/tunnel": { | |
"version": "0.0.3", | |
"resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz", | |
"integrity": "sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==", | |
"requires": { | |
"@types/node": "*" | |
} | |
}, | |
"agent-base": { | |
"version": "6.0.2", | |
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", | |
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", | |
"requires": { | |
"debug": "4" | |
} | |
}, | |
"asynckit": { | |
"version": "0.4.0", | |
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", | |
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" | |
}, | |
"axios": { | |
"version": "0.21.4", | |
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", | |
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", | |
"requires": { | |
"follow-redirects": "^1.14.0" | |
} | |
}, | |
"buffer-equal-constant-time": { | |
"version": "1.0.1", | |
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", | |
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" | |
}, | |
"combined-stream": { | |
"version": "1.0.8", | |
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", | |
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", | |
"requires": { | |
"delayed-stream": "~1.0.0" | |
} | |
}, | |
"debug": { | |
"version": "4.3.3", | |
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", | |
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", | |
"requires": { | |
"ms": "2.1.2" | |
} | |
}, | |
"define-lazy-prop": { | |
"version": "2.0.0", | |
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", | |
"integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" | |
}, | |
"delayed-stream": { | |
"version": "1.0.0", | |
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", | |
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" | |
}, | |
"ecdsa-sig-formatter": { | |
"version": "1.0.11", | |
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", | |
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", | |
"requires": { | |
"safe-buffer": "^5.0.1" | |
} | |
}, | |
"events": { | |
"version": "3.3.0", | |
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", | |
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" | |
}, | |
"follow-redirects": { | |
"version": "1.14.9", | |
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", | |
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" | |
}, | |
"form-data": { | |
"version": "4.0.0", | |
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", | |
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", | |
"requires": { | |
"asynckit": "^0.4.0", | |
"combined-stream": "^1.0.8", | |
"mime-types": "^2.1.12" | |
} | |
}, | |
"http-proxy-agent": { | |
"version": "4.0.1", | |
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", | |
"integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", | |
"requires": { | |
"@tootallnate/once": "1", | |
"agent-base": "6", | |
"debug": "4" | |
} | |
}, | |
"https-proxy-agent": { | |
"version": "5.0.0", | |
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", | |
"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", | |
"requires": { | |
"agent-base": "6", | |
"debug": "4" | |
} | |
}, | |
"is-docker": { | |
"version": "2.2.1", | |
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", | |
"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" | |
}, | |
"is-wsl": { | |
"version": "2.2.0", | |
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", | |
"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", | |
"requires": { | |
"is-docker": "^2.0.0" | |
} | |
}, | |
"jsonwebtoken": { | |
"version": "8.5.1", | |
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", | |
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", | |
"requires": { | |
"jws": "^3.2.2", | |
"lodash.includes": "^4.3.0", | |
"lodash.isboolean": "^3.0.3", | |
"lodash.isinteger": "^4.0.4", | |
"lodash.isnumber": "^3.0.3", | |
"lodash.isplainobject": "^4.0.6", | |
"lodash.isstring": "^4.0.1", | |
"lodash.once": "^4.0.0", | |
"ms": "^2.1.1", | |
"semver": "^5.6.0" | |
}, | |
"dependencies": { | |
"jws": { | |
"version": "3.2.2", | |
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", | |
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", | |
"requires": { | |
"jwa": "^1.4.1", | |
"safe-buffer": "^5.0.1" | |
} | |
} | |
} | |
}, | |
"jwa": { | |
"version": "1.4.1", | |
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", | |
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", | |
"requires": { | |
"buffer-equal-constant-time": "1.0.1", | |
"ecdsa-sig-formatter": "1.0.11", | |
"safe-buffer": "^5.0.1" | |
} | |
}, | |
"jws": { | |
"version": "4.0.0", | |
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", | |
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", | |
"requires": { | |
"jwa": "^2.0.0", | |
"safe-buffer": "^5.0.1" | |
}, | |
"dependencies": { | |
"jwa": { | |
"version": "2.0.0", | |
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", | |
"integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", | |
"requires": { | |
"buffer-equal-constant-time": "1.0.1", | |
"ecdsa-sig-formatter": "1.0.11", | |
"safe-buffer": "^5.0.1" | |
} | |
} | |
} | |
}, | |
"lodash.includes": { | |
"version": "4.3.0", | |
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", | |
"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" | |
}, | |
"lodash.isboolean": { | |
"version": "3.0.3", | |
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", | |
"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" | |
}, | |
"lodash.isinteger": { | |
"version": "4.0.4", | |
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", | |
"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" | |
}, | |
"lodash.isnumber": { | |
"version": "3.0.3", | |
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", | |
"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" | |
}, | |
"lodash.isplainobject": { | |
"version": "4.0.6", | |
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", | |
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" | |
}, | |
"lodash.isstring": { | |
"version": "4.0.1", | |
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", | |
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" | |
}, | |
"lodash.once": { | |
"version": "4.1.1", | |
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", | |
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" | |
}, | |
"mime-db": { | |
"version": "1.51.0", | |
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", | |
"integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" | |
}, | |
"mime-types": { | |
"version": "2.1.34", | |
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", | |
"integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", | |
"requires": { | |
"mime-db": "1.51.0" | |
} | |
}, | |
"ms": { | |
"version": "2.1.2", | |
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | |
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" | |
}, | |
"node-fetch": { | |
"version": "2.6.7", | |
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", | |
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", | |
"requires": { | |
"whatwg-url": "^5.0.0" | |
} | |
}, | |
"node-forge": { | |
"version": "1.2.1", | |
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", | |
"integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==" | |
}, | |
"open": { | |
"version": "8.4.0", | |
"resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", | |
"integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", | |
"requires": { | |
"define-lazy-prop": "^2.0.0", | |
"is-docker": "^2.1.1", | |
"is-wsl": "^2.2.0" | |
} | |
}, | |
"process": { | |
"version": "0.11.10", | |
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", | |
"integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" | |
}, | |
"psl": { | |
"version": "1.8.0", | |
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", | |
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" | |
}, | |
"punycode": { | |
"version": "2.1.1", | |
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", | |
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" | |
}, | |
"safe-buffer": { | |
"version": "5.2.1", | |
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", | |
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" | |
}, | |
"sax": { | |
"version": "1.2.4", | |
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", | |
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" | |
}, | |
"semver": { | |
"version": "5.7.1", | |
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", | |
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" | |
}, | |
"stoppable": { | |
"version": "1.1.0", | |
"resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", | |
"integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==" | |
}, | |
"tough-cookie": { | |
"version": "4.0.0", | |
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", | |
"integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", | |
"requires": { | |
"psl": "^1.1.33", | |
"punycode": "^2.1.1", | |
"universalify": "^0.1.2" | |
} | |
}, | |
"tr46": { | |
"version": "0.0.3", | |
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", | |
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" | |
}, | |
"tslib": { | |
"version": "2.3.1", | |
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", | |
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" | |
}, | |
"tunnel": { | |
"version": "0.0.6", | |
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", | |
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" | |
}, | |
"universalify": { | |
"version": "0.1.2", | |
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", | |
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" | |
}, | |
"uuid": { | |
"version": "8.3.2", | |
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", | |
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" | |
}, | |
"webidl-conversions": { | |
"version": "3.0.1", | |
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", | |
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" | |
}, | |
"whatwg-url": { | |
"version": "5.0.0", | |
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", | |
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", | |
"requires": { | |
"tr46": "~0.0.3", | |
"webidl-conversions": "^3.0.0" | |
} | |
}, | |
"xml2js": { | |
"version": "0.4.23", | |
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", | |
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", | |
"requires": { | |
"sax": ">=0.6.0", | |
"xmlbuilder": "~11.0.0" | |
} | |
}, | |
"xmlbuilder": { | |
"version": "11.0.1", | |
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", | |
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment