fluid-client
Version:
Client for accessing www.fluid.us
72 lines (58 loc) • 2.04 kB
JavaScript
;
/**
* Internal utilities for signing data packets
**/
const querystring = require('querystring');
const crypto = require('crypto');
const constants = require('./constants');
const errors = require('./errors');
const utilities = require('./utilities');
class HashUtils {
static checkHashKeys(hash, keySet) {
hash = HashUtils.compactHash(hash);
let keys = Object.getOwnPropertyNames(hash);
const missing = utilities.arrayDifference(keySet.required, keys);
const extra = utilities.arrayDifference(keys, keySet.allowed);
if (missing.length)
throw new errors.SignatureError(`Required hash keys missing: ${missing}`);
if (extra.length)
throw new errors.SignatureError(`Extra hash keys: ${extra}`);
}
static signHash(hash, secretKey) {
const text = this.hashToString(hash);
let hmac = crypto.createHmac('sha256', secretKey);
return hmac.update(text).digest('hex');
}
// Turns hash into a url style list
// Not using querystring.stringify because it needs to be sorted and filtered
static hashToString(hash) {
hash = HashUtils.compactHash(hash);
const keys = Object.getOwnPropertyNames(hash);
const params = keys.sort().map( (key) => {
const value = querystring.escape( hash[key] );
key = constants.LONG_TO_SHORT_KEY_MAP[key] || key;
return `${key}=${value}`;
} );
return params.join('&');
}
static stringToHash(string) {
if (!string)
return null;
const params = string.split('&');
return params.reduce( (hash, param) => {
let [key, value] = param.split('=');
key = constants.SHORT_TO_LONG_KEY_MAP[key] || key;
hash[key] = querystring.unescape(value);
return hash;
}, {});
}
static compactHash(hash) {
const keys = Object.getOwnPropertyNames(hash);
return keys.reduce( (memo, key) => {
if (utilities.isNotEmpty(hash[key]))
memo[key] = hash[key];
return memo;
}, {});
}
}
module.exports = HashUtils;