· 9 years ago · Nov 23, 2016, 11:50 PM
1import CryptoJS from 'crypto-js'
2
3function makeTwoDigits(n) {
4 if (n > 9) {
5 return n;
6 } else {
7 return '0' + n;
8 }
9}
10
11function getDateTimeString() {
12 var d = new Date();
13
14 //
15 // The additional ''s are used to force JavaScript to interpret the
16 // '+' operator as string concatenation rather than arithmetic.
17 //
18 return d.getUTCFullYear() + '' +
19 makeTwoDigits(d.getUTCMonth() + 1) + '' +
20 makeTwoDigits(d.getUTCDate()) + 'T' + '' +
21 makeTwoDigits(d.getUTCHours()) + '' +
22 makeTwoDigits(d.getUTCMinutes()) + '' +
23 makeTwoDigits(d.getUTCSeconds()) + 'Z';
24}
25
26function getDateString(dateTimeString) {
27 return dateTimeString.substring(0, dateTimeString.indexOf('T'));
28}
29
30function getSignatureKey(key, dateStamp, regionName, serviceName) {
31 var kDate = CryptoJS.HmacSHA256(dateStamp, 'AWS4' + key, {
32 asBytes: true
33 });
34 var kRegion = CryptoJS.HmacSHA256(regionName, kDate, {
35 asBytes: true
36 });
37 var kService = CryptoJS.HmacSHA256(serviceName, kRegion, {
38 asBytes: true
39 });
40 var kSigning = CryptoJS.HmacSHA256('aws4_request', kService, {
41 asBytes: true
42 });
43 return kSigning;
44}
45
46function signUrl(method, scheme, hostname, path, queryParams, accessId, secretKey,
47 region, serviceName, payload, today, now, debug, awsSTSToken) {
48
49 var signedHeaders = 'host';
50
51 var canonicalHeaders = 'host:' + hostname.toLowerCase() + '\n';
52
53 var canonicalRequest = method + '\n' + // method
54 path + '\n' + // path
55 queryParams + '\n' + // query params
56 canonicalHeaders + // headers
57 '\n' + // required
58 signedHeaders + '\n' + // signed header list
59 CryptoJS.SHA256(payload, {
60 asBytes: true
61 }); // hash of payload (empty string)
62
63 if (debug === true) {
64 console.log('canonical request: ' + canonicalRequest + '\n');
65 }
66
67 var hashedCanonicalRequest = CryptoJS.SHA256(canonicalRequest, {
68 asBytes: true
69 });
70
71 if (debug === true) {
72 console.log('hashed canonical request: ' + hashedCanonicalRequest + '\n');
73 }
74
75 var stringToSign = 'AWS4-HMAC-SHA256\n' +
76 now + '\n' +
77 today + '/' + region + '/' + serviceName + '/aws4_request\n' +
78 hashedCanonicalRequest;
79
80 if (debug === true) {
81 console.log('string to sign: ' + stringToSign + '\n');
82 }
83
84 var signingKey = getSignatureKey(secretKey, today, region, serviceName);
85
86 if (debug === true) {
87 console.log('signing key: ' + signingKey + '\n');
88 }
89
90 var signature = CryptoJS.HmacSHA256(stringToSign, signingKey, {
91 asBytes: true
92 });
93
94 if (debug === true) {
95 console.log('signature: ' + signature + '\n');
96 }
97
98 var finalParams = queryParams + '&X-Amz-Signature=' + signature;
99
100 if (awsSTSToken !== undefined) {
101 finalParams += '&X-Amz-Security-Token=' + encodeURIComponent(awsSTSToken);
102 }
103
104 var url = scheme + hostname + path + '?' + finalParams;
105
106 if (debug === true) {
107 console.log('url: ' + url + '\n');
108 }
109
110 return url;
111}
112
113function prepareWebSocketUrl(options, awsAccessId, awsSecretKey, awsSTSToken) {
114 var now = getDateTimeString();
115 var today = getDateString(now);
116 var path = '/mqtt';
117 var awsServiceName = 'iotdata';
118 var queryParams = 'X-Amz-Algorithm=AWS4-HMAC-SHA256' +
119 '&X-Amz-Credential=' + awsAccessId + '%2F' + today + '%2F' + options.region + '%2F' + awsServiceName + '%2Faws4_request' +
120 '&X-Amz-Date=' + now +
121 '&X-Amz-SignedHeaders=host';
122 var hostName = options.host;
123
124 // Include the port number in the hostname if it's not
125 // the standard wss port (443).
126 //
127 if ((options.port !== undefined) && options.port !== 443) {
128 hostName = options.host + ':' + options.port;
129 }
130 return signUrl('GET', 'wss://', hostName, path, queryParams,
131 awsAccessId, awsSecretKey, options.region, awsServiceName, '', today, now, options.debug, awsSTSToken);
132}
133
134export {
135 prepareWebSocketUrl
136}