From 2a968b00fe2f9af2ae265b535626ac563dc12b65 Mon Sep 17 00:00:00 2001 From: ale Date: Sat, 27 Dec 2025 03:58:56 +0100 Subject: [PATCH] fix tls connect Signed-off-by: ale --- src/core/c2s-server.js | 40 ++------------------- src/core/xmpp-stream.js | 78 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 38 deletions(-) diff --git a/src/core/c2s-server.js b/src/core/c2s-server.js index ae27a45..3dc18cb 100644 --- a/src/core/c2s-server.js +++ b/src/core/c2s-server.js @@ -24,15 +24,11 @@ class C2SServer extends EventEmitter { async start() { const port = this.config.get('network.c2s.port', 5222); const interface_ = this.config.get('network.c2s.interface', '0.0.0.0'); - const tlsEnabled = this.config.get('network.c2s.tls.enabled', true); return new Promise((resolve, reject) => { try { - if (tlsEnabled) { - this.startTLSServer(port, interface_, resolve, reject); - } else { - this.startPlainServer(port, interface_, resolve, reject); - } + // C2S always starts as plain connection and negotiates STARTTLS later + this.startPlainServer(port, interface_, resolve, reject); } catch (error) { reject(error); } @@ -55,38 +51,6 @@ class C2SServer extends EventEmitter { }); } - startTLSServer(port, interface_, resolve, reject) { - const tlsOptions = this.getTLSOptions(); - - this.server = tls.createServer(tlsOptions, (socket) => { - this.handleConnection(socket, true); - }); - - this.server.on('error', (error) => { - this.logger.error('C2S TLS server error:', error); - if (reject) reject(error); - }); - - this.server.on('tlsClientError', (error) => { - this.logger.error('TLS client error:', error); - }); - - this.server.listen(port, interface_, () => { - this.logger.info(`C2S TLS server listening on ${interface_}:${port}`); - if (resolve) resolve(); - }); - } - - getTLSOptions() { - // In production, load from config - return { - // key: fs.readFileSync(this.config.get('security.tlsKeyPath')), - // cert: fs.readFileSync(this.config.get('security.tlsCertPath')), - requestCert: false, - rejectUnauthorized: false - }; - } - handleConnection(socket, isSecure) { const remoteAddress = socket.remoteAddress; const connectionId = `c2s-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; diff --git a/src/core/xmpp-stream.js b/src/core/xmpp-stream.js index c4bc968..163ca73 100644 --- a/src/core/xmpp-stream.js +++ b/src/core/xmpp-stream.js @@ -7,6 +7,8 @@ const EventEmitter = require('events'); const ltx = require('ltx'); const Logger = require('../utils/logger'); const crypto = require('crypto'); +const tls = require('tls'); +const fs = require('fs'); // Simple XML stream parser class StreamParser extends EventEmitter { @@ -254,6 +256,12 @@ class XMPPStream extends EventEmitter { this.logger.debug('Received stanza:', stanza.name); try { + // Handle STARTTLS + if (stanza.name === 'starttls') { + this.handleStartTLS(stanza); + return; + } + // Handle authentication stanzas if (stanza.name === 'auth') { this.handleAuth(stanza); @@ -285,6 +293,76 @@ class XMPPStream extends EventEmitter { } } + handleStartTLS(stanza) { + if (this.secure) { + this.logger.warn('STARTTLS received on secure connection'); + return; + } + + this.logger.debug('STARTTLS negotiation initiated'); + + // Send proceed element + const proceed = new ltx.Element('proceed', { + xmlns: 'urn:ietf:params:xml:ns:xmpp-tls' + }); + this.send(proceed); + + // Get TLS options + const tlsOptions = this.getTLSOptions(); + + // Upgrade socket to TLS + const secureSocket = tls.connect({ + socket: this.socket, + ...tlsOptions, + rejectUnauthorized: false + }, () => { + this.logger.debug('TLS upgrade successful'); + + // Update socket and restart stream + this.socket = secureSocket; + this.secure = true; + + // Setup socket handlers for new socket + this.setupSocket(); + + // Reset state for stream restart + this.setState('wait-for-stream'); + this.streamId = this.generateStreamId(); + }); + + secureSocket.on('error', (error) => { + this.logger.error('TLS upgrade error:', error); + this.close(); + }); + } + + getTLSOptions() { + const tlsConfig = this.config.get('network.c2s.tls', {}); + + // Try to load certificates from config + let options = { + requestCert: false, + rejectUnauthorized: false + }; + + try { + const keyPath = tlsConfig.keyPath || '/home/ale/projects/xmpp/prosody-nodejs/certs/localhost-key.pem'; + const certPath = tlsConfig.certPath || '/home/ale/projects/xmpp/prosody-nodejs/certs/localhost.pem'; + + if (fs.existsSync(keyPath) && fs.existsSync(certPath)) { + options.key = fs.readFileSync(keyPath); + options.cert = fs.readFileSync(certPath); + this.logger.debug('Using configured TLS certificates'); + } else { + this.logger.warn('TLS certificates not found, using default options'); + } + } catch (error) { + this.logger.warn('Error loading TLS certificates:', error); + } + + return options; + } + handleAuth(stanza) { const mechanism = stanza.attrs.mechanism; this.logger.debug(`Authentication attempt with mechanism: ${mechanism}`);