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(`
-
-
-
- `)
-}
-
-// 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"