UNPKG

@seriousme/opifex

Version:

MQTT client & server for Deno & NodeJS

117 lines (109 loc) 3.05 kB
import type { Context } from "../context.ts"; import { AuthenticationResult, type ConnectPacket, logger, PacketType, type TAuthenticationResult, Timer, } from "../deps.ts"; /** * Checks if the client is authenticated based on the provided credentials * @param ctx - The connection context * @param packet - The MQTT CONNECT packet * @returns Authentication result indicating if the client is authenticated */ function isAuthenticated( ctx: Context, packet: ConnectPacket, ): TAuthenticationResult { if (ctx.handlers.isAuthenticated) { return ctx.handlers.isAuthenticated( ctx, packet.clientId || "", packet.username || "", packet.password || new Uint8Array(0), ); } return AuthenticationResult.ok; } /** * Validates the CONNECT packet * @param ctx - The connection context * @param packet - The MQTT CONNECT packet to validate * @returns Authentication result indicating if the CONNECT packet is valid */ function validateConnect( ctx: Context, packet: ConnectPacket, ): TAuthenticationResult { if (packet.protocolLevel !== 4) { return AuthenticationResult.unacceptableProtocol; } return isAuthenticated(ctx, packet); } /** * Processes the validated CONNECT packet * @param packet - The MQTT CONNECT packet * @param ctx - The connection context * @param clientId - The client ID */ function processValidatedConnect( returnCode: TAuthenticationResult, packet: ConnectPacket, ctx: Context, clientId: string, ): boolean { if (returnCode === AuthenticationResult.ok) { if (packet.will) { ctx.will = { type: PacketType.publish, qos: packet.will.qos, retain: packet.will.retain, topic: packet.will.topic, payload: packet.will.payload, }; } ctx.connect(clientId, packet.clean || false); const keepAlive = packet.keepAlive || 0; if (keepAlive > 0) { logger.debug(`Setting keepalive to ${keepAlive * 1500} ms`); ctx.timer = new Timer(() => { ctx.close(); }, Math.floor(keepAlive * 1500)); } // is this a new session? // either because its the first time for the client // or it specifically asked for a clean one const previousSession = ctx.store?.existingSession; // client now has a history if (!previousSession && ctx.store) { ctx.store.existingSession = true; } return previousSession || false; } return false; } /** * Handles the MQTT CONNECT packet * @param ctx - The connection context * @param packet - The MQTT CONNECT packet to handle */ export function handleConnect(ctx: Context, packet: ConnectPacket): void { const clientId = packet.clientId || `Opifex-${crypto.randomUUID()}`; const returnCode = validateConnect(ctx, packet); const sessionPresent = processValidatedConnect( returnCode, packet, ctx, clientId, ); ctx.send({ type: PacketType.connack, sessionPresent, returnCode, }); if (returnCode !== AuthenticationResult.ok) { ctx.close(); } }