]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/request/node_modules/hawk/lib/client.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / node_modules / request / node_modules / hawk / lib / client.js
1 // Load modules
2
3 var Url = require('url');
4 var Hoek = require('hoek');
5 var Cryptiles = require('cryptiles');
6 var Crypto = require('./crypto');
7 var Utils = require('./utils');
8
9
10 // Declare internals
11
12 var internals = {};
13
14
15 // Generate an Authorization header for a given request
16
17 /*
18     uri: 'http://example.com/resource?a=b' or object from Url.parse()
19     method: HTTP verb (e.g. 'GET', 'POST')
20     options: {
21
22         // Required
23
24         credentials: {
25             id: 'dh37fgj492je',
26             key: 'aoijedoaijsdlaksjdl',
27             algorithm: 'sha256'                                 // 'sha1', 'sha256'
28         },
29
30         // Optional
31
32         ext: 'application-specific',                        // Application specific data sent via the ext attribute
33         timestamp: Date.now(),                              // A pre-calculated timestamp
34         nonce: '2334f34f',                                  // A pre-generated nonce
35         localtimeOffsetMsec: 400,                           // Time offset to sync with server time (ignored if timestamp provided)
36         payload: '{"some":"payload"}',                      // UTF-8 encoded string for body hash generation (ignored if hash provided)
37         contentType: 'application/json',                    // Payload content-type (ignored if hash provided)
38         hash: 'U4MKKSmiVxk37JCCrAVIjV=',                    // Pre-calculated payload hash
39         app: '24s23423f34dx',                               // Oz application id
40         dlg: '234sz34tww3sd'                                // Oz delegated-by application id
41     }
42 */
43
44 exports.header = function (uri, method, options) {
45
46     var result = {
47         field: '',
48         artifacts: {}
49     };
50
51     // Validate inputs
52
53     if (!uri || (typeof uri !== 'string' && typeof uri !== 'object') ||
54         !method || typeof method !== 'string' ||
55         !options || typeof options !== 'object') {
56
57         result.err = 'Invalid argument type';
58         return result;
59     }
60
61     // Application time
62
63     var timestamp = options.timestamp || Utils.nowSecs(options.localtimeOffsetMsec);
64
65     // Validate credentials
66
67     var credentials = options.credentials;
68     if (!credentials ||
69         !credentials.id ||
70         !credentials.key ||
71         !credentials.algorithm) {
72
73         result.err = 'Invalid credential object';
74         return result;
75     }
76
77     if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
78         result.err = 'Unknown algorithm';
79         return result;
80     }
81
82     // Parse URI
83
84     if (typeof uri === 'string') {
85         uri = Url.parse(uri);
86     }
87
88     // Calculate signature
89
90     var artifacts = {
91         ts: timestamp,
92         nonce: options.nonce || Cryptiles.randomString(6),
93         method: method,
94         resource: uri.pathname + (uri.search || ''),                            // Maintain trailing '?'
95         host: uri.hostname,
96         port: uri.port || (uri.protocol === 'http:' ? 80 : 443),
97         hash: options.hash,
98         ext: options.ext,
99         app: options.app,
100         dlg: options.dlg
101     };
102
103     result.artifacts = artifacts;
104
105     // Calculate payload hash
106
107     if (!artifacts.hash &&
108         (options.payload || options.payload === '')) {
109
110         artifacts.hash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
111     }
112
113     var mac = Crypto.calculateMac('header', credentials, artifacts);
114
115     // Construct header
116
117     var hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== '';       // Other falsey values allowed
118     var header = 'Hawk id="' + credentials.id +
119                  '", ts="' + artifacts.ts +
120                  '", nonce="' + artifacts.nonce +
121                  (artifacts.hash ? '", hash="' + artifacts.hash : '') +
122                  (hasExt ? '", ext="' + Hoek.escapeHeaderAttribute(artifacts.ext) : '') +
123                  '", mac="' + mac + '"';
124
125     if (artifacts.app) {
126         header += ', app="' + artifacts.app +
127                   (artifacts.dlg ? '", dlg="' + artifacts.dlg : '') + '"';
128     }
129
130     result.field = header;
131
132     return result;
133 };
134
135
136 // Validate server response
137
138 /*
139     res:        node's response object
140     artifacts:  object received from header().artifacts
141     options: {
142         payload:    optional payload received
143         required:   specifies if a Server-Authorization header is required. Defaults to 'false'
144     }
145 */
146
147 exports.authenticate = function (res, credentials, artifacts, options) {
148
149     artifacts = Hoek.clone(artifacts);
150     options = options || {};
151
152     if (res.headers['www-authenticate']) {
153
154         // Parse HTTP WWW-Authenticate header
155
156         var wwwAttributes = Utils.parseAuthorizationHeader(res.headers['www-authenticate'], ['ts', 'tsm', 'error']);
157         if (wwwAttributes instanceof Error) {
158             return false;
159         }
160
161         // Validate server timestamp (not used to update clock since it is done via the SNPT client)
162
163         if (wwwAttributes.ts) {
164             var tsm = Crypto.calculateTsMac(wwwAttributes.ts, credentials);
165             if (tsm !== wwwAttributes.tsm) {
166                 return false;
167             }
168         }
169     }
170
171     // Parse HTTP Server-Authorization header
172
173     if (!res.headers['server-authorization'] &&
174         !options.required) {
175
176         return true;
177     }
178
179     var attributes = Utils.parseAuthorizationHeader(res.headers['server-authorization'], ['mac', 'ext', 'hash']);
180     if (attributes instanceof Error) {
181         return false;
182     }
183
184     artifacts.ext = attributes.ext;
185     artifacts.hash = attributes.hash;
186
187     var mac = Crypto.calculateMac('response', credentials, artifacts);
188     if (mac !== attributes.mac) {
189         return false;
190     }
191
192     if (!options.payload &&
193         options.payload !== '') {
194
195         return true;
196     }
197
198     if (!attributes.hash) {
199         return false;
200     }
201
202     var calculatedHash = Crypto.calculatePayloadHash(options.payload, credentials.algorithm, res.headers['content-type']);
203     return (calculatedHash === attributes.hash);
204 };
205
206
207 // Generate a bewit value for a given URI
208
209 /*
210     uri: 'http://example.com/resource?a=b' or object from Url.parse()
211     options: {
212
213         // Required
214
215         credentials: {
216             id: 'dh37fgj492je',
217             key: 'aoijedoaijsdlaksjdl',
218             algorithm: 'sha256'                             // 'sha1', 'sha256'
219         },
220         ttlSec: 60 * 60,                                    // TTL in seconds
221
222         // Optional
223
224         ext: 'application-specific',                        // Application specific data sent via the ext attribute
225         localtimeOffsetMsec: 400                            // Time offset to sync with server time
226     };
227 */
228
229 exports.getBewit = function (uri, options) {
230
231     // Validate inputs
232
233     if (!uri ||
234         (typeof uri !== 'string' && typeof uri !== 'object') ||
235         !options ||
236         typeof options !== 'object' ||
237         !options.ttlSec) {
238
239         return '';
240     }
241
242     options.ext = (options.ext === null || options.ext === undefined ? '' : options.ext);       // Zero is valid value
243
244     // Application time
245
246     var now = Utils.now(options.localtimeOffsetMsec);
247
248     // Validate credentials
249
250     var credentials = options.credentials;
251     if (!credentials ||
252         !credentials.id ||
253         !credentials.key ||
254         !credentials.algorithm) {
255
256         return '';
257     }
258
259     if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
260         return '';
261     }
262
263     // Parse URI
264
265     if (typeof uri === 'string') {
266         uri = Url.parse(uri);
267     }
268
269     // Calculate signature
270
271     var exp = Math.floor(now / 1000) + options.ttlSec;
272     var mac = Crypto.calculateMac('bewit', credentials, {
273         ts: exp,
274         nonce: '',
275         method: 'GET',
276         resource: uri.pathname + (uri.search || ''),                            // Maintain trailing '?'
277         host: uri.hostname,
278         port: uri.port || (uri.protocol === 'http:' ? 80 : 443),
279         ext: options.ext
280     });
281
282     // Construct bewit: id\exp\mac\ext
283
284     var bewit = credentials.id + '\\' + exp + '\\' + mac + '\\' + options.ext;
285     return Hoek.base64urlEncode(bewit);
286 };
287
288
289 // Generate an authorization string for a message
290
291 /*
292     host: 'example.com',
293     port: 8000,
294     message: '{"some":"payload"}',                          // UTF-8 encoded string for body hash generation
295     options: {
296
297         // Required
298
299         credentials: {
300             id: 'dh37fgj492je',
301             key: 'aoijedoaijsdlaksjdl',
302             algorithm: 'sha256'                             // 'sha1', 'sha256'
303         },
304
305         // Optional
306
307         timestamp: Date.now(),                              // A pre-calculated timestamp
308         nonce: '2334f34f',                                  // A pre-generated nonce
309         localtimeOffsetMsec: 400,                           // Time offset to sync with server time (ignored if timestamp provided)
310     }
311 */
312
313 exports.message = function (host, port, message, options) {
314
315     // Validate inputs
316
317     if (!host || typeof host !== 'string' ||
318         !port || typeof port !== 'number' ||
319         message === null || message === undefined || typeof message !== 'string' ||
320         !options || typeof options !== 'object') {
321
322         return null;
323     }
324
325     // Application time
326
327     var timestamp = options.timestamp || Utils.nowSecs(options.localtimeOffsetMsec);
328
329     // Validate credentials
330
331     var credentials = options.credentials;
332     if (!credentials ||
333         !credentials.id ||
334         !credentials.key ||
335         !credentials.algorithm) {
336
337         // Invalid credential object
338         return null;
339     }
340
341     if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
342         return null;
343     }
344
345     // Calculate signature
346
347     var artifacts = {
348         ts: timestamp,
349         nonce: options.nonce || Cryptiles.randomString(6),
350         host: host,
351         port: port,
352         hash: Crypto.calculatePayloadHash(message, credentials.algorithm)
353     };
354
355     // Construct authorization
356
357     var result = {
358         id: credentials.id,
359         ts: artifacts.ts,
360         nonce: artifacts.nonce,
361         hash: artifacts.hash,
362         mac: Crypto.calculateMac('message', credentials, artifacts)
363     };
364
365     return result;
366 };