File size: 1,367 Bytes
5bab120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { nanoid } from "nanoid";
import { createHmac } from "crypto";

import { env } from "../config.js";

const toBase64URL = (b) => Buffer.from(b).toString("base64url");
const fromBase64URL = (b) => Buffer.from(b, "base64url").toString();

const makeHmac = (header, payload) =>
    createHmac("sha256", env.jwtSecret)
        .update(`${header}.${payload}`)
        .digest("base64url");

const generate = () => {
    const exp = Math.floor(new Date().getTime() / 1000) + env.jwtLifetime;

    const header = toBase64URL(JSON.stringify({
        alg: "HS256",
        typ: "JWT"
    }));

    const payload = toBase64URL(JSON.stringify({
        jti: nanoid(8),
        exp,
    }));

    const signature = makeHmac(header, payload);

    return {
        token: `${header}.${payload}.${signature}`,
        exp: env.jwtLifetime - 2,
    };
}

const verify = (jwt) => {
    const [header, payload, signature] = jwt.split(".", 3);
    const timestamp = Math.floor(new Date().getTime() / 1000);

    if ([header, payload, signature].join('.') !== jwt) {
        return false;
    }

    const verifySignature = makeHmac(header, payload);

    if (verifySignature !== signature) {
        return false;
    }

    if (timestamp >= JSON.parse(fromBase64URL(payload)).exp) {
        return false;
    }

    return true;
}

export default {
    generate,
    verify,
}