-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathindex.js
156 lines (133 loc) · 3.61 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
'use strict';
var crypto = require('crypto');
var b64url = require('base64-url');
var inherits = require('util').inherits;
//
// JWT token error
//
function JWTError(message) {
Error.call(this);
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.message = message;
}
inherits(JWTError, Error);
//
// Utilities class
//
var utils = {};
utils.sign = function sign(alg, key, input) {
if ('hmac' === alg.type) {
return b64url.escape(crypto.createHmac(alg.hash, key)
.update(input)
.digest('base64'));
} else {// ('sign' === alg.type)
return b64url.escape(crypto.createSign(alg.hash)
.update(input)
.sign(key, 'base64'));
}
};
utils.verify = function verify(alg, key, input, sign) {
if ('hmac' === alg.type) {
return sign === this.sign(alg, key, input);
} else {// ('sign' === alg.type)
return crypto.createVerify(alg.hash)
.update(input)
.verify(key, b64url.unescape(sign), 'base64');
}
};
utils.fnError = function(err, cb) {
return cb ?
cb(err) :
{error: err};
};
utils.fnResult = function(res, cb) {
return cb ?
cb(undefined, res) :
{value: res};
};
//
// JSON Web Token
//
var jwt = module.exports;
jwt.JWTError = JWTError;
jwt._algorithms = {
HS256: {hash: 'sha256', type: 'hmac'},
HS384: {hash: 'sha384', type: 'hmac'},
HS512: {hash: 'sha512', type: 'hmac'},
RS256: {hash: 'RSA-SHA256', type: 'sign'}
};
jwt._search = function _search(alg) {
return this._algorithms[alg];
};
jwt.getAlgorithms = function getAlgorithms() {
return Object.keys(this._algorithms);
};
jwt.encode = function encode(key, payload, algorithm, cb) {
//
// some verifications
//
if (!algorithm || typeof algorithm === 'function') {
cb = algorithm;
algorithm = 'HS256';
}
// verify key & payload
if (!key || !payload) {
return utils.fnError(
new JWTError('The key and payload are mandatory!'), cb
);
} else if (!Object.keys(payload).length) {
return utils.fnError(new JWTError('The payload is empty object!'), cb);
} else {
// JWT header
var header = JSON.stringify({typ: 'JWT', alg: algorithm});
// get algorithm hash and type and check if is valid
algorithm = this._search(algorithm);
if (algorithm) {
var parts = b64url.encode(header) +
'.' + b64url.encode(JSON.stringify(payload));
var res = utils.sign(algorithm, key, parts);
return utils.fnResult(parts + '.' + res, cb);
} else {
return utils.fnError(
new JWTError('The algorithm is not supported!'), cb
);
}
}
};
jwt.decode = function decode(key, token, cb) {
if (!key || !token) {
return utils.fnError(new JWTError('The key and token are mandatory!'), cb);
} else {
var parts = token.split('.');
// check all parts're present
if (parts.length !== 3) {
return utils.fnError(
new JWTError('The JWT should consist of three parts!'), cb
);
}
// base64 decode and parse JSON
var header = JSON.parse(b64url.decode(parts[0]));
var payload = JSON.parse(b64url.decode(parts[1]));
// get algorithm hash and type and check if is valid
var algorithm = this._search(header.alg);
if (!algorithm) {
return utils.fnError(
new JWTError('The algorithm is not supported!'), cb
);
} else {
// verify the signature
var res = utils.verify(
algorithm,
key,
parts.slice(0, 2).join('.'),
parts[2]
);
if (res) {
return utils.fnResult(payload, cb);
} else {
return utils.fnError(new JWTError('Invalid key!'), cb);
}
}
}
};