UNPKG

oidc-lib

Version:

A library for creating OIDC Service Providers

430 lines (377 loc) 11.5 kB
var _module_views; const url_module = require('url'); var handlebars = require('./handlebars'); const protocolHandlerSig = 'web%2Bopenid%3A'; var res = new ResFactory(); var req = new ReqFactory(); var query = null; var body = null; var headers = []; var payload = null; var settings = { views: '\\views' } var entryPointUrlFunction = null; const PCOOKIE = 'pcookie_'; var dispatchPoints = []; var registeredCookies = {}; var renderScript = null; module.exports = function(){ Object.defineProperty(this, "module_views", { get: function() { if (_module_views){ return _module_views; } }, set: function(value) { _module_views = value; }, enumerable: true }); Object.defineProperty(this, "settings", { get: function() { return settings; }, enumerable: true }); Object.defineProperty(this, "options", { value: function(name, callback) { } }); Object.defineProperty(this, "registerCookie", { value: function(name) { name = PCOOKIE + name; if (registeredCookies[name] === undefined){ registeredCookies[name] = null; } } }); Object.defineProperty(this, "renderScript", { value: function(arg0, arg1, arg2, arg3, arg4, arg5) { return _module_views.scripts[renderScript][arg0](arg1,arg2,arg3,arg4,arg5); } }); Object.defineProperty(this, "renderDispatcher", { value: function(method, path, parameters) { var point = locateDispatchMatch(method, path); if (point === null){ throw create_claimer_error('server_error', 'No dispatchPoint matches: ' + method + ', ' + path); } method = method.toUpperCase(); switch (method){ case 'GET': req.query = parameters; break; case 'POST': req.body = parameters; break; case 'DEFAULT': throw create_claimer_error('server_error', 'invalid method in renderDispatcher: ' + method); } point.invokeThis(req, res); return payload; } }); /* Object.defineProperty(this, "get", { value: function(path, invokeThis) { var dispatchPoint = {path: 'GET' + path.toLowerCase(), invokeThis: invokeThis}; dispatchPoints.push(dispatchPoint); } }); Object.defineProperty(this, "post", { value: function(path, invokeThis) { var dispatchPoint = {path: 'POST' + path.toLowerCase(), invokeThis: invokeThis}; dispatchPoints.push(dispatchPoint); } }); */ // get and post may either take a path and a function, or path, cors callback and function // in the shim there is no cors since all access is via redirects but for compatibility // if a cors callback is present we ignore it and use the next parameter: the funciton Object.defineProperty(this, "get", { value: function(path, dummyCorsOrInvokeThis, undefinedOrInvokeThis) { var toInvoke = undefinedOrInvokeThis ? undefinedOrInvokeThis : dummyCorsOrInvokeThis; var dispatchPoint = {path: 'GET' + path.toLowerCase(), invokeThis: toInvoke}; dispatchPoints.push(dispatchPoint); } }); Object.defineProperty(this, "post", { value: function(path, dummyCorsOrInvokeThis, undefinedOrInvokeThis) { var toInvoke = undefinedOrInvokeThis ? undefinedOrInvokeThis : dummyCorsOrInvokeThis; var dispatchPoint = {path: 'POST' + path.toLowerCase(), invokeThis: toInvoke}; dispatchPoints.push(dispatchPoint); } }); Object.defineProperty(this, "invokeEntryPoint", { value: function() { var point = locateDispatchMatch(req.method, req.entryPointUrl); if (point !== null){ point.invokeThis(req, res); return; } throw create_claimer_error('server_error', 'No dispatchPoint matches ' + req.originalUrl); } }); Object.defineProperty(this, "entryPointUrlFunction", { set: function(value) { entryPointUrlFunction = value; }, enumerable: true }); return this; } function locateDispatchMatch(method, path){ var method = method.toUpperCase(); var path = path.toLowerCase(); var segs = path.split('/'); var w0 = method + path; var w1 = method + '/*/' + segs[2]; var w2 = method + '/' + segs[1] + '/*'; for (var count=0; count < dispatchPoints.length; count++){ var point = dispatchPoints[count]; var target = point.path; if (w0 === target || w1 === target || w2 === target){ return point; } } return null; } function ResFactory() { Object.defineProperty(this, "views", { get: function() { return _module_views; } }); Object.defineProperty(this, "cookie", { value: function(name, value, timeout) { var expires; if (timeout === undefined || timeout === 0){ expires = 0; } else{ var d = new Date(); expires = d.getTime() + timeout.maxAge; } var contentObj = { value: value, expires: expires }; content = JSON.stringify(contentObj); localStorage.setItem(PCOOKIE + name, content); return; }, enumerable: true }); Object.defineProperty(this, "redirect", { value: function(location) { window.location = location; return; } }); Object.defineProperty(this, "end", { value: function() { return; } }); Object.defineProperty(this, "json", { value: function(jsonObj) { payload = jsonObj; } }); Object.defineProperty(this, "jsonp", { value: function() { alert('res.jsonp not yet implemented in shim'); } }); Object.defineProperty(this, "render", { value: function (viewLocation, contentObject) { viewPage = expandView(viewLocation, contentObject); var template = handlebars.compile(viewPage); var outputPage = template(contentObject); var divEl = document.getElementById("render"); divEl.innerHTML = outputPage; renderScript = viewLocation.toLowerCase(); var selectedScript = res.views.scripts[renderScript]; if (selectedScript !== undefined){ var onload = selectedScript['onload']; if (onload !== undefined){ onload(); } } } }); Object.defineProperty(this, "send", { value: function() { alert('res.send not yet implemented in shim'); } }); Object.defineProperty(this, "sendFile", { value: function() { alert('res.sendFile not yet implemented in shim'); } }); Object.defineProperty(this, "sendStatus", { value: function() { alert('res.sendStatus not yet implemented in shim'); } }); } function ReqFactory() { Object.defineProperty(this, "cookies", { get: function() { var result = {}; for (var key in registeredCookies){ var content = localStorage.getItem(key); if (content === undefined || content === null){ continue; } var contentObj = JSON.parse(content); if (contentObj.expires !== null){ var now = new Date().getTime(); if (contentObj.expires <= now){ continue; } } result[key.substring(PCOOKIE.length)] = contentObj.value; } return result; }, enumerable: true }); Object.defineProperty(this, "redirect", { value: function(location) { window.location = location; return; } }); Object.defineProperty(this, "originalUrl", { get: function() { return window.location.href; }, enumerable: true }); Object.defineProperty(this, "hostname", { get: function() { return window.location.hostname; }, enumerable: true }); Object.defineProperty(this, "path", { get: function() { return window.location.pathname; }, enumerable: true }); Object.defineProperty(this, "hash", { get: function() { return window.location.hash; }, enumerable: true }); Object.defineProperty(this, "entryPointUrl", { get: function() { if (!entryPointUrlFunction){ alert("mandatory entryPointUrlFunction not defined in express shim.") return; } return entryPointUrlFunction(this); }, enumerable: true }); Object.defineProperty(this, "method", { get: function() { return 'GET'; }, enumerable: true }); Object.defineProperty(this, "query", { get: function() { if (query === null){ var urlInfo = url_module.parse(window.location.href); query = {}; if (urlInfo.query !== undefined && urlInfo.query !== null){ var keyValuePairs = urlInfo.query.split('&'); if (keyValuePairs.length === 1){ var keyValuePair = keyValuePairs[0].split('='); if (keyValuePair[0] === 'openid' && keyValuePair[1].startsWith(protocolHandlerSig)){ var payload = decodeURIComponent(keyValuePair[1].substring(protocolHandlerSig.length)); keyValuePairs = payload.split('&'); } } for (var count=0; count < keyValuePairs.length; count++){ var keyValuePair = keyValuePairs[count].split('='); var value = keyValuePair[1].replace(/\+/, ' '); query[decodeURIComponent(keyValuePair[0])] = decodeURIComponent(value); } } } return query; }, set: function(value){ query = value; }, enumerable: true }); Object.defineProperty(this, "body", { get: function() { return body; }, set: function(value) { body = value; }, enumerable: true }); Object.defineProperty(this, "headers", { get: function() { return headers; }, set: function(value) { headers = value; }, enumerable: true }); } function create_claimer_error(error, errorDescription){ var errorObj = { error: error, error_description: errorDescription }; return errorObj; } function expandView(viewLocation, contentObject){ var regex = /(\{include:\'([\w|\d]+)\'\})|(\{include:\$([\w|\d]+)\})/g; viewLocation = viewLocation.toLowerCase(); var viewBase64 = res.views.viewCollection[viewLocation]; if (viewBase64 === undefined){ var error = create_claimer_error('server_error', 'Unable to render missing view: ' + viewLocation); throw error; } var viewPage = pk.base64url.decode(viewBase64); do { var myArray = regex.exec(viewPage); if (myArray === null){ break; } var found, nextPage, target; if (myArray[2] !== undefined){ target = myArray[1]; nextPage = myArray[2]; } else if (myArray[4] !== undefined){ target = myArray[3]; var nextPageAttribute = myArray[4]; nextPage = contentObject[nextPageAttribute]; if (nextPage === undefined){ throw 'View ' + viewLocation + ' references attribute ' + nextPageAttribute + ' but it is not defined in contentObject'; } } else{ break; } var path = viewLocation.substring(0, viewLocation.lastIndexOf('\\') + 1); var subPage = expandView(path + nextPage, contentObject); viewPage = viewPage.replace(target, subPage); } while (true); return viewPage; }