node-23video
Version:
node-23video is a full implementation of The 23 Video API (or more correctly, The Visualplatform API) for Node.js.
105 lines (93 loc) • 3.96 kB
JavaScript
/*
TODO:
- General clean-up
- Write tests
- Test support for PLAINTEXT signatures
- Support for realms
*/
var querystring = require('querystring'),
crypto = require('crypto');
// Utility: Generate a random string to use as nonce
function getNonce(len) {
var nonce = [];
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
for (var i = 0; i < (len ? len : 32); i++) {
var pos = Math.floor(Math.random()*chars.length);
nonce.push(chars.substr(pos,1));
}
return(nonce.join(''));
}
// Utility: URL encoding is slightly complex in the OAuth spec
function uriEncode(s) {
var s= encodeURIComponent(s);
s = s.replace(/\!/g, "%21")
.replace(/\'/g, "%27")
.replace(/\(/g, "%28")
.replace(/\)/g, "%29")
.replace(/\*/g, "%2A");
return s;
}
// Utility: Mix content of one object into another (1:1 dublicate from restler.js; can be eliminated)
function mixin(target, source) {
Object.keys(source).forEach(function(key) {
target[key] = source[key];
});
return target;
}
// This function returns a fully signed Authorization header based on
// the restler request. Note that the code relies on pre-parsing done
// by resler beforehand; and notably that `url` is a parsed object,
// not a string.
exports.signature = function(url, options){
// Default some options
options.oauthSignatureMethod = options.oauthSignatureMethod||"HMAC-SHA1"
// 1. NORMALIZE URL
// Turn protocol into lower case
var normalizedURL = [
url.protocol.toLowerCase(),
'//', url.hostname,
((url.protocol==='http:' && url.port==='80') || (url.protocol==='https:' && url.port==='443') ? '' : ':' + url.port),
url.pathname
].join('');
// 2. NORMALIZE PARAMS (not sure if this is needed by restler, but good as a general approach)
var params = querystring.parse(url.query);
if (!options.multipart) mixin(params, querystring.parse(options.data));
params['oauth_timestamp'] = Math.round((+(new Date)/1000));
params['oauth_nonce'] = getNonce();
params['oauth_version'] = '1.0';
params['oauth_signature_method'] = options.oauthSignatureMethod;
params['oauth_consumer_key'] = options.oauthConsumerKey;
if(typeof options.oauthAccessToken != 'undefined' && options.oauthAccessToken != null && options.oauthAccessToken.length>0)
params['oauth_token'] = options.oauthAccessToken;
// order by parameter name
var keys = [];
for(var key in params) keys.push(key);
keys.sort();
// build a normalized querystring
var normalizedParts = [];
keys.forEach(function(key){
normalizedParts.push([uriEncode(key), '=', uriEncode(params[key])].join(''));
});
normalizedParams = normalizedParts.join('&')
// 3. Create a base string for signatures
var signatureBaseString = [options.method.toUpperCase(), uriEncode(normalizedURL), uriEncode(normalizedParams)].join('&');
// 4. And actually sign the string
var signatureSecret = [uriEncode(options.oauthConsumerSecret||''), uriEncode(options.oauthAccessTokenSecret||'')].join('&');
if (options.oauthSignatureMethod==="HMAC-SHA1") {
var hash = uriEncode(crypto.createHmac("sha1", signatureSecret).update(signatureBaseString).digest("base64"));
} else {
var hash = uriEncode(signatureSecret);
}
// 5. Build the Authentication
// select out the relevant heders, and build yet another string
var normalizedHeaderParts = [];
keys.forEach(function(key){
if(key.match(/^oauth_/) && key!='oauth_callback' && key!='oauth_verifier') {
normalizedHeaderParts.push([uriEncode(key), '="', uriEncode(params[key]), '"'].join(''));
}
});
normalizedHeaderParts.push(['oauth_signature="', hash, '"'].join(''));
normalizedHeader = 'OAuth ' + normalizedHeaderParts.join(', ');
// 6. Finally return our header
return(normalizedHeader);
}