@@ -24,15 +24,11 @@ class C2SServer extends EventEmitter {
|
|||||||
async start() {
|
async start() {
|
||||||
const port = this.config.get('network.c2s.port', 5222);
|
const port = this.config.get('network.c2s.port', 5222);
|
||||||
const interface_ = this.config.get('network.c2s.interface', '0.0.0.0');
|
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) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
if (tlsEnabled) {
|
// C2S always starts as plain connection and negotiates STARTTLS later
|
||||||
this.startTLSServer(port, interface_, resolve, reject);
|
this.startPlainServer(port, interface_, resolve, reject);
|
||||||
} else {
|
|
||||||
this.startPlainServer(port, interface_, resolve, reject);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reject(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) {
|
handleConnection(socket, isSecure) {
|
||||||
const remoteAddress = socket.remoteAddress;
|
const remoteAddress = socket.remoteAddress;
|
||||||
const connectionId = `c2s-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
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 ltx = require('ltx');
|
||||||
const Logger = require('../utils/logger');
|
const Logger = require('../utils/logger');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
const tls = require('tls');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
// Simple XML stream parser
|
// Simple XML stream parser
|
||||||
class StreamParser extends EventEmitter {
|
class StreamParser extends EventEmitter {
|
||||||
@@ -254,6 +256,12 @@ class XMPPStream extends EventEmitter {
|
|||||||
this.logger.debug('Received stanza:', stanza.name);
|
this.logger.debug('Received stanza:', stanza.name);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Handle STARTTLS
|
||||||
|
if (stanza.name === 'starttls') {
|
||||||
|
this.handleStartTLS(stanza);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle authentication stanzas
|
// Handle authentication stanzas
|
||||||
if (stanza.name === 'auth') {
|
if (stanza.name === 'auth') {
|
||||||
this.handleAuth(stanza);
|
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) {
|
handleAuth(stanza) {
|
||||||
const mechanism = stanza.attrs.mechanism;
|
const mechanism = stanza.attrs.mechanism;
|
||||||
this.logger.debug(`Authentication attempt with mechanism: ${mechanism}`);
|
this.logger.debug(`Authentication attempt with mechanism: ${mechanism}`);
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user