@@ -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 {
|
||||
// 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)}`;
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
Referencia en una nueva incidencia
Block a user