# Prosody Node.js A full-featured XMPP (Jabber) server implementation in Node.js, inspired by the Prosody XMPP server. ## Features - **Full XMPP Protocol Support** - Client-to-Server (C2S) connections over TCP/TLS - Server-to-Server (S2S) federation (in progress) - BOSH (HTTP binding) support - WebSocket support - Component protocol (XEP-0114) - **Core XMPP Features** - User authentication (PLAIN, SCRAM-SHA-1) - Roster management - Presence handling - Message routing and delivery - IQ request/response handling - Service discovery (disco) - **Advanced Features** - Multi-user chat (MUC) support - Message Archive Management (MAM) - Message Carbons - Client State Indication (CSI) - Publish-Subscribe (PubSub) - Personal Eventing Protocol (PEP) - File sharing - vCard support - Blocklist management - Bookmarks - **Server Architecture** - Modular plugin system - Virtual host support - Flexible configuration - Multiple storage backends - Comprehensive logging - Rate limiting - Connection limits ## Requirements - Node.js >= 18.0.0 - npm or yarn ## Installation ```bash # Clone the repository git clone https://github.com/yourusername/prosody-nodejs.git cd prosody-nodejs # Install dependencies npm install # Copy example environment file cp .env.example .env # Edit configuration nano config/default.yaml ``` ## Configuration The server can be configured through: 1. **YAML Configuration File** (`config/default.yaml`) 2. **Environment Variables** (`.env`) 3. **Custom Configuration File** (passed to server) ### Basic Configuration ```yaml # config/default.yaml server: domain: localhost version: "1.0.0" network: c2s: enabled: true port: 5222 tls: enabled: true virtualHosts: - domain: localhost enabled: true modules: - roster - saslauth - tls - disco ``` ### Environment Variables ```bash # .env SERVER_PORT=5222 SERVER_HOST=localhost TLS_ENABLED=true STORAGE_TYPE=memory LOG_LEVEL=info ``` ## Usage ### Starting the Server ```bash # Development mode (with auto-reload) npm run dev # Production mode npm start ``` ### Running Tests ```bash npm test ``` ### Linting ```bash npm run lint ``` ## Architecture ### Core Components #### Server The main server class that orchestrates all components: - Initializes core managers - Starts network listeners - Manages server lifecycle #### Config Manager Handles configuration loading and management: - YAML file parsing - Environment variable override - Configuration merging #### Session Manager Manages all active client sessions: - Session creation and authentication - JID mapping - Session lifecycle management #### Host Manager Manages virtual hosts: - Multi-domain support - Per-host configuration - Host-specific module loading #### Module Manager Plugin system for extending functionality: - Module loading/unloading - Module lifecycle hooks - Dependency management #### Stanza Router Routes XMPP stanzas to their destinations: - Message routing - Presence broadcasting - IQ handling - Filtering and hooks #### Storage Manager Abstracts data persistence: - Multiple backend support (memory, file, database) - Per-host storage isolation - Key-value and document storage ### Network Servers #### C2S Server (Client-to-Server) Handles direct client connections: - TCP and TLS support - XMPP stream negotiation - SASL authentication - Resource binding #### S2S Server (Server-to-Server) Federation with other XMPP servers: - Dialback authentication - Certificate validation - Connection pooling #### BOSH Server HTTP binding for web clients: - Long-polling support - Session management - Cross-origin support #### WebSocket Server Modern WebSocket-based XMPP: - Binary and text frames - XMPP framing protocol - Sub-protocol negotiation #### Component Server External component connections: - Component authentication - Stanza routing - Component management ## Module Development Create custom modules to extend server functionality: ```javascript // modules/mod_example.js module.exports = { name: 'example', version: '1.0.0', load(module) { const { logger, config, stanzaRouter } = module.api; logger.info('Example module loaded'); // Hook into events stanzaRouter.on('message', (stanza, session) => { logger.debug('Message received:', stanza.toString()); }); }, unload(module) { module.api.logger.info('Example module unloaded'); } }; ``` ## API Reference ### Session API ```javascript // Create a session const session = sessionManager.createSession({ id: 'session-id', jid: 'user@domain/resource', type: 'c2s' }); // Get session by JID const session = sessionManager.getSessionByJid('user@domain/resource'); // Close session sessionManager.closeSession(sessionId); ``` ### Storage API ```javascript // Get a store const store = storageManager.getStore('domain', 'storeName'); // Store data await store.set('key', { data: 'value' }); // Retrieve data const data = await store.get('key'); // Find data const results = await store.find(item => item.data === 'value'); ``` ### Stanza Routing ```javascript // Route a stanza stanzaRouter.route(stanza, session); // Add a filter stanzaRouter.addFilter((stanza, session) => { // Return false to block stanza return true; }); // Listen for events stanzaRouter.on('message', (stanza, session) => { // Handle message }); ``` ## Security ### Best Practices 1. **TLS/SSL**: Always enable TLS for production 2. **Authentication**: Use strong authentication mechanisms 3. **Rate Limiting**: Configure rate limits to prevent abuse 4. **Connection Limits**: Set per-IP connection limits 5. **Input Validation**: Validate all stanza content 6. **Logging**: Monitor logs for suspicious activity ### Configuration ```yaml security: maxStanzaSize: 262144 connectionTimeout: 60000 maxConnectionsPerIP: 5 tlsCiphers: "HIGH:!aNULL:!MD5" rateLimit: enabled: true maxPointsPerSecond: 10 blockDuration: 60 ``` ## Performance ### Optimization Tips 1. **Clustering**: Run multiple instances behind a load balancer 2. **Storage**: Use proper database for production (not memory) 3. **Caching**: Enable caching for frequently accessed data 4. **Compression**: Enable stream compression 5. **Monitoring**: Use monitoring tools to track performance ### Metrics The server exposes metrics for monitoring: - Active sessions - Message throughput - CPU and memory usage - Storage operations - Error rates ## Troubleshooting ### Common Issues #### Connection Refused - Check if the server is running - Verify port configuration - Check firewall settings #### Authentication Failed - Verify credentials - Check authentication backend - Review logs for errors #### TLS Errors - Verify certificate paths - Check certificate validity - Ensure proper permissions ### Debug Mode Enable debug logging: ```bash LOG_LEVEL=debug npm start ``` ## Contributing Contributions are welcome! Please follow these guidelines: 1. Fork the repository 2. Create a feature branch 3. Write tests for new features 4. Ensure all tests pass 5. Submit a pull request ## License MIT License - see LICENSE file for details ## Credits Inspired by [Prosody XMPP Server](https://prosody.im/) written in Lua. ## Support - Documentation: [docs/](docs/) - Issues: GitHub Issues - Community: XMPP MUC at prosody-nodejs@conference.example.com ## Roadmap ### Version 1.0 - [x] Core XMPP protocol - [x] C2S connections - [x] Basic authentication - [x] Message routing - [ ] Full S2S federation - [ ] Complete BOSH implementation - [ ] Complete WebSocket implementation ### Version 1.1 - [ ] Advanced authentication (SCRAM, EXTERNAL) - [ ] Stream Management (XEP-0198) - [ ] Message Archive Management - [ ] Multi-user chat - [ ] HTTP file upload ### Version 2.0 - [ ] Clustering support - [ ] Database storage backends - [ ] Admin interface - [ ] Metrics and monitoring - [ ] Push notifications - [ ] Advanced security features ## Examples ### Basic Client Connection ```javascript // Using node-xmpp-client const xmpp = require('node-xmpp-client'); const client = new xmpp.Client({ jid: 'user@localhost', password: 'password', host: 'localhost', port: 5222 }); client.on('online', () => { console.log('Connected!'); // Send presence client.send(new xmpp.Element('presence')); // Send message const message = new xmpp.Element('message', { to: 'friend@localhost', type: 'chat' }).c('body').t('Hello!'); client.send(message); }); ``` ### Custom Module Example See [docs/MODULE_DEVELOPMENT.md](docs/MODULE_DEVELOPMENT.md) for detailed guide. ## Comparison with Prosody | Feature | Prosody (Lua) | Prosody Node.js | |---------|---------------|-----------------| | Language | Lua | JavaScript/Node.js | | Protocol Support | Full XMPP | Core XMPP (expanding) | | Module System | Yes | Yes | | Performance | Excellent | Good (improving) | | Memory Usage | Low | Moderate | | Ease of Use | Easy | Easy | | Community | Large | Growing | ## FAQ **Q: Why Node.js instead of Lua?** A: Node.js offers a larger ecosystem, easier deployment, and familiarity for web developers. **Q: Is it production-ready?** A: Core features are stable. S2S federation and some advanced features are still in development. **Q: Can it replace Prosody?** A: For basic XMPP needs, yes. For advanced deployments, Prosody is still recommended. **Q: What about performance?** A: Node.js provides good performance for most use cases. Benchmarks show comparable throughput. ## References - [XMPP Standards Foundation](https://xmpp.org/) - [RFC 6120 - XMPP Core](https://tools.ietf.org/html/rfc6120) - [RFC 6121 - XMPP IM](https://tools.ietf.org/html/rfc6121) - [Prosody Documentation](https://prosody.im/doc/)