X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2Fui-server%2FUIWebSocketServer.ts;h=b973cf45b6663aa43be9fda38a2dd43ca04ad9a7;hb=eb3abc4fe41400debcf894e53f91937498e77571;hp=32f5262207873aaa62b71682ab92ac46d6fb316a;hpb=b20eb107fed5d02d7c6317944c4aef034aef49b2;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ui-server/UIWebSocketServer.ts b/src/charging-station/ui-server/UIWebSocketServer.ts index 32f52622..b973cf45 100644 --- a/src/charging-station/ui-server/UIWebSocketServer.ts +++ b/src/charging-station/ui-server/UIWebSocketServer.ts @@ -1,12 +1,13 @@ -import type { IncomingMessage } from 'http'; +import { IncomingMessage, createServer } from 'http'; +import type internal from 'stream'; -import WebSocket, { RawData } from 'ws'; +import { StatusCodes } from 'http-status-codes'; +import WebSocket, { RawData, WebSocketServer } from 'ws'; import BaseError from '../../exception/BaseError'; -import type { ServerOptions } from '../../types/ConfigurationData'; +import type { UIServerConfiguration } from '../../types/ConfigurationData'; import type { ProtocolRequest, ProtocolResponse } from '../../types/UIProtocol'; import { WebSocketCloseEventStatusCode } from '../../types/WebSocket'; -import Configuration from '../../utils/Configuration'; import logger from '../../utils/Logger'; import Utils from '../../utils/Utils'; import { AbstractUIServer } from './AbstractUIServer'; @@ -16,13 +17,19 @@ import { UIServiceUtils } from './ui-services/UIServiceUtils'; const moduleName = 'UIWebSocketServer'; export default class UIWebSocketServer extends AbstractUIServer { - public constructor(options?: ServerOptions) { - super(); - this.server = new WebSocket.Server(options ?? Configuration.getUIServer().options); + private readonly webSocketServer: WebSocketServer; + + public constructor(protected readonly uiServerConfiguration: UIServerConfiguration) { + super(uiServerConfiguration); + this.httpServer = createServer(); + this.webSocketServer = new WebSocketServer({ + handleProtocols: UIServiceUtils.handleProtocols, + noServer: true, + }); } public start(): void { - this.server.on('connection', (ws: WebSocket, request: IncomingMessage): void => { + this.webSocketServer.on('connection', (ws: WebSocket, req: IncomingMessage): void => { const [protocol, version] = UIServiceUtils.getProtocolAndVersion(ws.protocol); if (UIServiceUtils.isProtocolAndVersionSupported(protocol, version) === false) { logger.error( @@ -59,6 +66,24 @@ export default class UIWebSocketServer extends AbstractUIServer { ); }); }); + this.httpServer.on( + 'upgrade', + (req: IncomingMessage, socket: internal.Duplex, head: Buffer): void => { + this.authenticate(req, (err) => { + if (err) { + socket.write(`HTTP/1.1 ${StatusCodes.UNAUTHORIZED} Unauthorized\r\n\r\n`); + socket.destroy(); + return; + } + this.webSocketServer.handleUpgrade(req, socket, head, (ws: WebSocket) => { + this.webSocketServer.emit('connection', ws, req); + }); + }); + } + ); + if (this.httpServer.listening === false) { + this.httpServer.listen(this.uiServerConfiguration.options); + } } public stop(): void { @@ -84,13 +109,25 @@ export default class UIWebSocketServer extends AbstractUIServer { } private broadcastToClients(message: string): void { - for (const client of (this.server as WebSocket.Server).clients) { + for (const client of this.webSocketServer.clients) { if (client?.readyState === WebSocket.OPEN) { client.send(message); } } } + private authenticate(req: IncomingMessage, next: (err: Error) => void): void { + if (this.isBasicAuthEnabled() === true) { + if (this.isValidBasicAuth(req) === false) { + next(new Error('Unauthorized')); + } else { + next(undefined); + } + } else { + next(undefined); + } + } + private validateRawDataRequest(rawData: RawData): ProtocolRequest { // logger.debug( // `${this.logPrefix(