Advanced TCP Chat Room in Python

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] what is going on guys welcome to this tutorial in today's video we're going to build an advanced tcp chat room one of the most highly requested projects on this channel here because of the last video here we have the simple tcp chatroom and python tutorial one of the most popular videos on this channel and at the end of it i also said that i'm going to make a second part including kicking and banning features and maybe an admin role if this video um is popular and if you guys want it and a lot of you guys wrote in the comments please make a second part including kicking and banning so this is what we're going to do today we're going to take the code from this video so if you haven't watched it yet make sure you watch this video or you just have to copy the code then uh it's a very simple tutorial we had just a server multiple clients connecting to that server and chatting in uh in this server room and today we're going to add kicking banning and an admin role so make sure you have watched this video we have the code because we're going to just copy this code and build on top of it so now before we get right into it let me show you what we're going to end up with we're going to have a server here server is listening and we can have multiple clients connecting to that server so here we have the client one and we can choose a nickname here for example we can call it i don't know neural and we can see nickname of the client is neural we connect it to the server and now i can start writing messages hey what's up and so on but nobody is here to read those messages so what we're going to do is we're going to open up a second client [Music] um and now we can connect with it let's say it's just youtube and then we have youtube is also connected to the server we can see youtube join the chat so neural got the message that youtube joined the chat this is what we had already now i can also go ahead and say hey all that we had this in the last video already and now i can try to go ahead and say slash kick youtube for example and you can see commands can only be executed by the admin i can still write and continue nothing no exception was thrown here but i cannot just kick other other guys from this server here so i can try the same thing here slash kick neural commands can only be executed by the admin so what we can do here now is we can go ahead and connect with an admin account so i can just open up the client here let me just rearrange these windows here and i can now say i'm admin and then i need to enter a password for the admin so the right admin password or actually let's try the wrong one i will just enter something here it says connection refused wrong password and if i click enter the window closes now if i go ahead oh i opened up second server client there you go now if i go ahead and save admin and the password is admin pass we can see connected to the server and now i can also go ahead and say kick neural and what you can see now is neural was kicked by an admin here you were kicked by an admin an error occurred so i can press enter here and the window closes i can still write messages as an admin here and now the interesting thing is that i can still connect this neural because i was just kicked i was not banned and what i can now do is i can go ahead and say okay neural is still here or again here i can say hey i can say hey again and then i can just go ahead and say slash ben neural and again it says neuro was kicked by an admin you were kicked by admin error occurred and now if i try to connect again as neural you're going to see connection refuse because of ban however i can still enter it as another username so that's just a username connected to the server and i can continue to do that so this is what we're going to build today and we can get into the code right now let us quickly recap what we already have here we have a server file and a client file two python scripts and in the server we basically just listen at localhost we have this connection here we have two empty lists in the beginning clients nicknames which essentially the same we have klein and its respective nickname then we have the broadcast message that just sends a message to all the clients connected we have the receive method down here where we essentially just accept a connection print that we're connected we request the nickname by sending this keyword here um we encode it of course we then receive the nickname from the client hopefully then append our client and nickname to the list then print that the client is connected broadcast it that decline join the chat and then also tell the client you're connected to the server and essentially what you do then is you start a threading a thread using this handle function here and the handle function just handles the connection as the name already says we're receiving messages from the client whatever we receive we broadcast if there's any uh problem if we get any exception we essentially just remove the client from the list we remove the nickname we disconnect the client and we essentially terminate this handle function the threat that is responsible for handling this connection then on the client side we have first of all we ask for a nickname this is all happening on the client not the server asking the client but just the client deciding what the nickname will be then we're connecting to the server we're receiving messages from the server um if the message is nick so if the server is requesting a nickname we sent the nickname that we chose otherwise we just um go ahead and print the message and that's essentially it and then we have also a writing function here which just gets new user input all the time and sends it to the server encoded and then we have two threads running that receive messages from the server and send messages to the server so the first thing we're going to do here is we're going to check for the password when someone connects with the name admin because usually when you connect to the server you're not asked for a password you can just choose a nickname and you're connected and you can chat but if you connect with the name admin you have special privileges so you need a password in order to get those privileges so once someone connects with the name admin we're going to request a password and if the password is the correct password we're going to grant access and uh give him the privileges but if the password is wrong we're just going to disconnect so what we're going to do here in the receive method is we're going to say um if the nickname that we received right now because here remember we say nick as a keyword for a client to know send your nickname then we receive the nickname and if this nickname equals admin we're going to ask for another keyword so we're going to say client.send and we're going to send a next uh the next signal like nick uh indicating that we're requesting a password so we're going to say pass for example you can choose whatever you want you can say pvd you can say hello whatever it is but i'm going to just say pass and we're going to encode this into ascii again we're just going to send this to the client the same way that the client processes nick we're going to make it process pass so that it knows it has to send a password so hopefully the client will handle this request and we're going to get the password so we're going to say password equals client.receive 1024 bytes i'm going to decode the message and then we have the password now the next step is to check if this password is the right one so what we're going to do is we're going to say if the password equals or actually we're going to to uh want to check if the password is wrong because then we're going to disconnect and if it's right we're just going to proceed with this code here so if the password is not the right one then we're going to break we're going to uh refuse the connection close the connection and uh continue to listen for new connections but um if the password is right we're just going to continue now the thing is that in an actual project you would never just check for a password like this you would never just say if password is in some string you would always have a hash and a database so you would go ahead take the input from the user hash the the input from the user and compare it to the hash in the database because you know if the password is one two three you're going to hash123 in the database as the password and then when the user enters one two three you're going to hash his input and compare it to the input to the hash in the database and if it's the right password you're going or if it's the same hash you're going to grant access now in this case we're not going to make it that complicated because the focus here is on building the chat not building a login system that works i mean it works but that's super secure something so you can go ahead and work with files or encrypt or hash or whatever use databases uh we're just going to use a string here because it's not too complicated to set up a login system that's a little bit more secure than that however we're going to say if password is not admin pass that's just the password that we're going to choose for the admin if that is not the case we're going to say client.send and we're going to send another keyword that the client has to interpret which is refuse this is just another code we send we're going to send refuse encoded of course uh when the client receives that keyword uh it knows that the connection was refused because the password was wrong so we're going to say client dot close and the connection to the client is now closed and now we are going to use the continue keyword now we're not going to break it because remember we have one thread on the server running receiving new connections if we break the loop we're not going to be able to receive any more connections if we continue the loop we're just going to skip this attempt of connection so if the admin connects with the wrong password we're going to skip it so we're not going to execute this code here we're not going to connect to this admin client we're not going to add it to the clients list to the nicknames list but at the same time we're not going to stop the while uh the while true loop here we're just going to skip this one iteration so that new clients can connect and this is what we can do or what we are going to do on the server side so now let's go ahead and look at all of this from the client-side perspective the first thing we're going to do is when we enter a nickname we're going to check if this nickname is admin why because even though we haven't talked to the server yet we know that if the nickname is admin we will be asked for a password and if we know that it's more intelligent intelligent to prepare the password upfront instead of processing user input and asking for the password while talking to the server because that can lead to issues so the first thing that we're going to do is we're going to say if the nickname here is admin i know that i will need a password so i'm going to ask the user the client uh upfront what the password is now the actual checking if the password is correct or not will happen server-side because otherwise the client could just determine uh i'm going to use whatever password i want and i can connect as an admin uh this would lead to problems of course so the password processing is on the server side but we're still going to ask for the password here so if the nickname is admin we're going to say password equals and we're going to say input enter password for admin this is what we're going to do upfront already and then the next thing that we need to do is in the uh receive method we're going to receive the message nick we're going to send the nickname and after that we're going to receive the next message from the server depending on the nickname we just sent and the next message is just going to be the client receiving 1024 bytes decoding those bytes and then what we're going to check for is what this message actually is now if in in this scenario right now is uh if the nickname is um admin will always get the pass keyword if it's an ordinary nickname we're not going to get uh any keyword at all but later on if the uh keyword is banned for example because uh the username we used was uh is on the banned list we're going to get another keyword so we're going to use an if statement here is the next message here that we get is actually pass uh if this is the case we're just going to say okay client dot oh sorry i need a comparison operator here client dot send and we're going to send a password and code it using ascii of course and then we can check uh if the password was correct or not so we're going to say if um if client dot receive 1024 bytes decoded ascii if the next thing that we receive is the refuse keyword so the keyword that we sent when the password is not correct so we're going to say if this here is refuse we're just going to say print connection was refused wrong password and of course we're going to uh stop the thread here now for this we're going to enter uh or not enter we're going to create a new variable here we're going to say stop thread and we're going to say it's false but once we get a refuse connection we're just going to say um that the stop threat is going to be set to true now first of all we're going to make it global so in the beginning after the wild true statement we're going to say global stop threat and we're going to say if stop threat is true then we're just going to break the loop in the beginning not here but in the beginning in the next iteration we're not going to allow for this um so this is actually how you process it you ask for the nickname or you get asked for the nickname you send the nickname then if uh the server requests the pass so the password we're going to send a password and if the password was wrong we're going to say connection with refused wrong password stop thread equals true uh and if it was not wrong we're not going to do anything we're just going to proceed because obviously the connection was established everything's all right and i'm now connected with the nickname admin i don't need to do anything additional here because i'm actually connected as uh like an ordinary user just using the name admin that that is the only thing we're going to check so the next thing that we're going to do is we're going to manipulate the right method so that we can execute commands at least as an admin so uh the first thing we're going to do here though is we're going to add an if statement if stop thread equals true we're going to just break the loop here this is important because here uh if i if the server refuses the connection we say stop thread equals true if we were just to break the loop we would break this while true loop here the receive loop but the right loop would still be continuing so the whole script would be continuing since we have two threads running here so if we really want to terminate the script we're going to set this to true and we're going to check for it here and otherwise uh and if it's true we're going to break and we're going to check here and if it's true we're going to break so we're breaking both loops here um just a minor detail here now what we're going to do is we're going to create the message the way we did before and now we're going to check if this message starts with a slash kick or actually with a slash at all because slash will be the command uh the command symbol that we're going to give here or we're going to process here so we're going to say if the message and we're now going to cut off the username the colon and the space here so this here is going to be uh cut out of this message string so we're going to say uh we're going to skip the length of the nickname characters because if you have user as a nickname for letters you need to skip four letters one for the colon and one for the space so it totals six letters until you get to the actual command so what we're going to do is we're always going to take the length of the nickname and then we're going to add two more characters because we need to process or we need to cut off the colon and the space as well um and then we're going to check if this thing that comes afterwards starts with a slash so just for an example uh if i have something like username colon slash kick or slash whatever any command actually we're going to skip user name which is one two three four five six seven eight characters plus two which is colon and space we're going to actually ignore this and we're left with a slash whatever and what we're checking now is if this string the resulting string starts with a sl with a slash uh if this is the case we're going to know that we're trying to execute a command so this is what we check for and the next check is if the nickname is actually admin because otherwise there's no point in executing something because you don't have the permissions so i'm going to say if the nickname is admin we're going to say um whatever i'm just going to do a pass right now and otherwise we're going to print that the commands can only be executed by the admin so we're not allowed to do anything here now if the nickname is admin though we can send some signals to the server that the server will then process um and the signals are going to be kick or ban so in this video we're just going to do kicking and banning you can add multiple features as well here uh multiple additional features of course so what we're going to do is we're going to take the message the next message that we're going to say uh the message that we already uh created using this slash sign and if this message after the slash sign contains a kick and a username after that we're going to send a kick signal to the server and the username to be kicked so what we're exactly going to write here is we're going to say if the message and we're going again to say length nickname plus 2. if this message here starts with not only slash but with slash kick we're going to go ahead and send a message to the client so we're going to say client dot uh to the server sorry client.send and we're going to create an f string here and the symbol or the signal that we're going to send here is just a capital kick a large kick then one white space and then we're going to send the username so we're going to send uh what's after the kick now what is after the kick is actually just again uh cutting off what's before uh before the username so we're going to cut off um the length of the nickname then two additional characters and actually then after that five additional characters because we have slash uh or actually six sorry we have slash k i c k and a space these are six characters so we need to skip the username the colon the space and then the slash kick and then we get to the username that we're trying to kick so everything from here on is the username that we're trying to kick so what we sent to the server is actually just a capital kick and the username that we want to kick if there is a valid username after that and of course we're going to encode uh actually inside of there to encode this into ascii again so this is the kick message and we can do the same thing for the band so if it's not kick but banned so if actually let's just copy all of this here so we're going to replace that else if message length plus two starts with slash band but this time we don't skip six characters but five because slash band is one less character than slash kick uh and we do the same thing and of course we don't send kick but ban capital b-a-n so this is what we're going to do we're going to create a message if this message starts with slash we're going to uh know it's a command we're going to check if we are permitted to do so by being the admin actually um if this is the case we're just going to check if it's a slash kick or slash ban uh if it's something else we're just going to ignore it um and if it is a slash kick we're just going to send kik and the username or ban in the username if it's banned to the server and then we're going to process this on the server side now if we don't have a slash we're just going to say um else we're just going to send a normal message if it's a slash kick we're not going to broadcast the slash kick to all the other clients we're just going to process it without sending it to the server we're just going to send these code words here and if it's an ordinary message we're just going to send it to the server so now we're going to take a look at the server side and how we're going to process all this now in the handle function that we have right now that's running in a thread constantly uh currently we're just receiving the message and broadcasting the message now we're going to add uh an if statement that checks for what kind of message this is if it's a banned message or a kick message or an ordinary message so uh the only difficulty here is that we cannot or for some reason i get a lot of errors when i try to broadcast a message and uh use if statements onto it all the time i get stuck in some kind of loops um so the solution here is to just add an additional variable that's actually just the same so we're going to say msg which is also just message msg equals message equals client.receive so it's essentially just the same thing but the one thing is for broadcasting and the other thing is for checking if uh we have a kick or a banned message so what we're going to do first is we're going to say okay if message msg uh decode ascii if this thing here starts with kick starts with kick we know that this will be about kicking otherwise alif if message.decode come on ascii starts with ben we're just going to say okay ban and then if it's none of those two things we're just going to broadcast the message because if it's not kick if it's not ban uh it's going to uh to be a ordinary message that we can broadcast also notice that you cannot just go ahead and um as a client send k i c key and expect uh it to be processed because the message that you're creating as a client it's not just a message but it's also your nickname in front of it so unless you cut all this away which you cannot do while typing um you're not going to send a kick or ban signal so only the client can send it directly with this line of code here if you just write capital kick you're not going to get any signal or any response from the server other than you know your name and then kick as a message so no functionality at all so what we're going to do if there is a kick if um the message starts with a kick is we're going to say the name to kick we're going to save it the name to kick is essentially just a message decoded again and uh from this message we're just going to cut off the first five characters k i c key uh k i c k and uh a white space so the first five message uh letters are irrelevant and then we have the nickname the name to kick then the same thing goes for the band so name to ban come on name to ban msg decode ascii but this time of course four characters again since we have three letters instead of four and then what we do is we will call a method called kick user which we haven't defined yet we're going to define it in a second we're just going to kick the user essentially and uh i'm going to kick the name to kick and for the band we're going to do the same thing so when we ban someone we're going to sorry kick kick user name to ban this time and after we've kicked the user because of the ban we're also going to add him to the ban list because if you ask if you just kick the user the user can return to your server but if you ban the user the user should not be able to go back to the server because or at least not with the same name you can also try to do some ip bands by reading the socket ip address but we're not going to do that here we're just going to kick and ban names so after kicking it what we're going to do is we're going to say with open and we're going to open the bands.txt in appending mode and of course sf and then we're going to say we're just going to write file.right and we're going to add the name to ban so the name to be banned to the list and we're going to add a backslash n and of course we're going to then later on check if the name is banned when we connect to the server this is something that we're going to do in a second um and after that we're just going to print on the server screen uh that the name was banned so we're going to create an f string here again name to ban was banned so this is what we're going to do on the server side here we're going to remove the pass keyword here and now we are going to define the kick user method now the kick user method is actually kind of simple the only thing that we need to do is we need to remove the username and the client from the list so we need to disconnect them and we need to send a message that they are kicked essentially so we're just going to say deathkick user name as a parameter and we're going to say okay if the name even exists in the nicknames because you know you cannot kick someone who's not in the server right now if the name is in nicknames then we're just going to say name [Music] index we're going to calculate the index because remember we have a client list and a nickname list and the index of the client is the same as the index of the respective nickname so we're going to calculate the index of the name so we're going to say in nicknames.index giving me the name so we're we're calculating the position of the name and because of that we already have the position of the client in the client list so we also have client to kick since we have the name to kick client to kick is essentially just clients at the name index because it's the same and then what we do is we just say clients dot remove client to kick because we now know which client it is that we need to remove then we're going to send client to kick because we now haven't closed the connection yet we just removed it from the list but the client is still there just the client connection is still there uh so we're going to say client to kick send we're going to send a message you were kicked by an admin we're going to encode the message of course and after that we're going to just close the connection to the client and we're going to remove the nicknames as well so nickname remove nickname uh name sorry only name and then we're going to broadcast so that everyone knows that this client was kicked it's going to say name was kicked by an admin and we're going to encode this message as well of course so this is how you kick a user in this server and client constellation here so the last thing that we need to do is we need to check if a user is banned when he tries to connect so what we're going to do is we're going to get the nickname as always and then we're going to check if this nickname is in the band list so we're going to load the ban list by saying with open bans dot txt in reading mode as f and now we're going to say all the bands are essentially just f dot read redline so we get a list of all the names because remember we had uh the bands when we banned someone we added to the list and then we added a backslash and so what we get is a list of all these uh banned names and a backstage n at the end so we need to cut off the last two characters but that's essentially it so now the next thing we do is we say if nickname plus backslash n so instead of cutting it off we're actually just adding the backstage end because it's a little bit easier right now so we just say okay if the nickname with an additional backslash n is in the band's list here uh we're just going to refuse the connection so we're going to say client dot send the signal ban so that the client knows i'm not allowed to get in here i can now uh do everything necessary to uh close the connection and we're going to send this to the client we're going to say code ascii code come on encode ascii and uh then we're also going to close the connection to the client and we're going to continue so we're going to skip again in the same way that we skip here we're just going to skip the iteration and wait for new connections that is how we check if the name is banned and now on the client side what we need to do is we need to process the uh banned keywords so if you don't get nick or actually it's the next message right yeah if we send if you sent the nickname and you don't get a pass because you're not admin but you got another key here so if you get next message equals ban you know that you're banned the connection was already closed by the server so even if you ignore that ban you're still not connected to the server so you cannot just say i'm the client i want to still be connected i'm not going to uh to accept the ban because the connection is closed from the server you're not on the server you cannot do anything about it but you get the keyword so that you know okay i need to do this and that to close the connection and uh so that i don't get any errors or don't get into endless loops here so what we're going to do is we're going to just print if we get that keyword connection refused because of ban and then we're going to just close the connection here and set stop thread to true it's as simple as that and now we're actually done with the advanced chat room so now we're actually done with the tcp chat but i would like to add one more thing because i thought about it and i realized that the only uh checking if you're allowed to kick or ban is happening on the client side and this is never good because the server should have uh the server should handle the permissions if you're going to execute a kick command or a bank command it should not be the client's job to check if you're allowed to do so because i can manipulate my client i can write my own client i can exploit the client and thus exploit the server and the only thing that we're doing in order to check if we're allowed to kick or to ban is checking if the nickname on the client side is admin now the server as soon as the server receives kick or ban and a name it's going to perform the action so i just need to write a client that sends to the server kick or ban without any additional things and i can immediately just kick and ban people so this is not something that we want to do and because of that we're going to do the check client side the first thing that we're going to do when we receive a kick or a band is we're going to check if the nickname is admin because on the server side we only have the nickname admin in the nicknames list if we got the connection right and remember we're asking for a password server side so the only way that we're going to end up with a nickname admin in the nicknames list is when the admin is actually connected to the server so we're going to say if nicknames dot or not dot sorry if nicknames and then we're going to say clients.index client because remember we only have the client here and we want to get the nickname of the client that we're actually connected to right now so if the nickname is admin we will just execute these commands here and if it's not we're just going to say uh client dot send command was refused and then we're going to encode this ascii and we're going to do the same thing for the banning here so we're going to say if nicknames equals admin or if the nickname equals admin we're going to do all of that otherwise we're just going to send the same message command was refused so this is now the uh the client server we should now only be able to kick or ban if you're really connected as an admin so now we can go ahead and play around a little bit with what we created we can just run the server as i showed in the beginning and we can now connect with a bunch of clients so i can go ahead and say okay my name is neural then we have another client which is nine and then we have another client which is uh youtube for example and we have all these connections here and we can now go ahead and connect as an admin as well i can try with the wrong password it's not going to allow it it's going to terminate the script i can try again with the correct password admin pass connected to the server i can write hey and all the other clients i'm going to receive that message where all these clients there you go you have this one this one this one okay it's actually the admin one uh and now what we can do is we can try to kick someone for example youtube can try to kick neural neural and commands can only be executed by admin but i can still write messages so i don't have any disconnect because of that uh also neural is still here not kicked from the server now i can go ahead and kick neural neural was kicked by admin you can see you were kicked by an admin error occurred um and now i can go ahead and still proceed i can go ahead and ban uh nine for example nine was kicked by an admin uh we got an exception up here oh i know why it is uh we're going to fix it in a second but it's not a big problem because the server is still running so as you can see we get the exception but uh we still continue to uh process all the inputs so the server is still running we're going to fix that in a second um and now i can try to just go ahead and connect is nine because nine was banned and when i connect is nine you can see connection reviews because of bands so everything works uh the only reason why we get exceptions here is because uh the we get into this exception here but the problem is that we already kicked and banned kicked or banned the client so the username and the client is no longer in the list and because of that we cannot perform this action here so the only thing we need to do is we need to say if client in clients and then we should not get any exceptions anymore so i'm going to save that and i'm going to repeat the same process so we had some guy here guy and then we had an admin admin admin pass and then we can kick guy guy was kicked by an admin or kurt were kicked in the server doesn't have any exceptions so as you can see everything works fine so that's it for today's video hope you enjoyed hope you'll learn something of course feel free to add as many features as you want you can add multiple commands you can try direct messaging you can try multiple accounts for example with different privileges and so on uh feel free to be creative you now have the basic knowledge of how to do things how to process commands and inputs uh be creative and build your own chat tool if you want to also if you like this video if you enjoyed it let me know by hitting the like button like button and leaving a comment in the comment section down below of course subscribe to this channel to see more future videos for free and other than that thank you very much for watching see you in the next video and bye [Music] you
Info
Channel: NeuralNine
Views: 18,514
Rating: 4.9810877 out of 5
Keywords:
Id: F_JDA96AdEI
Channel Id: undefined
Length: 37min 22sec (2242 seconds)
Published: Mon Sep 21 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.