1 | var createHash = require('crypto').createHash;
|
---|
2 |
|
---|
3 | function get_header(header, credentials, opts) {
|
---|
4 | var type = header.split(' ')[0],
|
---|
5 | user = credentials[0],
|
---|
6 | pass = credentials[1];
|
---|
7 |
|
---|
8 | if (type == 'Digest') {
|
---|
9 | return digest.generate(header, user, pass, opts.method, opts.path);
|
---|
10 | } else if (type == 'Basic') {
|
---|
11 | return basic(user, pass);
|
---|
12 | }
|
---|
13 | }
|
---|
14 |
|
---|
15 | ////////////////////
|
---|
16 | // basic
|
---|
17 |
|
---|
18 | function md5(string) {
|
---|
19 | return createHash('md5').update(string).digest('hex');
|
---|
20 | }
|
---|
21 |
|
---|
22 | function basic(user, pass) {
|
---|
23 | var str = typeof pass == 'undefined' ? user : [user, pass].join(':');
|
---|
24 | return 'Basic ' + Buffer.from(str).toString('base64');
|
---|
25 | }
|
---|
26 |
|
---|
27 | ////////////////////
|
---|
28 | // digest
|
---|
29 | // logic inspired from https://github.com/simme/node-http-digest-client
|
---|
30 |
|
---|
31 | var digest = {};
|
---|
32 |
|
---|
33 | digest.parse_header = function(header) {
|
---|
34 | var challenge = {},
|
---|
35 | matches = header.match(/([a-z0-9_-]+)="?([a-z0-9_=\/\.@\s-\+)()]+)"?/gi);
|
---|
36 |
|
---|
37 | for (var i = 0, l = matches.length; i < l; i++) {
|
---|
38 | var parts = matches[i].split('='),
|
---|
39 | key = parts.shift(),
|
---|
40 | val = parts.join('=').replace(/^"/, '').replace(/"$/, '');
|
---|
41 |
|
---|
42 | challenge[key] = val;
|
---|
43 | }
|
---|
44 |
|
---|
45 | return challenge;
|
---|
46 | }
|
---|
47 |
|
---|
48 | digest.update_nc = function(nc) {
|
---|
49 | var max = 99999999;
|
---|
50 | nc++;
|
---|
51 |
|
---|
52 | if (nc > max)
|
---|
53 | nc = 1;
|
---|
54 |
|
---|
55 | var padding = new Array(8).join('0') + '';
|
---|
56 | nc = nc + '';
|
---|
57 | return padding.substr(0, 8 - nc.length) + nc;
|
---|
58 | }
|
---|
59 |
|
---|
60 | digest.generate = function(header, user, pass, method, path) {
|
---|
61 |
|
---|
62 | var nc = 1,
|
---|
63 | cnonce = null,
|
---|
64 | challenge = digest.parse_header(header);
|
---|
65 |
|
---|
66 | var ha1 = md5(user + ':' + challenge.realm + ':' + pass),
|
---|
67 | ha2 = md5(method.toUpperCase() + ':' + path),
|
---|
68 | resp = [ha1, challenge.nonce];
|
---|
69 |
|
---|
70 | if (typeof challenge.qop === 'string') {
|
---|
71 | cnonce = md5(Math.random().toString(36)).substr(0, 8);
|
---|
72 | nc = digest.update_nc(nc);
|
---|
73 | resp = resp.concat(nc, cnonce);
|
---|
74 | resp = resp.concat(challenge.qop, ha2);
|
---|
75 | } else {
|
---|
76 | resp = resp.concat(ha2);
|
---|
77 | }
|
---|
78 |
|
---|
79 |
|
---|
80 | var params = {
|
---|
81 | uri : path,
|
---|
82 | realm : challenge.realm,
|
---|
83 | nonce : challenge.nonce,
|
---|
84 | username : user,
|
---|
85 | response : md5(resp.join(':'))
|
---|
86 | }
|
---|
87 |
|
---|
88 | if (challenge.qop) {
|
---|
89 | params.qop = challenge.qop;
|
---|
90 | }
|
---|
91 |
|
---|
92 | if (challenge.opaque) {
|
---|
93 | params.opaque = challenge.opaque;
|
---|
94 | }
|
---|
95 |
|
---|
96 | if (cnonce) {
|
---|
97 | params.nc = nc;
|
---|
98 | params.cnonce = cnonce;
|
---|
99 | }
|
---|
100 |
|
---|
101 | header = []
|
---|
102 | for (var k in params)
|
---|
103 | header.push(k + '="' + params[k] + '"')
|
---|
104 |
|
---|
105 | return 'Digest ' + header.join(', ');
|
---|
106 | }
|
---|
107 |
|
---|
108 | module.exports = {
|
---|
109 | header : get_header,
|
---|
110 | basic : basic,
|
---|
111 | digest : digest.generate
|
---|
112 | }
|
---|