diff --git a/packages/obonode/obojobo-chunks-materia/package.json b/packages/obonode/obojobo-chunks-materia/package.json index a920d6579d..b8b9b8849d 100644 --- a/packages/obonode/obojobo-chunks-materia/package.json +++ b/packages/obonode/obojobo-chunks-materia/package.json @@ -27,7 +27,10 @@ "singleQuote": true }, "dependencies": { + "jsonwebtoken": "^9.0.2", + "node-jose": "^2.2.0", "oauth-signature": "^1.5.0", + "simple-oauth2": "^5.1.0", "uuid": "^8.3.2", "xml2js": "0.5.0" }, diff --git a/packages/obonode/obojobo-chunks-materia/server/config/materia-lti.json b/packages/obonode/obojobo-chunks-materia/server/config/materia-lti.json index 1b13695270..6220550e51 100644 --- a/packages/obonode/obojobo-chunks-materia/server/config/materia-lti.json +++ b/packages/obonode/obojobo-chunks-materia/server/config/materia-lti.json @@ -4,18 +4,27 @@ "oauthKey": "materia-lti-key", "oauthSecret": "materia-lti-secret", "oboFamilyCode": "obojobo-next", - "oboName": "Obojobo Next", - "oboGuid": "obojobo.next.default.guid" + "oboGuid": "obojobo.next.default.guid", + "oboJwtKey": "obojobo-jwt-key", + "oboLtiClientId": "1234", + "oboLtiUuid": "00000000-0000-0000-0000-000000000000", + "oboName": "Obojobo Next" }, "development": { - "clientMateriaHost": "https://localhost", - "optionalOboServerHost": "https://host.docker.internal:8080", - "oboGuid": "obojobo.next.local.dev" + "clientMateriaHost": "http://localhost:420", + "oboGuid": "obojobo.next.local.dev.guid", + "oboLtiUuid": "00000000-0000-0000-0000-000000000000", + "oboPrivateRsaKey": {"ENV": "OBO_PRIVATE_RSA_KEY"}, + "optionalOboServerHost": "https://host.docker.internal:8080" }, "production": { + "clientMateriaHost": {"ENV": "MATERIA_HOST"}, "oauthKey": {"ENV": "MATERIA_OAUTH_KEY"}, "oauthSecret": {"ENV": "MATERIA_OAUTH_SECRET"}, - "clientMateriaHost": {"ENV": "MATERIA_HOST"}, - "oboGuid": {"ENV": "OBO_LTI_GUID"} + "oboGuid": {"ENV": "OBO_LTI_GUID"}, + "oboJwtKey": {"ENV": "OBO_JWT_KEY"}, + "oboLtiClientId": {"ENV": "OBO_LTI_CLIENTID"}, + "oboLtiUuid": {"ENV": "OBO_LTI_UUID"}, + "oboPrivateRsaKey": {"ENV": "OBO_PRIVATE_RSA_KEY"} } } diff --git a/packages/obonode/obojobo-chunks-materia/server/index.js b/packages/obonode/obojobo-chunks-materia/server/index.js index f475cec2b8..5277285d93 100644 --- a/packages/obonode/obojobo-chunks-materia/server/index.js +++ b/packages/obonode/obojobo-chunks-materia/server/index.js @@ -1,20 +1,9 @@ +const jose = require('node-jose') +const jwt = require('jsonwebtoken') const router = require('express').Router() //eslint-disable-line new-cap -const logger = require('obojobo-express/server/logger') -const uuid = require('uuid').v4 -const bodyParser = require('body-parser') const oboEvents = require('obojobo-express/server/obo_events') -const Visit = require('obojobo-express/server/models/visit') const Draft = require('obojobo-express/server/models/draft') const config = require('obojobo-express/server/config').materiaLti -const { - widgetLaunchParams, - contentSelectionParams, - signLtiParams, - verifyScorePassback, - expandLisResultSourcedId, - createPassbackResult, - getValuesFromPassbackXML -} = require('./route-helpers') const materiaEvent = require('./materia-event') const { requireCurrentUser, @@ -29,6 +18,9 @@ oboEvents.on('EDITOR_SETTINGS', event => { } }) +const base64encode = str => Buffer.from(str).toString('base64') +const base64decode = str => Buffer.from(str, 'base64').toString() + // util to get a baseUrl to build urls for for this server // option `isForServerRequest` indicates the url will be // used by materia server to communicate with obo server @@ -39,6 +31,17 @@ const baseUrl = (req, isForServerRequest = true) => { return `${req.protocol}://${req.get('host')}` } +// util to get a csrf token from an existing request +// feels like a bit of a hack but seems to work +const csrfCookie = req => { + const cookies = req.headers.cookie.split(';') + let cookieCSRFToken = cookies.find(cookie => cookie.includes('csrftoken')) + if (cookieCSRFToken) { + cookieCSRFToken = cookieCSRFToken.split('=')[1] + } + return cookieCSRFToken +} + const renderError = (res, title, message) => { res.set('Content-Type', 'text/html') res.send( @@ -46,68 +49,6 @@ const renderError = (res, title, message) => { ) } -// constructs a signed lti request, renders on client and has the client submit it -const renderLtiLaunch = (paramsIn, method, endpoint, res) => { - const params = signLtiParams(paramsIn, method, endpoint) - const keys = Object.keys(params) - const htmlInput = keys - .map(key => ``) - .join('') - - res.set('Content-Type', 'text/html') - res.send(` - -
${htmlInput}
- - `) -} - -// receives scores passed back from Materia -router - .route('/materia-lti-score-passback') - .post(bodyParser.text({ type: '*/*' })) - .post(async (req, res) => { - let success - let visit = {} - let passBackData = {} - let sourcedIdData = {} - const messageId = uuid() - - try { - const verified = verifyScorePassback(req.headers, req.body, req.originalUrl, baseUrl(req)) - if (!verified) throw Error('Signature verification failed') - passBackData = await getValuesFromPassbackXML(req.body) - sourcedIdData = expandLisResultSourcedId(passBackData.sourcedId) - visit = await Visit.fetchById(sourcedIdData.visitId) - success = true - } catch (e) { - logger.error(e) - success = false - } - - await materiaEvent.insertLtiScorePassbackEvent({ - userId: visit.user_id, - draftId: visit.draft_id, - contentId: visit.draft_content_id, - resourceLinkId: sourcedIdData.nodeId, - messageRefId: passBackData.messageId, - lisResultSourcedId: passBackData.sourcedId, - messageId, - success, - ip: req.ip, - score: passBackData.score, - materiaHost: config.clientMateriaHost, - isPreview: visit.is_preview, - visitId: sourcedIdData.visitId - }) - - const xml = createPassbackResult({ success, messageId, messageRefId: passBackData.messageId }) - - res.status(success ? 200 : 500) - res.type('application/xml') - res.send(xml) - }) - // route to launch a materia widget // the viewer component sends the widget url // to this url and we build a page with all the params @@ -120,7 +61,6 @@ router // use the visitId to get the src from the materia chunk const currentDocument = await req.currentVisit.draftDocument const materiaNode = currentDocument.getChildNodeById(req.query.nodeId) - const method = 'POST' if (!materiaNode) { renderError( @@ -132,49 +72,60 @@ router } const materiaOboNodeId = materiaNode.node.id - const endpoint = materiaNode.node.content.src + const widgetEndpoint = materiaNode.node.content.src // verify the endpoint is the configured materia server - if (!endpoint.startsWith(config.clientMateriaHost)) { + if (!widgetEndpoint.startsWith(config.clientMateriaHost)) { renderError( res, 'Materia Widget Url Restricted', - `The widget url ${endpoint} does not match the configured Materia server located at ${config.clientMateriaHost}.` + `The widget url ${widgetEndpoint} does not match the configured Materia server located at ${config.clientMateriaHost}.` ) return } - const launchParams = widgetLaunchParams( - currentDocument, - req.currentVisit, - req.currentUser, - materiaOboNodeId, - baseUrl(req) - ) - await materiaEvent.insertLtiLaunchWidgetEvent({ userId: req.currentUser.id, draftId: currentDocument.draftId, contentId: currentDocument.contentId, visitId: req.currentVisit.id, isPreview: req.currentVisit.is_preview, - lisResultSourcedId: launchParams.lis_result_sourcedid, - resourceLinkId: launchParams.resource_link_id, - endpoint, + lisResultSourcedId: `${req.currentVisit.id}__${materiaOboNodeId}`, + resourceLinkId: `${req.currentVisit.resource_link_id}__${req.currentVisit.draft_id}__${materiaOboNodeId}`, + widgetEndpoint, ip: req.ip }) - renderLtiLaunch(launchParams, method, endpoint, res) + const endpoint = `${config.clientMateriaHost}/ltilaunch/` + + const loginHintObj = { + nodeId: materiaOboNodeId, + widgetEndpoint + } + const loginHint = base64encode(JSON.stringify(loginHintObj)) + const ltiMessageHint = 'resource' + res.redirect( + `${config.clientMateriaHost}/init/${config.oboLtiUuid}/?iss=${baseUrl(req)}&client_id=${ + config.oboLtiClientId + }&target_link_uri=${endpoint}&login_hint=${loginHint}<i_message_hint=${ltiMessageHint}` + ) }) -router.route('/materia-lti-picker-return').all((req, res) => { +router.route('/materia-lti-picker-return').post(async (req, res) => { // our Materia integration relies on postmessage // this is only here for Materia to redirect to // once a resource is selected. Normally, // the client will close the browser before this loads - // In the future, this will have to receive & validate - // a normal LTI ContentItemSelectionRequest results and - // pass it to the client - if (req.query.embed_type && req.query.url) { + const materia_jwks = await fetch(`${config.clientMateriaHost}/.well-known/jwks.json`).then(r => + r.json() + ) + const keystore = jose.JWK.createKeyStore() + for (const jwk of materia_jwks.keys) { + await keystore.add(jwk) + } + const result = await jose.JWS.createVerify(keystore).verify(req.body.JWT) + const payload = JSON.parse(result.payload.toString()) + + if (payload.type === 'ltiResourceLink' && req.url) { res.type('text/html') res.send(`Materia Widget Selection Complete`) } @@ -185,18 +136,8 @@ router .get([requireCurrentUser, requireCanViewEditor]) .get(async (req, res) => { const { draftId, contentId, nodeId } = req.query - const clientBaseUrl = baseUrl(req, false) - const serverBaseUrl = baseUrl(req) const currentDocument = await Draft.fetchDraftByVersion(draftId, contentId) - const method = 'POST' - const endpoint = `${config.clientMateriaHost}/lti/picker` - const launchParams = contentSelectionParams( - currentDocument, - nodeId, - req.currentUser, - clientBaseUrl, - serverBaseUrl - ) + const endpoint = `${config.clientMateriaHost}/ltilaunch/` await materiaEvent.insertLtiPickerLaunchEvent({ userId: req.currentUser.id, @@ -207,7 +148,110 @@ router ip: req.ip }) - renderLtiLaunch(launchParams, method, endpoint, res) + const loginHintObj = { + nodeId: nodeId, + documentTitle: currentDocument.getTitle() + } + + const loginHint = base64encode(JSON.stringify(loginHintObj)) + const ltiMessageHint = 'picker' + res.redirect( + `${config.clientMateriaHost}/init/${config.oboLtiUuid}/?iss=${baseUrl(req)}&client_id=${ + config.oboLtiClientId + }&target_link_uri=${endpoint}&login_hint=${loginHint}<i_message_hint=${ltiMessageHint}` + ) + }) + +router + .route('/materia-lti-auth') + .get([requireCurrentUser]) + .get(async (req, res) => { + const { client_id, redirect_uri, login_hint, lti_message_hint, nonce, state } = req.query + + if (lti_message_hint === 'picker' && !req.currentUser.hasPermission('canViewEditor')) { + renderError( + res, + 'Action Not Allowed', + 'Widget picker event launched by user lacking editor rights.' + ) + return + } + + const now = Math.floor(Date.now() / 1000) + + const nodeContext = JSON.parse(base64decode(login_hint)) + + const payload = { + iss: baseUrl(req), + aud: client_id, + iat: now, + exp: now + 300, + nonce, + sub: req.currentUser.username, // this... may not be necessary? + email: req.currentUser.email, + given_name: req.currentUser.firstName, + family_name: req.currentUser.lastName, + 'https://purl.imsglobal.org/spec/lti/claim/lis': { + person_sourcedid: req.currentUser.username + }, + 'https://purl.imsglobal.org/spec/lti/claim/version': '1.3.0', + 'https://purl.imsglobal.org/spec/lti/claim/message_type': + lti_message_hint === 'picker' ? 'LtiDeepLinkingRequest' : 'LtiResourceLinkRequest', + 'https://purl.imsglobal.org/spec/lti/claim/deployment_id': 'obojobo-deployment-id', + 'https://purl.imsglobal.org/spec/lti/claim/target_link_uri': + lti_message_hint === 'picker' ? redirect_uri : nodeContext.widgetEndpoint, + // transporting the node ID of the Materia node being embedded via the login hint + // there may be a more intelligent way of doing this? + 'https://purl.imsglobal.org/spec/lti/claim/resource_link': { id: nodeContext.nodeId }, + 'https://purl.imsglobal.org/spec/lti/claim/roles': [ + // this may be a bit naive, but we can probably assume that + // students will not be able to use the draft editor, so anybody + // getting this far is an instructor + req.currentUser.hasPermission('canViewEditor') + ? 'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor' + : 'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner' + ], + // need to somehow address this + 'https://purl.imsglobal.org/spec/lti/claim/context': { + id: nodeContext.nodeId, + title: nodeContext.draftTitle + } + } + if (lti_message_hint === 'picker') { + payload['https://purl.imsglobal.org/spec/lti-dl/claim/deep_linking_settings'] = { + deep_link_return_url: `${baseUrl(req)}/materia-lti-picker-return`, + accept_types: ['ltiResourceLink'], + accept_presentation_document_targets: ['iframe', 'window', 'embed'] + } + } + + const idToken = jwt.sign(payload, config.oboPrivateRsaKey, { + algorithm: 'RS256', + keyid: config.oboJwtKey + }) + + res.set('Content-Type', 'text/html') + res.send(` +
+ + + + +
+ + `) }) +// this might make more sense somewhere else, but currently it only matters for the materia integration +router.route('/.well-known/jwks.json').get(async (req, res) => { + const key = await jose.JWK.asKey(config.oboPrivateRsaKey, 'pem') + + const jwk = key.toJSON() + jwk.use = 'sig' + jwk.alg = 'RS256' + jwk.kid = config.oboJwtKey + + res.json({ keys: [jwk] }) +}) + module.exports = router diff --git a/packages/obonode/obojobo-chunks-materia/server/route-helpers.js b/packages/obonode/obojobo-chunks-materia/server/route-helpers.js deleted file mode 100644 index 1d47e6aa05..0000000000 --- a/packages/obonode/obojobo-chunks-materia/server/route-helpers.js +++ /dev/null @@ -1,262 +0,0 @@ -const querystring = require('querystring') -const logger = require('obojobo-express/server/logger') -const xml2js = require('xml2js') -const crypto = require('crypto') -const config = require('obojobo-express/server/config').materiaLti -const sig = require('oauth-signature') - -const buildLTIUser = user => ({ - lis_person_contact_email_primary: user.email, - lis_person_name_family: user.lastName, - lis_person_name_full: `${user.firstName} ${user.lastName}`, - lis_person_name_given: user.firstName, - lis_person_sourcedid: user.username, - roles: [], - user_id: user.id, - user_image: user.avatarUrl -}) - -const ltiContextFromDocument = draft => ({ - context_id: draft.draftId, - context_title: draft.getTitle(), - context_type: 'CourseSection' -}) - -// create compound ids for materia -const expandLisResultSourcedId = lisResultSourcedId => { - const [visitId, nodeId] = lisResultSourcedId.split('__') - return { visitId, nodeId } -} - -const buildLTIStudent = user => ({ ...buildLTIUser(user), roles: ['Student'] }) - -const buildLTIInstructor = user => ({ ...buildLTIUser(user), roles: ['Instructor'] }) - -const ltiToolConsumer = baseUrl => ({ - tool_consumer_info_product_family_code: config.oboFamilyCode, - tool_consumer_instance_guid: config.oboGuid, - tool_consumer_instance_name: config.oboName, - tool_consumer_instance_url: baseUrl -}) - -const widgetLaunchParams = (document, visit, user, materiaOboNodeId, baseUrl) => { - const params = { - lti_message_type: 'basic-lti-launch-request', - lti_version: 'LTI-1p0', - // materia will send scores here - lis_outcome_service_url: `${baseUrl}/materia-lti-score-passback`, - // represents the container for the user's score this widget can set/update - lis_result_sourcedid: `${visit.id}__${materiaOboNodeId}`, - // unique placement of this widget (take into account the module's unique placement in a course + the widget's place in the module) - // we are intentionally not including user id (not part of the placement) or draft_content_id (to allow updates to a module) - resource_link_id: `${visit.resource_link_id}__${visit.draft_id}__${materiaOboNodeId}`, - custom_obo_node_id: materiaOboNodeId, - custom_visit_id: visit.id, - custom_draft_id: visit.draft_id, - custom_draft_content_id: visit.draft_content_id, - custom_passthrough_resource_link_id: visit.resource_link_id - } - - // materia currently uses context_id to group scores and attempts - // obojobo doesn't support materia as scoreable questions yet, so the key in use here is intended to: - // * support materia in content pages - // * re lti launch will reset scores/attempts - // * browser reload of the window will resume an attempt/score window - // a visit id is a representation of: user_id + lti launch + draft_id + draft_content_id - const overrideKeys = { context_id: params.lis_result_sourcedid } - - const ltiUser = visit.is_preview ? buildLTIInstructor(user) : buildLTIStudent(user) - return { - ...ltiUser, - ...params, - ...ltiToolConsumer(baseUrl), - ...ltiContextFromDocument(document), - ...overrideKeys - } -} - -const contentSelectionParams = (document, materiaOboNodeId, user, clientBaseUrl, serverBaseUrl) => { - const params = { - lti_message_type: 'ContentItemSelectionRequest', - lti_version: 'LTI-1p0', - accept_media_types: 'application/vnd.ims.lti.v1.ltiassignment', - accept_presentation_document_targets: 'iframe', - accept_unsigned: true, - accept_multiple: false, - accept_copy_advice: false, - auto_create: false, - content_item_return_url: `${clientBaseUrl}/materia-lti-picker-return`, - data: `draftId=${document.draftId}&contentId=${document.contentId}&nodeId=${materiaOboNodeId}` - } - - return { - ...buildLTIInstructor(user), - ...params, - ...ltiToolConsumer(serverBaseUrl), - ...ltiContextFromDocument(document) - } -} - -const getValuesFromPassbackXML = async body => { - const result = await xml2js.parseStringPromise(body, { - normalize: true, - normalizeTags: true, - explicitArray: false - }) - const messageId = - result.imsx_poxenveloperequest.imsx_poxheader.imsx_poxrequestheaderinfo.imsx_messageidentifier - const sourcedId = - result.imsx_poxenveloperequest.imsx_poxbody.replaceresultrequest.resultrecord.sourcedguid - .sourcedid - const score = - parseFloat( - result.imsx_poxenveloperequest.imsx_poxbody.replaceresultrequest.resultrecord.result - .resultscore.textstring - ) * 100 - - return { - messageId, - sourcedId, - score - } -} - -// extract request headers into an object we can use -const extractAuthHeaders = headers => { - if (!headers || !headers.authorization) { - throw Error('Authorization header missing from score passback request') - } - return headers.authorization - .split(' ')[1] - .replace(/"/g, '') - .split(',') - .reduce((all, cur) => { - return Object.assign({}, all, querystring.parse(cur)) - }, {}) -} - -const verifyBodyHash = (body, expectedHash) => { - const bodyHash = crypto - .createHash('sha1') - .update(body) - .digest('base64') - // check if our body hash matches - if (bodyHash !== expectedHash) { - logger.info('Materia Body Hash Mismatch') - logger.info(body) - logger.info(`calculated hash ${bodyHash} expected hash ${expectedHash}`) - throw Error('Materia Body Hash Mismatch') - } - - return bodyHash -} - -const verifyAuthSignature = (endpoint, authHeaders, bodyHash) => { - // re-construct the headers so we can sign them - const headers = { - oauth_version: authHeaders.oauth_version, - oauth_nonce: authHeaders.oauth_nonce, - oauth_timestamp: authHeaders.oauth_timestamp, - oauth_consumer_key: authHeaders.oauth_consumer_key, - oauth_body_hash: bodyHash, - oauth_signature_method: authHeaders.oauth_signature_method - } - - // sign oauth headers with our secret - const hmac_sha1 = sig.generate('POST', endpoint, headers, config.oauthSecret, '', { - encodeSignature: false - }) - - // check our signature against the one we received - if (hmac_sha1 !== authHeaders.oauth_signature) { - logger.error('Materia Replace Result Header oAuth Signature Mismatch') - logger.info(headers) - logger.info(endpoint) - logger.info(hmac_sha1) - throw Error('Materia Replace Result Header oAuth Signature Mismatch') - } - - return true -} - -// check the bodyHash of an LTI 1 score passback to verify -// it matches when hashed with the secret we have locally -// returns true when matching, false when it fails verification -const verifyScorePassback = (headers, body, originalUrl, baseUrl) => { - try { - const authHeaders = extractAuthHeaders(headers) - - // verify all the required properties exist in auth header - const requiredKeys = [ - 'oauth_body_hash', - 'oauth_version', - 'oauth_timestamp', - 'oauth_nonce', - 'oauth_consumer_key', - 'oauth_signature_method', - 'oauth_signature' - ] - - requiredKeys.forEach(key => { - if (!authHeaders[key]) throw Error(`LTI score passback authorization header missing "${key}"`) - }) - - const bodyHash = verifyBodyHash(body, authHeaders.oauth_body_hash) - - const endpoint = `${baseUrl}${originalUrl}` - return verifyAuthSignature(endpoint, authHeaders, bodyHash) - } catch (e) { - logger.error('Materia score passback verification error') - logger.error(e) - return false - } -} - -const createPassbackResult = ({ success, messageId, messageRefId }) => { - return ` - - - - V1.0 - ${messageId} - - ${success ? 'success' : 'failure'} - status - ${messageRefId} - replaceResult - - - - - - - ` -} - -const signLtiParams = (params, method, endpoint) => { - // add the required oauth params to the given prams - const oauthParams = { - oauth_nonce: Math.round(new Date().getTime() / 1000.0), - oauth_timestamp: Math.round(new Date().getTime() / 1000.0), - oauth_callback: 'about:blank', - oauth_consumer_key: config.oauthKey, - oauth_signature_method: 'HMAC-SHA1', - oauth_version: '1.0' - } - const result = { ...params, ...oauthParams } - const hmac_sha1 = sig.generate(method, endpoint, result, config.oauthSecret, '', { - encodeSignature: false - }) - result['oauth_signature'] = hmac_sha1 - return result -} - -module.exports = { - contentSelectionParams, - widgetLaunchParams, - expandLisResultSourcedId, - createPassbackResult, - getValuesFromPassbackXML, - verifyScorePassback, - signLtiParams -} diff --git a/yarn.lock b/yarn.lock index d2a92d117f..7344e00fb5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1198,6 +1198,44 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@hapi/boom@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-10.0.1.tgz#ebb14688275ae150aa6af788dbe482e6a6062685" + integrity sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/bourne@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-3.0.0.tgz#f11fdf7dda62fe8e336fa7c6642d9041f30356d7" + integrity sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w== + +"@hapi/hoek@^11.0.2", "@hapi/hoek@^11.0.4": + version "11.0.7" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-11.0.7.tgz#56a920793e0a42d10e530da9a64cc0d3919c4002" + integrity sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ== + +"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": + version "9.3.0" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" + integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== + +"@hapi/topo@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@hapi/wreck@^18.0.0": + version "18.1.0" + resolved "https://registry.yarnpkg.com/@hapi/wreck/-/wreck-18.1.0.tgz#68e631fc7568ebefc6252d5b86cb804466c8dbe6" + integrity sha512-0z6ZRCmFEfV/MQqkQomJ7sl/hyxvcZM7LtuVqN3vdAO4vM9eBbowl0kaqQj9EJJQab+3Uuh1GxbGIBFy4NfJ4w== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/bourne" "^3.0.0" + "@hapi/hoek" "^11.0.2" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -2340,6 +2378,23 @@ dependencies: "@octokit/openapi-types" "^5.3.2" +"@sideway/address@^4.1.5": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" + integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f" + integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -3273,6 +3328,16 @@ asap@^2.0.0: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= +asn1.js@^5.0.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + asn1@~0.2.0, asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" @@ -4128,6 +4193,11 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +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== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -4206,6 +4276,11 @@ bluebird@^3.1.1, bluebird@^3.7.2: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== +bn.js@^4.0.0: + version "4.12.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.2.tgz#3d8fed6796c24e177737f7cc5172ee04ef39ec99" + integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw== + body-parser@1.20.1, body-parser@^1.19.0: version "1.20.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" @@ -4334,6 +4409,11 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" +buffer-equal-constant-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -4357,6 +4437,14 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + builtins@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" @@ -4689,7 +4777,7 @@ chokidar@^3.2.2: optionalDependencies: fsevents "~2.3.1" -chownr@^1.1.1: +chownr@^1.1.1, chownr@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -5995,6 +6083,13 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + editorconfig@^0.15.3: version "0.15.3" resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5" @@ -6225,6 +6320,11 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +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== + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -6946,6 +7046,13 @@ fs-extra@^9.1.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-minipass@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + fs-minipass@^2.0.0, fs-minipass@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -7337,7 +7444,7 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -8802,6 +8909,17 @@ jiti@^1.18.2: resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.1.tgz#fa99e4b76a23053e0e7cde098efe1704a14c16f1" integrity sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg== +joi@^17.6.4: + version "17.13.3" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.13.3.tgz#0f5cc1169c999b30d344366d384b12d92558bcec" + integrity sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA== + dependencies: + "@hapi/hoek" "^9.3.0" + "@hapi/topo" "^5.1.0" + "@sideway/address" "^4.1.5" + "@sideway/formula" "^3.0.1" + "@sideway/pinpoint" "^2.0.0" + js-base64@^2.4.9: version "2.6.4" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4" @@ -8980,6 +9098,22 @@ jsonparse@^1.2.0, jsonparse@^1.3.1: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= +jsonwebtoken@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + 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 "^7.5.4" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -8998,6 +9132,23 @@ jsprim@^1.2.2: array-includes "^3.1.2" object.assign "^4.1.2" +jwa@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.2.tgz#16011ac6db48de7b102777e57897901520eec7b9" + integrity sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw== + dependencies: + buffer-equal-constant-time "^1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + katex@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/katex/-/katex-0.13.1.tgz#a3f4764f7e513eed554600e0732f5ac2fa202165" @@ -9284,16 +9435,51 @@ lodash.flattendeep@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + lodash.ismatch@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + lodash.orderby@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.orderby/-/lodash.orderby-4.6.0.tgz#e697f04ce5d78522f54d9338b32b81a3393e4eb3" @@ -9347,6 +9533,11 @@ loglevel@^1.6.8: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== +long@^5.2.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== + loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -9812,6 +10003,14 @@ minipass-sized@^1.0.3: dependencies: minipass "^3.0.0" +minipass@^2.6.0, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" @@ -9833,6 +10032,13 @@ minipass@^4.0.0: dependencies: yallist "^4.0.0" +minizlib@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -10072,12 +10278,50 @@ node-forge@^0.10.0: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== +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-fs@~0.1.5: version "0.1.7" resolved "https://registry.yarnpkg.com/node-fs/-/node-fs-0.1.7.tgz#32323cccb46c9fbf0fc11812d45021cc31d325bb" integrity sha1-MjI8zLRsn78PwRgS1FAhzDHTJbs= -node-gyp@^5.0.2, node-gyp@^7.1.0, node-gyp@^8.0.0, node-gyp@^8.4.1: +node-gyp@^5.0.2: + version "5.1.1" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e" + integrity sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.2" + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.1.2" + request "^2.88.0" + rimraf "^2.6.3" + semver "^5.7.1" + tar "^4.4.12" + which "^1.3.1" + +node-gyp@^7.1.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" + integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.3" + nopt "^5.0.0" + npmlog "^4.1.2" + request "^2.88.2" + rimraf "^3.0.2" + semver "^7.3.2" + tar "^6.0.2" + which "^2.0.2" + +node-gyp@^8.4.1: version "8.4.1" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== @@ -10098,6 +10342,21 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= +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: + 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" + node-modules-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" @@ -10161,6 +10420,14 @@ nodemon@^2.0.4: undefsafe "^2.0.3" update-notifier "^4.1.0" +nopt@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== + dependencies: + abbrev "1" + osenv "^0.1.4" + nopt@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" @@ -10565,11 +10832,19 @@ os-homedir@^1.0.0: resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= -os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" @@ -10740,6 +11015,11 @@ pacote@^11.2.6: ssri "^8.0.1" tar "^6.1.0" +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== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -10904,6 +11184,13 @@ peek-readable@^4.1.0: resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-4.1.0.tgz#4ece1111bf5c2ad8867c314c81356847e8a62e72" integrity sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg== +pem-jwk@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pem-jwk/-/pem-jwk-2.0.0.tgz#1c5bb264612fc391340907f5c1de60c06d22f085" + integrity sha512-rFxu7rVoHgQ5H9YsP50dDWf0rHjreVA2z0yPiWr5WdH/UHb29hKtF7h6l8vNd1cbYR1t0QL+JKhW55a2ZV4KtA== + dependencies: + asn1.js "^5.0.1" + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -11241,6 +11528,11 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +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== + progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -12002,7 +12294,7 @@ request-promise-native@^1.0.9: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.88.2: +request@^2.88.0, request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -12188,7 +12480,7 @@ rxjs@^6.6.0, rxjs@^6.6.6: dependencies: tslib "^1.9.0" -safe-buffer@*, safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@*, safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -12603,6 +12895,16 @@ simple-get@^4.0.0, simple-get@^4.0.1: once "^1.3.1" simple-concat "^1.0.0" +simple-oauth2@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/simple-oauth2/-/simple-oauth2-5.1.0.tgz#1398fe2b8f4b4066298d63c155501b31b42238f2" + integrity sha512-gWDa38Ccm4MwlG5U7AlcJxPv3lvr80dU7ARJWrGdgvOKyzSj1gr3GBPN1rABTedAYvC/LsGYoFuFxwDBPtGEbw== + dependencies: + "@hapi/hoek" "^11.0.4" + "@hapi/wreck" "^18.0.0" + debug "^4.3.4" + joi "^17.6.4" + simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" @@ -13588,6 +13890,19 @@ tar-stream@^3.1.5: fast-fifo "^1.2.0" streamx "^2.15.0" +tar@^4.4.12: + version "4.4.19" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" + integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== + dependencies: + chownr "^1.1.4" + fs-minipass "^1.2.7" + minipass "^2.9.0" + minizlib "^1.3.3" + mkdirp "^0.5.5" + safe-buffer "^5.2.1" + yallist "^3.1.1" + tar@^6.0.2, tar@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83" @@ -14246,6 +14561,11 @@ uuid@^8.3.0, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + uuid@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" @@ -14824,6 +15144,11 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= +yallist@^3.0.0, yallist@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"