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,
}
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
)
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('.')
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 &&
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,
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)
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 {
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(
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)
}
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,
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,
)
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)