Use explicit global variable for current configuration rather than config.get()
[KiwiIRC.git] / server / weblistener.js
1 var ws = require('socket.io'),
2 events = require('events'),
3 http = require('http'),
4 https = require('https'),
5 util = require('util'),
6 fs = require('fs'),
7 dns = require('dns'),
8 url = require('url'),
9 _ = require('underscore'),
10 config = require('./configuration.js'),
11 Client = require('./client.js').Client,
12 HttpHandler = require('./httphandler.js').HttpHandler,
13 rehash = require('./rehash.js');
14
15
16
17 rehash.on('rehashed', function (files) {
18 Client = require('./client.js').Client;
19 HttpHandler = require('./httphandler.js').HttpHandler;
20 });
21
22
23 // Instance of HttpHandler
24 var http_handler;
25
26
27 var WebListener = function (web_config, transports) {
28 var hs, opts, ws_opts,
29 that = this;
30
31
32 events.EventEmitter.call(this);
33
34 http_handler = new HttpHandler(web_config);
35
36 // Standard options for the socket.io connections
37 ws_opts = {
38 'log level': 0,
39 'log colors': 0
40 };
41
42
43 if (web_config.ssl) {
44 opts = {
45 key: fs.readFileSync(__dirname + '/' + web_config.ssl_key),
46 cert: fs.readFileSync(__dirname + '/' + web_config.ssl_cert)
47 };
48
49 // Do we have an intermediate certificate?
50 if (typeof web_config.ssl_ca !== 'undefined') {
51 opts.ca = fs.readFileSync(__dirname + '/' + web_config.ssl_ca);
52 }
53
54
55 hs = https.createServer(opts, handleHttpRequest);
56
57 // Start socket.io listening on this weblistener
58 this.ws = ws.listen(hs, _.extend({ssl: true}, ws_opts));
59 hs.listen(web_config.port, web_config.address);
60
61 console.log('Listening on ' + web_config.address + ':' + web_config.port.toString() + ' with SSL');
62 } else {
63
64 // Start some plain-text server up
65 hs = http.createServer(handleHttpRequest);
66
67 // Start socket.io listening on this weblistener
68 this.ws = ws.listen(hs, _.extend({ssl: false}, ws_opts));
69 hs.listen(web_config.port, web_config.address);
70
71 console.log('Listening on ' + web_config.address + ':' + web_config.port.toString() + ' without SSL');
72 }
73
74 this.ws.enable('browser client minification');
75 this.ws.enable('browser client etag');
76 this.ws.set('transports', transports);
77 this.ws.set('resource', (global.config.http_base_path || '') + '/transport');
78
79 this.ws.of('/kiwi').authorization(authoriseConnection)
80 .on('connection', function () {
81 newConnection.apply(that, arguments);
82 }
83 );
84 this.ws.of('/kiwi').on('error', console.log);
85 };
86 util.inherits(WebListener, events.EventEmitter);
87
88
89
90 function handleHttpRequest(request, response) {
91 var uri = url.parse(request.url, true);
92
93 // If this isn't a socket.io request, pass it onto the http handler
94 if (uri.pathname.substr(0, 10) !== '/socket.io') {
95 http_handler.serve(request, response);
96 }
97 }
98
99
100 /**
101 * Get the reverse DNS entry for this connection.
102 * Used later on for webirc, etc functionality
103 */
104 function authoriseConnection(handshakeData, callback) {
105 var address = handshakeData.address.address;
106
107 // If a forwarded-for header is found, switch the source address
108 if (handshakeData.headers['x-forwarded-for']) {
109 // Check we're connecting from a whitelisted proxy
110 if (!global.config.http_proxies || global.config.http_proxies.indexOf(address) < 0) {
111 console.log('Unlisted proxy:', address);
112 callback(null, false);
113 return;
114 }
115
116 // We're sent from a whitelisted proxy, replace the hosts
117 address = handshakeData.headers['x-forwarded-for'];
118 }
119
120 handshakeData.real_address = address;
121
122 // If enabled, don't go over the connection limit
123 if (global.config.max_client_conns && global.config.max_client_conns > 0) {
124 if (global.clients.numOnAddress(address) + 1 > global.config.max_client_conns) {
125 return callback(null, false);
126 }
127 }
128
129 dns.reverse(address, function (err, domains) {
130 if (err || domains.length === 0) {
131 handshakeData.revdns = address;
132 } else {
133 handshakeData.revdns = _.first(domains) || address;
134 }
135
136 // All is well, authorise the connection
137 callback(null, true);
138 });
139 }
140
141 function newConnection(websocket) {
142 var client, that = this;
143 client = new Client(websocket);
144 client.on('destroy', function () {
145 that.emit('destroy', this);
146 });
147 this.emit('connection', client);
148 }
149
150
151
152
153
154 module.exports = WebListener;