Skip to content

Commit

Permalink
Make Dynamic Registration configuration extensible
Browse files Browse the repository at this point in the history
This change allows the Dynamic Registration configuration to be extended
 with properties that can be set per-installation (As opposed to once
at the top-level for all installs).

This is done by taking the third (currently unused) parameter to the
`lti.DynamicRegistration.register`, and performing a deep merge with the
default registration object, which I assume was the original
intent of that parameter.

```javascript
lti.DynamicRegistration.register(
  req.query.openid_configuration,
  req.query.registration_token, {
    'https://purl.imsglobal.org/spec/lti-tool-configuration': {
      custom_parameters: {
        'custom1': 'value1',
        'custom2': 'value2'
      }
    }
  }
)
```

This fixes issue #144
  • Loading branch information
pfgray committed Apr 17, 2024
1 parent 00993bd commit 8b611a7
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 6 deletions.
40 changes: 37 additions & 3 deletions dist/Provider/Services/DynamicRegistration.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,40 @@ const crypto = require('crypto');
const _url = require('fast-url-parser');
const provDynamicRegistrationDebug = require('debug')('provider:dynamicRegistrationService');

/**
* Simple object check. taken from https://stackoverflow.com/a/34749873
* @param item
* @returns {boolean}
*/
function isObject(item) {
return item && typeof item === 'object' && !Array.isArray(item);
}

/**
* Deep merge two objects. taken from https://stackoverflow.com/a/34749873
* @param target
* @param ...sources
*/
function mergeDeep(target, ...sources) {
if (!sources.length) return target;
const source = sources.shift();
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, {
[key]: {}
});
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, {
[key]: source[key]
});
}
}
}
return mergeDeep(target, ...sources);
}

// Helper method to build URLs
const buildUrl = (url, path) => {
if (path === '/') return url;
Expand Down Expand Up @@ -94,7 +128,7 @@ class DynamicRegistration {
* @param {String} [registrationToken] - Registration Token. Retrieved from req.query.registration_token.
* @param {Object} [options] - Replacements or extensions to default registration options.
*/
async register(openidConfiguration, registrationToken, options) {
async register(openidConfiguration, registrationToken, options = {}) {
if (!openidConfiguration) throw new Error('MISSING_OPENID_CONFIGURATION');
provDynamicRegistrationDebug('Starting dynamic registration process');
// Get Platform registration configurations
Expand All @@ -107,7 +141,7 @@ class DynamicRegistration {
if (_classPrivateFieldGet(_useDeepLinking, this)) messages.push({
type: 'LtiDeepLinkingRequest'
});
const registration = {
const registration = mergeDeep({
application_type: 'web',
response_types: ['id_token'],
grant_types: ['implicit', 'client_credentials'],
Expand All @@ -126,7 +160,7 @@ class DynamicRegistration {
claims: configuration.claims_supported,
messages
}
};
}, options);
provDynamicRegistrationDebug('Tool registration request:');
provDynamicRegistrationDebug(registration);
provDynamicRegistrationDebug('Sending Tool registration request');
Expand Down
38 changes: 35 additions & 3 deletions src/Provider/Services/DynamicRegistration.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,38 @@ const _url = require('fast-url-parser')

const provDynamicRegistrationDebug = require('debug')('provider:dynamicRegistrationService')

/**
* Simple object check. taken from https://stackoverflow.com/a/34749873
* @param item
* @returns {boolean}
*/
function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
}

/**
* Deep merge two objects. taken from https://stackoverflow.com/a/34749873
* @param target
* @param ...sources
*/
function mergeDeep(target, ...sources) {
if (!sources.length) return target;
const source = sources.shift();

if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} });
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}

return mergeDeep(target, ...sources);
}

// Helper method to build URLs
const buildUrl = (url, path) => {
if (path === '/') return url
Expand Down Expand Up @@ -90,7 +122,7 @@ class DynamicRegistration {
* @param {String} [registrationToken] - Registration Token. Retrieved from req.query.registration_token.
* @param {Object} [options] - Replacements or extensions to default registration options.
*/
async register (openidConfiguration, registrationToken, options) {
async register (openidConfiguration, registrationToken, options = {}) {
if (!openidConfiguration) throw new Error('MISSING_OPENID_CONFIGURATION')
provDynamicRegistrationDebug('Starting dynamic registration process')
// Get Platform registration configurations
Expand All @@ -99,7 +131,7 @@ class DynamicRegistration {
// Building registration object
const messages = [{ type: 'LtiResourceLink' }]
if (this.#useDeepLinking) messages.push({ type: 'LtiDeepLinkingRequest' })
const registration = {
const registration = mergeDeep({
application_type: 'web',
response_types: ['id_token'],
grant_types: ['implicit', 'client_credentials'],
Expand All @@ -118,7 +150,7 @@ class DynamicRegistration {
claims: configuration.claims_supported,
messages
}
}
}, options)
provDynamicRegistrationDebug('Tool registration request:')
provDynamicRegistrationDebug(registration)
provDynamicRegistrationDebug('Sending Tool registration request')
Expand Down

0 comments on commit 8b611a7

Please sign in to comment.