tlsd 2.11.1 → 2.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/tlsd.js +121 -192
package/package.json
CHANGED
package/tlsd.js
CHANGED
|
@@ -8,6 +8,11 @@ const connect = require( "connect" );
|
|
|
8
8
|
const websocket = require( "websocket" );
|
|
9
9
|
const serveStatic = require( "serve-static" )
|
|
10
10
|
|
|
11
|
+
const body_parser = require( "body-parser" ).json( { limit: "10mb" } );
|
|
12
|
+
const compression = require( "compression" )();
|
|
13
|
+
const cors = require( "cors" )();
|
|
14
|
+
const queryString = require( "querystring" );
|
|
15
|
+
|
|
11
16
|
require( "sleepless" ).globalize();
|
|
12
17
|
|
|
13
18
|
const L = log5.mkLog( "TLSD: " );
|
|
@@ -31,7 +36,7 @@ function usage() {
|
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
let seq = 0;
|
|
34
|
-
|
|
39
|
+
function next_seq() {
|
|
35
40
|
seq += 1;
|
|
36
41
|
return seq;
|
|
37
42
|
}
|
|
@@ -39,7 +44,7 @@ const next_seq = function() {
|
|
|
39
44
|
|
|
40
45
|
// Handles incoming RPC msgs.
|
|
41
46
|
// Tries to load the rpc handler module from root and if successful, passes the msg to it
|
|
42
|
-
|
|
47
|
+
function rpc_handler( root, msg, xport, _okay, _fail ) {
|
|
43
48
|
|
|
44
49
|
let ll = toInt( msg.log_level );
|
|
45
50
|
if( ll > 0 ) {
|
|
@@ -89,7 +94,7 @@ const rpc_handler = function( root, msg, xport, _okay, _fail ) {
|
|
|
89
94
|
|
|
90
95
|
// Glue function to call rpc handler module and then return response
|
|
91
96
|
// via the websockets msg object
|
|
92
|
-
|
|
97
|
+
function ws_msg_handler( root, msg ) {
|
|
93
98
|
rpc_handler( root, msg.msg, "WS", data => {
|
|
94
99
|
msg.reply( data );
|
|
95
100
|
}, error => {
|
|
@@ -99,115 +104,113 @@ const ws_msg_handler = function( root, msg ) {
|
|
|
99
104
|
};
|
|
100
105
|
|
|
101
106
|
|
|
102
|
-
//
|
|
103
|
-
// XXX This has got to be inefficient at best, as it's creating a
|
|
104
|
-
// connect app on every request. No idea how much of this gets optimized
|
|
105
|
-
// out by V8.
|
|
106
|
-
const basic_handler = function( root ) {
|
|
107
|
-
|
|
108
|
-
const app = connect();
|
|
109
|
-
|
|
110
|
-
app.use( require( "body-parser" ).json( { limit: "10mb" } ) );
|
|
111
|
-
app.use( require( "compression" )() );
|
|
112
|
-
app.use( require( "cors" )() ); // allow requests from other domains
|
|
113
|
-
|
|
114
|
-
// populate req.query
|
|
115
|
-
app.use( function( req, res, next ) {
|
|
116
|
-
req.query = require( "querystring" ).parse( req._parsedUrl.query );
|
|
117
|
-
next();
|
|
118
|
-
} );
|
|
119
|
-
|
|
120
|
-
// logger
|
|
121
|
-
app.use( function( req, res, next ) {
|
|
122
|
-
const host = req.headers[ "host" ];
|
|
123
|
-
let { method, url, query, body } = req;
|
|
124
|
-
url = url.split( "?" ).shift();
|
|
125
|
-
I( host + ": " + method + " " + o2j(url) + " " + o2j( query, null, 2 ) + "/" + o2j( body, null, 2 ) );
|
|
126
|
-
next();
|
|
127
|
-
} );
|
|
128
|
-
|
|
129
|
-
// Intercept and service POST requests for "/rpc"
|
|
130
|
-
app.use( function( req, res, next ) {
|
|
131
|
-
|
|
132
|
-
let { method, url, query, body } = req;
|
|
133
|
-
|
|
134
|
-
url = url.split( "?" ).shift();
|
|
135
|
-
|
|
136
|
-
// if not an rpc request, pass on to static
|
|
137
|
-
if( url != "/rpc" && url != "/rpc/" ) {
|
|
138
|
-
next();
|
|
139
|
-
return
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Only allow POSTS to /rpc in tlsd mode.
|
|
143
|
-
// In dev mode, GET is allowed as well with query args.
|
|
144
|
-
let input = body;
|
|
145
|
-
if( method != "POST" ) {
|
|
146
|
-
if( ! ( method == "GET" && dev_mode ) ) {
|
|
147
|
-
W( "GET /rpc is disallowed in tlsd mode" );
|
|
148
|
-
res.writeHead( 405 ); // Method Not Allowed
|
|
149
|
-
res.end();
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
input = query;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Set up callbacks
|
|
156
|
-
const done = ( error, data ) => {
|
|
157
|
-
res.writeHead( 200, {
|
|
158
|
-
"Content-Type": "application/json",
|
|
159
|
-
"Cache-Control": "no-store",
|
|
160
|
-
});
|
|
161
|
-
res.write( o2j( data ) );
|
|
162
|
-
res.end();
|
|
163
|
-
};
|
|
164
|
-
const okay = ( data ) => { done( null, data ); };
|
|
165
|
-
// XXX wrong
|
|
166
|
-
const fail = ( error, body ) => { done( error, body ); };
|
|
107
|
+
// -----------------------
|
|
167
108
|
|
|
168
|
-
// Summon the rpc handler for the domain root.
|
|
169
|
-
rpc_handler( root, input, "REST", okay, fail );
|
|
170
109
|
|
|
171
|
-
|
|
110
|
+
// Handler that populates the req.query var with what's in query args
|
|
111
|
+
function populate_query( req, res, next ) {
|
|
112
|
+
req.query = queryString.parse( req._parsedUrl.query );
|
|
113
|
+
next();
|
|
114
|
+
}
|
|
172
115
|
|
|
116
|
+
// Simple logging handler
|
|
117
|
+
function logger( req, res, next ) {
|
|
118
|
+
const host = req.headers[ "host" ];
|
|
119
|
+
let { method, url, query, body } = req;
|
|
120
|
+
url = url.split( "?" ).shift();
|
|
121
|
+
I( host + ": " + method + " " + o2j( url ) + " " + o2j( query, null, 2 ) + "/" + o2j( body, null, 2 ) );
|
|
122
|
+
next();
|
|
123
|
+
}
|
|
173
124
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
125
|
+
// Creates and returns a handler function that intercepts and services
|
|
126
|
+
// POST requests to "/rpc" endpoint.
|
|
127
|
+
function rpc_post( root ) {
|
|
128
|
+
return function( req, res, next ) {
|
|
129
|
+
let { method, url, query, body } = req;
|
|
179
130
|
|
|
131
|
+
url = url.split( "?" ).shift();
|
|
132
|
+
if( url != "/rpc" && url != "/rpc/" ) {
|
|
133
|
+
next();
|
|
134
|
+
return
|
|
135
|
+
}
|
|
180
136
|
|
|
181
|
-
|
|
182
|
-
|
|
137
|
+
// Only allow POSTS in TLS mode.
|
|
138
|
+
// In dev mode, GET is allowed as well with query args.
|
|
139
|
+
let input = body;
|
|
140
|
+
if( method != "POST" ) {
|
|
141
|
+
if( ! ( method == "GET" && dev_mode ) ) {
|
|
142
|
+
W( "GET /rpc is disallowed in TLS mode" );
|
|
143
|
+
res.writeHead( 405 ); // Method Not Allowed
|
|
144
|
+
res.end();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
input = query;
|
|
148
|
+
}
|
|
183
149
|
|
|
150
|
+
// Set up callbacks
|
|
151
|
+
const done = ( error, data ) => {
|
|
152
|
+
res.writeHead( 200, {
|
|
153
|
+
"Content-Type": "application/json",
|
|
154
|
+
"Cache-Control": "no-store",
|
|
155
|
+
});
|
|
156
|
+
res.write( o2j( data ) );
|
|
157
|
+
res.end();
|
|
158
|
+
};
|
|
159
|
+
const okay = ( data ) => { done( null, data ); };
|
|
160
|
+
// XXX wrong
|
|
161
|
+
const fail = ( error, body ) => { done( error, body ); };
|
|
162
|
+
|
|
163
|
+
// Summon the rpc handler for the domain root.
|
|
164
|
+
rpc_handler( root, input, "REST", okay, fail );
|
|
165
|
+
};
|
|
166
|
+
}
|
|
184
167
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
168
|
+
// Handler for tlsd's own static files.
|
|
169
|
+
// This is so that "GET /rpc/rpc.js" can return the client-side code for
|
|
170
|
+
// sending WS RPC messages (similar to how socket.io works).
|
|
171
|
+
const rpc_static = serveStatic( __dirname + "/rpc_static" );
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
// Creates and returns a handler that checks for "/404" at root.
|
|
175
|
+
// If found, it redirects to it, otherwise it responds with 404.
|
|
176
|
+
function not_found( root ) {
|
|
177
|
+
return function( req, res, next ) {
|
|
178
|
+
// Can't just do a redirect here because if /404 doesn't exist, it will
|
|
179
|
+
// just go into a redirect loop. So test to see if the dir exists first.
|
|
180
|
+
let path = root + "/static/404";
|
|
181
|
+
is_dir( path, so => {
|
|
182
|
+
if( so ) {
|
|
183
|
+
let p404 = "/404/?original_path=" + encodeURIComponent( req.url );
|
|
184
|
+
res.writeHead( 302, { "Location": p404, } ); // redirect to path
|
|
197
185
|
} else {
|
|
198
|
-
|
|
186
|
+
res.writeHead( 404 );
|
|
199
187
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
188
|
+
res.end();
|
|
189
|
+
} );
|
|
190
|
+
}
|
|
191
|
+
}
|
|
203
192
|
|
|
193
|
+
// Create and return a connect app/function that implements
|
|
194
|
+
// default (basic) functionality.
|
|
195
|
+
function basic_handler( root ) {
|
|
196
|
+
const app = connect();
|
|
197
|
+
app.use( body_parser );
|
|
198
|
+
app.use( compression );
|
|
199
|
+
app.use( cors ); // allow requests from other domains
|
|
200
|
+
app.use( populate_query );
|
|
201
|
+
app.use( logger );
|
|
202
|
+
app.use( rpc_post( root ) );
|
|
203
|
+
app.use( rpc_static );
|
|
204
|
+
app.use( serveStatic( root + "/static" ) ); // static files for domain
|
|
205
|
+
app.use( not_found( root ) );
|
|
204
206
|
return app;
|
|
205
|
-
|
|
206
207
|
}
|
|
207
208
|
|
|
208
209
|
|
|
210
|
+
const cached_basic_handlers = {};
|
|
211
|
+
|
|
209
212
|
// Handle REST calls (as opposed to websocket messages)
|
|
210
|
-
|
|
213
|
+
function rest_handler( root, req, rsp ) {
|
|
211
214
|
|
|
212
215
|
I( req.headers[ "host" ] + ": " + req.method + " " + req.url );
|
|
213
216
|
D( "rest_handler root: " + root );
|
|
@@ -231,21 +234,31 @@ const rest_handler = function( root, req, rsp ) {
|
|
|
231
234
|
D( "Using custom REST handler loaded from "+root );
|
|
232
235
|
call( handler );
|
|
233
236
|
} catch( err ) {
|
|
234
|
-
//
|
|
235
|
-
|
|
237
|
+
// attempt to load custom handler threw an exception
|
|
238
|
+
|
|
239
|
+
let handler = cached_basic_handlers[ root ];
|
|
240
|
+
if( ! handler ) {
|
|
241
|
+
handler = basic_handler( root );
|
|
242
|
+
cached_basic_handlers[ root ] = handler;
|
|
243
|
+
}
|
|
244
|
+
|
|
236
245
|
D( "Using basic REST handler" );
|
|
237
246
|
call( handler );
|
|
238
247
|
}
|
|
239
248
|
};
|
|
240
249
|
|
|
241
250
|
|
|
251
|
+
// -----------------------
|
|
252
|
+
|
|
253
|
+
|
|
242
254
|
// tracked websocket connections
|
|
243
255
|
const ws_connections = {};
|
|
244
256
|
|
|
245
257
|
|
|
246
|
-
|
|
258
|
+
// Associate a websocket message handler (msg_handler) to a webserver instance (server)
|
|
259
|
+
function ws_attach( server, msg_handler ) {
|
|
247
260
|
|
|
248
|
-
const wsd = new websocket.server( { httpServer, autoAcceptConnections: false, } );
|
|
261
|
+
const wsd = new websocket.server( { httpServer: server, autoAcceptConnections: false, } );
|
|
249
262
|
|
|
250
263
|
wsd.on( "request", function( wsreq ) {
|
|
251
264
|
V( "WS: connection request from "+wsreq.remoteAddress+" "+wsreq.resource )
|
|
@@ -254,7 +267,7 @@ const ws_attach = function( httpServer, msg_handler ) {
|
|
|
254
267
|
|
|
255
268
|
const socket = wsreq.accept( null, wsreq.origin );
|
|
256
269
|
|
|
257
|
-
const name = "ws-
|
|
270
|
+
const name = "ws-conn-"+next_seq(); // XXX just use the websocket id
|
|
258
271
|
|
|
259
272
|
// send msg to connected client
|
|
260
273
|
const send = function( msg , cb ) {
|
|
@@ -316,84 +329,6 @@ const ws_attach = function( httpServer, msg_handler ) {
|
|
|
316
329
|
};
|
|
317
330
|
|
|
318
331
|
|
|
319
|
-
|
|
320
|
-
/*
|
|
321
|
-
const build_sass = function( path ) {
|
|
322
|
-
const sass = require( "sass" );
|
|
323
|
-
const result = sass.compile( path );
|
|
324
|
-
fs.writeFileSync( path + ".css", result.css, "utf8" );
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
const auto_builders = [
|
|
328
|
-
[ /\.(sass|scss)$/, build_sass ],
|
|
329
|
-
];
|
|
330
|
-
|
|
331
|
-
// Do auto-build processes (dev mode only)
|
|
332
|
-
const auto_build = function( paths ) {
|
|
333
|
-
|
|
334
|
-
for( let path of paths ) {
|
|
335
|
-
for( const bldr of auto_builders ) {
|
|
336
|
-
if( bldr[ 0 ].test( path ) ) {
|
|
337
|
-
bldr[ 1 ]( path );
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
// Engage the filesystem watcher (dev mode only)
|
|
347
|
-
const enable_fs_watch = function( root ) {
|
|
348
|
-
|
|
349
|
-
let paths_noted = {};
|
|
350
|
-
|
|
351
|
-
let hot_reload_tid = null;
|
|
352
|
-
let hot_reload_count = 0;
|
|
353
|
-
|
|
354
|
-
function hot_reload_tick() {
|
|
355
|
-
hot_reload_count -= 1; // reduce count by 1
|
|
356
|
-
if( hot_reload_count <= 0 ) {
|
|
357
|
-
// counter reached 0
|
|
358
|
-
clearInterval( hot_reload_tid ); // turn off the ticker
|
|
359
|
-
hot_reload_tid = null;
|
|
360
|
-
|
|
361
|
-
auto_build( Object.keys( paths_noted ) );
|
|
362
|
-
paths_noted = {};
|
|
363
|
-
|
|
364
|
-
// send RELOAD msg to all client that have an active ws connection
|
|
365
|
-
for( let conn of Object.values( ws_connections ) ) {
|
|
366
|
-
conn.send( { msg: "RELOAD" } ); // send RELOAD msg to browser
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
function note( evt, path ) {
|
|
372
|
-
// A change of some sort was seen
|
|
373
|
-
// Hundreds of these can happen very rapidly, so the timer stuff
|
|
374
|
-
// above is used to delay sending the RELOAD command until
|
|
375
|
-
// a second or so has passed without any more calls to this function
|
|
376
|
-
|
|
377
|
-
paths_noted[ path ] = evt; // XXX
|
|
378
|
-
//D( "noted fs change: [" + evt + "] " + path );
|
|
379
|
-
|
|
380
|
-
hot_reload_count = 5;
|
|
381
|
-
if( hot_reload_tid === null ) {
|
|
382
|
-
// ticker isn't running, so start it
|
|
383
|
-
hot_reload_tid = setInterval( hot_reload_tick, 200 );
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
// tell OS to start watching for any changes in root
|
|
389
|
-
fs.watch( root, { recursive: true, }, function( evt, path ) {
|
|
390
|
-
note( evt, root + "/" + path );
|
|
391
|
-
} );
|
|
392
|
-
|
|
393
|
-
};
|
|
394
|
-
*/
|
|
395
|
-
|
|
396
|
-
|
|
397
332
|
// -----------------------
|
|
398
333
|
|
|
399
334
|
const argv = process.argv;
|
|
@@ -415,12 +350,11 @@ if( argv.length == 2 ) {
|
|
|
415
350
|
maintainerEmail: MAINTAINER_EMAIL,
|
|
416
351
|
configDir: "./greenlock.d",
|
|
417
352
|
cluster: false,
|
|
418
|
-
//notify
|
|
419
353
|
} ).ready( glx => {
|
|
420
354
|
|
|
421
|
-
var
|
|
355
|
+
var server = glx.httpsServer();
|
|
422
356
|
|
|
423
|
-
ws_attach(
|
|
357
|
+
ws_attach( server, ( msg, conn, domain ) => {
|
|
424
358
|
const root = path.resolve( DOMAINS_ROOT + "/" + domain );
|
|
425
359
|
ws_msg_handler( root, msg );
|
|
426
360
|
} );
|
|
@@ -454,22 +388,17 @@ if( argv.length == 5 ) {
|
|
|
454
388
|
V( "SITE_ROOT: " + SITE_ROOT );
|
|
455
389
|
V( "PORT: " + PORT );
|
|
456
390
|
|
|
457
|
-
const
|
|
391
|
+
const server = http.createServer( ( req, res ) => {
|
|
458
392
|
rest_handler( SITE_ROOT, req, res );
|
|
459
393
|
} );
|
|
460
394
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
ws_attach( httpd, ( msg, conn, domain ) => {
|
|
465
|
-
ws_msg_handler( SITE_ROOT, msg );
|
|
466
|
-
} );
|
|
395
|
+
ws_attach( server, ( msg, conn, domain ) => {
|
|
396
|
+
ws_msg_handler( SITE_ROOT, msg );
|
|
397
|
+
} );
|
|
467
398
|
|
|
468
|
-
|
|
469
|
-
// enable_fs_watch( SITE_ROOT );
|
|
399
|
+
server.listen( toInt( PORT ), () => {
|
|
470
400
|
|
|
471
401
|
I( "Listening on " + PORT + " & serving from " + SITE_ROOT );
|
|
472
|
-
|
|
473
402
|
} );
|
|
474
403
|
|
|
475
404
|
} else {
|