diff options
Diffstat (limited to 'app/auth.js')
-rw-r--r-- | app/auth.js | 41 |
1 files changed, 17 insertions, 24 deletions
diff --git a/app/auth.js b/app/auth.js index cd771ca..7859a24 100644 --- a/app/auth.js +++ b/app/auth.js @@ -1,23 +1,18 @@ -"use strict"; +import {readFile as rf, writeFile as wf} from "node:fs/promises"; +import {readFileSync, rename} from "node:fs"; +import {randomBytes} from "node:crypto"; +import argon2 from "argon2"; -const fs = require("fs"); -const util = require("util"); -const crypto = require("crypto"); -const argon2 = require("argon2"); -const {sj, parseCookies, res204, err400, err401, err500} = require("./utils"); +import {sj, parseCookies, res204, err400, err401, err500} from "./utils.js"; -const rf = util.promisify(fs.readFile); -const wf = util.promisify(fs.writeFile); -const randHex = len => crypto.randomBytes(len).toString("hex"); - -module.exports = config => { +import {DOMAIN, SECURE, auth as authConfig} from "./config.js"; const { TOKEN_RENEW_AGE, TOKEN_MAX_AGE, TOKEN_LENGTH, SESSION_ID_LENGTH, USERNAME_MAX_LENGTH, PASSWORD_MIN_LENGTH, PASSWORD_MAX_LENGTH, - RATE_LIMIT_MAX_LEVEL, RATE_LIMIT_MAX_WAITING, - fingerprintIP} = config.auth; -const {DOMAIN, SECURE} = config; -const exports = {}; + RATE_LIMIT_MAX_LEVEL, RATE_LIMIT_MAX_WAITING, fingerprintIP, +} = authConfig; + +const randHex = len => randomBytes(len).toString("hex"); // Run once immediately, then every interval until not called function debounce(fn, interval=100) { @@ -42,10 +37,10 @@ function debounce(fn, interval=100) { function loadJSONSync(path) { const obj = {}; try { - Object.assign(obj, JSON.parse(fs.readFileSync(path))); + Object.assign(obj, JSON.parse(readFileSync(path))); } catch(e) { console.log(Date.now()+` Error loading ${path}, creating fallback empty set`); - fs.rename(path, path+".bad."+Date.now(), err => {}); + rename(path, path+".bad."+Date.now(), err => {}); } return obj; } @@ -64,9 +59,9 @@ const userIDsFile = "private/userIDs.json"; const userNames = loadJSONSync(userIDsFile), userIDs = {}; for (const [uid, username] of Object.entries(userNames)) userIDs[username.toLowerCase()] = uid; const writeUIDs = debounce(() => wf(userIDsFile, JSON.stringify(userNames))); -const getUID = exports.getUID = username => +export const getUID = username => userIDs.hasOwnProperty(username.toLowerCase()) && userIDs[username.toLowerCase()]; -const getUsername = exports.getUsername = uid => +export const getUsername = uid => userNames.hasOwnProperty(uid) && userNames[uid]; const createUID = username => { let uid; do { uid = randHex(5); } while (getUsername(uid)); @@ -385,7 +380,7 @@ const rateLimit = fn => (req, res, ...rest) => { }, rateLimitTime(rl.level)); } -function authed(fn) { return rateLimit((req, res, ...rest) => { +export function authed(fn) { return rateLimit((req, res, ...rest) => { const token = parseCookies(req)?.token; if (!token) return err401(res); @@ -421,9 +416,9 @@ function authed(fn) { return rateLimit((req, res, ...rest) => { req.uid = uid; req.sessionID = tokenData.sessionID; return fn(req, res, ...rest); -}); } exports.authed = authed; +}); } -exports.attach = (app) => { // TODO make endpoints RESTier? +export const attach = (app) => { // TODO make endpoints RESTier? app.jpost("/login", rateLimit(login)); // {username, password[, keepSession]} -> {success[, msg][, mustChangePassword]} app.post("/logout", rateLimit(logout)); app.jpost("/change-password", rateLimit(changePassword)); // {password, newPassword[, username[, keepSession]]} -> {success[, msg]} @@ -444,5 +439,3 @@ exports.attach = (app) => { // TODO make endpoints RESTier? // - https://github.com/zxcvbn-ts/zxcvbn // - non-login-event user notification system (warnings, must change password...) // - encrypt `private/` on disk using TPM? - -return exports; }; |