caccl-authorizer
Advanced tools
Comparing version 1.1.26 to 1.1.27
@@ -105,2 +105,3 @@ const randomstring = require('randomstring'); | ||
body.lis_person_sourcedid = options.profile.login_id; | ||
body.lis_course_offering_sourcedid = options.course.sis_id; | ||
body.lti_message_type = 'basic-lti-launch-request'; | ||
@@ -107,0 +108,0 @@ body.lti_version = 'LTI-1p0'; |
{ | ||
"name": "caccl-authorizer", | ||
"version": "1.1.26", | ||
"version": "1.1.27", | ||
"description": "Acquires Canvas tokens through via OAuth, stores refresh tokens, and refreshes access tokens when they expire.", | ||
@@ -32,3 +32,3 @@ "main": "index.js", | ||
"body-parser": "^1.19.0", | ||
"caccl": "^1.1.36", | ||
"caccl": "^1.1.41", | ||
"caccl-canvas-partial-simulator": "^1.0.43", | ||
@@ -46,2 +46,3 @@ "dce-selenium": "^1.0.58", | ||
"https": "^1.0.0", | ||
"ims-lti": "^3.0.2", | ||
"mocha": "^8.2.1" | ||
@@ -52,3 +53,3 @@ }, | ||
"caccl-error": "^1.0.7", | ||
"caccl-lti": "^1.1.6", | ||
"caccl-lti": "^1.1.8", | ||
"caccl-send-request": "^1.0.15", | ||
@@ -55,0 +56,0 @@ "ejs": "^2.7.4", |
@@ -11,2 +11,3 @@ const API = require('caccl-api'); | ||
course, // Canvas course object for test course | ||
isValid, // function that checks if a launch request is valid (ret: promise) | ||
nonceValid, // function that checks if a nonce is valid | ||
@@ -154,276 +155,289 @@ getOnLoginTimestamp, | ||
app.post(launchPath, (req, res) => { | ||
let html = '<style>td {\nborder: 1px solid black;\n}</style>\n'; | ||
html += '<h1>Review, then click play to resume tests</h1>\n'; | ||
html += '<table style="width: 100%">\n<tr><td>Item</td><td>Value</td><td>Expected/Requirement</td><td>Results</td><td>Pass/Fail</td>\n'; | ||
isValid(req) | ||
.then((valid) => { | ||
let html = '<style>td {\nborder: 1px solid black;\n}</style>\n'; | ||
html += '<h1>Review, then click play to resume tests</h1>\n'; | ||
html += '<table style="width: 100%">\n<tr><td>Item</td><td>Value</td><td>Expected/Requirement</td><td>Results</td><td>Pass/Fail</td>\n'; | ||
// eslint-disable-next-line max-params | ||
const addRow = (prop, expected, results, pass) => { | ||
html += `<tr style="background-color: ${pass ? 'white' : 'red'}; color: ${pass ? 'black' : 'white'}"><td>${prop}</td><td>${req.body[prop]}</td><td>${expected}</td><td>${results}</td><td>${pass ? 'Pass!' : 'Fail!'}</td></tr>\n`; | ||
}; | ||
// eslint-disable-next-line max-params | ||
const addRow = (prop, expected, results, pass) => { | ||
html += `<tr style="background-color: ${pass ? 'white' : 'red'}; color: ${pass ? 'black' : 'white'}"><td>${prop}</td><td>${req.body[prop]}</td><td>${expected}</td><td>${results}</td><td>${pass ? 'Pass!' : 'Fail!'}</td></tr>\n`; | ||
}; | ||
// Consumer key | ||
let pass = (req.body.oauth_consumer_key === 'consumer_key'); | ||
addRow( | ||
'oauth_consumer_key', | ||
'Equals', | ||
'consumer_key', | ||
pass | ||
); | ||
// Consumer key | ||
let pass = (req.body.oauth_consumer_key === 'consumer_key'); | ||
addRow( | ||
'oauth_consumer_key', | ||
'Equals', | ||
'consumer_key', | ||
pass | ||
); | ||
// Request validity | ||
addRow( | ||
'oauth_signature', | ||
'is valid', | ||
valid, | ||
valid | ||
); | ||
// Request validity | ||
addRow( | ||
'oauth_signature', | ||
'is valid', | ||
valid, | ||
valid | ||
); | ||
// Nonce | ||
pass = nonceValid(req.body.oauth_nonce); | ||
addRow( | ||
'oauth_nonce', | ||
'Never used', | ||
pass ? 'Never used' : 'Used', | ||
pass | ||
); | ||
// Nonce | ||
pass = nonceValid(req.body.oauth_nonce); | ||
addRow( | ||
'oauth_nonce', | ||
'Never used', | ||
pass ? 'Never used' : 'Used', | ||
pass | ||
); | ||
// Timestamp | ||
const age = ( | ||
(Date.now() / 1000) | ||
- (req.body.oauth_timestamp || 0) | ||
); | ||
pass = (age > -1 && age <= 5); | ||
addRow( | ||
'oauth_timestamp', | ||
'Within last 4s', | ||
`Age: ${age.toFixed(3)}s`, | ||
pass | ||
); | ||
// Timestamp | ||
const age = ( | ||
(Date.now() / 1000) | ||
- (req.body.oauth_timestamp || 0) | ||
); | ||
pass = (age > -1 && age <= 5); | ||
addRow( | ||
'oauth_timestamp', | ||
'Within last 4s', | ||
`Age: ${age.toFixed(3)}s`, | ||
pass | ||
); | ||
// Context id | ||
pass = (req.body.context_id === course.uuid); | ||
addRow( | ||
'context_id', | ||
'Equals the course uuid', | ||
`Should be: ${course.uuid}`, | ||
pass | ||
); | ||
pass = (req.body.resource_link_id === course.uuid); | ||
addRow( | ||
'resource_link_id', | ||
'Equals the course uuid', | ||
`Should be: ${course.uuid}`, | ||
pass | ||
); | ||
// Context id | ||
pass = (req.body.context_id === course.uuid); | ||
addRow( | ||
'context_id', | ||
'Equals the course uuid', | ||
`Should be: ${course.uuid}`, | ||
pass | ||
); | ||
pass = (req.body.resource_link_id === course.uuid); | ||
addRow( | ||
'resource_link_id', | ||
'Equals the course uuid', | ||
`Should be: ${course.uuid}`, | ||
pass | ||
); | ||
// Context label | ||
pass = (req.body.context_label === course.course_code); | ||
addRow( | ||
'context_label', | ||
'Equals the course code', | ||
`Should be: ${course.course_code}`, | ||
pass | ||
); | ||
// Context label | ||
pass = (req.body.context_label === course.course_code); | ||
addRow( | ||
'context_label', | ||
'Equals the course code', | ||
`Should be: ${course.course_code}`, | ||
pass | ||
); | ||
// Context title | ||
pass = (req.body.context_title === course.name); | ||
addRow( | ||
'context_title', | ||
'Equals the course name', | ||
`Should be: ${course.name}`, | ||
pass | ||
); | ||
// Context title | ||
pass = (req.body.context_title === course.name); | ||
addRow( | ||
'context_title', | ||
'Equals the course name', | ||
`Should be: ${course.name}`, | ||
pass | ||
); | ||
// Custom api domain | ||
pass = (req.body.custom_canvas_api_domain === 'localhost:8088'); | ||
addRow( | ||
'custom_canvas_api_domain', | ||
'Equals localhost:8088', | ||
pass, | ||
pass | ||
); | ||
// Custom api domain | ||
pass = (req.body.custom_canvas_api_domain === 'localhost:8088'); | ||
addRow( | ||
'custom_canvas_api_domain', | ||
'Equals localhost:8088', | ||
pass, | ||
pass | ||
); | ||
// Canvas course id | ||
pass = ( | ||
String(req.body.custom_canvas_course_id) === String(course.id) | ||
); | ||
addRow( | ||
'custom_canvas_course_id', | ||
'Equals course id', | ||
`Should be: ${course.id}`, | ||
pass | ||
); | ||
// Canvas course id | ||
pass = ( | ||
String(req.body.custom_canvas_course_id) === String(course.id) | ||
); | ||
addRow( | ||
'custom_canvas_course_id', | ||
'Equals course id', | ||
`Should be: ${course.id}`, | ||
pass | ||
); | ||
// custom_canvas_enrollment_state | ||
pass = (req.body.custom_canvas_enrollment_state === 'active'); | ||
addRow( | ||
'custom_canvas_enrollment_state', | ||
'Is active', | ||
pass, | ||
pass | ||
); | ||
// custom_canvas_enrollment_state | ||
pass = (req.body.custom_canvas_enrollment_state === 'active'); | ||
addRow( | ||
'custom_canvas_enrollment_state', | ||
'Is active', | ||
pass, | ||
pass | ||
); | ||
// user id | ||
pass = (req.body.custom_canvas_user_id === String(user.id)); | ||
addRow( | ||
'custom_canvas_user_id', | ||
'Equals user.id', | ||
user.id, | ||
pass | ||
); | ||
// user id | ||
pass = (req.body.custom_canvas_user_id === String(user.id)); | ||
addRow( | ||
'custom_canvas_user_id', | ||
'Equals user.id', | ||
user.id, | ||
pass | ||
); | ||
// login id | ||
pass = (req.body.custom_canvas_user_login_id === user.login_id); | ||
addRow( | ||
'custom_canvas_user_login_id', | ||
'Equals login id', | ||
user.login_id, | ||
pass | ||
); | ||
// login id | ||
pass = (req.body.custom_canvas_user_login_id === user.login_id); | ||
addRow( | ||
'custom_canvas_user_login_id', | ||
'Equals login id', | ||
user.login_id, | ||
pass | ||
); | ||
// custom_canvas_workflow_state | ||
pass = (req.body.custom_canvas_workflow_state === 'available'); | ||
addRow( | ||
'custom_canvas_workflow_state', | ||
'Is available', | ||
pass, | ||
pass | ||
); | ||
// custom_canvas_workflow_state | ||
pass = (req.body.custom_canvas_workflow_state === 'available'); | ||
addRow( | ||
'custom_canvas_workflow_state', | ||
'Is available', | ||
pass, | ||
pass | ||
); | ||
// ext role | ||
pass = (req.body.ext_roles.includes(course.enrollments[0].role)); | ||
addRow( | ||
'ext_roles', | ||
'Matches course enrollment role', | ||
`Should be: ${course.enrollments[0].role}`, | ||
pass | ||
); | ||
// ext role | ||
pass = (req.body.ext_roles.includes(course.enrollments[0].role)); | ||
addRow( | ||
'ext_roles', | ||
'Matches course enrollment role', | ||
`Should be: ${course.enrollments[0].role}`, | ||
pass | ||
); | ||
// launch_presentation_document_target | ||
pass = ( | ||
['window', 'iframe'] | ||
.indexOf(req.body.launch_presentation_document_target) >= 0 | ||
); | ||
addRow( | ||
'launch_presentation_document_target', | ||
'Is either "iframe" or "window"', | ||
pass, | ||
pass | ||
); | ||
// launch_presentation_document_target | ||
pass = ( | ||
['window', 'iframe'] | ||
.indexOf(req.body.launch_presentation_document_target) >= 0 | ||
); | ||
addRow( | ||
'launch_presentation_document_target', | ||
'Is either "iframe" or "window"', | ||
pass, | ||
pass | ||
); | ||
// locale | ||
pass = ( | ||
req.body.launch_presentation_locale === user.effective_locale | ||
); | ||
addRow( | ||
'launch_presentation_locale', | ||
'Equals user locale', | ||
`Should be: ${user.effective_locale}`, | ||
pass | ||
); | ||
// locale | ||
pass = ( | ||
req.body.launch_presentation_locale === user.effective_locale | ||
); | ||
addRow( | ||
'launch_presentation_locale', | ||
'Equals user locale', | ||
`Should be: ${user.effective_locale}`, | ||
pass | ||
); | ||
// last name | ||
const lastName = user.sortable_name.split(',')[0].trim(); | ||
pass = (req.body.lis_person_name_family === lastName); | ||
addRow( | ||
'lis_person_name_family', | ||
'Equals user last name', | ||
`Should be: ${lastName}`, | ||
pass | ||
); | ||
// last name | ||
const lastName = user.sortable_name.split(',')[0].trim(); | ||
pass = (req.body.lis_person_name_family === lastName); | ||
addRow( | ||
'lis_person_name_family', | ||
'Equals user last name', | ||
`Should be: ${lastName}`, | ||
pass | ||
); | ||
// first name | ||
const firstName = user.sortable_name.split(',')[1].trim(); | ||
pass = (req.body.lis_person_name_given === firstName); | ||
addRow( | ||
'lis_person_name_given', | ||
'Equals user first name', | ||
`Should be: ${firstName}`, | ||
pass | ||
); | ||
// first name | ||
const firstName = user.sortable_name.split(',')[1].trim(); | ||
pass = (req.body.lis_person_name_given === firstName); | ||
addRow( | ||
'lis_person_name_given', | ||
'Equals user first name', | ||
`Should be: ${firstName}`, | ||
pass | ||
); | ||
// full name | ||
pass = (req.body.lis_person_name_full === user.name); | ||
addRow( | ||
'lis_person_name_full', | ||
'Equals user full name', | ||
`Should be ${user.name}`, | ||
pass | ||
); | ||
// full name | ||
pass = (req.body.lis_person_name_full === user.name); | ||
addRow( | ||
'lis_person_name_full', | ||
'Equals user full name', | ||
`Should be ${user.name}`, | ||
pass | ||
); | ||
// login id | ||
pass = (req.body.lis_person_sourcedid === user.login_id); | ||
addRow( | ||
'lis_person_sourcedid', | ||
'Equals user login id', | ||
`Should be ${user.login_id}`, | ||
pass | ||
); | ||
// login id | ||
pass = (req.body.lis_person_sourcedid === user.login_id); | ||
addRow( | ||
'lis_person_sourcedid', | ||
'Equals user login id', | ||
`Should be ${user.login_id}`, | ||
pass | ||
); | ||
// lti_message_type: 'basic-lti-launch-request', | ||
pass = (req.body.lti_message_type === 'basic-lti-launch-request'); | ||
addRow( | ||
'lti_message_type', | ||
'Equals:', | ||
'basic-lti-launch-request', | ||
pass | ||
); | ||
// LIS identifier for the course offering, | ||
// Also called sis_course_id, sis_id, and ssid in Canvas | ||
pass = (req.body.lis_course_offering_sourcedid === course.sis_id); | ||
addRow( | ||
'lis_course_offering_sourcedid', | ||
'Equals LIS identifier for the course offering', | ||
`Should be ${course.sis_id}`, | ||
pass | ||
); | ||
// lti_version: 'LTI-1p0', | ||
pass = (req.body.lti_version === 'LTI-1p0'); | ||
addRow( | ||
'lti_version', | ||
'Equals:', | ||
'LTI-1p0', | ||
pass | ||
); | ||
// lti_message_type: 'basic-lti-launch-request', | ||
pass = (req.body.lti_message_type === 'basic-lti-launch-request'); | ||
addRow( | ||
'lti_message_type', | ||
'Equals:', | ||
'basic-lti-launch-request', | ||
pass | ||
); | ||
// roles | ||
pass = (req.body.roles.includes(course.enrollments[0].role)); | ||
addRow( | ||
'roles', | ||
'Includes', | ||
course.enrollments[0].role, | ||
pass | ||
); | ||
// lti_version: 'LTI-1p0', | ||
pass = (req.body.lti_version === 'LTI-1p0'); | ||
addRow( | ||
'lti_version', | ||
'Equals:', | ||
'LTI-1p0', | ||
pass | ||
); | ||
// tool family | ||
pass = (req.body.tool_consumer_info_product_family_code === 'canvas'); | ||
addRow( | ||
'tool_consumer_info_product_family_code', | ||
'Equals', | ||
'canvas', | ||
pass | ||
); | ||
// roles | ||
pass = (req.body.roles.includes(course.enrollments[0].role)); | ||
addRow( | ||
'roles', | ||
'Includes', | ||
course.enrollments[0].role, | ||
pass | ||
); | ||
// cloud | ||
pass = (req.body.tool_consumer_info_version === 'cloud'); | ||
addRow( | ||
'tool_consumer_info_version', | ||
'Equals', | ||
'cloud', | ||
pass | ||
); | ||
// tool family | ||
pass = (req.body.tool_consumer_info_product_family_code === 'canvas'); | ||
addRow( | ||
'tool_consumer_info_product_family_code', | ||
'Equals', | ||
'canvas', | ||
pass | ||
); | ||
// user uuid | ||
pass = (req.body.user_id === user.lti_user_id); | ||
addRow( | ||
'user_id', | ||
'Equals LTI user id', | ||
user.lti_user_id, | ||
pass | ||
); | ||
// cloud | ||
pass = (req.body.tool_consumer_info_version === 'cloud'); | ||
addRow( | ||
'tool_consumer_info_version', | ||
'Equals', | ||
'cloud', | ||
pass | ||
); | ||
// User image | ||
pass = (req.body.user_image === user.avatar_url); | ||
addRow( | ||
'user_image', | ||
'Equals user.avatar_url', | ||
user.avatar_url, | ||
pass | ||
); | ||
// user uuid | ||
pass = (req.body.user_id === user.lti_user_id); | ||
addRow( | ||
'user_id', | ||
'Equals LTI user id', | ||
user.lti_user_id, | ||
pass | ||
); | ||
html += '\n</table>'; | ||
return res.send(html); | ||
// User image | ||
pass = (req.body.user_image === user.avatar_url); | ||
addRow( | ||
'user_image', | ||
'Equals user.avatar_url', | ||
user.avatar_url, | ||
pass | ||
); | ||
html += '\n</table>'; | ||
return res.send(html); | ||
}); | ||
}); | ||
}; |
@@ -8,2 +8,3 @@ const initCACCL = require('caccl/script'); | ||
const https = require('https'); | ||
const lti = require('ims-lti'); | ||
const initCanvasSimulation = require('caccl-canvas-partial-simulator'); | ||
@@ -48,2 +49,16 @@ | ||
/*------------------------------------------------------------------------*/ | ||
/* Set up lti validator */ | ||
/*------------------------------------------------------------------------*/ | ||
const provider = new lti.Provider('consumer_key', 'consumer_secret'); | ||
const isValid = (req) => { | ||
return new Promise((resolve) => { | ||
provider.valid_request(req, (err, valid) => { | ||
resolve(!err && valid); | ||
}); | ||
}); | ||
}; | ||
/*------------------------------------------------------------------------*/ | ||
/* Initialize and create constants */ | ||
@@ -288,2 +303,3 @@ /*------------------------------------------------------------------------*/ | ||
user, | ||
isValid, | ||
nonceValid, | ||
@@ -290,0 +306,0 @@ getOnLoginTimestamp, |
94454
2177
16
Updatedcaccl-lti@^1.1.8