From b9a1c0b285c74addbf32a9cdb209d019031075cb Mon Sep 17 00:00:00 2001 From: Joakim Olsson Date: Mon, 8 Apr 2024 13:10:20 +0200 Subject: [PATCH] feat: replace keystore handling with node-jose --- app.js | 136 +++++++++++++++++++++++++++++++-------------------- cert.js | 128 ------------------------------------------------ package.json | 5 +- yarn.lock | 67 ++++++++++++++++++------- 4 files changed, 134 insertions(+), 202 deletions(-) delete mode 100644 cert.js diff --git a/app.js b/app.js index dc18445..895ffcd 100644 --- a/app.js +++ b/app.js @@ -8,12 +8,12 @@ const Debug = require('debug') const path = require('path') const cors = require('cors') const bodyParser = require('body-parser') +const jose = require('node-jose'); const favicon = require('serve-favicon') -const cert = require('./cert') const initialUsers = require('./users') -let issuer = process.env.ISSUER || 'localhost:3333' -let jwksOrigin = `https://${issuer}/` +const issuer = process.env.ISSUER || 'localhost:3333' +const jwksOrigin = `https://${issuer}/` const audience = process.env.AUDIENCE || 'https://generic-audience' const adminCustomClaim = process.env.ADMIN_CUSTOM_CLAIM || 'https://unbound.se/admin' @@ -22,7 +22,9 @@ const emailCustomClaim = const debug = Debug('app') -let { privateKey, certDer, thumbprint, exponent, modulus } = cert(jwksOrigin) +const keyStore = jose.JWK.createKeyStore() +keyStore.generate('RSA', 2048, { alg: 'RS256', use: 'sig' }) +// let { privateKey, certDer, thumbprint, exponent, modulus } = cert(jwksOrigin) const users = initialUsers(process.env.USERS_FILE || './users.json') const sessions = {} const challenges = {} @@ -42,11 +44,12 @@ const addCustomClaims = (email, customClaims, token) => { }, token) } -const signToken = (token) => { - return jwt.sign(Buffer.from(JSON.stringify(token)), privateKey, { - algorithm: 'RS256', - keyid: thumbprint - }) +const signToken = async (token) => { + const [key] = keyStore.all({ use: 'sig' }) + const opt = { compact: true, jwk: key, fields: { typ: 'jwt' } } + return await jose.JWS.createSign(opt, key) + .update(JSON.stringify(token)) + .final() } // Configure our small auth0-mock-server @@ -60,10 +63,10 @@ app .use(favicon(path.join(__dirname, 'public', 'favicon.ico'))) // This route can be used to generate a valid jwt-token. -app.post('/oauth/token', (req, res) => { - let date = Math.floor(Date.now() / 1000) +app.post('/oauth/token', async (req, res) => { + const date = Math.floor(Date.now() / 1000) if (req.body.grant_type === 'client_credentials' && req.body.client_id) { - let accessToken = signToken({ + const accessToken = await signToken({ iss: jwksOrigin, aud: [audience], sub: 'auth0|management', @@ -72,7 +75,7 @@ app.post('/oauth/token', (req, res) => { azp: req.body.client_id }) - let idToken = signToken({ + const idToken = await signToken({ iss: jwksOrigin, aud: req.body.client_id, sub: 'auth0|management', @@ -94,7 +97,7 @@ app.post('/oauth/token', (req, res) => { } else if (req.body.code) { const code = req.body.code const session = sessions[code] - let accessToken = signToken( + const accessToken = await signToken( addCustomClaims(session.email, session.customClaims, { iss: jwksOrigin, aud: [audience], @@ -105,7 +108,7 @@ app.post('/oauth/token', (req, res) => { }) ) - let idToken = signToken( + const idToken = await signToken( addCustomClaims(session.email, session.customClaims, { iss: jwksOrigin, aud: session.clientId, @@ -294,26 +297,78 @@ app.get('/v2/logout', (req, res) => { res.redirect(req.query.returnTo) }) -app.get('/.well-known/jwks.json', (req, res) => { +app.get('/.well-known/openid-configuration', (req, res) => { + debug('Fetching OpenID configuration') res.contentType('application/json').send( JSON.stringify({ - keys: [ - { - alg: 'RS256', - // e: 'AQAB', - e: exponent, - kid: thumbprint, - kty: 'RSA', - n: modulus, - use: 'sig', - x5c: [certDer], - x5t: thumbprint - } - ] + "issuer": + "https://auth0", + "authorization_endpoint": + "https://server.example.com/authorize", + "token_endpoint": + "https://server.example.com/oauth/token", + "token_endpoint_auth_methods_supported": + ["client_secret_basic", "private_key_jwt"], + "token_endpoint_auth_signing_alg_values_supported": + ["RS256"], + "userinfo_endpoint": + "https://server.example.com/userinfo", + "check_session_iframe": + "https://server.example.com/check_session", + "end_session_endpoint": + "https://server.example.com/end_session", + "jwks_uri": + "https://server.example.com/.well-known/jwks.json", + "registration_endpoint": + "https://server.example.com/register", + "scopes_supported": + ["openid", "profile", "email", "address", + "phone", "offline_access"], + "response_types_supported": + ["code", "code id_token", "id_token", "id_token token"], + "acr_values_supported": + [], + "subject_types_supported": + ["public", "pairwise"], + "userinfo_signing_alg_values_supported": + ["RS256", "ES256", "HS256"], + "userinfo_encryption_alg_values_supported": + ["RSA-OAEP-256", "A128KW"], + "userinfo_encryption_enc_values_supported": + ["A128CBC-HS256", "A128GCM"], + "id_token_signing_alg_values_supported": + ["RS256", "ES256", "HS256"], + "id_token_encryption_alg_values_supported": + ["RSA-OAEP-256", "A128KW"], + "id_token_encryption_enc_values_supported": + ["A128CBC-HS256", "A128GCM"], + "request_object_signing_alg_values_supported": + ["none", "RS256", "ES256"], + "display_values_supported": + ["page", "popup"], + "claim_types_supported": + ["normal", "distributed"], + "claims_supported": + ["sub", "iss", "auth_time", "acr", + "name", "given_name", "family_name", "nickname", + "profile", "picture", "website", + "email", "email_verified", "locale", "zoneinfo", + "https://unbound.se/email", "https://unbound.se/admin"], + "claims_parameter_supported": + true, + "service_documentation": + "http://auth0/", + "ui_locales_supported": + ["en-US"] }) ) }) +app.get('/.well-known/jwks.json', (req, res) => { + debug('Fetching JWKS') + res.contentType('application/json').send(keyStore.toJSON()) +}) + // This route returns the inside of a jwt-token. Your main application // should use this route to keep the auth0-flow app.post('/tokeninfo', (req, res) => { @@ -331,29 +386,6 @@ app.post('/tokeninfo', (req, res) => { } }) -app.post('/issuer', (req, res) => { - if (!req.body.issuer) { - debug('No issuer given in the body!') - return res.status(401).send('missing issuer') - } - issuer = req.body.issuer - jwksOrigin = `https://${issuer}/` - const { - privateKey: key, - certDer: der, - thumbprint: thumb, - exponent: exp, - modulus: mod - } = cert(jwksOrigin) - privateKey = key - certDer = der - thumbprint = thumb - exponent = exp - modulus = mod - debug('Issuer set to ' + req.body.issuer) - res.send('ok') -}) - app.get('/api/v2/users-by-email', (req, res) => { const email = req.query.email console.log('users', users) diff --git a/cert.js b/cert.js deleted file mode 100644 index 6bc18a3..0000000 --- a/cert.js +++ /dev/null @@ -1,128 +0,0 @@ -const base64url = require('base64-url') -const createHash = require('crypto').createHash -const forge = require('node-forge') -const NodeRSA = require('node-rsa') - -const PRIVATE_KEY_PEM = - '-----BEGIN RSA PRIVATE KEY-----\n' + - 'MIIEpAIBAAKCAQEApoocpO3bbUF6o8eyJlQCfwLahEsunWdVF++yOEyKu4Lp1j0m\n' + - '2j/P7iHOtxBAkjdM2X2oW3qO1mR0sIFefqnm93g0q2nRuYEoS+W3o6X50wjOVm8f\n' + - 'r/tLqELzy5BoET0AQl7Axp1DNsb0HNOBcoIBt+xVY4I+k6uXJJJMzbgvahAgSLZ9\n' + - 'RW0Z0WT+dCHZpZUj0nLxNXIPdci65Bw6IognqXHP6AwKZXpT6jCzjzq9uyHxVcud\n' + - 'qw6j0kQw48/A5A6AN5fIVy1cKnd0sKdqRX1NUqVoiOrO4jaDB1IdLD+YmRE/JjOH\n' + - 'sWIMElYCPxKqnsNo6VCslGX/ziinArHhqRBrHwIDAQABAoIBAHAdmpsN5iLvafjI\n' + - 'f45+EBAhg6p8Uq102zx6CakNHniN8Y5hLL7RJtJRwDBNqKrGv93LUoQDRhXfGw+Y\n' + - 'iF0NVIhVTF/5pU8VPGOcCr0JB96ilwZpWRPIQW7NZAMu/GBeiMYls/IB/TXrSnv9\n' + - 'h6/nBfEkEXgkPqx7YA0m0L3NuV3U1lCY/LhBJY4Xvi0uRdqu3tTHXftehuPwC4UB\n' + - '42eJTWv/qLeOlkCdUUV4f7+dNaES88Vdhj6lu/BusnNhvnwHQik4dNwzPCGeP8NV\n' + - '5gaesWiNWFZuTURGKk1B65p5LzNPjsVT50RDuW8FnSZwIvNcohrX9ILPsmg/t0Kr\n' + - 'ozcOksECgYEA4XWOK4twx5RG162zveRHqU7H9RBWSz7/PzM9Eob9vx/tC/b1YqBR\n' + - 'VShk23vje19eNiYWAkxcpobIP4ek/0ZT8nHkJg8wl+J/hnXADcvwv2dKnoFnm5pn\n' + - 'rTBUKc8R3wrSlAV8XQAtdnxsfFa5AOQJ6WFVI9AdfH3Iw8XZk4gIIPMCgYEAvRlY\n' + - 'y80HnR3kwMOqY488V1qk41dmfNqa+YDL+zkPF1HhHI9VnK5BQuI7lyKJl984KwHu\n' + - '0gbwx3Wp4XkD5JUboEpl5LnaLsjEWemjTaQWdvJHPd5wkJ0m/jRQ2YeT4g2gFu4y\n' + - 'Pi/pWkrzhnzQQVAmOdAm5Kj27LtDzp0lspw3uCUCgYEAw2YdvFGSgfZZW4147QeO\n' + - 'sAbON+9bysUjdMPUl10VR/LEgA0d6MdnFfX3S13Y7tDdlvJ1OrKxzcWcgaru7ism\n' + - 'kEXy5KVfiRNNUNx2gb6RvWEpA6zFfc9ZMXlkSAPlyjfX/1+tw/Bmdn0pjK2gk0wP\n' + - '5wtrPameFInzWPD9O+a2nM8CgYBZ6UhgNs+M9B7FTQOiLQPa4R2PfwobCXIwef4D\n' + - 'KIE1bFgl1T02r2AWZi1BUkmr7ZXuVQ/xyx0HKbopm/mu4PruvxEtrPTB0/IQcleU\n' + - 'XhXUXqRjFXXePOrCaaubkqxNCn95B67aBLvmk8awxn3a4DocuQ0VIgWuT+gQwIWh\n' + - 'JEgWBQKBgQDKD+2Yh1/rUzu15lbPH0JSpozUinuFjePieR/4n+5CtEUxWJ2f0WeK\n' + - 's4XWWf2qgUccjpiGju2UR840mgWROoZ8BfSTd5tg1F7bo0HMgu2hu0RIRpZcRhsA\n' + - 'Cd0GrJvf1t0QIdDCXAy+RpgU1SLSq4Q6Lomc0WA5C5nBw9RKEUOV9A==\n' + - '-----END RSA PRIVATE KEY-----\n' - -const PUBLIC_KEY_PEM = - '-----BEGIN PUBLIC KEY-----\n' + - 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApoocpO3bbUF6o8eyJlQC\n' + - 'fwLahEsunWdVF++yOEyKu4Lp1j0m2j/P7iHOtxBAkjdM2X2oW3qO1mR0sIFefqnm\n' + - '93g0q2nRuYEoS+W3o6X50wjOVm8fr/tLqELzy5BoET0AQl7Axp1DNsb0HNOBcoIB\n' + - 't+xVY4I+k6uXJJJMzbgvahAgSLZ9RW0Z0WT+dCHZpZUj0nLxNXIPdci65Bw6Iogn\n' + - 'qXHP6AwKZXpT6jCzjzq9uyHxVcudqw6j0kQw48/A5A6AN5fIVy1cKnd0sKdqRX1N\n' + - 'UqVoiOrO4jaDB1IdLD+YmRE/JjOHsWIMElYCPxKqnsNo6VCslGX/ziinArHhqRBr\n' + - 'HwIDAQAB\n' + - '-----END PUBLIC KEY-----\n' - -const createCertificate = ({ publicKey, privateKey, jwksOrigin }) => { - const cert = forge.pki.createCertificate() - cert.publicKey = publicKey - cert.serialNumber = '123' - const attrs = [ - { - name: 'commonName', - value: `${jwksOrigin}` - } - ] - cert.validity.notBefore = new Date() - cert.validity.notAfter = new Date() - cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1) - cert.setSubject(attrs) - cert.setIssuer(attrs) - cert.sign(privateKey) - return forge.pki.certificateToPem(cert) -} - -const getCertThumbprint = (certificate) => { - const shasum = createHash('sha1') - const der = Buffer.from(certificate).toString('binary') - shasum.update(der) - return shasum.digest('base64') -} - -const createKeyPair = () => { - const privateKey = forge.pki.privateKeyFromPem(PRIVATE_KEY_PEM) - const publicKey = forge.pki.publicKeyFromPem(PUBLIC_KEY_PEM) - return { - privateKey, - publicKey - } -} - -const bnToB64 = (bn) => { - let hex = BigInt(bn).toString(16) - if (hex.length % 2) { - hex = '0' + hex - } - - const bin = [] - let i = 0 - let d - let b - while (i < hex.length) { - d = parseInt(hex.slice(i, i + 2), 16) - b = String.fromCharCode(d) - bin.push(b) - i += 2 - } - - return Buffer.from(bin.join(''), 'binary').toString('base64') -} - -const setup = (jwksOrigin) => { - const { privateKey, publicKey } = createKeyPair() - const certPem = createCertificate({ - jwksOrigin, - privateKey, - publicKey - }) - const certDer = forge.util.encode64( - forge.asn1 - .toDer(forge.pki.certificateToAsn1(forge.pki.certificateFromPem(certPem))) - .getBytes() - ) - const thumbprint = base64url.encode(getCertThumbprint(certDer)) - - const helperKey = new NodeRSA() - helperKey.importKey(forge.pki.privateKeyToPem(privateKey)) - const { n: modulus, e: exponent } = helperKey.exportKey('components') - - return { - privateKey: forge.pki.privateKeyToPem(privateKey), - certDer, - thumbprint: thumbprint.toString(), - exponent: bnToB64(exponent), - modulus: modulus.toString('base64') - } -} - -module.exports = setup diff --git a/package.json b/package.json index ac60829..e8f3ec4 100644 --- a/package.json +++ b/package.json @@ -14,17 +14,14 @@ "author": "", "license": "MIT", "dependencies": { - "base64-url": "^2.3.3", "body-parser": "^1.20.2", - "buffer": "^6.0.3", "cookie-parser": "^1.4.6", "cors": "^2.8.3", "debug": "^4.3.4", "express": "^4.18.2", "https-localhost": "^4.7.1", "jsonwebtoken": "^9.0.2", - "node-forge": "^1.3.1", - "node-rsa": "^1.1.1", + "node-jose": "^2.2.0", "nodemon": "^3.1.0", "serve-favicon": "^2.4.2" }, diff --git a/yarn.lock b/yarn.lock index 0b297df..603ecb8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -33,13 +33,6 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== -asn1@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -50,10 +43,10 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -base64-url@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/base64-url/-/base64-url-2.3.3.tgz#645b71455c75109511f27d98450327e455f488ec" - integrity sha512-dLMhIsK7OplcDauDH/tZLvK7JmUZK3A7KiQpjNzsBrM6Etw7hzNI1tLEywqJk9NnwkgWuFKSlx/IUO7vF6Mo8Q== +base64url@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" + integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== binary-extensions@^2.0.0: version "2.0.0" @@ -282,6 +275,11 @@ es-errors@^1.3.0: resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es6-promise@^4.2.8: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -595,6 +593,16 @@ lodash.once@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +long@^5.2.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -676,17 +684,25 @@ negotiator@0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -node-forge@^1.3.1: +node-forge@^1.2.1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-rsa@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/node-rsa/-/node-rsa-1.1.1.tgz#efd9ad382097782f506153398496f79e4464434d" - integrity sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw== +node-jose@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/node-jose/-/node-jose-2.2.0.tgz#b64f3225ad6bec328509a420800de597ba2bf3ed" + integrity sha512-XPCvJRr94SjLrSIm4pbYHKLEaOsDvJCpyFw/6V/KK/IXmyZ6SFBzAUDO9HQf4DB/nTEFcRGH87mNciOP23kFjw== dependencies: - asn1 "^0.2.4" + base64url "^3.0.1" + buffer "^6.0.3" + es6-promise "^4.2.8" + lodash "^4.17.21" + long "^5.2.0" + node-forge "^1.2.1" + pako "^2.0.4" + process "^0.11.10" + uuid "^9.0.0" nodemon@^3.1.0: version "3.1.0" @@ -743,6 +759,11 @@ on-headers@~1.0.2: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== +pako@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" + integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== + parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -773,6 +794,11 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -852,7 +878,7 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -"safer-buffer@>= 2.1.2 < 3", safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -1044,6 +1070,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uuid@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"