}
if (
chargingStation.stationInfo.chargingStationId == null ||
- isEmpty(chargingStation.stationInfo.chargingStationId.trim())
+ isEmpty(chargingStation.stationInfo.chargingStationId)
) {
throw new BaseError('Missing chargingStationId in stationInfo properties')
}
if (
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
chargingStation.stationInfo.hashId == null ||
- isEmpty(chargingStation.stationInfo.hashId.trim())
+ isEmpty(chargingStation.stationInfo.hashId)
) {
throw new BaseError(`${chargingStationId}: Missing hashId in stationInfo properties`)
}
if (
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
chargingStation.stationInfo.templateName == null ||
- isEmpty(chargingStation.stationInfo.templateName.trim())
+ isEmpty(chargingStation.stationInfo.templateName)
) {
throw new BaseError(`${chargingStationId}: Missing templateName in stationInfo properties`)
}
}
private isValidBasicAuth (req: IncomingMessage, next: (err?: Error) => void): boolean {
- const [username, password] = getUsernameAndPasswordFromAuthorizationToken(
+ const usernameAndPassword = getUsernameAndPasswordFromAuthorizationToken(
req.headers.authorization?.split(/\s+/).pop() ?? '',
next
)
+ if (usernameAndPassword == null) {
+ return false
+ }
+ const [username, password] = usernameAndPassword
return this.isValidUsernameAndPassword(username, password)
}
private isValidProtocolBasicAuth (req: IncomingMessage, next: (err?: Error) => void): boolean {
const authorizationProtocol = req.headers['sec-websocket-protocol']?.split(/,\s+/).pop()
- const [username, password] = getUsernameAndPasswordFromAuthorizationToken(
+ const usernameAndPassword = getUsernameAndPasswordFromAuthorizationToken(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/restrict-template-expressions
`${authorizationProtocol}${Array(((4 - (authorizationProtocol!.length % 4)) % 4) + 1).join(
'='
.pop() ?? '',
next
)
+ if (usernameAndPassword == null) {
+ return false
+ }
+ const [username, password] = usernameAndPassword
return this.isValidUsernameAndPassword(username, password)
}
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'))
+): [string, string] | undefined => {
+ try {
+ const authentication = Buffer.from(authorizationToken, 'base64').toString('utf8')
+ const separatorIndex = authentication.indexOf(':')
+ if (separatorIndex === -1) {
+ next(new BaseError('Invalid basic authentication token format: missing ":" separator'))
+ return undefined
+ }
+ const username = authentication.slice(0, separatorIndex)
+ const password = authentication.slice(separatorIndex + 1)
+ if (isEmpty(username)) {
+ next(new BaseError('Invalid basic authentication token format: empty username'))
+ return undefined
+ }
+ return [username, password]
+ } catch (error) {
+ next(new BaseError(`Invalid basic authentication token format: ${(error as Error).message}`))
+ return undefined
}
- 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(':')]
}
export const handleProtocols = (
protocols: Set<string>,
_request: IncomingMessage
): false | string => {
- let protocol: Protocol | undefined
- let version: ProtocolVersion | undefined
if (isEmpty(protocols)) {
return false
}
- for (const fullProtocol of protocols) {
- if (isProtocolAndVersionSupported(fullProtocol)) {
- return fullProtocol
+ for (const protocol of protocols) {
+ if (isProtocolAndVersionSupported(protocol)) {
+ return protocol
}
}
logger.error(
`${logPrefix(
' UI WebSocket Server |'
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
- )} Unsupported protocol: '${protocol}' or protocol version: '${version}'`
+ )} Unsupported protocol in client request: '${Array.from(protocols).join(', ')}'`
)
return false
}
export const isProtocolAndVersionSupported = (protocolStr: string): boolean => {
- const [protocol, version] = getProtocolAndVersion(protocolStr)
+ const protocolAndVersion = getProtocolAndVersion(protocolStr)
+ if (protocolAndVersion == null) {
+ return false
+ }
+ const [protocol, version] = protocolAndVersion
return (
Object.values(Protocol).includes(protocol) && Object.values(ProtocolVersion).includes(version)
)
}
-export const getProtocolAndVersion = (protocolStr: string): [Protocol, ProtocolVersion] => {
+export const getProtocolAndVersion = (
+ protocolStr: string
+): [Protocol, ProtocolVersion] | undefined => {
+ if (isEmpty(protocolStr)) {
+ return undefined
+ }
+ if (!protocolStr.startsWith(Protocol.UI)) {
+ return undefined
+ }
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]
+ const protocol = protocolStr.substring(protocolIndex, protocolIndex + Protocol.UI.length)
+ const version = protocolStr.substring(protocolIndex + Protocol.UI.length)
+ if (isEmpty(protocol) || isEmpty(version)) {
+ return undefined
+ }
+ return [protocol, version] as [Protocol, ProtocolVersion]
}
export const isLoopback = (address: string): boolean => {
const type = (value: unknown): string => {
if (value === null) return 'Null'
if (value === undefined) return 'Undefined'
+ if (typeof value === 'string') return 'String'
if (Number.isNaN(value)) return 'NaN'
if (Array.isArray(value)) return 'Array'
return Object.prototype.toString.call(value).slice(8, -1)
}
if (!value) return true
+ if (valueType === 'String') {
+ return (value as string).trim().length === 0
+ }
+
if (valueType === 'Object') {
return Object.keys(value as Record<string, unknown>).length === 0
}