diff options
| -rw-r--r-- | .gitignore | 7 | ||||
| -rw-r--r-- | build/server.js | 43 | ||||
| -rw-r--r-- | src/server/HttpServer.hx | 14 | ||||
| -rw-r--r-- | src/server/Main.hx | 4 | ||||
| -rw-r--r-- | test/tests/TestServer.hx | 46 | ||||
| -rw-r--r-- | tests.hxml | 17 |
6 files changed, 104 insertions, 27 deletions
@@ -1,8 +1,9 @@ /node_modules
+/build/tests.js
/res/temp
-/user/config.json
+/user/crashes/
+/user/logs/
/user/state.json
+/user/config.json
/user/users.json
/user/res/
-/user/logs/
-/user/crashes/
diff --git a/build/server.js b/build/server.js index 773c774..e2ada6a 100644 --- a/build/server.js +++ b/build/server.js @@ -3613,7 +3613,7 @@ server_HttpServer.init = function(dir,customDir,allowLocalRequests) { server_HttpServer.allowLocalRequests = allowLocalRequests; }; server_HttpServer.serveFiles = function(req,res) { - var url = decodeURI(req.url); + var url = server_HttpServer.safeDecodeURI(req.url); if(url == "/") { url = "/index.html"; } @@ -3747,7 +3747,7 @@ server_HttpServer.proxyUrl = function(req,res) { server_HttpServer.proxyRequest = function(url,req,res,fn) { var url1; try { - url1 = new js_node_url_URL(decodeURI(url)); + url1 = new js_node_url_URL(server_HttpServer.safeDecodeURI(url)); } catch( _g ) { return null; } @@ -3782,6 +3782,14 @@ server_HttpServer.getMimeType = function(ext) { } return contentType; }; +server_HttpServer.safeDecodeURI = function(data) { + try { + data = decodeURI(data); + } catch( _g ) { + } + data = data.replace(server_HttpServer.ctrlCharacters.r,""); + return data; +}; var server_Logger = function(folder,maxCount,verbose) { this.matchFileFormat = new EReg("[0-9_-]+\\.json$",""); this.logs = []; @@ -3931,7 +3939,7 @@ server_Main.prototype = { }); this.wss = new js_npm_ws_Server({ server : server}); this.wss.on("connection",$bind(this,this.onConnect)); - server.listen(this.port); + server.listen(this.port,$bind(this,this.onServerInited)); new haxe_Timer(25000).run = function() { var _g = 0; var _g1 = _gthis.clients; @@ -3947,6 +3955,8 @@ server_Main.prototype = { } }; } + ,onServerInited: function() { + } ,exit: function() { this.saveState(); this.logger.saveLog(); @@ -3998,7 +4008,7 @@ server_Main.prototype = { var field = _g1[_g]; ++_g; if(Reflect.field(config,field) == null) { - haxe_Log.trace("Warning: config field \"" + field + "\" is unknown",{ fileName : "src/server/Main.hx", lineNumber : 180, className : "server.Main", methodName : "getUserConfig"}); + haxe_Log.trace("Warning: config field \"" + field + "\" is unknown",{ fileName : "src/server/Main.hx", lineNumber : 182, className : "server.Main", methodName : "getUserConfig"}); } config[field] = Reflect.field(customConfig,field); } @@ -4009,14 +4019,14 @@ server_Main.prototype = { var emote = _g1[_g]; ++_g; if(emoteCopies_h[emote.name]) { - haxe_Log.trace("Warning: emote name \"" + emote.name + "\" has copy",{ fileName : "src/server/Main.hx", lineNumber : 186, className : "server.Main", methodName : "getUserConfig"}); + haxe_Log.trace("Warning: emote name \"" + emote.name + "\" has copy",{ fileName : "src/server/Main.hx", lineNumber : 188, className : "server.Main", methodName : "getUserConfig"}); } emoteCopies_h[emote.name] = true; if(!this.verbose) { continue; } if(emoteCopies_h[emote.image]) { - haxe_Log.trace("Warning: emote url of name \"" + emote.name + "\" has copy",{ fileName : "src/server/Main.hx", lineNumber : 190, className : "server.Main", methodName : "getUserConfig"}); + haxe_Log.trace("Warning: emote url of name \"" + emote.name + "\" has copy",{ fileName : "src/server/Main.hx", lineNumber : 192, className : "server.Main", methodName : "getUserConfig"}); } emoteCopies_h[emote.image] = true; } @@ -4058,7 +4068,7 @@ server_Main.prototype = { js_node_Fs.writeFileSync("" + folder + "/users.json",JSON.stringify({ admins : users1, bans : _g, salt : users.salt},null,"\t")); } ,saveState: function() { - haxe_Log.trace("Saving state...",{ fileName : "src/server/Main.hx", lineNumber : 229, className : "server.Main", methodName : "saveState"}); + haxe_Log.trace("Saving state...",{ fileName : "src/server/Main.hx", lineNumber : 231, className : "server.Main", methodName : "saveState"}); var json = JSON.stringify({ videoList : this.videoList, isPlaylistOpen : this.isPlaylistOpen, itemPos : this.itemPos, messages : this.messages, timer : { time : this.videoTimer.getTime(), paused : this.videoTimer.isPaused()}},null,"\t"); js_node_Fs.writeFileSync(this.statePath,json); this.writeUsers(this.userList); @@ -4067,7 +4077,7 @@ server_Main.prototype = { if(!sys_FileSystem.exists(this.statePath)) { return; } - haxe_Log.trace("Loading state...",{ fileName : "src/server/Main.hx", lineNumber : 247, className : "server.Main", methodName : "loadState"}); + haxe_Log.trace("Loading state...",{ fileName : "src/server/Main.hx", lineNumber : 249, className : "server.Main", methodName : "loadState"}); var data = JSON.parse(js_node_Fs.readFileSync(this.statePath,{ encoding : "utf8"})); this.videoList.length = 0; this.messages.length = 0; @@ -4084,7 +4094,7 @@ server_Main.prototype = { this.videoTimer.pause(); } ,logError: function(type,data) { - haxe_Log.trace(type,{ fileName : "src/server/Main.hx", lineNumber : 265, className : "server.Main", methodName : "logError", customParams : [data]}); + haxe_Log.trace(type,{ fileName : "src/server/Main.hx", lineNumber : 267, className : "server.Main", methodName : "logError", customParams : [data]}); var crashesFolder = "" + this.rootDir + "/user/crashes"; server_Utils.ensureDir(crashesFolder); js_node_Fs.writeFileSync("" + crashesFolder + "/" + (DateTools.format(new Date(),"%Y-%m-%d_%H_%M_%S") + "-" + type) + ".json",JSON.stringify(data,null,"\t")); @@ -4101,7 +4111,7 @@ server_Main.prototype = { if(_gthis.clients.length == 0) { return; } - haxe_Log.trace("Ping " + url,{ fileName : "src/server/Main.hx", lineNumber : 282, className : "server.Main", methodName : "initIntergationHandlers"}); + haxe_Log.trace("Ping " + url,{ fileName : "src/server/Main.hx", lineNumber : 284, className : "server.Main", methodName : "initIntergationHandlers"}); js_node_Http.get(url,null,function(r) { }); }; @@ -4122,13 +4132,13 @@ server_Main.prototype = { password += this.config.salt; var hash = haxe_crypto_Sha256.encode(password); this.userList.admins.push({ name : name, hash : hash}); - haxe_Log.trace("Admin " + name + " added.",{ fileName : "src/server/Main.hx", lineNumber : 306, className : "server.Main", methodName : "addAdmin"}); + haxe_Log.trace("Admin " + name + " added.",{ fileName : "src/server/Main.hx", lineNumber : 308, className : "server.Main", methodName : "addAdmin"}); } ,removeAdmin: function(name) { HxOverrides.remove(this.userList.admins,Lambda.find(this.userList.admins,function(item) { return item.name == name; })); - haxe_Log.trace("Admin " + name + " removed.",{ fileName : "src/server/Main.hx", lineNumber : 313, className : "server.Main", methodName : "removeAdmin"}); + haxe_Log.trace("Admin " + name + " removed.",{ fileName : "src/server/Main.hx", lineNumber : 315, className : "server.Main", methodName : "removeAdmin"}); } ,replayLog: function(events) { var _gthis = this; @@ -4172,7 +4182,7 @@ server_Main.prototype = { var ip = this.clientIp(req); var id = this.freeIds.length > 0 ? this.freeIds.shift() : this.clients.length; var name = "Guest " + (id + 1); - haxe_Log.trace("" + name + " connected (" + ip + ")",{ fileName : "src/server/Main.hx", lineNumber : 351, className : "server.Main", methodName : "onConnect"}); + haxe_Log.trace("" + name + " connected (" + ip + ")",{ fileName : "src/server/Main.hx", lineNumber : 353, className : "server.Main", methodName : "onConnect"}); var client = new Client(ws,req,id,name,0); client.setGroupFlag(ClientGroup.Admin,this.config.localAdmins && req.socket.localAddress == ip); this.clients.push(client); @@ -4184,7 +4194,7 @@ server_Main.prototype = { var obj = _gthis.wsEventParser.fromJson(data); if(_gthis.wsEventParser.errors.length > 0 || _gthis.noTypeObj(obj)) { var errors = "" + ("Wrong request for type \"" + obj.type + "\":") + "\n" + json2object_ErrorUtils.convertErrorArray(_gthis.wsEventParser.errors); - haxe_Log.trace(errors,{ fileName : "src/server/Main.hx", lineNumber : 367, className : "server.Main", methodName : "onConnect"}); + haxe_Log.trace(errors,{ fileName : "src/server/Main.hx", lineNumber : 369, className : "server.Main", methodName : "onConnect"}); _gthis.serverMessage(client,errors); return; } @@ -4320,7 +4330,7 @@ server_Main.prototype = { if(!internal) { return; } - haxe_Log.trace("Client " + client.name + " disconnected",{ fileName : "src/server/Main.hx", lineNumber : 426, className : "server.Main", methodName : "onMessage"}); + haxe_Log.trace("Client " + client.name + " disconnected",{ fileName : "src/server/Main.hx", lineNumber : 428, className : "server.Main", methodName : "onMessage"}); server_Utils.sortedPush(this.freeIds,client.id); HxOverrides.remove(this.clients,client); this.sendClientList(); @@ -4724,7 +4734,7 @@ server_Main.prototype = { client.setGroupFlag(ClientGroup.Banned,!isOutdated); if(isOutdated) { HxOverrides.remove(this.userList.bans,ban); - haxe_Log.trace("" + client.name + " ban removed",{ fileName : "src/server/Main.hx", lineNumber : 879, className : "server.Main", methodName : "checkBan"}); + haxe_Log.trace("" + client.name + " ban removed",{ fileName : "src/server/Main.hx", lineNumber : 881, className : "server.Main", methodName : "checkBan"}); this.sendClientList(); } break; @@ -5061,5 +5071,6 @@ server_HttpServer.allowedLocalFiles = new haxe_ds_StringMap(); server_HttpServer.allowLocalRequests = false; server_HttpServer.matchLang = new EReg("^[A-z]+",""); server_HttpServer.matchVarString = new EReg("\\${([A-z_]+)}","g"); +server_HttpServer.ctrlCharacters = new EReg("[\\u0000-\\u001F\\u007F-\\u009F\\u2000-\\u200D\\uFEFF]","g"); server_Main.main(); })(typeof window != "undefined" ? window : typeof global != "undefined" ? global : typeof self != "undefined" ? self : this); diff --git a/src/server/HttpServer.hx b/src/server/HttpServer.hx index c4853ee..7f257a4 100644 --- a/src/server/HttpServer.hx +++ b/src/server/HttpServer.hx @@ -50,7 +50,7 @@ class HttpServer { } public static function serveFiles(req:IncomingMessage, res:ServerResponse):Void { - var url = decodeURI(req.url); + var url = safeDecodeURI(req.url); if (url == "/") url = "/index.html"; var filePath = dir + url; final ext = Path.extension(filePath).toLowerCase(); @@ -183,7 +183,7 @@ class HttpServer { fn:(req:IncomingMessage) -> Bool ):Null<ClientRequest> { final url = try { - new URL(decodeURI(url)); + new URL(safeDecodeURI(url)); } catch (e) return null; if (url.host == req.headers["host"]) return null; final options = { @@ -216,6 +216,16 @@ class HttpServer { return contentType; } + static final ctrlCharacters = ~/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/g; + + static function safeDecodeURI(data:String):String { + try { + data = decodeURI(data); + } catch (err) {} + data = ctrlCharacters.replace(data, ""); + return data; + } + static inline function decodeURI(data:String):String { return js.Syntax.code("decodeURI({0})", data); } diff --git a/src/server/Main.hx b/src/server/Main.hx index b038f01..49ac025 100644 --- a/src/server/Main.hx +++ b/src/server/Main.hx @@ -123,7 +123,7 @@ class Main { }); wss = new WSServer({server: server}); wss.on("connection", onConnect); - server.listen(port); + server.listen(port, onServerInited); new Timer(25000).run = () -> { for (client in clients) { @@ -137,6 +137,8 @@ class Main { }; } + dynamic function onServerInited():Void {}; + public function exit():Void { saveState(); logger.saveLog(); diff --git a/test/tests/TestServer.hx b/test/tests/TestServer.hx new file mode 100644 index 0000000..4fcbb2e --- /dev/null +++ b/test/tests/TestServer.hx @@ -0,0 +1,46 @@ +package test.tests; + +import js.node.Http; +import server.Main; +import utest.Assert; +import utest.Async; +import utest.Test; + +@:access(server) +class TestServer extends Test { + @:timeout(500) + function testBadRequests(async:Async) { + final server = new Main(); + server.onServerInited = () -> { + final url = 'http://${server.localIp}:${server.port}'; + request('$url/你好,世界!@$^&*)_+-=', data -> { + Assert.equals("File 你好,世界!@$^&*)_+-= not found.", data); + }); + request('$url/Привет%00мир!', data -> { + Assert.equals("File Приветмир! not found.", data); + }); + request('$url/Ы%ы%00ы!', data -> { + Assert.equals("File %D0%AB%%D1%8B%00%D1%8B! not found.", data); + }); + request('$url/video/skins/default.php?dir_inc=/etc/passwd%00', data -> { + Assert.equals("File video/skins/default.php?dir_inc=/etc/passwd not found.", data); + }); + request('$url/%20', data -> { + Assert.equals("File not found.", data); + }); + request('$url/build/../../server.js', data -> { + Assert.equals("File server.js not found.", data); + async.done(); + }); + } + } + + function request(url:String, onComplete:(data:String) -> Void):Void { + Http.get(url, r -> { + r.setEncoding("utf8"); + final data = new StringBuf(); + r.on("data", chunk -> data.add(chunk)); + r.on("end", _ -> onComplete(data.toString())); + }).on("error", e -> trace(e)); + } +} @@ -1,6 +1,13 @@ --cp src --cp test +--library hxnodejs +--library hxnodejs-ws +--library json2object +# Client libs for completion +--library youtubeIFramePlayer:git:https://github.com/okawa-h/youtubeIFramePlayer-externs.git +--library hls.js-extern:git:https://github.com/grosmar/hls.js-haxe-extern.git +--library utest +--class-path src +--class-path test --main Main --lib utest ---interp -#-D test=9133 +# -D UTEST_PATTERN=testMain +--js build/tests.js +--cmd node build/tests.js |
