aboutsummaryrefslogtreecommitdiff
path: root/vnext/server
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2024-10-24 13:37:32 +0300
committerGravatar Vitaly Takmazov2024-10-24 23:40:41 +0300
commite9464b8a10eb57d9b021251ff97bcbd9c53a1e98 (patch)
tree6d9d37c1d9b39a667d869fe4f2784e1add2e9959 /vnext/server
parent4bb9c0dd855e1f79308908a97106bf173088cfb8 (diff)
`rememberme` middleware: authorize using Spring Security cookie
Diffstat (limited to 'vnext/server')
-rw-r--r--vnext/server/app.js4
-rw-r--r--vnext/server/db/Users.js1
-rw-r--r--vnext/server/middleware/rememberme.js50
3 files changed, 55 insertions, 0 deletions
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()
+}