aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRblSb <msrblsb@gmail.com>2024-08-15 08:29:24 +0300
committerRblSb <msrblsb@gmail.com>2024-08-15 08:33:17 +0300
commit4ac52a44ced3691581a1390bbdbdc0906074b3f3 (patch)
treedb18acc64e20d5837c0ef92787ccf8ab1eb6af2d
parent38cc0a1d9b4b146af7110c681389378fd26761fa (diff)
Add uuids for better reconection
Kick zombie users with same uuids. Minimal node version is 14.
-rw-r--r--README.md4
-rw-r--r--build/server.js98
-rw-r--r--package-lock.json3
-rw-r--r--package.json3
-rw-r--r--res/client.js8
-rw-r--r--src/Client.hx1
-rw-r--r--src/Types.hx1
-rw-r--r--src/client/ClientSettings.hx1
-rw-r--r--src/client/Main.hx8
-rw-r--r--src/server/Main.hx31
10 files changed, 113 insertions, 45 deletions
diff --git a/README.md b/README.md
index 6e7c30a..1266ed7 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ Default channel example: https://synctube.onrender.com/
### Setup
- Open `4200` port in your router settings (port is customizable)
-- `npm install ws` in this project folder ([NodeJS](https://nodejs.org) required)
+- `npm install ws` in this project folder ([NodeJS 14+](https://nodejs.org) required)
- Run `node build/server.js`
- Open showed "Local" link for yourself and send "Global" link to friends
@@ -34,7 +34,7 @@ As alternative, you can install Docker and run:
> docker run --rm -it -p 4200:4200 -v ${PWD}/user:/usr/src/app/user synctube
> ```
-or
+or
> ```shell
> docker compose up -d
diff --git a/build/server.js b/build/server.js
index 076051d..7279f04 100644
--- a/build/server.js
+++ b/build/server.js
@@ -523,7 +523,7 @@ JsonParser_$1.__name__ = true;
JsonParser_$1.__super__ = json2object_reader_BaseParser;
JsonParser_$1.prototype = $extend(json2object_reader_BaseParser.prototype,{
onIncorrectType: function(pos,variable) {
- this.errors.push(json2object_Error.IncorrectType(variable,"{ ?updatePlaylist : Null<{ videoList : Array<VideoItem> }>, ?updateClients : Null<{ clients : Array<ClientData> }>, type : WsEventType, ?togglePlaylistLock : Null<{ isOpen : Bool }>, ?toggleItemType : Null<{ pos : Int }>, ?skipVideo : Null<{ url : String }>, ?setTime : Null<{ time : Float }>, ?setRate : Null<{ rate : Float }>, ?setNextItem : Null<{ pos : Int }>, ?setLeader : Null<{ clientName : String }>, ?serverMessage : Null<{ textId : String }>, ?rewind : Null<{ time : Float }>, ?removeVideo : Null<{ url : String }>, ?playItem : Null<{ pos : Int }>, ?play : Null<{ time : Float }>, ?pause : Null<{ time : Float }>, ?message : Null<{ text : String, clientName : String }>, ?logout : Null<{ oldClientName : String, clients : Array<ClientData>, clientName : String }>, ?login : Null<{ ?passHash : Null<String>, ?isUnknownClient : Null<Bool>, ?clients : Null<Array<ClientData>>, clientName : String }>, ?kickClient : Null<{ name : String }>, ?getYoutubeVideoInfo : Null<{ url : String, ?response : Null<utils.YouTubeVideoInfo> }>, ?getTime : Null<{ time : Float, ?rate : Null<Float>, ?paused : Null<Bool> }>, ?dump : Null<{ data : String }>, ?connected : Null<{ videoList : Array<VideoItem>, itemPos : Int, isUnknownClient : Bool, isPlaylistOpen : Bool, history : Array<Message>, globalIp : String, config : Config, clients : Array<ClientData>, clientName : String }>, ?banClient : Null<{ time : Float, name : String }>, ?addVideo : Null<{ item : VideoItem, atEnd : Bool }> }",pos));
+ this.errors.push(json2object_Error.IncorrectType(variable,"{ ?updatePlaylist : Null<{ videoList : Array<VideoItem> }>, ?updateClients : Null<{ clients : Array<ClientData> }>, type : WsEventType, ?togglePlaylistLock : Null<{ isOpen : Bool }>, ?toggleItemType : Null<{ pos : Int }>, ?skipVideo : Null<{ url : String }>, ?setTime : Null<{ time : Float }>, ?setRate : Null<{ rate : Float }>, ?setNextItem : Null<{ pos : Int }>, ?setLeader : Null<{ clientName : String }>, ?serverMessage : Null<{ textId : String }>, ?rewind : Null<{ time : Float }>, ?removeVideo : Null<{ url : String }>, ?playItem : Null<{ pos : Int }>, ?play : Null<{ time : Float }>, ?pause : Null<{ time : Float }>, ?message : Null<{ text : String, clientName : String }>, ?logout : Null<{ oldClientName : String, clients : Array<ClientData>, clientName : String }>, ?login : Null<{ ?passHash : Null<String>, ?isUnknownClient : Null<Bool>, ?clients : Null<Array<ClientData>>, clientName : String }>, ?kickClient : Null<{ name : String }>, ?getYoutubeVideoInfo : Null<{ url : String, ?response : Null<utils.YouTubeVideoInfo> }>, ?getTime : Null<{ time : Float, ?rate : Null<Float>, ?paused : Null<Bool> }>, ?dump : Null<{ data : String }>, ?connected : Null<{ videoList : Array<VideoItem>, uuid : String, itemPos : Int, isUnknownClient : Bool, isPlaylistOpen : Bool, history : Array<Message>, globalIp : String, config : Config, clients : Array<ClientData>, clientName : String }>, ?banClient : Null<{ time : Float, name : String }>, ?addVideo : Null<{ item : VideoItem, atEnd : Bool }> }",pos));
json2object_reader_BaseParser.prototype.onIncorrectType.call(this,pos,variable);
}
,loadJsonNull: function(pos,variable) {
@@ -1862,7 +1862,7 @@ JsonParser_$7.__name__ = true;
JsonParser_$7.__super__ = json2object_reader_BaseParser;
JsonParser_$7.prototype = $extend(json2object_reader_BaseParser.prototype,{
onIncorrectType: function(pos,variable) {
- this.errors.push(json2object_Error.IncorrectType(variable,"{ videoList : Array<VideoItem>, itemPos : Int, isUnknownClient : Bool, isPlaylistOpen : Bool, history : Array<Message>, globalIp : String, config : Config, clients : Array<ClientData>, clientName : String }",pos));
+ this.errors.push(json2object_Error.IncorrectType(variable,"{ videoList : Array<VideoItem>, uuid : String, itemPos : Int, isUnknownClient : Bool, isPlaylistOpen : Bool, history : Array<Message>, globalIp : String, config : Config, clients : Array<ClientData>, clientName : String }",pos));
json2object_reader_BaseParser.prototype.onIncorrectType.call(this,pos,variable);
}
,loadJsonNull: function(pos,variable) {
@@ -1870,7 +1870,7 @@ JsonParser_$7.prototype = $extend(json2object_reader_BaseParser.prototype,{
}
,loadJsonObject: function(o,pos,variable) {
var assigned = new haxe_ds_StringMap();
- this.objectSetupAssign(assigned,["clientName","clients","config","globalIp","history","isPlaylistOpen","isUnknownClient","itemPos","videoList"],[false,false,false,false,false,false,false,false,false]);
+ this.objectSetupAssign(assigned,["clientName","clients","config","globalIp","history","isPlaylistOpen","isUnknownClient","itemPos","uuid","videoList"],[false,false,false,false,false,false,false,false,false,false]);
this.value = this.getAuto();
var _g = 0;
while(_g < o.length) {
@@ -1901,6 +1901,9 @@ JsonParser_$7.prototype = $extend(json2object_reader_BaseParser.prototype,{
case "itemPos":
this.value.itemPos = this.loadObjectField(($_=new JsonParser_$52(this.errors,this.putils,1),$bind($_,$_.loadJson)),field,"itemPos",assigned,this.value.itemPos,pos);
break;
+ case "uuid":
+ this.value.uuid = this.loadObjectField(($_=new JsonParser_$44(this.errors,this.putils,1),$bind($_,$_.loadJson)),field,"uuid",assigned,this.value.uuid,pos);
+ break;
case "videoList":
this.value.videoList = this.loadObjectField(($_=new JsonParser_$41(this.errors,this.putils,1),$bind($_,$_.loadJson)),field,"videoList",assigned,this.value.videoList,pos);
break;
@@ -1911,7 +1914,7 @@ JsonParser_$7.prototype = $extend(json2object_reader_BaseParser.prototype,{
this.objectErrors(assigned,pos);
}
,getAuto: function() {
- return { clientName : new JsonParser_$44([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), clients : new JsonParser_$49([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), config : new JsonParser_$81([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), globalIp : new JsonParser_$44([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), history : new JsonParser_$82([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), isPlaylistOpen : new JsonParser_$46([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), isUnknownClient : new JsonParser_$46([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), itemPos : new JsonParser_$52([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), videoList : new JsonParser_$41([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1)))};
+ return { clientName : new JsonParser_$44([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), clients : new JsonParser_$49([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), config : new JsonParser_$81([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), globalIp : new JsonParser_$44([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), history : new JsonParser_$82([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), isPlaylistOpen : new JsonParser_$46([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), isUnknownClient : new JsonParser_$46([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), itemPos : new JsonParser_$52([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), uuid : new JsonParser_$44([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1))), videoList : new JsonParser_$41([],this.putils,0).loadJson(new hxjsonast_Json(hxjsonast_JsonValue.JNull,new hxjsonast_Position("",0,1)))};
}
,__class__: JsonParser_$7
});
@@ -3870,6 +3873,7 @@ js_Boot.__isNativeObj = function(o) {
js_Boot.__resolveNativeClass = function(name) {
return $global[name];
};
+var js_node_Crypto = require("crypto");
var js_node_Fs = require("fs");
var js_node_Http = require("http");
var js_node_Https = require("https");
@@ -4578,7 +4582,7 @@ var server_Main = function(opts) {
preparePort = function() {
server_Utils.isPortFree(_gthis.port,function(isFree) {
if(!isFree && attempts > 0) {
- haxe_Log.trace("Warning: port " + _gthis.port + " is already in use. Changed to " + (_gthis.port + 1),{ fileName : "src/server/Main.hx", lineNumber : 122, className : "server.Main", methodName : "new"});
+ haxe_Log.trace("Warning: port " + _gthis.port + " is already in use. Changed to " + (_gthis.port + 1),{ fileName : "src/server/Main.hx", lineNumber : 124, className : "server.Main", methodName : "new"});
attempts -= 1;
_gthis.port++;
preparePort();
@@ -4596,13 +4600,13 @@ server_Main.main = function() {
server_Main.prototype = {
runServer: function() {
var _gthis = this;
- haxe_Log.trace("Local: http://" + this.localIp + ":" + this.port,{ fileName : "src/server/Main.hx", lineNumber : 135, className : "server.Main", methodName : "runServer"});
+ haxe_Log.trace("Local: http://" + this.localIp + ":" + this.port,{ fileName : "src/server/Main.hx", lineNumber : 137, className : "server.Main", methodName : "runServer"});
if(this.config.localNetworkOnly) {
- haxe_Log.trace("Global network is disabled in config",{ fileName : "src/server/Main.hx", lineNumber : 137, className : "server.Main", methodName : "runServer"});
+ haxe_Log.trace("Global network is disabled in config",{ fileName : "src/server/Main.hx", lineNumber : 139, className : "server.Main", methodName : "runServer"});
} else if(!this.isNoState) {
server_Utils.getGlobalIp(function(ip) {
_gthis.globalIp = ip;
- haxe_Log.trace("Global: http://" + _gthis.globalIp + ":" + _gthis.port,{ fileName : "src/server/Main.hx", lineNumber : 141, className : "server.Main", methodName : "runServer"});
+ haxe_Log.trace("Global: http://" + _gthis.globalIp + ":" + _gthis.port,{ fileName : "src/server/Main.hx", lineNumber : 143, className : "server.Main", methodName : "runServer"});
});
}
var dir = "" + this.rootDir + "/res";
@@ -4687,7 +4691,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 : 210, className : "server.Main", methodName : "getUserConfig"});
+ haxe_Log.trace("Warning: config field \"" + field + "\" is unknown",{ fileName : "src/server/Main.hx", lineNumber : 212, className : "server.Main", methodName : "getUserConfig"});
}
config[field] = Reflect.field(customConfig,field);
}
@@ -4698,14 +4702,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 : 216, className : "server.Main", methodName : "getUserConfig"});
+ haxe_Log.trace("Warning: emote name \"" + emote.name + "\" has copy",{ fileName : "src/server/Main.hx", lineNumber : 218, 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 : 220, className : "server.Main", methodName : "getUserConfig"});
+ haxe_Log.trace("Warning: emote url of name \"" + emote.name + "\" has copy",{ fileName : "src/server/Main.hx", lineNumber : 222, className : "server.Main", methodName : "getUserConfig"});
}
emoteCopies_h[emote.image] = true;
}
@@ -4743,7 +4747,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 : 259, className : "server.Main", methodName : "saveState"});
+ haxe_Log.trace("Saving state...",{ fileName : "src/server/Main.hx", lineNumber : 261, className : "server.Main", methodName : "saveState"});
var json = JSON.stringify(this.getCurrentState(),null,"\t");
js_node_Fs.writeFileSync(this.statePath,json);
this.writeUsers(this.userList);
@@ -4758,7 +4762,7 @@ server_Main.prototype = {
if(!sys_FileSystem.exists(this.statePath)) {
return;
}
- haxe_Log.trace("Loading state...",{ fileName : "src/server/Main.hx", lineNumber : 282, className : "server.Main", methodName : "loadState"});
+ haxe_Log.trace("Loading state...",{ fileName : "src/server/Main.hx", lineNumber : 284, className : "server.Main", methodName : "loadState"});
var state = JSON.parse(js_node_Fs.readFileSync(this.statePath,{ encoding : "utf8"}));
this.videoList.setItems(state.videoList);
this.videoList.isOpen = state.isPlaylistOpen;
@@ -4777,7 +4781,7 @@ server_Main.prototype = {
this.videoTimer.pause();
}
,logError: function(type,data) {
- haxe_Log.trace(type,{ fileName : "src/server/Main.hx", lineNumber : 300, className : "server.Main", methodName : "logError", customParams : [data]});
+ haxe_Log.trace(type,{ fileName : "src/server/Main.hx", lineNumber : 302, className : "server.Main", methodName : "logError", customParams : [data]});
var crashesFolder = "" + this.rootDir + "/user/crashes";
server_Utils.ensureDir(crashesFolder);
var name = DateTools.format(new Date(),"%Y-%m-%d_%H_%M_%S") + "-" + type;
@@ -4795,7 +4799,7 @@ server_Main.prototype = {
if(_gthis.clients.length == 0) {
return;
}
- haxe_Log.trace("Ping " + url,{ fileName : "src/server/Main.hx", lineNumber : 317, className : "server.Main", methodName : "initIntergationHandlers"});
+ haxe_Log.trace("Ping " + url,{ fileName : "src/server/Main.hx", lineNumber : 319, className : "server.Main", methodName : "initIntergationHandlers"});
js_node_Http.get(url,null,function(r) {
});
};
@@ -4815,13 +4819,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 : 340, className : "server.Main", methodName : "addAdmin"});
+ haxe_Log.trace("Admin " + name + " added.",{ fileName : "src/server/Main.hx", lineNumber : 342, 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 : 347, className : "server.Main", methodName : "removeAdmin"});
+ haxe_Log.trace("Admin " + name + " removed.",{ fileName : "src/server/Main.hx", lineNumber : 349, className : "server.Main", methodName : "removeAdmin"});
}
,replayLog: function(events) {
var _gthis = this;
@@ -4860,14 +4864,38 @@ server_Main.prototype = {
}
};
}
+ ,randomUuid: function() {
+ return js_node_Crypto.randomUUID();
+ }
+ ,getUrlUuid: function(link) {
+ try {
+ if(StringTools.startsWith(link,"/")) {
+ link = "http://127.0.0.1" + link;
+ }
+ return new js_node_url_URL(link).searchParams.get("uuid");
+ } catch( _g ) {
+ return null;
+ }
+ }
,onConnect: function(ws,req) {
var _gthis = this;
+ var uuid;
+ var tmp = this.getUrlUuid(req.url);
+ uuid = tmp != null ? tmp : this.randomUuid();
+ var oldClient = Lambda.find(this.clients,function(client) {
+ return client.uuid == uuid;
+ });
+ if(oldClient != null) {
+ this.send(oldClient,{ type : "KickClient"});
+ this.onMessage(oldClient,{ type : "Disconnected"},true);
+ }
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(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 385, className : "server.Main", methodName : "onConnect", customParams : ["" + name + " connected (" + ip + ")"]});
+ haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 408, className : "server.Main", methodName : "onConnect", customParams : ["" + name + " connected (" + ip + ")"]});
var isAdmin = this.config.localAdmins && req.socket.localAddress == ip;
var client = new Client(ws,req,id,name,0);
+ client.uuid = uuid;
client.setGroupFlag(ClientGroup.Admin,isAdmin);
this.clients.push(client);
ws.on("pong",function() {
@@ -4878,7 +4906,7 @@ server_Main.prototype = {
var obj = _gthis.wsEventParser.fromJson(data.toString());
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 : 401, className : "server.Main", methodName : "onConnect"});
+ haxe_Log.trace(errors,{ fileName : "src/server/Main.hx", lineNumber : 425, className : "server.Main", methodName : "onConnect"});
_gthis.serverMessage(client,errors);
return;
}
@@ -4957,20 +4985,20 @@ server_Main.prototype = {
return;
}
var name = data.banClient.name;
- var bannedClient = ClientTools.getByName(this.clients,name);
- if(bannedClient == null) {
+ var tmp = ClientTools.getByName(this.clients,name);
+ if(tmp == null) {
return;
}
- if(client.name == name || (bannedClient.group & 8) != 0) {
+ if(client.name == name || (tmp.group & 8) != 0) {
this.serverMessage(client,"adminsCannotBeBannedError");
return;
}
- var ip = this.clientIp(bannedClient.req);
+ var ip = this.clientIp(tmp.req);
HxOverrides.remove(this.userList.bans,Lambda.find(this.userList.bans,function(item) {
return item.ip == ip;
}));
if(data.banClient.time == 0) {
- bannedClient.setGroupFlag(ClientGroup.Banned,false);
+ tmp.setGroupFlag(ClientGroup.Banned,false);
this.sendClientList();
return;
}
@@ -4980,8 +5008,8 @@ server_Main.prototype = {
return;
}
this.userList.bans.push({ ip : ip, toDate : new Date(time)});
- this.checkBan(bannedClient);
- this.serverMessage(client,"" + bannedClient.name + " (" + ip + ") has been banned.");
+ this.checkBan(tmp);
+ this.serverMessage(client,"" + tmp.name + " (" + ip + ") has been banned.");
this.sendClientList();
break;
case "ClearChat":
@@ -5022,14 +5050,14 @@ server_Main.prototype = {
}
}
this.checkBan(client);
- this.send(client,{ type : "Connected", connected : { config : this.config, history : this.messages, isUnknownClient : true, clientName : client.name, clients : this.clientList(), videoList : this.videoList.items, isPlaylistOpen : this.videoList.isOpen, itemPos : this.videoList.pos, globalIp : this.globalIp}});
+ this.send(client,{ type : "Connected", connected : { uuid : client.uuid, config : this.config, history : this.messages, isUnknownClient : true, clientName : client.name, clients : this.clientList(), videoList : this.videoList.items, isPlaylistOpen : this.videoList.isOpen, itemPos : this.videoList.pos, globalIp : this.globalIp}});
this.sendClientListExcept(client);
break;
case "Disconnected":
if(!internal) {
return;
}
- haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 462, className : "server.Main", methodName : "onMessage", customParams : ["Client " + client.name + " disconnected"]});
+ haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 487, className : "server.Main", methodName : "onMessage", customParams : ["Client " + client.name + " disconnected"]});
server_Utils.sortedPush(this.freeIds,client.id);
HxOverrides.remove(this.clients,client);
this.sendClientList();
@@ -5131,15 +5159,15 @@ server_Main.prototype = {
return;
}
var name = data.kickClient.name;
- var kickedClient = ClientTools.getByName(this.clients,name);
- if(kickedClient == null) {
+ var tmp = ClientTools.getByName(this.clients,name);
+ if(tmp == null) {
return;
}
- if(client.name != name && (kickedClient.group & 8) != 0) {
+ if(client.name != name && (tmp.group & 8) != 0) {
this.serverMessage(client,"adminsCannotBeBannedError");
return;
}
- this.send(kickedClient,{ type : "KickClient"});
+ this.send(tmp,{ type : "KickClient"});
break;
case "Login":
var name = StringTools.trim(data.login.clientName);
@@ -5170,7 +5198,7 @@ server_Main.prototype = {
this.send(client,{ type : "LoginError"});
return;
}
- haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 552, className : "server.Main", methodName : "onMessage", customParams : ["Client " + client.name + " logged as " + name]});
+ haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 575, className : "server.Main", methodName : "onMessage", customParams : ["Client " + client.name + " logged as " + name]});
client.name = name;
client.setGroupFlag(ClientGroup.User,true);
this.checkBan(client);
@@ -5183,7 +5211,7 @@ server_Main.prototype = {
var oldName = client.name;
client.name = "Guest " + (this.clients.indexOf(client) + 1);
client.setGroupFlag(ClientGroup.User,false);
- haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 573, className : "server.Main", methodName : "onMessage", customParams : ["Client " + oldName + " logout to " + client.name]});
+ haxe_Log.trace(HxOverrides.dateStr(new Date()),{ fileName : "src/server/Main.hx", lineNumber : 596, className : "server.Main", methodName : "onMessage", customParams : ["Client " + oldName + " logout to " + client.name]});
this.send(client,{ type : data.type, logout : { oldClientName : oldName, clientName : client.name, clients : this.clientList()}});
this.sendClientListExcept(client);
break;
@@ -5498,7 +5526,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 : 985, className : "server.Main", methodName : "checkBan"});
+ haxe_Log.trace("" + client.name + " ban removed",{ fileName : "src/server/Main.hx", lineNumber : 1008, className : "server.Main", methodName : "checkBan"});
this.sendClientList();
}
break;
diff --git a/package-lock.json b/package-lock.json
index ee0a3fd..e229b84 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,9 @@
"license": "MIT",
"dependencies": {
"ws": "^8.17.1"
+ },
+ "engines": {
+ "node": ">=14.17.0"
}
},
"node_modules/ws": {
diff --git a/package.json b/package.json
index bc88ab9..808284b 100644
--- a/package.json
+++ b/package.json
@@ -18,5 +18,8 @@
"homepage": "https://github.com/RblSb/SyncTube#readme",
"dependencies": {
"ws": "^8.17.1"
+ },
+ "engines": {
+ "node": ">=14.17.0"
}
}
diff --git a/res/client.js b/res/client.js
index fc9bc48..df2a27d 100644
--- a/res/client.js
+++ b/res/client.js
@@ -1272,7 +1272,7 @@ var client_Main = function() {
if(this.host == "") {
this.host = "localhost";
}
- client_Settings.init({ version : 4, name : "", hash : "", isExtendedPlayer : false, playerSize : 1, chatSize : 300, synchThreshold : 2, isSwapped : false, isUserListHidden : true, latestLinks : [], latestSubs : [], hotkeysEnabled : true, showHintList : true},$bind(this,this.settingsPatcher));
+ client_Settings.init({ version : 4, uuid : null, name : "", hash : "", isExtendedPlayer : false, playerSize : 1, chatSize : 300, synchThreshold : 2, isSwapped : false, isUserListHidden : true, latestLinks : [], latestSubs : [], hotkeysEnabled : true, showHintList : true},$bind(this,this.settingsPatcher));
this.settings = client_Settings.read();
this.initListeners();
this.onTimeGet = new haxe_Timer(this.settings.synchThreshold * 1000);
@@ -1353,7 +1353,7 @@ client_Main.prototype = {
var port = $global.location.port;
var colonPort = port.length > 0 ? ":" + port : port;
var path = $global.location.pathname;
- this.ws = new WebSocket("" + protocol + "//" + this.host + colonPort + path);
+ this.ws = new WebSocket("" + protocol + "//" + this.host + colonPort + path + (this.settings.uuid == null ? "" : "?uuid=" + this.settings.uuid));
this.ws.onmessage = $bind(this,this.onMessage);
this.ws.onopen = function() {
var tmp = _gthis.disconnectNotification;
@@ -1609,7 +1609,7 @@ client_Main.prototype = {
var data = JSON.parse(e.data);
if(this.config != null && this.config.isVerbose) {
var t = data.type;
- haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 418, className : "client.Main", methodName : "onMessage", customParams : [Reflect.field(data,t.charAt(0).toLowerCase() + HxOverrides.substr(t,1,null))]});
+ haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 420, className : "client.Main", methodName : "onMessage", customParams : [Reflect.field(data,t.charAt(0).toLowerCase() + HxOverrides.substr(t,1,null))]});
}
client_JsApi.fireOnceEvent(data);
switch(data.type) {
@@ -1805,6 +1805,8 @@ client_Main.prototype = {
}
,onConnected: function(data) {
var connected = data.connected;
+ this.settings.uuid = connected.uuid;
+ client_Settings.write(this.settings);
this.globalIp = connected.globalIp;
this.setConfig(connected.config);
if(connected.isUnknownClient) {
diff --git a/src/Client.hx b/src/Client.hx
index 64d7e54..dc1a555 100644
--- a/src/Client.hx
+++ b/src/Client.hx
@@ -25,6 +25,7 @@ class Client {
public final ws:WebSocket;
public final req:IncomingMessage;
public final id:Int;
+ public var uuid:String;
public var isAlive = true;
#end
public var name:String;
diff --git a/src/Types.hx b/src/Types.hx
index a02b4a9..0e89b85 100644
--- a/src/Types.hx
+++ b/src/Types.hx
@@ -133,6 +133,7 @@ typedef FlashbackItem = {
typedef WsEvent = {
type:WsEventType,
?connected:{
+ uuid:String,
config:Config,
history:Array<Message>,
clients:Array<ClientData>,
diff --git a/src/client/ClientSettings.hx b/src/client/ClientSettings.hx
index 8403ff3..a004213 100644
--- a/src/client/ClientSettings.hx
+++ b/src/client/ClientSettings.hx
@@ -2,6 +2,7 @@ package client;
typedef ClientSettings = {
version:Int,
+ uuid:Null<String>,
name:String,
hash:String,
isExtendedPlayer:Bool,
diff --git a/src/client/Main.hx b/src/client/Main.hx
index 8cdd914..6d50b5e 100644
--- a/src/client/Main.hx
+++ b/src/client/Main.hx
@@ -61,6 +61,7 @@ class Main {
final defaults:ClientSettings = {
version: SETTINGS_VERSION,
+ uuid: null,
name: "",
hash: "",
isExtendedPlayer: false,
@@ -124,7 +125,8 @@ class Main {
final port = Browser.location.port;
final colonPort = port.length > 0 ? ':$port' : port;
final path = Browser.location.pathname;
- ws = new WebSocket('$protocol//$host$colonPort$path');
+ final query = settings.uuid == null ? "" : '?uuid=${settings.uuid}';
+ ws = new WebSocket('$protocol//$host$colonPort$path$query');
ws.onmessage = onMessage;
ws.onopen = () -> {
disconnectNotification?.stop();
@@ -585,6 +587,10 @@ class Main {
function onConnected(data:WsEvent):Void {
final connected = data.connected;
+
+ settings.uuid = connected.uuid;
+ Settings.write(settings);
+
globalIp = connected.globalIp;
setConfig(connected.config);
if (connected.isUnknownClient) {
diff --git a/src/server/Main.hx b/src/server/Main.hx
index 2b1aafa..a0b255e 100644
--- a/src/server/Main.hx
+++ b/src/server/Main.hx
@@ -13,8 +13,10 @@ import haxe.Timer;
import haxe.crypto.Sha256;
import js.Node.__dirname;
import js.Node.process;
+import js.node.Crypto;
import js.node.Http;
import js.node.http.IncomingMessage;
+import js.node.url.URL;
import js.npm.ws.Server as WSServer;
import js.npm.ws.WebSocket;
import json2object.ErrorUtils;
@@ -378,13 +380,35 @@ class Main {
}
}
+ function randomUuid():String {
+ return (Crypto : Dynamic).randomUUID();
+ }
+
+ function getUrlUuid(link:String):Null<String> {
+ try {
+ if (link.startsWith('/')) link = 'http://127.0.0.1$link';
+ final url = new URL(link);
+ return url.searchParams.get("uuid");
+ } catch (e) {
+ return null;
+ }
+ }
+
function onConnect(ws:WebSocket, req:IncomingMessage):Void {
+ final uuid = getUrlUuid(req.url) ?? randomUuid();
+ final oldClient = clients.find(client -> client.uuid == uuid);
+ if (oldClient != null) {
+ send(oldClient, {type: KickClient});
+ onMessage(oldClient, {type: Disconnected}, true);
+ }
+
final ip = clientIp(req);
final id = freeIds.length > 0 ? freeIds.shift() : clients.length;
final name = 'Guest ${id + 1}';
trace(Date.now().toString(), '$name connected ($ip)');
final isAdmin = config.localAdmins && req.socket.localAddress == ip;
final client = new Client(ws, req, id, name, 0);
+ client.uuid = uuid;
client.isAdmin = isAdmin;
clients.push(client);
ws.on("pong", () -> client.isAlive = true);
@@ -444,6 +468,7 @@ class Main {
send(client, {
type: Connected,
connected: {
+ uuid: client.uuid,
config: config,
history: messages,
isUnknownClient: true,
@@ -490,8 +515,7 @@ class Main {
case BanClient:
if (!checkPermission(client, BanClientPerm)) return;
final name = data.banClient.name;
- final bannedClient = clients.getByName(name);
- if (bannedClient == null) return;
+ final bannedClient = clients.getByName(name) ?? return;
if (client.name == name || bannedClient.isAdmin) {
serverMessage(client, "adminsCannotBeBannedError");
return;
@@ -517,8 +541,7 @@ class Main {
case KickClient:
if (!checkPermission(client, BanClientPerm)) return;
final name = data.kickClient.name;
- final kickedClient = clients.getByName(name);
- if (kickedClient == null) return;
+ final kickedClient = clients.getByName(name) ?? return;
if (client.name != name && kickedClient.isAdmin) {
serverMessage(client, "adminsCannotBeBannedError");
return;
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage