mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Use WebSocket2023Channel identifier for WebSocket URL
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import type { IncomingMessage } from 'http';
|
||||
import type { WebSocket } from 'ws';
|
||||
import type { InteractionRoute } from '../../../identity/interaction/routing/InteractionRoute';
|
||||
import { getLoggerFor } from '../../../logging/LogUtil';
|
||||
import { WebSocketServerConfigurator } from '../../WebSocketServerConfigurator';
|
||||
import type { NotificationChannelStorage } from '../NotificationChannelStorage';
|
||||
@@ -16,27 +15,17 @@ export class WebSocket2023Listener extends WebSocketServerConfigurator {
|
||||
|
||||
private readonly storage: NotificationChannelStorage;
|
||||
private readonly handler: WebSocket2023Handler;
|
||||
private readonly path: string;
|
||||
private readonly baseUrl: string;
|
||||
|
||||
public constructor(storage: NotificationChannelStorage, handler: WebSocket2023Handler, route: InteractionRoute) {
|
||||
public constructor(storage: NotificationChannelStorage, handler: WebSocket2023Handler, baseUrl: string) {
|
||||
super();
|
||||
this.storage = storage;
|
||||
this.handler = handler;
|
||||
this.path = new URL(route.getPath()).pathname;
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
protected async handleConnection(webSocket: WebSocket, upgradeRequest: IncomingMessage): Promise<void> {
|
||||
const { path, id } = parseWebSocketRequest(upgradeRequest);
|
||||
|
||||
if (path !== this.path) {
|
||||
webSocket.send('Unknown WebSocket target.');
|
||||
return webSocket.close();
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
webSocket.send('Missing auth parameter from WebSocket URL.');
|
||||
return webSocket.close();
|
||||
}
|
||||
const id = parseWebSocketRequest(this.baseUrl, upgradeRequest);
|
||||
|
||||
const channel = await this.storage.get(id);
|
||||
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
import type { IncomingMessage } from 'http';
|
||||
import { BadRequestHttpError } from '../../../util/errors/BadRequestHttpError';
|
||||
|
||||
/**
|
||||
* Generates a WebSocket URL by converting an HTTP(S) URL into a WS(S) URL
|
||||
* and adding the `auth` query parameter using the identifier.
|
||||
* @param url - The HTTP(S) URL.
|
||||
* @param id - The identifier to use as `auth` parameter.
|
||||
* Generates a WebSocket URL by converting an HTTP(S) URL into a WS(S) URL.
|
||||
* @param id - The identifier of the channel. Needs to be a URL.
|
||||
*/
|
||||
export function generateWebSocketUrl(url: string, id: string): string {
|
||||
return `ws${url.slice('http'.length)}?auth=${encodeURIComponent(id)}`;
|
||||
export function generateWebSocketUrl(id: string): string {
|
||||
return `ws${id.slice('http'.length)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a {@link IncomingMessage} to extract both its path and the identifier used for authentication.
|
||||
* The returned path is relative to the host.
|
||||
*
|
||||
* E.g., a request to `ws://example.com/foo/bar?auth=123456` would return `{ path: '/foo/bar', id: '123456' }`.
|
||||
* Parses a {@link IncomingMessage} to extract its path used for authentication.
|
||||
*
|
||||
* @param baseUrl - The base URL of the server.
|
||||
* @param request - The request to parse.
|
||||
*/
|
||||
export function parseWebSocketRequest(request: IncomingMessage): { path: string; id?: string } {
|
||||
// Base doesn't matter since we just want the path and query parameter
|
||||
const { pathname, searchParams } = new URL(request.url ?? '', 'http://example.com');
|
||||
export function parseWebSocketRequest(baseUrl: string, request: IncomingMessage): string {
|
||||
const path = request.url;
|
||||
|
||||
let auth: string | undefined;
|
||||
if (searchParams.has('auth')) {
|
||||
auth = decodeURIComponent(searchParams.get('auth')!);
|
||||
if (!path) {
|
||||
throw new BadRequestHttpError('Missing url parameter in WebSocket request');
|
||||
}
|
||||
|
||||
return {
|
||||
path: pathname,
|
||||
id: auth,
|
||||
};
|
||||
// Use dummy base and then explicitly set the host and protocol from the base URL.
|
||||
const id = new URL(path, 'http://example.com');
|
||||
const base = new URL(baseUrl);
|
||||
id.host = base.host;
|
||||
id.protocol = base.protocol;
|
||||
|
||||
return id.href;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export class WebSocketChannel2023Type extends BaseChannelType {
|
||||
return {
|
||||
...channel,
|
||||
type: NOTIFY.WebSocketChannel2023,
|
||||
receiveFrom: generateWebSocketUrl(this.path, channel.id),
|
||||
receiveFrom: generateWebSocketUrl(channel.id),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user