1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | 'use strict'
|
7 |
|
8 | const {jws: {JWS}} = require('jsrsasign')
|
9 | const uuidv4 = require('uuid/v4')
|
10 | const uuidv5 = require('uuid/v5')
|
11 | const debug = require('@tadashi/debug')('tadashi-jwt')
|
12 | const {matchClaims, parseJWT} = require('./lib/util')
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | const {
|
21 | TADASHI_ALG = 'HS512',
|
22 | TADASHI_ALG_ACCEPTABLE = 'HS512 HS256',
|
23 | TADASHI_SECRET_KEY_JWT = 'de66bd178d5abc9e848787b678f9b613'
|
24 | } = process.env
|
25 |
|
26 | const alg = TADASHI_ALG
|
27 | const algs = TADASHI_ALG_ACCEPTABLE
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | function _jti() {
|
36 | const NAMESPACE = uuidv4()
|
37 | return uuidv5(`tadashi_${Number(Date.now()).toString(26)}`, NAMESPACE)
|
38 | }
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 | function sign(payload, options = {}, secret = TADASHI_SECRET_KEY_JWT) {
|
55 | const {duration = 0, useData = true} = options
|
56 | const _claims = ['jti', 'iss', 'aud', 'sub']
|
57 | const _header = {alg, typ: 'JWT'}
|
58 |
|
59 | const tNow = Math.floor(Date.now() / 1000)
|
60 | const tEnd = tNow + duration
|
61 |
|
62 | const _payload = Object.create(null)
|
63 |
|
64 | if (useData) {
|
65 | _payload.data = payload
|
66 | } else {
|
67 | Object.keys(payload).forEach(k => {
|
68 | _payload[k] = payload[k]
|
69 | })
|
70 | }
|
71 |
|
72 | Object.keys(options).forEach(k => {
|
73 | if (_claims.includes(k)) {
|
74 | _payload[k] = options[k]
|
75 | }
|
76 | })
|
77 |
|
78 | if (duration > 0) {
|
79 | _payload.exp = tEnd
|
80 | }
|
81 |
|
82 | _payload.jti = _payload.jti || _jti()
|
83 | _payload.iat = tNow
|
84 | _payload.nbf = tNow
|
85 |
|
86 | const sHeader = JSON.stringify(_header)
|
87 | const sPayload = JSON.stringify(_payload)
|
88 | const sSecret = {utf8: secret}
|
89 | return JWS.sign(alg, sHeader, sPayload, sSecret)
|
90 | }
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 | function verify(jwt, options = {}, secret = TADASHI_SECRET_KEY_JWT) {
|
101 | try {
|
102 | const sSecret = {utf8: secret}
|
103 | const fields = Object.keys(options)
|
104 | const claims = Object.create(null)
|
105 | fields.forEach(k => {
|
106 | claims[k] = options[k].split(' ')
|
107 | })
|
108 | claims.alg = algs.split(' ')
|
109 | if (matchClaims(jwt, fields)) {
|
110 | return JWS.verifyJWT(jwt, sSecret, claims)
|
111 | }
|
112 | return false
|
113 | } catch (err) {
|
114 | debug.error('verifyJWT', err.message)
|
115 | return false
|
116 | }
|
117 | }
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 | function parse(jwt) {
|
126 | try {
|
127 | return parseJWT(jwt)
|
128 | } catch (err) {
|
129 | debug.error('parseJWT', err.message)
|
130 | return null
|
131 | }
|
132 | }
|
133 |
|
134 | exports.sign = sign
|
135 | exports.verify = verify
|
136 | exports.parse = parse
|