refactor: factor out UI Server helpers into arrow functions
authorJérôme Benoit <jerome.benoit@sap.com>
Thu, 15 Feb 2024 22:58:56 +0000 (23:58 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Thu, 15 Feb 2024 22:58:56 +0000 (23:58 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ui-server/AbstractUIServer.ts
src/charging-station/ui-server/UIHttpServer.ts
src/charging-station/ui-server/UIServerFactory.ts
src/charging-station/ui-server/UIServerUtils.ts
src/charging-station/ui-server/UIWebSocketServer.ts

index 495729fa27e39c3e8369f19980dd3eb395f35c32..b17dec30110aea46abae4ec911782c6eb8f690d5 100644 (file)
@@ -5,6 +5,7 @@ import type { WebSocket } from 'ws'
 
 import type { AbstractUIService } from './ui-services/AbstractUIService.js'
 import { UIServiceFactory } from './ui-services/UIServiceFactory.js'
+import { getUsernameAndPasswordFromAuthorizationToken } from './UIServerUtils.js'
 import { BaseError } from '../../exception/index.js'
 import {
   ApplicationProtocolVersion,
@@ -129,7 +130,7 @@ export abstract class AbstractUIServer {
   }
 
   private isValidBasicAuth (req: IncomingMessage, next: (err?: Error) => void): boolean {
-    const [username, password] = this.getUsernameAndPasswordFromAuthorizationToken(
+    const [username, password] = getUsernameAndPasswordFromAuthorizationToken(
       req.headers.authorization?.split(/\s+/).pop() ?? '',
       next
     )
@@ -138,7 +139,7 @@ export abstract class AbstractUIServer {
 
   private isValidProtocolBasicAuth (req: IncomingMessage, next: (err?: Error) => void): boolean {
     const authorizationProtocol = req.headers['sec-websocket-protocol']?.split(/,\s+/).pop()
-    const [username, password] = this.getUsernameAndPasswordFromAuthorizationToken(
+    const [username, password] = getUsernameAndPasswordFromAuthorizationToken(
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
       `${authorizationProtocol}${Array(((4 - (authorizationProtocol!.length % 4)) % 4) + 1).join('=')}`
         .split('.')
@@ -148,21 +149,6 @@ export abstract class AbstractUIServer {
     return this.isValidUsernameAndPassword(username, password)
   }
 
-  private getUsernameAndPasswordFromAuthorizationToken (
-    authorizationToken: string,
-    next: (err?: Error) => void
-  ): [string, string] {
-    if (
-      !/^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/.test(authorizationToken)
-    ) {
-      next(new BaseError('Invalid basic authentication token format'))
-    }
-    const authentication = Buffer.from(authorizationToken, 'base64').toString()
-    const authenticationParts = authentication.split(/:/)
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    return [authenticationParts.shift()!, authenticationParts.join(':')]
-  }
-
   private isValidUsernameAndPassword (username: string, password: string): boolean {
     return (
       this.uiServerConfiguration.authentication?.username === username &&
index bd10a6841e9c7e077007f94c13ba146d9d6cffe6..fb967ef4ecb0403d54b074738e11dcfb8446af05 100644 (file)
@@ -3,7 +3,7 @@ import type { IncomingMessage, ServerResponse } from 'node:http'
 import { StatusCodes } from 'http-status-codes'
 
 import { AbstractUIServer } from './AbstractUIServer.js'
-import { UIServerUtils } from './UIServerUtils.js'
+import { isProtocolAndVersionSupported } from './UIServerUtils.js'
 import { BaseError } from '../../exception/index.js'
 import {
   ApplicationProtocolVersion,
@@ -109,7 +109,7 @@ export class UIHttpServer extends AbstractUIServer {
     this.responseHandlers.set(uuid, res)
     try {
       const fullProtocol = `${protocol}${version}`
-      if (!UIServerUtils.isProtocolAndVersionSupported(fullProtocol)) {
+      if (!isProtocolAndVersionSupported(fullProtocol)) {
         throw new BaseError(`Unsupported UI protocol version: '${fullProtocol}'`)
       }
       this.registerProtocolVersionUIService(version)
index 2a87a582f95f81c64e90699e086ed5c8a74ec8fc..d6dea71b5483ac512df27c6dd4b5eb827ba708bf 100644 (file)
@@ -2,7 +2,7 @@ import chalk from 'chalk'
 
 import type { AbstractUIServer } from './AbstractUIServer.js'
 import { UIHttpServer } from './UIHttpServer.js'
-import { UIServerUtils } from './UIServerUtils.js'
+import { isLoopback } from './UIServerUtils.js'
 import { UIWebSocketServer } from './UIWebSocketServer.js'
 import { BaseError } from '../../exception/index.js'
 import {
@@ -39,7 +39,7 @@ export class UIServerFactory {
     if (
       uiServerConfiguration.authentication?.enabled !== true &&
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      !UIServerUtils.isLoopback(uiServerConfiguration.options!.host!)
+      !isLoopback(uiServerConfiguration.options!.host!)
     ) {
       console.warn(
         chalk.yellow(
index 4d621172b94e7875f6c6bfd683ebd3050f68ec42..2aa2e92b0727a11c4796745142ed06e6c00e7371 100644 (file)
@@ -1,57 +1,64 @@
 import type { IncomingMessage } from 'node:http'
 
+import { BaseError } from '../../exception/index.js'
 import { Protocol, ProtocolVersion } from '../../types/index.js'
 import { logPrefix, logger } from '../../utils/index.js'
 
-// eslint-disable-next-line @typescript-eslint/no-extraneous-class
-export class UIServerUtils {
-  private constructor () {
-    // This is intentional
+export const getUsernameAndPasswordFromAuthorizationToken = (
+  authorizationToken: string,
+  next: (err?: Error) => void
+): [string, string] => {
+  if (
+    !/^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/.test(authorizationToken)
+  ) {
+    next(new BaseError('Invalid basic authentication token format'))
   }
+  const authentication = Buffer.from(authorizationToken, 'base64').toString()
+  const authenticationParts = authentication.split(/:/)
+  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+  return [authenticationParts.shift()!, authenticationParts.join(':')]
+}
 
-  public static readonly handleProtocols = (
-    protocols: Set<string>,
-    request: IncomingMessage
-  ): string | false => {
-    let protocol: Protocol | undefined
-    let version: ProtocolVersion | undefined
-    if (protocols.size === 0) {
-      return false
-    }
-    for (const fullProtocol of protocols) {
-      if (UIServerUtils.isProtocolAndVersionSupported(fullProtocol)) {
-        return fullProtocol
-      }
-    }
-    logger.error(
-      `${logPrefix(
-        ' UI WebSocket Server |'
-      )} Unsupported protocol: '${protocol}' or protocol version: '${version}'`
-    )
+export const handleProtocols = (
+  protocols: Set<string>,
+  _request: IncomingMessage
+): string | false => {
+  let protocol: Protocol | undefined
+  let version: ProtocolVersion | undefined
+  if (protocols.size === 0) {
     return false
   }
-
-  public static readonly isProtocolAndVersionSupported = (protocolStr: string): boolean => {
-    const [protocol, version] = UIServerUtils.getProtocolAndVersion(protocolStr)
-    return (
-      Object.values(Protocol).includes(protocol) && Object.values(ProtocolVersion).includes(version)
-    )
+  for (const fullProtocol of protocols) {
+    if (isProtocolAndVersionSupported(fullProtocol)) {
+      return fullProtocol
+    }
   }
+  logger.error(
+    `${logPrefix(
+      ' UI WebSocket Server |'
+    )} Unsupported protocol: '${protocol}' or protocol version: '${version}'`
+  )
+  return false
+}
 
-  public static readonly getProtocolAndVersion = (
-    protocolStr: string
-  ): [Protocol, ProtocolVersion] => {
-    const protocolIndex = protocolStr.indexOf(Protocol.UI)
-    const protocol = protocolStr.substring(
-      protocolIndex,
-      protocolIndex + Protocol.UI.length
-    ) as Protocol
-    const version = protocolStr.substring(protocolIndex + Protocol.UI.length) as ProtocolVersion
-    return [protocol, version]
-  }
+export const isProtocolAndVersionSupported = (protocolStr: string): boolean => {
+  const [protocol, version] = getProtocolAndVersion(protocolStr)
+  return (
+    Object.values(Protocol).includes(protocol) && Object.values(ProtocolVersion).includes(version)
+  )
+}
 
-  public static isLoopback (address: string): boolean {
-    // eslint-disable-next-line no-useless-escape
-    return /^localhost$|^127(?:\.\d+){0,2}\.\d+$|^(?:0*\:)*?:?0*1$/i.test(address)
-  }
+export const getProtocolAndVersion = (protocolStr: string): [Protocol, ProtocolVersion] => {
+  const protocolIndex = protocolStr.indexOf(Protocol.UI)
+  const protocol = protocolStr.substring(
+    protocolIndex,
+    protocolIndex + Protocol.UI.length
+  ) as Protocol
+  const version = protocolStr.substring(protocolIndex + Protocol.UI.length) as ProtocolVersion
+  return [protocol, version]
+}
+
+export const isLoopback = (address: string): boolean => {
+  // eslint-disable-next-line no-useless-escape
+  return /^localhost$|^127(?:\.\d+){0,2}\.\d+$|^(?:0*\:)*?:?0*1$/i.test(address)
 }
index 16477146f0c638fbd1776213df0d336e3fa9f62d..368a09fe90d4f5522a593133a31e679a109ff23a 100644 (file)
@@ -5,7 +5,11 @@ import { StatusCodes } from 'http-status-codes'
 import { type RawData, WebSocket, WebSocketServer } from 'ws'
 
 import { AbstractUIServer } from './AbstractUIServer.js'
-import { UIServerUtils } from './UIServerUtils.js'
+import {
+  getProtocolAndVersion,
+  handleProtocols,
+  isProtocolAndVersionSupported
+} from './UIServerUtils.js'
 import {
   type ProtocolRequest,
   type ProtocolResponse,
@@ -30,14 +34,14 @@ export class UIWebSocketServer extends AbstractUIServer {
   public constructor (protected readonly uiServerConfiguration: UIServerConfiguration) {
     super(uiServerConfiguration)
     this.webSocketServer = new WebSocketServer({
-      handleProtocols: UIServerUtils.handleProtocols,
+      handleProtocols,
       noServer: true
     })
   }
 
   public start (): void {
     this.webSocketServer.on('connection', (ws: WebSocket, _req: IncomingMessage): void => {
-      if (!UIServerUtils.isProtocolAndVersionSupported(ws.protocol)) {
+      if (!isProtocolAndVersionSupported(ws.protocol)) {
         logger.error(
           `${this.logPrefix(
             moduleName,
@@ -46,7 +50,7 @@ export class UIWebSocketServer extends AbstractUIServer {
         )
         ws.close(WebSocketCloseEventStatusCode.CLOSE_PROTOCOL_ERROR)
       }
-      const [, version] = UIServerUtils.getProtocolAndVersion(ws.protocol)
+      const [, version] = getProtocolAndVersion(ws.protocol)
       this.registerProtocolVersionUIService(version)
       ws.on('message', rawData => {
         const request = this.validateRawDataRequest(rawData)