| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 | // Load modulesvar Sntp = require('sntp');var Boom = require('boom');// Declare internalsvar 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                            $2internals.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 contentexports.parseContentType = function (header) {    if (!header) {        return '';    }    return header.split(';')[0].trim().toLowerCase();};// Convert node's  to request configuration objectexports.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 headerexports.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);};
 |