You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					370 lines
				
				10 KiB
			
		
		
			
		
	
	
					370 lines
				
				10 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								// Load modules
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var Url = require('url');
							 | 
						||
| 
								 | 
							
								var Hoek = require('hoek');
							 | 
						||
| 
								 | 
							
								var Cryptiles = require('cryptiles');
							 | 
						||
| 
								 | 
							
								var Crypto = require('./crypto');
							 | 
						||
| 
								 | 
							
								var Utils = require('./utils');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Declare internals
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var internals = {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Generate an Authorization header for a given request
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								    uri: 'http://example.com/resource?a=b' or object from Url.parse()
							 | 
						||
| 
								 | 
							
								    method: HTTP verb (e.g. 'GET', 'POST')
							 | 
						||
| 
								 | 
							
								    options: {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Required
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        credentials: {
							 | 
						||
| 
								 | 
							
								            id: 'dh37fgj492je',
							 | 
						||
| 
								 | 
							
								            key: 'aoijedoaijsdlaksjdl',
							 | 
						||
| 
								 | 
							
								            algorithm: 'sha256'                                 // 'sha1', 'sha256'
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Optional
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ext: 'application-specific',                        // Application specific data sent via the ext attribute
							 | 
						||
| 
								 | 
							
								        timestamp: Date.now(),                              // A pre-calculated timestamp
							 | 
						||
| 
								 | 
							
								        nonce: '2334f34f',                                  // A pre-generated nonce
							 | 
						||
| 
								 | 
							
								        localtimeOffsetMsec: 400,                           // Time offset to sync with server time (ignored if timestamp provided)
							 | 
						||
| 
								 | 
							
								        payload: '{"some":"payload"}',                      // UTF-8 encoded string for body hash generation (ignored if hash provided)
							 | 
						||
| 
								 | 
							
								        contentType: 'application/json',                    // Payload content-type (ignored if hash provided)
							 | 
						||
| 
								 | 
							
								        hash: 'U4MKKSmiVxk37JCCrAVIjV=',                    // Pre-calculated payload hash
							 | 
						||
| 
								 | 
							
								        app: '24s23423f34dx',                               // Oz application id
							 | 
						||
| 
								 | 
							
								        dlg: '234sz34tww3sd'                                // Oz delegated-by application id
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								exports.header = function (uri, method, options) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var result = {
							 | 
						||
| 
								 | 
							
								        field: '',
							 | 
						||
| 
								 | 
							
								        artifacts: {}
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Validate inputs
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!uri || (typeof uri !== 'string' && typeof uri !== 'object') ||
							 | 
						||
| 
								 | 
							
								        !method || typeof method !== 'string' ||
							 | 
						||
| 
								 | 
							
								        !options || typeof options !== 'object') {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        result.err = 'Invalid argument type';
							 | 
						||
| 
								 | 
							
								        return result;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Application time
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var timestamp = options.timestamp || Utils.nowSecs(options.localtimeOffsetMsec);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Validate credentials
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var credentials = options.credentials;
							 | 
						||
| 
								 | 
							
								    if (!credentials ||
							 | 
						||
| 
								 | 
							
								        !credentials.id ||
							 | 
						||
| 
								 | 
							
								        !credentials.key ||
							 | 
						||
| 
								 | 
							
								        !credentials.algorithm) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        result.err = 'Invalid credential object';
							 | 
						||
| 
								 | 
							
								        return result;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
							 | 
						||
| 
								 | 
							
								        result.err = 'Unknown algorithm';
							 | 
						||
| 
								 | 
							
								        return result;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Parse URI
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (typeof uri === 'string') {
							 | 
						||
| 
								 | 
							
								        uri = Url.parse(uri);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Calculate signature
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var artifacts = {
							 | 
						||
| 
								 | 
							
								        ts: timestamp,
							 | 
						||
| 
								 | 
							
								        nonce: options.nonce || Cryptiles.randomString(6),
							 | 
						||
| 
								 | 
							
								        method: method,
							 | 
						||
| 
								 | 
							
								        resource: uri.pathname + (uri.search || ''),                            // Maintain trailing '?'
							 | 
						||
| 
								 | 
							
								        host: uri.hostname,
							 | 
						||
| 
								 | 
							
								        port: uri.port || (uri.protocol === 'http:' ? 80 : 443),
							 | 
						||
| 
								 | 
							
								        hash: options.hash,
							 | 
						||
| 
								 | 
							
								        ext: options.ext,
							 | 
						||
| 
								 | 
							
								        app: options.app,
							 | 
						||
| 
								 | 
							
								        dlg: options.dlg
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    result.artifacts = artifacts;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Calculate payload hash
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!artifacts.hash &&
							 | 
						||
| 
								 | 
							
								        (options.payload || options.payload === '')) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        artifacts.hash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var mac = Crypto.calculateMac('header', credentials, artifacts);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Construct header
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== '';       // Other falsey values allowed
							 | 
						||
| 
								 | 
							
								    var header = 'Hawk id="' + credentials.id +
							 | 
						||
| 
								 | 
							
								                 '", ts="' + artifacts.ts +
							 | 
						||
| 
								 | 
							
								                 '", nonce="' + artifacts.nonce +
							 | 
						||
| 
								 | 
							
								                 (artifacts.hash ? '", hash="' + artifacts.hash : '') +
							 | 
						||
| 
								 | 
							
								                 (hasExt ? '", ext="' + Hoek.escapeHeaderAttribute(artifacts.ext) : '') +
							 | 
						||
| 
								 | 
							
								                 '", mac="' + mac + '"';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (artifacts.app) {
							 | 
						||
| 
								 | 
							
								        header += ', app="' + artifacts.app +
							 | 
						||
| 
								 | 
							
								                  (artifacts.dlg ? '", dlg="' + artifacts.dlg : '') + '"';
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    result.field = header;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return result;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Validate server response
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								    res:        node's response object
							 | 
						||
| 
								 | 
							
								    artifacts:  object received from header().artifacts
							 | 
						||
| 
								 | 
							
								    options: {
							 | 
						||
| 
								 | 
							
								        payload:    optional payload received
							 | 
						||
| 
								 | 
							
								        required:   specifies if a Server-Authorization header is required. Defaults to 'false'
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								exports.authenticate = function (res, credentials, artifacts, options) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    artifacts = Hoek.clone(artifacts);
							 | 
						||
| 
								 | 
							
								    options = options || {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (res.headers['www-authenticate']) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Parse HTTP WWW-Authenticate header
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        var wwwAttributes = Utils.parseAuthorizationHeader(res.headers['www-authenticate'], ['ts', 'tsm', 'error']);
							 | 
						||
| 
								 | 
							
								        if (wwwAttributes instanceof Error) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Validate server timestamp (not used to update clock since it is done via the SNPT client)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (wwwAttributes.ts) {
							 | 
						||
| 
								 | 
							
								            var tsm = Crypto.calculateTsMac(wwwAttributes.ts, credentials);
							 | 
						||
| 
								 | 
							
								            if (tsm !== wwwAttributes.tsm) {
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Parse HTTP Server-Authorization header
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!res.headers['server-authorization'] &&
							 | 
						||
| 
								 | 
							
								        !options.required) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var attributes = Utils.parseAuthorizationHeader(res.headers['server-authorization'], ['mac', 'ext', 'hash']);
							 | 
						||
| 
								 | 
							
								    if (attributes instanceof Error) {
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    artifacts.ext = attributes.ext;
							 | 
						||
| 
								 | 
							
								    artifacts.hash = attributes.hash;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var mac = Crypto.calculateMac('response', credentials, artifacts);
							 | 
						||
| 
								 | 
							
								    if (mac !== attributes.mac) {
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!options.payload &&
							 | 
						||
| 
								 | 
							
								        options.payload !== '') {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!attributes.hash) {
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var calculatedHash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, res.headers['content-type']);
							 | 
						||
| 
								 | 
							
								    return (calculatedHash === attributes.hash);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Generate a bewit value for a given URI
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								    uri: 'http://example.com/resource?a=b' or object from Url.parse()
							 | 
						||
| 
								 | 
							
								    options: {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Required
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        credentials: {
							 | 
						||
| 
								 | 
							
								            id: 'dh37fgj492je',
							 | 
						||
| 
								 | 
							
								            key: 'aoijedoaijsdlaksjdl',
							 | 
						||
| 
								 | 
							
								            algorithm: 'sha256'                             // 'sha1', 'sha256'
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								        ttlSec: 60 * 60,                                    // TTL in seconds
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Optional
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ext: 'application-specific',                        // Application specific data sent via the ext attribute
							 | 
						||
| 
								 | 
							
								        localtimeOffsetMsec: 400                            // Time offset to sync with server time
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								exports.getBewit = function (uri, options) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Validate inputs
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!uri ||
							 | 
						||
| 
								 | 
							
								        (typeof uri !== 'string' && typeof uri !== 'object') ||
							 | 
						||
| 
								 | 
							
								        !options ||
							 | 
						||
| 
								 | 
							
								        typeof options !== 'object' ||
							 | 
						||
| 
								 | 
							
								        !options.ttlSec) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return '';
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    options.ext = (options.ext === null || options.ext === undefined ? '' : options.ext);       // Zero is valid value
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Application time
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var now = Utils.now(options.localtimeOffsetMsec);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Validate credentials
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var credentials = options.credentials;
							 | 
						||
| 
								 | 
							
								    if (!credentials ||
							 | 
						||
| 
								 | 
							
								        !credentials.id ||
							 | 
						||
| 
								 | 
							
								        !credentials.key ||
							 | 
						||
| 
								 | 
							
								        !credentials.algorithm) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return '';
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
							 | 
						||
| 
								 | 
							
								        return '';
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Parse URI
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (typeof uri === 'string') {
							 | 
						||
| 
								 | 
							
								        uri = Url.parse(uri);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Calculate signature
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var exp = Math.floor(now / 1000) + options.ttlSec;
							 | 
						||
| 
								 | 
							
								    var mac = Crypto.calculateMac('bewit', credentials, {
							 | 
						||
| 
								 | 
							
								        ts: exp,
							 | 
						||
| 
								 | 
							
								        nonce: '',
							 | 
						||
| 
								 | 
							
								        method: 'GET',
							 | 
						||
| 
								 | 
							
								        resource: uri.pathname + (uri.search || ''),                            // Maintain trailing '?'
							 | 
						||
| 
								 | 
							
								        host: uri.hostname,
							 | 
						||
| 
								 | 
							
								        port: uri.port || (uri.protocol === 'http:' ? 80 : 443),
							 | 
						||
| 
								 | 
							
								        ext: options.ext
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Construct bewit: id\exp\mac\ext
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var bewit = credentials.id + '\\' + exp + '\\' + mac + '\\' + options.ext;
							 | 
						||
| 
								 | 
							
								    return Hoek.base64urlEncode(bewit);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Generate an authorization string for a message
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								    host: 'example.com',
							 | 
						||
| 
								 | 
							
								    port: 8000,
							 | 
						||
| 
								 | 
							
								    message: '{"some":"payload"}',                          // UTF-8 encoded string for body hash generation
							 | 
						||
| 
								 | 
							
								    options: {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Required
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        credentials: {
							 | 
						||
| 
								 | 
							
								            id: 'dh37fgj492je',
							 | 
						||
| 
								 | 
							
								            key: 'aoijedoaijsdlaksjdl',
							 | 
						||
| 
								 | 
							
								            algorithm: 'sha256'                             // 'sha1', 'sha256'
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Optional
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        timestamp: Date.now(),                              // A pre-calculated timestamp
							 | 
						||
| 
								 | 
							
								        nonce: '2334f34f',                                  // A pre-generated nonce
							 | 
						||
| 
								 | 
							
								        localtimeOffsetMsec: 400,                           // Time offset to sync with server time (ignored if timestamp provided)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								exports.message = function (host, port, message, options) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Validate inputs
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!host || typeof host !== 'string' ||
							 | 
						||
| 
								 | 
							
								        !port || typeof port !== 'number' ||
							 | 
						||
| 
								 | 
							
								        message === null || message === undefined || typeof message !== 'string' ||
							 | 
						||
| 
								 | 
							
								        !options || typeof options !== 'object') {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return null;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Application time
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var timestamp = options.timestamp || Utils.nowSecs(options.localtimeOffsetMsec);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Validate credentials
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var credentials = options.credentials;
							 | 
						||
| 
								 | 
							
								    if (!credentials ||
							 | 
						||
| 
								 | 
							
								        !credentials.id ||
							 | 
						||
| 
								 | 
							
								        !credentials.key ||
							 | 
						||
| 
								 | 
							
								        !credentials.algorithm) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Invalid credential object
							 | 
						||
| 
								 | 
							
								        return null;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
							 | 
						||
| 
								 | 
							
								        return null;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Calculate signature
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var artifacts = {
							 | 
						||
| 
								 | 
							
								        ts: timestamp,
							 | 
						||
| 
								 | 
							
								        nonce: options.nonce || Cryptiles.randomString(6),
							 | 
						||
| 
								 | 
							
								        host: host,
							 | 
						||
| 
								 | 
							
								        port: port,
							 | 
						||
| 
								 | 
							
								        hash: Crypto.calculatePayloadHash(message, credentials.algorithm)
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Construct authorization
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var result = {
							 | 
						||
| 
								 | 
							
								        id: credentials.id,
							 | 
						||
| 
								 | 
							
								        ts: artifacts.ts,
							 | 
						||
| 
								 | 
							
								        nonce: artifacts.nonce,
							 | 
						||
| 
								 | 
							
								        hash: artifacts.hash,
							 | 
						||
| 
								 | 
							
								        mac: Crypto.calculateMac('message', credentials, artifacts)
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return result;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 |