gl-store-s3.js/node_modules/aws-sdk/lib/cloudfront/signer.js

211 lines
7.2 KiB
JavaScript

var AWS = require('../core'),
url = AWS.util.url,
crypto = AWS.util.crypto.lib,
base64Encode = AWS.util.base64.encode,
inherit = AWS.util.inherit;
var queryEncode = function (string) {
var replacements = {
'+': '-',
'=': '_',
'/': '~'
};
return string.replace(/[\+=\/]/g, function (match) {
return replacements[match];
});
};
var signPolicy = function (policy, privateKey) {
var sign = crypto.createSign('RSA-SHA1');
sign.write(policy);
return queryEncode(sign.sign(privateKey, 'base64'));
};
var signWithCannedPolicy = function (url, expires, keyPairId, privateKey) {
var policy = JSON.stringify({
Statement: [
{
Resource: url,
Condition: { DateLessThan: { 'AWS:EpochTime': expires } }
}
]
});
return {
Expires: expires,
'Key-Pair-Id': keyPairId,
Signature: signPolicy(policy.toString(), privateKey)
};
};
var signWithCustomPolicy = function (policy, keyPairId, privateKey) {
policy = policy.replace(/\s/mg, '');
return {
Policy: queryEncode(base64Encode(policy)),
'Key-Pair-Id': keyPairId,
Signature: signPolicy(policy, privateKey)
};
};
var determineScheme = function (url) {
var parts = url.split('://');
if (parts.length < 2) {
throw new Error('Invalid URL.');
}
return parts[0].replace('*', '');
};
var getRtmpUrl = function (rtmpUrl) {
var parsed = url.parse(rtmpUrl);
return parsed.path.replace(/^\//, '') + (parsed.hash || '');
};
var getResource = function (url) {
switch (determineScheme(url)) {
case 'http':
case 'https':
return url;
case 'rtmp':
return getRtmpUrl(url);
default:
throw new Error('Invalid URI scheme. Scheme must be one of'
+ ' http, https, or rtmp');
}
};
var handleError = function (err, callback) {
if (!callback || typeof callback !== 'function') {
throw err;
}
callback(err);
};
var handleSuccess = function (result, callback) {
if (!callback || typeof callback !== 'function') {
return result;
}
callback(null, result);
};
AWS.CloudFront.Signer = inherit({
/**
* A signer object can be used to generate signed URLs and cookies for granting
* access to content on restricted CloudFront distributions.
*
* @see http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html
*
* @param keyPairId [String] (Required) The ID of the CloudFront key pair
* being used.
* @param privateKey [String] (Required) A private key in RSA format.
*/
constructor: function Signer(keyPairId, privateKey) {
if (keyPairId === void 0 || privateKey === void 0) {
throw new Error('A key pair ID and private key are required');
}
this.keyPairId = keyPairId;
this.privateKey = privateKey;
},
/**
* Create a signed Amazon CloudFront Cookie.
*
* @param options [Object] The options to create a signed cookie.
* @option options url [String] The URL to which the signature will grant
* access. Required unless you pass in a full
* policy.
* @option options expires [Number] A Unix UTC timestamp indicating when the
* signature should expire. Required unless you
* pass in a full policy.
* @option options policy [String] A CloudFront JSON policy. Required unless
* you pass in a url and an expiry time.
*
* @param cb [Function] if a callback is provided, this function will
* pass the hash as the second parameter (after the error parameter) to
* the callback function.
*
* @return [Object] if called synchronously (with no callback), returns the
* signed cookie parameters.
* @return [null] nothing is returned if a callback is provided.
*/
getSignedCookie: function (options, cb) {
var signatureHash = 'policy' in options
? signWithCustomPolicy(options.policy, this.keyPairId, this.privateKey)
: signWithCannedPolicy(options.url, options.expires, this.keyPairId, this.privateKey);
var cookieHash = {};
for (var key in signatureHash) {
if (Object.prototype.hasOwnProperty.call(signatureHash, key)) {
cookieHash['CloudFront-' + key] = signatureHash[key];
}
}
return handleSuccess(cookieHash, cb);
},
/**
* Create a signed Amazon CloudFront URL.
*
* Keep in mind that URLs meant for use in media/flash players may have
* different requirements for URL formats (e.g. some require that the
* extension be removed, some require the file name to be prefixed
* - mp4:<path>, some require you to add "/cfx/st" into your URL).
*
* @param options [Object] The options to create a signed URL.
* @option options url [String] The URL to which the signature will grant
* access. Any query params included with
* the URL should be encoded. Required.
* @option options expires [Number] A Unix UTC timestamp indicating when the
* signature should expire. Required unless you
* pass in a full policy.
* @option options policy [String] A CloudFront JSON policy. Required unless
* you pass in a url and an expiry time.
*
* @param cb [Function] if a callback is provided, this function will
* pass the URL as the second parameter (after the error parameter) to
* the callback function.
*
* @return [String] if called synchronously (with no callback), returns the
* signed URL.
* @return [null] nothing is returned if a callback is provided.
*/
getSignedUrl: function (options, cb) {
try {
var resource = getResource(options.url);
} catch (err) {
return handleError(err, cb);
}
var parsedUrl = url.parse(options.url, true),
signatureHash = Object.prototype.hasOwnProperty.call(options, 'policy')
? signWithCustomPolicy(options.policy, this.keyPairId, this.privateKey)
: signWithCannedPolicy(resource, options.expires, this.keyPairId, this.privateKey);
parsedUrl.search = null;
for (var key in signatureHash) {
if (Object.prototype.hasOwnProperty.call(signatureHash, key)) {
parsedUrl.query[key] = signatureHash[key];
}
}
try {
var signedUrl = determineScheme(options.url) === 'rtmp'
? getRtmpUrl(url.format(parsedUrl))
: url.format(parsedUrl);
} catch (err) {
return handleError(err, cb);
}
return handleSuccess(signedUrl, cb);
}
});
/**
* @api private
*/
module.exports = AWS.CloudFront.Signer;