From e9464b8a10eb57d9b021251ff97bcbd9c53a1e98 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 24 Oct 2024 13:37:32 +0300 Subject: `rememberme` middleware: authorize using Spring Security cookie --- vnext/server/app.js | 4 +++ vnext/server/db/Users.js | 1 + vnext/server/middleware/rememberme.js | 50 +++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 vnext/server/middleware/rememberme.js (limited to 'vnext/server') diff --git a/vnext/server/app.js b/vnext/server/app.js index 223868f1..4249b922 100644 --- a/vnext/server/app.js +++ b/vnext/server/app.js @@ -1,5 +1,6 @@ import express from 'express' import { raw } from 'body-parser' +import cookieParser from 'cookie-parser' import cors from 'cors' import config from 'config' @@ -14,11 +15,14 @@ import path from 'path' import { webhook, webhookPath } from './durov' import { webfinger } from './middleware/webfinger' import { jsonMeta, nodeinfo, xmlMeta } from './middleware/host-meta' +import { rememberMeParser } from './middleware/rememberme' // initialize the application and create the routes export const app = express() app.use(raw()) app.use(cors()) +app.use(cookieParser()) +app.use(rememberMeParser) const router = express.Router() router.post('/api/v2/sender', event) diff --git a/vnext/server/db/Users.js b/vnext/server/db/Users.js index 3f4422e2..445b0ff0 100644 --- a/vnext/server/db/Users.js +++ b/vnext/server/db/Users.js @@ -7,6 +7,7 @@ const User = db.define('user', { primaryKey: true }, nick: DataTypes.STRING, + passw: DataTypes.STRING, banned: DataTypes.INTEGER, last_seen: DataTypes.DATE }, { diff --git a/vnext/server/middleware/rememberme.js b/vnext/server/middleware/rememberme.js new file mode 100644 index 00000000..1c0a2ee4 --- /dev/null +++ b/vnext/server/middleware/rememberme.js @@ -0,0 +1,50 @@ +import config from 'config' +import { createHash } from 'node:crypto' +import debug from 'debug' +import { getUserByName } from '../db/Users' +const log = debug('auth') + +const auth_key = config.get('service.auth.key') +const JUICK_COOKIE_NAME = 'juick-remember-me' + +export const rememberMeParser = (req, _res, next) => { + if (req.cookies && !!req.cookies[JUICK_COOKIE_NAME]) { + validate_cookie(req.cookies[JUICK_COOKIE_NAME]).then(visitor => { + req.visitor = visitor + setImmediate(next) + }).catch(() => { + setImmediate(next) + }) + } else { + setImmediate(next) + } +} + +const validate_cookie = async (cookie) => { + const [ username, expiry_time, , signature ] = Buffer.from(cookie, 'base64').toString('ascii').split(':', 4) + if (is_token_expired(expiry_time)) { + log(`Token expired at: ${new Date(expiry_time)}`) + return '' + } + const user = await getUserByName(username) + if (!user) { + log(`User not found: ${username}`) + return '' + } + const expected_signature = make_token_signature(expiry_time, username, user['passw']) + if (expected_signature === signature) { + log(`Signature verified: ${username}`) + return username + } + log(`Invalid token signature: ${username}`) + return '' +} + +const make_token_signature = (expiry_time, username, password) => { + const data = `${username}:${expiry_time}:{noop}${password}:${auth_key}` + return createHash('sha256').update(data).digest('hex') +} + +const is_token_expired = (expiry_time) => { + return new Date(expiry_time) < new Date() +} -- cgit v1.2.3