UNPKG

dynatrace-cordova-outsystems-plugin

Version:

This plugin gives you the ability to use the Dynatrace instrumentation in your hybrid application (Cordova, Ionic, ..). It uses the Mobile Agent, the JavaScript Agent and the Javascript Bridge. The Mobile Agent will give you all device specific values con

185 lines (121 loc) 4.55 kB
// Load modules var Sntp = require('sntp'); var Boom = require('boom'); // Declare internals var internals = {}; exports.version = function () { return require('../package.json').version; }; exports.limits = { maxMatchLength: 4096 // Limit the length of uris and headers to avoid a DoS attack on string matching }; // Extract host and port from request // $1 $2 internals.hostHeaderRegex = /^(?:(?:\r\n)?\s)*((?:[^:]+)|(?:\[[^\]]+\]))(?::(\d+))?(?:(?:\r\n)?\s)*$/; // (IPv4, hostname)|(IPv6) exports.parseHost = function (req, hostHeaderName) { hostHeaderName = (hostHeaderName ? hostHeaderName.toLowerCase() : 'host'); var hostHeader = req.headers[hostHeaderName]; if (!hostHeader) { return null; } if (hostHeader.length > exports.limits.maxMatchLength) { return null; } var hostParts = hostHeader.match(internals.hostHeaderRegex); if (!hostParts) { return null; } return { name: hostParts[1], port: (hostParts[2] ? hostParts[2] : (req.connection && req.connection.encrypted ? 443 : 80)) }; }; // Parse Content-Type header content exports.parseContentType = function (header) { if (!header) { return ''; } return header.split(';')[0].trim().toLowerCase(); }; // Convert node's to request configuration object exports.parseRequest = function (req, options) { if (!req.headers) { return req; } // Obtain host and port information var host; if (!options.host || !options.port) { host = exports.parseHost(req, options.hostHeaderName); if (!host) { return new Error('Invalid Host header'); } } var request = { method: req.method, url: req.url, host: options.host || host.name, port: options.port || host.port, authorization: req.headers.authorization, contentType: req.headers['content-type'] || '' }; return request; }; exports.now = function (localtimeOffsetMsec) { return Sntp.now() + (localtimeOffsetMsec || 0); }; exports.nowSecs = function (localtimeOffsetMsec) { return Math.floor(exports.now(localtimeOffsetMsec) / 1000); }; internals.authHeaderRegex = /^(\w+)(?:\s+(.*))?$/; // Header: scheme[ something] internals.attributeRegex = /^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~]+$/; // !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9 // Parse Hawk HTTP Authorization header exports.parseAuthorizationHeader = function (header, keys) { keys = keys || ['id', 'ts', 'nonce', 'hash', 'ext', 'mac', 'app', 'dlg']; if (!header) { return Boom.unauthorized(null, 'Hawk'); } if (header.length > exports.limits.maxMatchLength) { return Boom.badRequest('Header length too long'); } var headerParts = header.match(internals.authHeaderRegex); if (!headerParts) { return Boom.badRequest('Invalid header syntax'); } var scheme = headerParts[1]; if (scheme.toLowerCase() !== 'hawk') { return Boom.unauthorized(null, 'Hawk'); } var attributesString = headerParts[2]; if (!attributesString) { return Boom.badRequest('Invalid header syntax'); } var attributes = {}; var errorMessage = ''; var verify = attributesString.replace(/(\w+)="([^"\\]*)"\s*(?:,\s*|$)/g, function ($0, $1, $2) { // Check valid attribute names if (keys.indexOf($1) === -1) { errorMessage = 'Unknown attribute: ' + $1; return; } // Allowed attribute value characters if ($2.match(internals.attributeRegex) === null) { errorMessage = 'Bad attribute value: ' + $1; return; } // Check for duplicates if (attributes.hasOwnProperty($1)) { errorMessage = 'Duplicate attribute: ' + $1; return; } attributes[$1] = $2; return ''; }); if (verify !== '') { return Boom.badRequest(errorMessage || 'Bad header format'); } return attributes; }; exports.unauthorized = function (message, attributes) { return Boom.unauthorized(message, 'Hawk', attributes); };