mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
WebSocket Session Authentication (#21837)
* session auth experiments * simplified cookie parsing * forgot the package json * Create brave-walls-scream.md * prettier
This commit is contained in:
5
.changeset/brave-walls-scream.md
Normal file
5
.changeset/brave-walls-scream.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@directus/api": patch
|
||||
---
|
||||
|
||||
Added WebSocket Session Authentication
|
||||
@@ -92,6 +92,7 @@
|
||||
"@rollup/plugin-alias": "5.1.0",
|
||||
"@rollup/plugin-node-resolve": "15.2.3",
|
||||
"@rollup/plugin-virtual": "3.0.2",
|
||||
"@types/cookie": "0.6.0",
|
||||
"argon2": "0.40.1",
|
||||
"async": "3.2.5",
|
||||
"axios": "1.6.7",
|
||||
@@ -102,6 +103,7 @@
|
||||
"chokidar": "3.6.0",
|
||||
"commander": "12.0.0",
|
||||
"content-disposition": "0.5.4",
|
||||
"cookie": "0.6.0",
|
||||
"cookie-parser": "1.4.6",
|
||||
"cors": "2.8.5",
|
||||
"cron-parser": "4.9.0",
|
||||
|
||||
@@ -4,7 +4,6 @@ import type { Accountability } from '@directus/types';
|
||||
import { parseJSON, toBoolean } from '@directus/utils';
|
||||
import type { IncomingMessage, Server as httpServer } from 'http';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import type { ParsedUrlQuery } from 'querystring';
|
||||
import type { RateLimiterAbstract } from 'rate-limiter-flexible';
|
||||
import type internal from 'stream';
|
||||
import { parse } from 'url';
|
||||
@@ -22,6 +21,7 @@ import { getExpiresAtForToken } from '../utils/get-expires-at-for-token.js';
|
||||
import { getMessageType } from '../utils/message.js';
|
||||
import { waitForAnyMessage, waitForMessageType } from '../utils/wait-for-message.js';
|
||||
import { registerWebSocketEvents } from './hooks.js';
|
||||
import cookie from 'cookie';
|
||||
|
||||
const TOKEN_CHECK_INTERVAL = 15 * 60 * 1000; // 15 minutes
|
||||
|
||||
@@ -132,10 +132,20 @@ export default abstract class SocketController {
|
||||
return;
|
||||
}
|
||||
|
||||
const env = useEnv();
|
||||
const cookies = request.headers.cookie ? cookie.parse(request.headers.cookie) : {};
|
||||
const context: UpgradeContext = { request, socket, head };
|
||||
const sessionCookieName = env['SESSION_COOKIE_NAME'] as string;
|
||||
|
||||
if (cookies[sessionCookieName]) {
|
||||
const token = cookies[sessionCookieName] as string;
|
||||
await this.handleTokenUpgrade(context, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.authentication.mode === 'strict') {
|
||||
await this.handleStrictUpgrade(context, query);
|
||||
const token = query['access_token'] as string;
|
||||
await this.handleTokenUpgrade(context, token);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -151,11 +161,10 @@ export default abstract class SocketController {
|
||||
});
|
||||
}
|
||||
|
||||
protected async handleStrictUpgrade({ request, socket, head }: UpgradeContext, query: ParsedUrlQuery) {
|
||||
protected async handleTokenUpgrade({ request, socket, head }: UpgradeContext, token: string) {
|
||||
let accountability: Accountability | null, expires_at: number | null;
|
||||
|
||||
try {
|
||||
const token = query['access_token'] as string;
|
||||
accountability = await getAccountabilityForToken(token);
|
||||
expires_at = getExpiresAtForToken(token);
|
||||
} catch {
|
||||
|
||||
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@@ -119,6 +119,9 @@ importers:
|
||||
'@rollup/plugin-virtual':
|
||||
specifier: 3.0.2
|
||||
version: 3.0.2(rollup@4.12.0)
|
||||
'@types/cookie':
|
||||
specifier: 0.6.0
|
||||
version: 0.6.0
|
||||
argon2:
|
||||
specifier: 0.40.1
|
||||
version: 0.40.1
|
||||
@@ -149,6 +152,9 @@ importers:
|
||||
content-disposition:
|
||||
specifier: 0.5.4
|
||||
version: 0.5.4
|
||||
cookie:
|
||||
specifier: 0.6.0
|
||||
version: 0.6.0
|
||||
cookie-parser:
|
||||
specifier: 1.4.6
|
||||
version: 1.4.6
|
||||
@@ -7962,6 +7968,10 @@ packages:
|
||||
resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==}
|
||||
dev: true
|
||||
|
||||
/@types/cookie@0.6.0:
|
||||
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
||||
dev: false
|
||||
|
||||
/@types/cookiejar@2.1.5:
|
||||
resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==}
|
||||
dev: true
|
||||
@@ -10622,6 +10632,11 @@ packages:
|
||||
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
/cookie@0.6.0:
|
||||
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/cookiejar@2.1.4:
|
||||
resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==}
|
||||
dev: true
|
||||
@@ -18575,6 +18590,9 @@ packages:
|
||||
/sqlite3@5.1.7:
|
||||
resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==}
|
||||
requiresBuild: true
|
||||
peerDependenciesMeta:
|
||||
node-gyp:
|
||||
optional: true
|
||||
dependencies:
|
||||
bindings: 1.5.0
|
||||
node-addon-api: 7.0.0
|
||||
|
||||
Reference in New Issue
Block a user