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.1.0 to 0.2.0

lib/utils.js

36

lib/error.js

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

var NodeUtil = require('util');
var Hoek = require('hoek');
var Utils = require('./utils');

@@ -16,4 +16,4 @@

Hoek.assert(this.constructor === internals.Error, 'Error must be instantiated using new');
Hoek.assert(code >= 400, 'Error code must be 4xx or 5xx');
Utils.assert(this.constructor === internals.Error, 'Error must be instantiated using new');
Utils.assert(code >= 400, 'Error code must be 4xx or 5xx');

@@ -60,4 +60,30 @@ Error.call(this);

return internals.Error.unauthorizedWithTs(message);
};
internals.Error.unauthorizedWithTs = function (message, now, ntp) {
var err = new internals.Error(401, message);
err.headers['WWW-Authenticate'] = 'Hawk' + (message ? ' error="' + Hoek.escapeHeaderAttribute(message) + '"' : '');
var attributes = '';
if (now) {
attributes += 'ts="' + now + '"';
}
if (ntp) {
if (attributes) {
attributes += ', ';
}
attributes += 'ntp="' + ntp + '"';
}
if (message) {
if (attributes) {
attributes += ', ';
}
attributes += 'error="' + Utils.escapeHeaderAttribute(message) + '"';
}
err.headers['WWW-Authenticate'] = 'Hawk' + (attributes ? ' ' + attributes : '');
return err;

@@ -70,3 +96,3 @@ };

var err = new internals.Error(500, message);
err.trace = Hoek.displayStack(1);
err.trace = Utils.displayStack(1);
err.data = data;

@@ -73,0 +99,0 @@

173

lib/index.js

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

var Err = require('./error');
var Utils = require('./utils');

@@ -11,7 +12,10 @@

var internals = {
randomSource: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
};
var internals = {};
// Export utilities
exports.utils = Utils;
// Hawk authentication

@@ -48,15 +52,24 @@

*
* 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.
* 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.
*
* nonceFunc - optional nonce validation function. The function signature is function(nonce, ts, callback)
* where 'callback' must be called using the signature function(err).
* nonceFunc - optional nonce validation function. The function signature is function(nonce, ts, callback)
* where 'callback' must be called using the signature function(err).
*
* timestampSkewSec - 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 - local clock time offset express in a number of milliseconds (positive or negative).
* Defaults to 0.
*
* ntp - hostname of the ntp server used to synchronize time between the client and the server. The
* ntp server name is included when the client's timestamp is stale along with the server's
* current timestamp. This allows browser-based clients to sync their application clock directly
* with the server, while native clients can be smarter about managing time sync and caching
* multiple clock offsets using the ntp server value provided. Defaults to 'pool.ntp.org'.
*/
exports.authenticate = function (req, credentialsFunc, arg1, arg2) {
exports.authenticate = function (req, credentialsFunc, options, callback) {
var callback = (arg2 ? arg2 : arg1);
var options = (arg2 ? arg1 : {});
// Default options

@@ -66,3 +79,10 @@

options.nonceFunc = options.nonceFunc || function (nonce, ts, callback) { return callback(); };
options.timestampSkewSec = options.timestampSkewSec || 60; // 60 seconds
options.localtimeOffsetMsec = options.localtimeOffsetMsec || 0; // 0 milliseconds
options.ntp = options.ntp || 'pool.ntp.org';
// Application time
var now = Date.now() + options.localtimeOffsetMsec;
// Check required HTTP headers: host, authentication

@@ -76,3 +96,3 @@

if (!req.headers.authorization) {
return callback(Err.unauthorized('Missing Authorization header'), null, null);
return callback(Err.unauthorizedWithTs('', now, options.ntp), null, null);
}

@@ -82,10 +102,50 @@

var attributes = exports.parseHeader(req.headers.authorization);
var headerParts = req.headers.authorization.match(/^(\w+)(?:\s+(.*))?$/); // Header: scheme[ something]
if (!headerParts) {
return callback(Err.badRequest('Invalid header syntax'), null, null);
}
// Verify authentication scheme
var scheme = headerParts[1];
if (scheme.toLowerCase() !== 'hawk') {
return callback(Err.unauthorizedWithTs('', now, options.ntp), null, null);
}
if (attributes instanceof Error) {
return callback(attributes, null, null);
var attributesString = headerParts[2];
if (!attributesString) {
return callback(Err.badRequest('Invalid header syntax'), null, null);
}
var attributes = {};
var errorMessage = '';
var verify = attributesString.replace(/(\w+)="([^"\\]*)"\s*(?:,\s*|$)/g, function ($0, $1, $2) {
// Check valid attribute names
if (['id', 'ts', 'nonce', 'ext', 'mac'].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(Err.badRequest(errorMessage || 'Bad header format'), null, null);
}
// Verify required header attributes

@@ -100,2 +160,8 @@

}
// Check timestamp staleness
if (Math.abs((attributes.ts * 1000) - now) > (options.timestampSkewSec * 1000)) {
return callback(Err.unauthorizedWithTs('Stale timestamp', now, options.ntp), null, attributes.ext);
}

@@ -142,3 +208,3 @@ // Obtain host and port information

var mac = exports.calculateMAC(credentials.key, credentials.algorithm, attributes.ts, attributes.nonce, req.method, req.url, host, port, attributes.ext);
if (!exports.fixedTimeComparison(mac, attributes.mac)) {
if (!Utils.fixedTimeComparison(mac, attributes.mac)) {
return callback(Err.unauthorized('Bad mac'), credentials, attributes.ext);

@@ -199,36 +265,2 @@ }

// Extract attribute from MAC header (strict)
exports.parseHeader = function (header) {
var headerRegex = /^([Hh][Aa][Ww][Kk])(?:\s+(.*))?$/;
var headerParts = header.match(headerRegex);
if (!headerParts) {
return Err.unauthorized('Incorrect scheme');
}
if (!headerParts[2]) {
return Err.badRequest('Invalid header format');
}
var attributes = {};
var attributesRegex = /(id|ts|nonce|ext|mac)="([^"\\]*)"\s*(?:,\s*|$)/g;
var verify = headerParts[2].replace(attributesRegex, function ($0, $1, $2) {
if (attributes[$1] === undefined) {
attributes[$1] = $2;
return '';
}
});
if (verify !== '') {
return Err.badRequest('Unknown attributes');
}
return attributes;
};
// Generate an Authorization header for a given request

@@ -255,3 +287,3 @@

timestamp = timestamp || Math.floor(((new Date()).getTime() / 1000));
nonce = nonce || exports.randomString(6);
nonce = nonce || Utils.randomString(6);
var mac = exports.calculateMAC(credentials.key, credentials.algorithm, timestamp, nonce, method, uri, host, port, ext);

@@ -265,3 +297,3 @@

var header = 'Hawk id="' + credentials.id + '", ts="' + timestamp + '", nonce="' + nonce + (ext ? '", ext="' + ext : '') + '", mac="' + mac + '"';
var header = 'Hawk id="' + credentials.id + '", ts="' + timestamp + '", nonce="' + nonce + (ext ? '", ext="' + Utils.escapeHeaderAttribute (ext) : '') + '", mac="' + mac + '"';
return header;

@@ -271,34 +303,1 @@ };

// Generate a random string of given size (not for crypto)
exports.randomString = function (size) {
var result = [];
var len = internals.randomSource.length;
for (var i = 0; i < size; ++i) {
result.push(internals.randomSource[Math.floor(Math.random() * len)]);
}
return result.join('');
};
// Compare two strings using fixed time algorithm (to prevent time-based analysis of MAC digest match)
exports.fixedTimeComparison = function (a, b) {
var mismatch = (a.length === b.length ? 0 : 1);
if (mismatch) {
b = a;
}
for (var i = 0, il = a.length; i < il; ++i) {
var ac = a.charCodeAt(i);
var bc = b.charCodeAt(i);
mismatch += (ac === bc ? 0 : 1);
}
return (mismatch === 0);
};
{
"name": "hawk",
"description": "HTTP Hawk Authentication Scheme",
"version": "0.1.0",
"version": "0.2.0",
"author": "Eran Hammer <eran@hueniverse.com> (http://hueniverse.com)",

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

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

Current version: **0.1.0**
Current version: **0.2.0**

@@ -14,2 +14,3 @@ [![Build Status](https://secure.travis-ci.org/hueniverse/hawk.png)](http://travis-ci.org/hueniverse/hawk)

- [**Introduction**](#introduction)
- [Time Synchronization](#time-synchronization)
- [Usage Example](#usage-example)

@@ -26,3 +27,3 @@ - [Protocol Example](#protocol-example)

**Hawk** is an HTTP authentication scheme providing a method for making authenticated HTTP requests with
**Hawk** is an HTTP authentication scheme providing methods for making authenticated HTTP requests with
partial cryptographic verification of the request, covering the HTTP method, request URI, and host.

@@ -45,9 +46,30 @@

Unlike the HTTP [Digest authentication scheme](http://www.ietf.org/rfc/rfc2617.txt), **Hawk** provides limited
Unlike the HTTP [Digest authentication scheme](http://www.ietf.org/rfc/rfc2617.txt), **Hawk** provides optional
protection against replay attacks which does not require prior interaction with the server. Instead, the client
provides a timestamp which the server can use to prevent replay attacks outside a narrow time window. Also unlike
Digest, this mechanism is not intended to protect the key itself (user's password in Digest) because the client
and server both have access to the key material in the clear.
provides a timestamp and a nonce which the server can use to prevent replay attacks outside a narrow time window.
Also unlike Digest, this mechanism is not intended to protect the key itself (user's password in Digest) because
the client and server must both have access to the key material in the clear.
## Time Synchronization
When making requests, the client includes a timestamp and nonce in order to enable the server to prevent replay
attacks. The nonce is generated by the client and is a string unique across all requests with the same timestamp and
key identifier combination. Without replay protection, an attacker can use a compromised (but otherwise valid and
authenticated) request more than once, gaining long term access to a protected resource.
Including a timestamp with the nonce removes the need to retain an infinite number of nonce values for future checks.
The timestamp enables the server to restrict the time period after which a request with an old timestamp is rejected.
However, this requires the client's clock to be in sync with the server's clock. Unlike other protocols, **Hawk**
requires the client to ensure its clock is in sync. To accomplish that, the server provides the client with its current
time in response to a bad timestamp or as part of a challenge.
In addition, to increase the protocol scalability for clients communicating with many different servers, the server
provides the name of an NTP server which can be used as a time reference for clock sync with the server.
There is no expectation that the client will adjust its system clock to match the server. In fact, that would be a
potential attack vector on the client. Instead, the client only uses the server's time to calculate an offset used only
for communications with that particular server.
## Usage Example

@@ -59,3 +81,3 @@

var Http = require('http');
var Hawk = require('../lib/hawk');
var Hawk = require('hawk');

@@ -80,3 +102,3 @@

Hawk.authenticate(req, credentialsFunc, function (err, isAuthenticated, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials, ext) {

@@ -95,3 +117,3 @@ res.writeHead(isAuthenticated ? 200 : 401, { 'Content-Type': 'text/plain' });

var Request = require('request');
var Hawk = require('../lib/hawk');
var Hawk = require('hawk');

@@ -134,7 +156,8 @@

The resource server returns the following authentication challenge:
The resource server returns an authentication challenge. The challenge provides the client with the server's current
time and NTP server used for clock sync, which enable the client to offset its clock when making requests.
```
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Hawk
WWW-Authenticate: Hawk ts="1353832200", ntp="pool.ntp.org"
```

@@ -240,3 +263,27 @@

### Future Time Manipulation
The protocol relies on a clock sync between the client and server. To accomplish this, the server informs the client of its
current time as well as identifies the NTP server used (the client can opt to use either one to calculate the offset used for
further interactions with the server).
If an attacker is able to manipulate this information and cause the client to use an incorrect time, it would be able to cause
the client to generate authenticated requests using time in the future. Such requests will fail when sent by the client, and will
not likely leave a trace on the server (given the common implementation of nonce, if at all enforced). The attacker will then
be able to replay the request at the correct time without detection.
The client must only use the time information provided by the server if it is sent over a TLS connection and the server identity
has been verified.
### Client Clock Poisoning
When receiving a request with a bad timestamp, the server provides the client with its current time as well as the name of an
NTP server which can be used as a time reference. The client must never use the time received from the server to adjust its own
clock, and must only use it to calculate an offset for communicating with that particular server.
In addition, the client must not draw any correlation between the server's time provided via the 'ts' attribute and the current
time at the NTP server indicated via the 'ntp' variable. In other works, the client must not make any conclusion about the NTP
server indicated based on the server response.
# Frequently Asked Questions

@@ -247,3 +294,4 @@

If you are looking for some prose explaining how all this works, there isn't any. **Hawk** is being developed as an open source
project instead of a standard. In other words, the [code](/hueniverse/hawk/tree/master/lib) is the specification.
project instead of a standard. In other words, the [code](/hueniverse/hawk/tree/master/lib) is the specification. Not sure about
something? Open an issue!

@@ -268,4 +316,7 @@ ### Is it done?

At this time, **Hawk** is only implemented in JavaScript as a node.js module. Check this space for future support of other
languages (and such contributions are always welcome).
**Hawk** is only officially implemented in JavaScript as a node.js module. However, others are actively porting it to other
platforms. There is already a [PHP](https://github.com/alexbilbie/PHP-Hawk),
[.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
port. A cross-platform test-suite is in the works.

@@ -283,3 +334,3 @@ ### Why isn't the algorithm part of the challenge or dynamically negotiated?

design violates the HTTP header boundaries, repeats information, and introduces other security issues because firewalls
will not be aware of these “hidden” headers. In addition, any information repeated must be compared to the duplicated
will not be aware of these "hidden" headers. In addition, any information repeated must be compared to the duplicated
information in the header and therefore only moves the problem elsewhere.

@@ -294,3 +345,14 @@

### Why bother with all this nonce and timestamp business?
**Hawk** is an attempt to find a reasonable, practical compromise between security and usability. OAuth 1.0 got timestamp
and nonces half the way right but failed when it came to scalability and consistent developer experience. **Hawk** addresses
it by requiring the client to sync its clock, but provides it with tools to accomplish it.
In general, replay protection is a matter of application-specific threat model. It is less of an issue on a TLS-protected
system where the clients are implemented using best practices and are under the control of the server. Instead of dropping
replay protection, **Hawk** offers a required time window and an optional nonce verification. Together, it provides developers
with the ability to decide how to enforce their security policy without impacting the client's implementation.
# Acknowledgements

@@ -297,0 +359,0 @@

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

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -112,3 +112,3 @@ expect(err).to.not.exist;

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353832234000 - Date.now() }, function (err, credentials, ext) {

@@ -121,2 +121,25 @@ expect(err).to.not.exist;

it('should fail on a stale timestamp', function (done) {
var req = {
headers: {
authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", mac="hpf5lg0G0rtKrT04CiRf0Q+IDjkGkyvKdMjtqu1XV/s=", ext="some-app-data"',
host: 'example.com:8000'
},
method: 'GET',
url: '/resource/1?b=1&a=2'
};
Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
expect(err).to.exist;
expect(err.toResponse().payload.message).to.equal('Stale timestamp');
var header = err.headers['WWW-Authenticate'];
var ts = header.match(/^Hawk ts\=\"(\d+)\"\, ntp\=\"pool.ntp.org\"\, error=\"Stale timestamp\"$/);
var now = Date.now();
expect(parseInt(ts[1], 10)).to.be.within(now - 1, now + 1);
done();
});
});
it('should fail on a replay', function (done) {

@@ -135,2 +158,3 @@

var options = {
localtimeOffsetMsec: 1353788437000 - Date.now(),
nonceFunc: function (nonce, ts, callback) {

@@ -172,6 +196,6 @@

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {
expect(err).to.exist;
expect(err.toResponse().payload.message).to.equal('Incorrect scheme');
expect(err.toResponse().payload.message).to.equal('');
done();

@@ -181,2 +205,21 @@ });

it('should fail on an invalid authentication header: no scheme', function (done) {
var req = {
headers: {
authorization: '!@#',
host: 'example.com:8080'
},
method: 'GET',
url: '/resource/4?filter=a'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {
expect(err).to.exist;
expect(err.toResponse().payload.message).to.equal('Invalid header syntax');
done();
});
});
it('should fail on an missing authorization header', function (done) {

@@ -195,3 +238,6 @@

expect(err).to.exist;
expect(err.toResponse().payload.message).to.equal('Missing Authorization header');
var header = err.headers['WWW-Authenticate'];
var ts = header.match(/^Hawk ts\=\"(\d+)\"\, ntp\=\"pool.ntp.org\"$/);
var now = Date.now();
expect(parseInt(ts[1], 10)).to.be.within(now - 1, now + 1);
done();

@@ -211,3 +257,3 @@ });

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -231,3 +277,3 @@ expect(err).to.exist;

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -251,3 +297,3 @@ expect(err).to.exist;

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -271,3 +317,3 @@ expect(err).to.exist;

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -291,3 +337,3 @@ expect(err).to.exist;

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -311,6 +357,6 @@ expect(err).to.exist;

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {
expect(err).to.exist;
expect(err.toResponse().payload.message).to.equal('Unknown attributes');
expect(err.toResponse().payload.message).to.equal('Unknown attribute: x');
done();

@@ -320,2 +366,78 @@ });

it('should fail on an bad authorization header format', function (done) {
var req = {
headers: {
authorization: 'Hawk id="123\\", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"',
host: 'example.com:8080'
},
method: 'GET',
url: '/resource/4?filter=a'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {
expect(err).to.exist;
expect(err.toResponse().payload.message).to.equal('Bad header format');
done();
});
});
it('should fail on an bad authorization attribute value', function (done) {
var req = {
headers: {
authorization: 'Hawk id="\t", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"',
host: 'example.com:8080'
},
method: 'GET',
url: '/resource/4?filter=a'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {
expect(err).to.exist;
expect(err.toResponse().payload.message).to.equal('Bad attribute value: id');
done();
});
});
it('should fail on an empty authorization attribute value', function (done) {
var req = {
headers: {
authorization: 'Hawk id="", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"',
host: 'example.com:8080'
},
method: 'GET',
url: '/resource/4?filter=a'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {
expect(err).to.exist;
expect(err.toResponse().payload.message).to.equal('Bad attribute value: id');
done();
});
});
it('should fail on duplicated authorization attribute key', function (done) {
var req = {
headers: {
authorization: 'Hawk id="123", id="456", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"',
host: 'example.com:8080'
},
method: 'GET',
url: '/resource/4?filter=a'
};
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {
expect(err).to.exist;
expect(err.toResponse().payload.message).to.equal('Duplicate attribute: id');
done();
});
});
it('should fail on an invalid authorization header format', function (done) {

@@ -332,6 +454,6 @@

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {
expect(err).to.exist;
expect(err.toResponse().payload.message).to.equal('Invalid header format');
expect(err.toResponse().payload.message).to.equal('Invalid header syntax');
done();

@@ -352,3 +474,3 @@ });

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -377,3 +499,3 @@ expect(err).to.exist;

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -402,3 +524,3 @@ expect(err).to.exist;

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -432,3 +554,3 @@ expect(err).to.exist;

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -464,3 +586,3 @@ expect(err).to.exist;

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -496,3 +618,3 @@ expect(err).to.exist;

Hawk.authenticate(req, credentialsFunc, {}, function (err, credentials, ext) {
Hawk.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Date.now() }, function (err, credentials, ext) {

@@ -555,47 +677,3 @@ expect(err).to.exist;

});
describe('#fixedTimeComparison', function () {
var a = Hawk.randomString(50000);
var b = Hawk.randomString(150000);
it('should take the same amount of time comparing different string sizes', function (done) {
var now = Date.now();
Hawk.fixedTimeComparison(b, a);
var t1 = Date.now() - now;
now = Date.now();
Hawk.fixedTimeComparison(b, b);
var t2 = Date.now() - now;
expect(t2 - t1).to.be.within(-1, 1);
done();
});
it('should return true for equal strings', function (done) {
expect(Hawk.fixedTimeComparison(a, a)).to.equal(true);
done();
});
it('should return false for different strings (size, a < b)', function (done) {
expect(Hawk.fixedTimeComparison(a, a + 'x')).to.equal(false);
done();
});
it('should return false for different strings (size, a > b)', function (done) {
expect(Hawk.fixedTimeComparison(a + 'x', a)).to.equal(false);
done();
});
it('should return false for different strings (size, a = b)', function (done) {
expect(Hawk.fixedTimeComparison(a + 'x', a + 'y')).to.equal(false);
done();
});
});
});
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