SECURITY FIX: Kiwi is vulnerable to XSS attack due to unsanitised topic text. Issue...
[KiwiIRC.git] / server / kiwi.js
CommitLineData
69b7b1e6
D
1/*jslint continue: true, forin: true, regexp: true, undef: false, node: true, nomen: true, plusplus: true, maxerr: 50, indent: 4 */
2"use strict";
3var tls = require('tls'),
4 net = require('net'),
5 http = require('http'),
6 https = require('https'),
7 node_static = require('node-static'),
8 fs = require('fs'),
9 url = require('url'),
10 dns = require('dns'),
11 crypto = require('crypto'),
12 events = require("events"),
13 util = require('util'),
14 ws = require('socket.io'),
15 jsp = require("uglify-js").parser,
16 pro = require("uglify-js").uglify,
17 _ = require('./lib/underscore.min.js'),
18 starttls = require('./lib/starttls.js'),
19 app = require(__dirname + '/app.js');
fd779420
D
20
21
69b7b1e6
D
22// Libraries may need to know kiwi.js path as __dirname
23// only gives that librarys path. Set it here for usage later.
24this.kiwi_root = __dirname;
25
26
27
28// How to handle log output
29this.log = function(str, level) {
30 level = level || 0;
31 console.log(str);
32}
33
34
35/*
36 * Configuration and rehashing routines
37 */
fd779420 38var config_filename = 'config.json',
69b7b1e6
D
39 config_dirs = ['/etc/kiwiirc/', this.kiwi_root + '/'];
40
41this.config = {};
42this.loadConfig = function () {
43 var i, j,
44 nconf = {},
45 cconf = {},
46 found_config = false;
47
48 for (i in config_dirs) {
49 try {
50 if (fs.lstatSync(config_dirs[i] + config_filename).isDirectory() === false) {
51 found_config = true;
52 nconf = JSON.parse(fs.readFileSync(config_dirs[i] + config_filename, 'ascii'));
53 for (j in nconf) {
54 // If this has changed from the previous config, mark it as changed
55 if (!_.isEqual(this.config[j], nconf[j])) {
56 cconf[j] = nconf[j];
57 }
58
59 this.config[j] = nconf[j];
60 }
61
62 this.log('Loaded config file ' + config_dirs[i] + config_filename);
63 break;
64 }
65 } catch (e) {
66 switch (e.code) {
67 case 'ENOENT': // No file/dir
68 break;
69 default:
70 this.log('An error occured parsing the config file ' + config_dirs[i] + config_filename + ': ' + e.message);
71 return false;
72 }
73 continue;
4a30a583 74 }
69b7b1e6
D
75 }
76 if (Object.keys(this.config).length === 0) {
77 if (!found_config) {
78 this.log('Couldn\'t find a config file!');
4926321f 79 }
69b7b1e6 80 return false;
fd779420 81 }
69b7b1e6
D
82 return [nconf, cconf];
83};
84
85
86// Reloads the config during runtime
87this.rehash = function () {
88 return app.rehash();
4926321f 89}
4a30a583 90
69b7b1e6
D
91// Reloads app.js during runtime for any recoding
92this.recode = function () {
93 if (typeof require.cache[this.kiwi_root + '/app.js'] !== 'undefined'){
94 delete require.cache[this.kiwi_root + '/app.js'];
95 }
96
97 app = null;
98 app = require(__dirname + '/app.js');
99
100 var objs = {tls:tls, net:net, http:http, https:https, node_static:node_static, fs:fs, url:url, dns:dns, crypto:crypto, events:events, util:util, ws:ws, jsp:jsp, pro:pro, _:_, starttls:starttls};
101 app.init(objs);
102 app.rebindIRCCommands();
103
104 return true;
fd779420
D
105}
106
69b7b1e6
D
107
108
109
110
111
112/*
113 * Before we continue we need the config loaded
114 */
115if (!this.loadConfig()) {
116 process.exit(0);
117}
118
119
120
121
122
123
124
125/*
126 * HTTP file serving
127 */
128if (this.config.handle_http) {
129 this.fileServer = new (require('node-static').Server)(__dirname + this.config.public_http);
130 this.cache = {alljs: '', html: []};
131}
132this.httpServers = [];
133this.httpHandler = function (request, response) {
134 return app.httpHandler(request, response);
135}
136
137
138
139
140
141
142/*
143 * Websocket handling
144 */
145this.connections = {};
146this.io = [];
147this.websocketListen = function (servers, handler) {
148 return app.websocketListen(servers, handler);
149}
150this.websocketConnection = function (websocket) {
151 return app.websocketConnection(websocket);
152}
153this.websocketDisconnect = function () {
154 return app.websocketDisconnect(this);
155}
156this.websocketMessage = function (msg, callback) {
157 return app.websocketMessage(this, msg, callback);
158}
159this.websocketKiwiMessage = function (msg, callback) {
160 return app.websocketKiwiMessage(this, msg, callback);
161}
162this.websocketIRCConnect = function (nick, host, port, ssl, callback) {
163 return app.websocketIRCConnect(this, nick, host, port, ssl, callback);
fd779420
D
164}
165
166
68ad40c6 167
b0ad9f0a 168
69b7b1e6
D
169/*
170 * IRC handling
171 */
172this.parseIRCMessage = function (websocket, ircSocket, data) {
173 return app.parseIRCMessage(websocket, ircSocket, data);
174}
175this.ircSocketDataHandler = function (data, websocket, ircSocket) {
176 return app.ircSocketDataHandler(data, websocket, ircSocket);
177}
178this.IRCConnection = function (websocket, nick, host, port, ssl, password, callback) {
179 return app.IRCConnection.call(this, websocket, nick, host, port, ssl, password, callback);
180}
181util.inherits(this.IRCConnection, events.EventEmitter);
f52d8543 182
69b7b1e6
D
183this.bindIRCCommands = function (irc_connection, websocket) {
184 return app.bindIRCCommands.call(this, irc_connection, websocket);
897abfc3 185}
69b7b1e6
D
186this.rebindIRCCommands = function () {
187 return app.rebindIRCCommands.call(this);
fd779420 188}
709031df 189
69b7b1e6
D
190
191
192
193
194
195/*
196 * Load up main application source
197 */
198if (!this.recode()) {
199 process.exit(0);
200}
201
202
203
204// Set the process title
205app.setTitle();
206
207
208
209/*
210 * Load the modules as set in the config and print them out
211 */
212this.kiwi_mod = require('./lib/kiwi_mod.js');
213this.kiwi_mod.loadModules(this.kiwi_root, this.config);
214this.kiwi_mod.printMods();
215
216
217// Make sure Kiwi doesn't simply quit on an exception
3c892e03
D
218process.on('uncaughtException', function (e) {
219 console.log('[Uncaught exception] ' + e);
220});
69b7b1e6
D
221
222// Start the server up
223this.websocketListen(this.config.servers, this.httpHandler);
224
225// Now we're listening on the network, set our UID/GIDs if required
226app.changeUser();
227
228// Listen for controll messages
87a6abbe 229process.stdin.resume();
69b7b1e6
D
230process.stdin.on('data', function (data) { app.manageControll(data); });
231
232
233
234