Socket
Socket
Sign inDemoInstall

hawk

Package Overview
Dependencies
Maintainers
1
Versions
85
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hawk - npm Package Compare versions

Comparing version 0.9.0 to 0.10.0

lib/client.js

20

example/usage.js

@@ -13,3 +13,3 @@ // Load modules

dh37fgj492je: {
id: 'dh37fgj492je', // Required by Hawk.getAuthorizationHeader
id: 'dh37fgj492je', // Required by Hawk.client.header
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',

@@ -35,6 +35,12 @@ algorithm: 'sha256',

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
res.writeHead(!err ? 200 : 401, { 'Content-Type': 'text/plain' });
res.end(!err ? 'Hello ' + credentials.user + ' ' + attributes.ext : 'Shoosh!');
var payload = (!err ? 'Hello ' + credentials.user + ' ' + artifacts.ext : 'Shoosh!');
var headers = {
'Content-Type': 'text/plain',
'Authorization': Hawk.server.header(artifacts, { payload: payload, contentType: 'text/plain' })
};
res.writeHead(!err ? 200 : 401, headers);
res.end(payload);
});

@@ -56,2 +62,3 @@ };

var header = Hawk.client.header('http://127.0.0.1:8000/resource/1?b=1&a=2', 'GET', { credentials: internals.credentials.dh37fgj492je, ext: 'and welcome!' });
var options = {

@@ -61,3 +68,3 @@ uri: 'http://127.0.0.1:8000/resource/1?b=1&a=2',

headers: {
authorization: Hawk.getAuthorizationHeader('http://127.0.0.1:8000/resource/1?b=1&a=2', 'GET', { credentials: internals.credentials.dh37fgj492je, ext: 'and welcome!' })
authorization: header.field
}

@@ -70,3 +77,4 @@ };

console.log(response.statusCode + ': ' + body);
var isValid = Hawk.client.authenticate(response, header.artifacts, { payload: body });
console.log(response.statusCode + ': ' + body + (isValid ? ' (valid)' : ' (invalid)'));
process.exit(0);

@@ -73,0 +81,0 @@ });

@@ -5,2 +5,3 @@ // Load modules

var Url = require('url');
var Utils = require('./utils');

@@ -26,4 +27,4 @@

/*
options = {
type: 'header', // 'header', 'bewit'
type: 'header' // 'header', 'bewit', 'response'
options: {
credentials: {

@@ -37,3 +38,3 @@ key: 'aoijedoaijsdlaksjdl',

port: 8080,
timestamp: 1357718381034,
ts: 1357718381034,
nonce: 'd3d345f',

@@ -44,8 +45,8 @@ hash: 'U4MKKSmiVxk37JCCrAVIjV/OhB3y+NdwoCr6RShbVkE=',

dlg: 'd8djwekds9cj' // Delegated by application id (Oz), requires options.app
};
}
*/
exports.calculateMac = function (options) {
exports.calculateMac = function (type, options) {
var normalized = exports.generateNormalizedString(options);
var normalized = exports.generateNormalizedString(type, options);

@@ -58,6 +59,6 @@ var hmac = Crypto.createHmac(options.credentials.algorithm, options.credentials.key).update(normalized);

exports.generateNormalizedString = function (options) {
exports.generateNormalizedString = function (type, options) {
var normalized = 'hawk.' + exports.headerVersion + '.' + options.type + '\n' +
options.timestamp + '\n' +
var normalized = 'hawk.' + exports.headerVersion + '.' + type + '\n' +
options.ts + '\n' +
options.nonce + '\n' +

@@ -85,7 +86,19 @@ options.method.toUpperCase() + '\n' +

exports.calculateHash = function (payload, algorithm) {
exports.calculateHash = function (payload, algorithm, contentType) {
var hash = Crypto.createHash(algorithm);
var digest = hash.update(payload).digest('base64');
return digest;
hash.update('hawk.' + exports.headerVersion + '.payload\n');
hash.update(Utils.parseContentType(contentType) + '\n');
hash.update(payload || '');
hash.update('\n');
return hash.digest('base64');
};
exports.calculateTsMac = function (ts, credentials) {
var hash = Crypto.createHash(credentials.algorithm);
hash.update('hawk.' + exports.headerVersion + '.ts\n' + ts + '\n');
return hash.digest('base64');
};

@@ -1,373 +0,11 @@

// Load modules
var Url = require('url');
var Boom = require('boom');
var Cryptiles = require('cryptiles');
var Sntp = require('sntp');
var Crypto = require('./crypto');
var Utils = require('./utils');
var Uri = require('./uri');
// Declare internals
var internals = {};
// Export sub-modules
exports.crypto = Crypto;
exports.error = exports.Error = Boom;
exports.sntp = Sntp;
exports.uri = Uri;
exports.utils = Utils;
exports.error = exports.Error = require('boom');
exports.sntp = require('sntp');
exports.server = require('./server');
exports.client = require('./client');
exports.uri = require('./uri');
exports.crypto = require('./crypto');
exports.utils = require('./utils');
// Hawk authentication
/*
* req - node's HTTP request object or an object as follows:
*
* var request = {
* method: 'GET',
* url: '/resource/4?a=1&b=2',
* host: 'example.com',
* port: 8080,
* authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="'
* };
*
* credentialsFunc - required function to lookup the set of Hawk credentials based on the provided credentials id.
* The credentials include the MAC key, MAC algorithm, and other attributes (such as username)
* needed by the application. This function is the equivalent of verifying the username and
* password in Basic authentication.
*
* var credentialsFunc = function (id, callback) {
*
* // Lookup credentials in database
* db.lookup(id, function (err, item) {
*
* if (err || !item) {
* return callback(err);
* }
*
* var credentials = {
* // Required
* key: item.key,
* algorithm: item.algorithm,
* // Application specific
* user: item.user
* };
*
* return callback(null, credentials);
* });
* };
*
* options:
*
* hostHeaderName - optional header field name, used to override the default 'Host' header when used
* behind a cache of a proxy. Apache2 changes the value of the 'Host' header while preserving
* the original (which is what the module must verify) in the 'x-forwarded-host' header field.
* Only used when passed a node Http.ServerRequest object.
*
* nonceFunc - optional nonce validation function. The function signature is function(nonce, ts, callback)
* where 'callback' must be called using the signature function(err).
*
* timestampSkewSec - optional number of seconds of permitted clock skew for incoming timestamps. Defaults to 60 seconds.
* Provides a +/- skew which means actual allowed window is double the number of seconds.
*
* localtimeOffsetMsec - optional local clock time offset express in a number of milliseconds (positive or negative).
* Defaults to 0.
*
* payload - optional payload for validation. The client calculates the hash value and includes it via the 'hash'
* header attribute. The server always ensures the value provided has been included in the request
* MAC. When this option is provided, it validates the hash value itself. Validation is done by calculating
* a hash value over the entire payload (assuming it has already be normalized to the same format and
* encoding used by the client to calculate the hash on request). If the payload is not available at the time
* of authentication, the validatePayload() method can be used by passing it the credentials and
* attributes.hash returned in the authenticate callback.
*/
exports.authenticate = function (req, credentialsFunc, options, callback) {
// Default options
options.nonceFunc = options.nonceFunc || function (nonce, ts, callback) { return callback(); }; // No validation
options.timestampSkewSec = options.timestampSkewSec || 60; // 60 seconds
// Application time
var now = Utils.now() + (options.localtimeOffsetMsec || 0);
// Convert node Http request object to a request configuration object
var request = Utils.parseRequest(req, options);
if (request instanceof Error) {
return callback(Boom.badRequest(request.message));
}
// Parse HTTP Authorization header
if (!request.authorization) {
return callback(Boom.unauthorized(null, 'Hawk', { ts: now }));
}
var headerParts = request.authorization.match(/^(\w+)(?:\s+(.*))?$/); // Header: scheme[ something]
if (!headerParts) {
return callback(Boom.badRequest('Invalid header syntax'));
}
var scheme = headerParts[1];
if (scheme.toLowerCase() !== 'hawk') {
return callback(Boom.unauthorized(null, 'Hawk', { ts: now }));
}
var attributesString = headerParts[2];
if (!attributesString) {
return callback(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 (['id', 'ts', 'nonce', 'hash', 'ext', 'mac', 'app', 'dlg'].indexOf($1) === -1) {
errorMessage = 'Unknown attribute: ' + $1;
return;
}
// Allowed attribute value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9
if ($2.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~]+$/) === 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 callback(Boom.badRequest(errorMessage || 'Bad header format'));
}
// Verify required header attributes
if (!attributes.id ||
!attributes.ts ||
!attributes.nonce ||
!attributes.mac) {
return callback(Boom.badRequest('Missing attributes'), null, attributes);
}
// Check timestamp staleness
if (Math.abs((attributes.ts * 1000) - now) > (options.timestampSkewSec * 1000)) {
return callback(Boom.unauthorized('Stale timestamp', 'Hawk', { ts: now }), null, attributes);
}
// Fetch Hawk credentials
credentialsFunc(attributes.id, function (err, credentials) {
if (err) {
return callback(err, credentials || null, attributes);
}
if (!credentials) {
return callback(Boom.unauthorized('Unknown credentials', 'Hawk'), null, attributes);
}
if (!credentials.key ||
!credentials.algorithm) {
return callback(Boom.internal('Invalid credentials'), credentials, attributes);
}
if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
return callback(Boom.internal('Unknown algorithm'), credentials, attributes);
}
// Calculate MAC
var mac = Crypto.calculateMac({
type: 'header',
credentials: credentials,
timestamp: attributes.ts,
nonce: attributes.nonce,
method: request.method,
resource: request.url,/////////////////////////////////////////////////
host: request.host,
port: request.port,
hash: attributes.hash,
ext: attributes.ext,
app: attributes.app,
dlg: attributes.dlg
});
if (!Cryptiles.fixedTimeComparison(mac, attributes.mac)) {
return callback(Boom.unauthorized('Bad mac', 'Hawk'), credentials, attributes);
}
// Check payload hash
if (options.payload !== null &&
options.payload !== undefined) { // '' is valid
if (!attributes.hash) {
return callback(Boom.unauthorized('Missing required payload hash', 'Hawk'), credentials, attributes);
}
var hash = Crypto.calculateHash(options.payload, credentials.algorithm);
if (!Cryptiles.fixedTimeComparison(hash, attributes.hash)) {
return callback(Boom.unauthorized('Bad payload hash', 'Hawk'), credentials, attributes);
}
}
// Check nonce
options.nonceFunc(attributes.nonce, attributes.ts, function (err) {
if (err) {
return callback(Boom.unauthorized('Invalid nonce', 'Hawk'), credentials, attributes);
}
// Successful authentication
return callback(null, credentials, attributes);
});
});
};
// 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
none: '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
app: '24s23423f34dx', // Oz application id
dlg: '234sz34tww3sd' // Oz delegated-by application id
};
*/
exports.getAuthorizationHeader = function (uri, method, options) {
// Validate inputs
if (!uri ||
(typeof uri !== 'string' && typeof uri !== 'object') ||
!method ||
typeof method !== 'string' ||
!options ||
typeof options !== 'object') {
return '';
}
// Application time
var timestamp = options.timestamp || Math.floor((Utils.now() + (options.localtimeOffsetMsec || 0)) / 1000)
// Validate credentials
var credentials = options.credentials;
if (!credentials ||
!credentials.id ||
!credentials.key ||
!credentials.algorithm) {
// Invalid credential object
return '';
}
if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
return '';
}
// Calculate payload hash
var hash = null;
if (options.payload !== null &&
options.payload !== undefined) {
hash = Crypto.calculateHash(options.payload, credentials.algorithm);
}
// Parse URI
if (typeof uri === 'string') {
uri = Url.parse(uri);
}
// Calculate signature
var artifacts = {
type: 'header',
credentials: credentials,
timestamp: 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: hash,
ext: options.ext,
app: options.app,
dlg: options.dlg
};
var mac = Crypto.calculateMac(artifacts);
// Construct header
var hasExt = options.ext !== null && options.ext !== undefined && options.ext !== ''; // Other falsey values allowed
var header = 'Hawk id="' + credentials.id +
'", ts="' + artifacts.timestamp +
'", nonce="' + artifacts.nonce +
(hash ? '", hash="' + hash : '') +
(hasExt ? '", ext="' + Utils.escapeHeaderAttribute(options.ext) : '') +
'", mac="' + mac + '"';
if (options.app) {
header += ', app="' + options.app +
(options.dlg ? '", dlg="' + options.dlg : '') + '"';
}
return header;
};
// Validate payload hash
exports.validatePayload = function (payload, credentials, hash) {
var calculatedHash = Crypto.calculateHash(payload, credentials.algorithm);
return Cryptiles.fixedTimeComparison(calculatedHash, hash);
};

@@ -130,6 +130,5 @@ // Load modules

var mac = Crypto.calculateMac({
type: 'bewit',
var mac = Crypto.calculateMac('bewit', {
credentials: credentials,
timestamp: bewit.exp,
ts: bewit.exp,
nonce: '',

@@ -223,6 +222,5 @@ method: 'GET',

var exp = Math.floor(now / 1000) + options.ttlSec;
var mac = Crypto.calculateMac({
type: 'bewit',
var mac = Crypto.calculateMac('bewit', {
credentials: credentials,
timestamp: exp,
ts: exp,
nonce: '',

@@ -229,0 +227,0 @@ method: 'GET',

@@ -5,2 +5,3 @@ // Load modules

var Sntp = require('sntp');
var Boom = require('boom');

@@ -62,2 +63,14 @@

// 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

@@ -78,3 +91,3 @@

var req = {
var request = {
method: req.method,

@@ -84,6 +97,7 @@ url: req.url,

port: host.port,
authorization: req.headers.authorization
authorization: req.headers.authorization,
contentType: req.headers['content-type'] || ''
};
return req;
return request;
};

@@ -97,1 +111,62 @@

// 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');
}
var headerParts = header.match(/^(\w+)(?:\s+(.*))?$/); // Header: scheme[ something]
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: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9
if ($2.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~]+$/) === 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;
};
{
"name": "hawk",
"description": "HTTP Hawk Authentication Scheme",
"version": "0.9.0",
"version": "0.10.0",
"author": "Eran Hammer <eran@hueniverse.com> (http://hueniverse.com)",

@@ -6,0 +6,0 @@ "contributors": [],

@@ -6,4 +6,6 @@ ![hawk Logo](https://raw.github.com/hueniverse/hawk/master/images/hawk.png)

Current version: **0.9.0**
Current version: **0.10.0**
Last protocol change: **0.10.0** (changed payload hash method)
[![Build Status](https://secure.travis-ci.org/hueniverse/hawk.png)](http://travis-ci.org/hueniverse/hawk)

@@ -120,9 +122,25 @@

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
// Authenticate incoming request
res.writeHead(!err ? 200 : 401, { 'Content-Type': 'text/plain' });
res.end(!err ? 'Hello ' + credentials.user : 'Shoosh!');
Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
// Prepare response
var payload = (!err ? 'Hello ' + credentials.user + ' ' + artifacts.ext : 'Shoosh!');
var headers = { 'Content-Type': 'text/plain' };
// Generate Authorization response header
var header = Hawk.server.header(artifacts, { payload: payload, contentType: headers['Content-Type'] });
headers.Authorization = header;
// Send the response back
res.writeHead(!err ? 200 : 401, headers);
res.end(payload);
});
};
// Start server
Http.createServer(handler).listen(8000, 'example.com');

@@ -146,15 +164,26 @@ ```

// Send authenticated request
// Request options
var options = {
var requestOptions = {
uri: 'http://example.com:8000/resource/1?b=1&a=2',
method: 'GET',
headers: {
authorization: Hawk.getAuthorizationHeader('http://example.com:8000/resource/1?b=1&a=2', 'GET', { credentials: credentials, ext: 'some-app-data' })
}
headers: {}
};
Request(options, function (error, response, body) {
// Generate Authorization request header
console.log(response.statusCode + ': ' + body);
var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', { credentials: credentials, ext: 'some-app-data' });
requestOptions.headers.Authorization = header.field;
// Send authenticated request
Request(requestOptions, function (error, response, body) {
// Authenticate the server's response
var isValid = Hawk.client.authenticate(response, header.artifacts, { payload: body });
// Output results
console.log(response.statusCode + ': ' + body + (isValid ? ' (valid)' : ' (invalid)'));
});

@@ -240,8 +269,28 @@ ```

**Hawk** provides optional payload validation. When generating the authentication header, the client calculates a payload hash
using the specified hash algorithm. The hash is calculated over the request payload prior to any content encoding (the exact
representation requirements should be specified by the server for payloads other than simple single-part ascii to ensure interoperability):
using the specified hash algorithm. The hash is calculated over the concatenated value of:
* `hawk.1.payload`
* the content-type in lowercase, without any parameters (e.g. `application/json`)
* the request payload prior to any content encoding (the exact representation requirements should be specified by the server for payloads other than simple single-part ascii to ensure interoperability)
Payload: `Thank you for flying Hawk`
Hash (sha256): `CBbyqZ/H0rd6nKdg3O9FS5uiQZ5NmgcXUPLut9heuyo=`
For example:
* Payload: `Thank you for flying Hawk`
* Content Type: `text/plain`
* Hash (sha256): `Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=`
Results in the following input to the payload hash function (newline separated values):
```
hawk.1.payload
text/plain
Thank you for flying Hawk
```
Which produces the following hash value:
```
Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=
```
The client constructs the normalized request string (newline separated values):

@@ -257,3 +306,3 @@

8000
CBbyqZ/H0rd6nKdg3O9FS5uiQZ5NmgcXUPLut9heuyo=
Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=
some-app-ext-data

@@ -269,3 +318,3 @@

Host: example.com:8000
Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", hash="CBbyqZ/H0rd6nKdg3O9FS5uiQZ5NmgcXUPLut9heuyo=", ext="some-app-ext-data", mac="D0pHf7mKEh55AxFZ+qyiJ/fVE8uL0YgkoJjOMcOhVQU="
Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", hash="Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=", ext="some-app-ext-data", mac="aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw="
```

@@ -477,3 +526,3 @@

[.NET](https://github.com/pcibraro/hawknet), and [JAVA](https://github.com/wealdtech/hawk) libraries available. The full list
is maintained [here](https://github.com/hueniverse/hawk/issues?labels=port). Please add an issue is you are working on another
is maintained [here](https://github.com/hueniverse/hawk/issues?labels=port). Please add an issue if you are working on another
port. A cross-platform test-suite is in the works.

@@ -480,0 +529,0 @@

@@ -25,4 +25,3 @@ // Load modules

expect(Hawk.crypto.generateNormalizedString({
type: 'header',
expect(Hawk.crypto.generateNormalizedString('header', {
credentials: {

@@ -32,3 +31,3 @@ key: 'dasdfasdf',

},
timestamp: 1357747017,
ts: 1357747017,
nonce: 'k3k4j5',

@@ -46,4 +45,3 @@ method: 'GET',

expect(Hawk.crypto.generateNormalizedString({
type: 'header',
expect(Hawk.crypto.generateNormalizedString('header', {
credentials: {

@@ -53,3 +51,3 @@ key: 'dasdfasdf',

},
timestamp: 1357747017,
ts: 1357747017,
nonce: 'k3k4j5',

@@ -68,4 +66,3 @@ method: 'GET',

expect(Hawk.crypto.generateNormalizedString({
type: 'header',
expect(Hawk.crypto.generateNormalizedString('header', {
credentials: {

@@ -75,3 +72,3 @@ key: 'dasdfasdf',

},
timestamp: 1357747017,
ts: 1357747017,
nonce: 'k3k4j5',

@@ -78,0 +75,0 @@ method: 'GET',

@@ -43,10 +43,10 @@ // Load modules

req.authorization = Hawk.getAuthorizationHeader(Url.parse('http://example.com:8080/resource/4?filter=a'), req.method, { credentials: credentials, ext: 'some-app-data' });
req.authorization = Hawk.client.header(Url.parse('http://example.com:8080/resource/4?filter=a'), req.method, { credentials: credentials, ext: 'some-app-data' }).field;
expect(req.authorization).to.exist;
Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
expect(err).to.not.exist;
expect(credentials.user).to.equal('steve');
expect(attributes.ext).to.equal('some-app-data');
expect(artifacts.ext).to.equal('some-app-data');
done();

@@ -60,17 +60,34 @@ });

var req = {
method: 'GET',
method: 'POST',
url: '/resource/4?filter=a',
headers: {
host: 'example.com:8080'
host: 'example.com:8080',
'content-type': 'text/plain;x=y'
}
};
var payload = 'some not so random text';
credentialsFunc('123456', function (err, credentials) {
req.headers.authorization = Hawk.getAuthorizationHeader('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' });
Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
var reqHeader = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] });
req.headers.authorization = reqHeader.field;
Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
expect(err).to.not.exist;
expect(credentials.user).to.equal('steve');
expect(attributes.ext).to.equal('some-app-data');
expect(artifacts.ext).to.equal('some-app-data');
expect(Hawk.server.authenticatePayload(payload, credentials, artifacts.hash, req.headers['content-type'])).to.equal(true);
var res = {
headers: {
'content-type': 'text/plain'
}
};
res.headers.authorization = Hawk.server.header(artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' });
expect(res.headers.authorization).to.exist;
expect(Hawk.client.authenticate(res, artifacts, { payload: 'some reply' })).to.equal(true);
done();

@@ -92,8 +109,8 @@ });

req.authorization = Hawk.getAuthorizationHeader('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' });
Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
expect(err).to.not.exist;
expect(credentials.user).to.equal('steve');
expect(attributes.ext).to.equal('some-app-data');
expect(artifacts.ext).to.equal('some-app-data');
done();

@@ -115,10 +132,10 @@ });

req.authorization = Hawk.getAuthorizationHeader('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' });
Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
expect(err).to.not.exist;
expect(credentials.user).to.equal('steve');
expect(attributes.ext).to.equal('some-app-data');
expect(Hawk.validatePayload('hola!', credentials, attributes.hash)).to.be.true;
expect(Hawk.validatePayload('hello!', credentials, attributes.hash)).to.be.false;
expect(artifacts.ext).to.equal('some-app-data');
expect(Hawk.server.authenticatePayload('hola!', credentials, artifacts.hash)).to.be.true;
expect(Hawk.server.authenticatePayload('hello!', credentials, artifacts.hash)).to.be.false;
done();

@@ -140,10 +157,10 @@ });

req.authorization = Hawk.getAuthorizationHeader('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased', dlg: '23434szr3q4d' });
Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased', dlg: '23434szr3q4d' }).field;
Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
expect(err).to.not.exist;
expect(credentials.user).to.equal('steve');
expect(attributes.ext).to.equal('some-app-data');
expect(attributes.app).to.equal('asd23ased');
expect(attributes.dlg).to.equal('23434szr3q4d');
expect(artifacts.ext).to.equal('some-app-data');
expect(artifacts.app).to.equal('asd23ased');
expect(artifacts.dlg).to.equal('23434szr3q4d');
done();

@@ -165,4 +182,4 @@ });

req.authorization = Hawk.getAuthorizationHeader('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' });
Hawk.authenticate(req, credentialsFunc, { payload: 'byebye!' }, function (err, credentials, attributes) {
req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field;
Hawk.server.authenticate(req, credentialsFunc, { payload: 'byebye!' }, function (err, credentials, artifacts) {

@@ -187,6 +204,6 @@ expect(err).to.exist;

req.authorization = Hawk.getAuthorizationHeader('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' });
req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field;
req.url = '/something/else';
Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {

@@ -199,626 +216,2 @@ expect(err).to.exist;

});
describe('#authenticate', function () {
it('should parse a valid authentication header (sha1)', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="1", ts="1353788437", nonce="k3j4h2", mac="zy79QQ5/EYFmQqutVnYb73gAc/U=", ext="hello"',
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.not.exist;
expect(credentials.user).to.equal('steve');
done();
});
});
it('should parse a valid authentication header (sha256)', function (done) {
var req = {
method: 'GET',
url: '/resource/1?b=1&a=2',
host: 'example.com',
port: 8000,
authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", mac="m8r1rHbXN6NgO+KIIhjO7sFRyd78RNGVUwehe8Cp2dU=", ext="some-app-data"',
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353832234000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.not.exist;
expect(credentials.user).to.equal('steve');
done();
});
});
it('should parse a valid authentication header (POST with payload)', function (done) {
var req = {
method: 'POST',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123456", ts="1357926341", nonce="1AwuJD", hash="qAiXIVv+yjDATneWxZP2YCTa9aHRgQdnH9b3Wc+o3dg=", ext="some-app-data", mac="UeYcj5UoTVaAWXNvJfLVia7kU3VabxCqrccXP8sUGC4="',
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1357926341000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.not.exist;
expect(credentials.user).to.equal('steve');
done();
});
});
it('should fail on missing hash', function (done) {
var req = {
method: 'GET',
url: '/resource/1?b=1&a=2',
host: 'example.com',
port: 8000,
authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", mac="m8r1rHbXN6NgO+KIIhjO7sFRyd78RNGVUwehe8Cp2dU=", ext="some-app-data"',
};
Hawk.authenticate(req, credentialsFunc, { payload: 'body', localtimeOffsetMsec: 1353832234000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Missing required payload hash');
done();
});
});
it('should fail on a stale timestamp', function (done) {
var req = {
method: 'GET',
url: '/resource/1?b=1&a=2',
host: 'example.com',
port: 8000,
authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", mac="m8r1rHbXN6NgO+KIIhjO7sFRyd78RNGVUwehe8Cp2dU=", ext="some-app-data"',
};
Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Stale timestamp');
var header = err.response.headers['WWW-Authenticate'];
var ts = header.match(/^Hawk ts\=\"(\d+)\"\, error=\"Stale timestamp\"$/);
var now = Hawk.utils.now();
expect(parseInt(ts[1], 10)).to.be.within(now - 1, now + 1);
done();
});
});
it('should fail on a replay', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="bXx7a7p1h9QYQNZ8x7QhvDQym8ACgab4m3lVSFn4DBw=", ext="hello"',
};
var memoryCache = {};
var options = {
localtimeOffsetMsec: 1353788437000 - Hawk.utils.now(),
nonceFunc: function (nonce, ts, callback) {
if (memoryCache[nonce]) {
return callback(new Error());
}
memoryCache[nonce] = true;
return callback();
}
};
Hawk.authenticate(req, credentialsFunc, options, function (err, credentials, attributes) {
expect(err).to.not.exist;
expect(credentials.user).to.equal('steve');
Hawk.authenticate(req, credentialsFunc, options, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Invalid nonce');
done();
});
});
});
it('should fail on an invalid authentication header: wrong scheme', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Basic asdasdasdasd'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.not.exist;
done();
});
});
it('should fail on an invalid authentication header: no scheme', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: '!@#'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Invalid header syntax');
done();
});
});
it('should fail on an missing authorization header', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080
};
Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.isMissing).to.equal(true);
var header = err.response.headers['WWW-Authenticate'];
var ts = header.match(/^Hawk ts\=\"(\d+)\"$/);
var now = Hawk.utils.now();
expect(parseInt(ts[1], 10)).to.be.within(now - 1, now + 1);
done();
});
});
it('should fail on an missing host header', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
headers: {
authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
}
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Invalid Host header');
done();
});
});
it('should fail on an missing authorization attribute (id)', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Missing attributes');
done();
});
});
it('should fail on an missing authorization attribute (ts)', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Missing attributes');
done();
});
});
it('should fail on an missing authorization attribute (nonce)', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Missing attributes');
done();
});
});
it('should fail on an missing authorization attribute (mac)', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", ext="hello"'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Missing attributes');
done();
});
});
it('should fail on an unknown authorization attribute', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", x="3", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Unknown attribute: x');
done();
});
});
it('should fail on an bad authorization header format', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123\\", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Bad header format');
done();
});
});
it('should fail on an bad authorization attribute value', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="\t", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Bad attribute value: id');
done();
});
});
it('should fail on an empty authorization attribute value', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Bad attribute value: id');
done();
});
});
it('should fail on duplicated authorization attribute key', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123", id="456", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Duplicate attribute: id');
done();
});
});
it('should fail on an invalid authorization header format', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Invalid header syntax');
done();
});
});
it('should fail on an bad host header (missing host)', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
headers: {
host: ':8080',
authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
}
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Invalid Host header');
done();
});
});
it('should fail on an bad host header (pad port)', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
headers: {
host: 'example.com:something',
authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
}
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Invalid Host header');
done();
});
});
it('should fail on credentialsFunc error', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
var credentialsFunc = function (id, callback) {
return callback(new Error('Unknown user'));
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.message).to.equal('Unknown user');
done();
});
});
it('should fail on missing credentials', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
var credentialsFunc = function (id, callback) {
return callback(null, null);
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Unknown credentials');
done();
});
});
it('should fail on invalid credentials', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
var credentialsFunc = function (id, callback) {
var credentials = {
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
user: 'steve'
};
return callback(null, credentials);
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.message).to.equal('Invalid credentials');
expect(err.response.payload.message).to.equal('An internal server error occurred');
done();
});
});
it('should fail on unknown credentials algorithm', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
var credentialsFunc = function (id, callback) {
var credentials = {
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
algorithm: 'hmac-sha-0',
user: 'steve'
};
return callback(null, credentials);
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.message).to.equal('Unknown algorithm');
expect(err.response.payload.message).to.equal('An internal server error occurred');
done();
});
});
it('should fail on unknown bad mac', function (done) {
var req = {
method: 'GET',
url: '/resource/4?filter=a',
host: 'example.com',
port: 8080,
authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcU4jlr7T/wuKe3dKijvTvSos=", ext="hello"'
};
var credentialsFunc = function (id, callback) {
var credentials = {
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
algorithm: 'sha256',
user: 'steve'
};
return callback(null, credentials);
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, attributes) {
expect(err).to.exist;
expect(err.response.payload.message).to.equal('Bad mac');
done();
});
});
});
describe('#getAuthorizationHeader', function () {
it('should return a valid authorization header (sha1)', function (done) {
var credentials = {
id: '123456',
key: '2983d45yun89q',
algorithm: 'sha1'
};
var header = Hawk.getAuthorizationHeader('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about' });
expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="eQJ6qAuxoMrLdTMb5IJiv04W4F4=", ext="Bazinga!", mac="Ti2SMCBfDGp4DLoOw2OpFjOs+nI="');
done();
});
it('should return a valid authorization header (sha256)', function (done) {
var credentials = {
id: '123456',
key: '2983d45yun89q',
algorithm: 'sha256'
};
var header = Hawk.getAuthorizationHeader('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about' });
expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="Yz+K6hTiKD4IVEckK1yPIBdb/gh4LdtWwpXvM776Edg=", ext="Bazinga!", mac="Uk1EHe77nOiAo4Hgm8Qio21+MtU7jEcVSIaqw21Yy48="');
done();
});
it('should return an empty authorization header on missing options', function (done) {
var header = Hawk.getAuthorizationHeader('https://example.net/somewhere/over/the/rainbow', 'POST');
expect(header).to.equal('');
done();
});
it('should return an empty authorization header on invalid credentials', function (done) {
var credentials = {
key: '2983d45yun89q',
algorithm: 'sha256'
};
var header = Hawk.getAuthorizationHeader('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207 });
expect(header).to.equal('');
done();
});
it('should return an empty authorization header on invalid algorithm', function (done) {
var credentials = {
id: '123456',
key: '2983d45yun89q',
algorithm: 'hmac-sha-0'
};
var header = Hawk.getAuthorizationHeader('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, payload: 'something, anything!', ext: 'Bazinga!', timestamp: 1353809207 });
expect(header).to.equal('');
done();
});
});
});

@@ -39,3 +39,3 @@ // Load modules

var header = Hawk.getAuthorizationHeader('http://example.com:8000/resource/1?b=1&a=2', 'GET', options);
var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', options).field;

@@ -48,6 +48,5 @@ expect(header).to.equal('Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="');

var normalized = Hawk.crypto.generateNormalizedString({
type: 'header',
var normalized = Hawk.crypto.generateNormalizedString('header', {
credentials: credentials,
timestamp: options.timestamp,
ts: options.timestamp,
nonce: options.nonce,

@@ -67,8 +66,9 @@ method: 'GET',

payloadOptions.payload = 'Thank you for flying Hawk';
payloadOptions.contentType = 'text/plain';
it('should generate a header protocol example (with payload)', function (done) {
var header = Hawk.getAuthorizationHeader('http://example.com:8000/resource/1?b=1&a=2', 'POST', payloadOptions);
var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'POST', payloadOptions).field;
expect(header).to.equal('Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", hash="CBbyqZ/H0rd6nKdg3O9FS5uiQZ5NmgcXUPLut9heuyo=", ext="some-app-ext-data", mac="D0pHf7mKEh55AxFZ+qyiJ/fVE8uL0YgkoJjOMcOhVQU="');
expect(header).to.equal('Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", hash="Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=", ext="some-app-ext-data", mac="aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw="');
done();

@@ -79,6 +79,5 @@ });

var normalized = Hawk.crypto.generateNormalizedString({
type: 'header',
var normalized = Hawk.crypto.generateNormalizedString('header', {
credentials: credentials,
timestamp: options.timestamp,
ts: options.timestamp,
nonce: options.nonce,

@@ -89,7 +88,7 @@ method: 'POST',

port: 8000,
hash: Hawk.crypto.calculateHash(payloadOptions.payload, credentials.algorithm),
hash: Hawk.crypto.calculateHash(payloadOptions.payload, credentials.algorithm, payloadOptions.contentType),
ext: options.ext
});
expect(normalized).to.equal('hawk.1.header\n1353832234\nj4h3g2\nPOST\n/resource?a=1&b=2\nexample.com\n8000\nCBbyqZ/H0rd6nKdg3O9FS5uiQZ5NmgcXUPLut9heuyo=\nsome-app-ext-data\n');
expect(normalized).to.equal('hawk.1.header\n1353832234\nj4h3g2\nPOST\n/resource?a=1&b=2\nexample.com\n8000\nYi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\nsome-app-ext-data\n');
done();

@@ -96,0 +95,0 @@ });

@@ -143,4 +143,3 @@ // Load modules

var ext = 'some-app-data';
var mac = Hawk.crypto.calculateMac({
type: 'bewit',
var mac = Hawk.crypto.calculateMac('bewit', {
credentials: credentials,

@@ -147,0 +146,0 @@ timestamp: exp,

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc