-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.js
75 lines (62 loc) · 2.4 KB
/
utils.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
const Database = require("better-sqlite3");
const Crypto = require("node:crypto");
const jsonwebtoken = require("jsonwebtoken");
const fs = require("node:fs");
require("dotenv").config()
module.exports.createDatabase = name => {
const db = Database(name, { verbose: console.log });
db.pragma("foreign_keys = ON");
db.pragma("journal_mode = WAL");
db.exec(fs.readFileSync("migration.sql", { encoding: 'utf-8' }));
return db;
};
const promisify =
fn =>
(...args) =>
new Promise((resolve, reject) =>
fn(...args, (err, res) => (err ? reject(err) : resolve(res)))
);
module.exports.Password = {
async hash(password) {
if (password.length < 8 || password.length > 100) throw new this.PasswordLengthError();
const salt = Crypto.randomBytes(32).toString("hex");
const hash = (await this.scrypt(password, salt, 64)).toString("hex");
return salt + "." + hash;
},
async verify({ hashed, password }) {
const [salt, hash] = hashed.split(".");
const candidate = (await this.scrypt(password, salt, 64)).toString("hex");
return candidate === hash;
},
scrypt: promisify(Crypto.scrypt),
PasswordLengthError: class extends Error { },
};
if (!process.env.JWT_SECRET) throw new Error("Missing JWT_SECRET environment variable");
module.exports.useJwt = (secret, algorithm, expiresIn) => [
payload => jsonwebtoken.sign(payload, secret, { algorithm, expiresIn }),
(req, res, next) => {
const header = req.headers.authorization;
if (!header) return res.status(401).json({ error: "Missing Authorization header" });
const [scheme, token] = header.split(" ");
if (scheme !== "Bearer")
return res.status(401).json({ error: "Invalid Authorization header" });
try {
const { username } = jsonwebtoken.verify(token, secret, { algorithms: [algorithm] });
req.username = username;
next();
} catch (err) {
return res.status(401).json({ error: "Invalid token" });
}
},
];
module.exports.cacher = ms => fn => {
let [timeOfLastCall, lastResult] = [0, null];
return (...args) => {
const now = Date.now();
if (!timeOfLastCall || now - timeOfLastCall > ms) {
timeOfLastCall = now;
lastResult = fn(...args);
}
return lastResult;
};
};