diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/LDN10/.idea/.gitignore b/LDN10/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/LDN10/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/LDN10/.idea/LDN10.iml b/LDN10/.idea/LDN10.iml new file mode 100644 index 0000000..2c80e12 --- /dev/null +++ b/LDN10/.idea/LDN10.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/LDN10/.idea/inspectionProfiles/profiles_settings.xml b/LDN10/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/LDN10/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/LDN10/.idea/misc.xml b/LDN10/.idea/misc.xml new file mode 100644 index 0000000..32cefa8 --- /dev/null +++ b/LDN10/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/LDN10/.idea/modules.xml b/LDN10/.idea/modules.xml new file mode 100644 index 0000000..0c9003c --- /dev/null +++ b/LDN10/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/LDN10/.idea/vcs.xml b/LDN10/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/LDN10/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LDN10/certs/clients.pem b/LDN10/certs/clients.pem new file mode 100644 index 0000000..46af955 --- /dev/null +++ b/LDN10/certs/clients.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDizCCAnOgAwIBAgIUVPHhcVC0FfI3dsbcMAd0AEifmPMwDQYJKoZIhvcNAQEL +BQAwVTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEOMAwGA1UEAwwFamFuZXowHhcNMjQw +NTI2MTU1ODQ4WhcNMjUwNTI2MTU1ODQ4WjBVMQswCQYDVQQGEwJBVTETMBEGA1UE +CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MQ4wDAYDVQQDDAVqYW5lejCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJd9GojC/SaEAUFopY1T6P/U2jZlBkYlGgLh4QWLOdwQr3O9SwbKovVaCANtFWBo +vXFaduJ2d19RaEI8CbffjONlYIGecppoeKXoSe9z7qSjQPvqnijcOVLyuLNsTM1U +mewsdDjVxa+ZjLNAkqU3QrKl28ms945nogYYvOYiyNelwb6VkCi+Sm+Gu7lDQytZ +OteFA9o3OLXP5tbPJT3AjRbXReuARHFy3Q6rburszyUfeT9XatQQ9zLWAlnU3w3X +a5vP7lJHLoF1NiVdbmE2H12LPR43Ima0zLfDOf8YpY2DQaENlNuMuJ4NRjUydI69 +kbonAaZNX196FmX03GHZUCUCAwEAAaNTMFEwHQYDVR0OBBYEFKE0+A+tQNYWGRff +dPhuISf1W7qvMB8GA1UdIwQYMBaAFKE0+A+tQNYWGRffdPhuISf1W7qvMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAD0uiU+vjpLIRqshFBtzWJ7K +zRXb6zR1EGhbs63HRoTmW4s/YCuwZqdvmggd4j5a9RtFCIRO/4MjswrXV6rG0IiN +JXSb4ugz44oGUXsWboGHq3e8/pTJMq+cT4EO2t+irZ2qPe+jtZOJQwDU2NEJzkN6 +P+mcNR1I3pVfA+h1kLDspyv/6pbGQrfo0S8sJzetGYSFPBvEOagS6iHRlC7PwqrZ +gCADDHeewNksX8wGqiselXYQbiIrcGrb42fDgoX0aovEqUuux8Ukifm+DU1P9Hzv +FdMuT/pFNcwOXaETKN4oS4zMB/qGxqEnh3d7oItSBY3XjTgSORC25yf3irTWTww= +-----END CERTIFICATE----- diff --git a/LDN10/certs/janez_cert.crt b/LDN10/certs/janez_cert.crt new file mode 100644 index 0000000..46af955 --- /dev/null +++ b/LDN10/certs/janez_cert.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDizCCAnOgAwIBAgIUVPHhcVC0FfI3dsbcMAd0AEifmPMwDQYJKoZIhvcNAQEL +BQAwVTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEOMAwGA1UEAwwFamFuZXowHhcNMjQw +NTI2MTU1ODQ4WhcNMjUwNTI2MTU1ODQ4WjBVMQswCQYDVQQGEwJBVTETMBEGA1UE +CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MQ4wDAYDVQQDDAVqYW5lejCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJd9GojC/SaEAUFopY1T6P/U2jZlBkYlGgLh4QWLOdwQr3O9SwbKovVaCANtFWBo +vXFaduJ2d19RaEI8CbffjONlYIGecppoeKXoSe9z7qSjQPvqnijcOVLyuLNsTM1U +mewsdDjVxa+ZjLNAkqU3QrKl28ms945nogYYvOYiyNelwb6VkCi+Sm+Gu7lDQytZ +OteFA9o3OLXP5tbPJT3AjRbXReuARHFy3Q6rburszyUfeT9XatQQ9zLWAlnU3w3X +a5vP7lJHLoF1NiVdbmE2H12LPR43Ima0zLfDOf8YpY2DQaENlNuMuJ4NRjUydI69 +kbonAaZNX196FmX03GHZUCUCAwEAAaNTMFEwHQYDVR0OBBYEFKE0+A+tQNYWGRff +dPhuISf1W7qvMB8GA1UdIwQYMBaAFKE0+A+tQNYWGRffdPhuISf1W7qvMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAD0uiU+vjpLIRqshFBtzWJ7K +zRXb6zR1EGhbs63HRoTmW4s/YCuwZqdvmggd4j5a9RtFCIRO/4MjswrXV6rG0IiN +JXSb4ugz44oGUXsWboGHq3e8/pTJMq+cT4EO2t+irZ2qPe+jtZOJQwDU2NEJzkN6 +P+mcNR1I3pVfA+h1kLDspyv/6pbGQrfo0S8sJzetGYSFPBvEOagS6iHRlC7PwqrZ +gCADDHeewNksX8wGqiselXYQbiIrcGrb42fDgoX0aovEqUuux8Ukifm+DU1P9Hzv +FdMuT/pFNcwOXaETKN4oS4zMB/qGxqEnh3d7oItSBY3XjTgSORC25yf3irTWTww= +-----END CERTIFICATE----- diff --git a/LDN10/certs/janez_private.key b/LDN10/certs/janez_private.key new file mode 100644 index 0000000..6b74fd1 --- /dev/null +++ b/LDN10/certs/janez_private.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXfRqIwv0mhAFB +aKWNU+j/1No2ZQZGJRoC4eEFizncEK9zvUsGyqL1WggDbRVgaL1xWnbidndfUWhC +PAm334zjZWCBnnKaaHil6Envc+6ko0D76p4o3DlS8rizbEzNVJnsLHQ41cWvmYyz +QJKlN0KypdvJrPeOZ6IGGLzmIsjXpcG+lZAovkpvhru5Q0MrWTrXhQPaNzi1z+bW +zyU9wI0W10XrgERxct0Oq27q7M8lH3k/V2rUEPcy1gJZ1N8N12ubz+5SRy6BdTYl +XW5hNh9diz0eNyJmtMy3wzn/GKWNg0GhDZTbjLieDUY1MnSOvZG6JwGmTV9fehZl +9Nxh2VAlAgMBAAECggEADrICoHC16QYWLxetM6QHrsWhs3QiYyyXNN9fmk+Suc/e +jU44GH0QyNdGfrqWv8b5VaUucjKGyvbVM9OqJ62md6qubXSG7oai6Yk6nuFyrYLu +u2FbnWAbqXnFRBaF7sc9tUTss1S9fBbbqMnjT+an8DeZthsy2pwgAhJlRLfsHssd +2nbXhF2Ko9lMHECzqPggD0LKN7UfDTOqdJHiSm1svMiY026ec1VUe0UepC7F1o2V +mG39RPqFjTnsXJ2ajzFDVMvWM75J8DfTvsdAyaxjvoWamMrZap8ibWpnm0UxSWIh +A46O5y4/CSxUVl3Bp/Oxnu+Agdo5fHA8yqlilC5a8wKBgQDPDajNhaC3YnvBiftg +ImKqbjbprPppbjs6IQfNw4tMoKgQ6zPOCAm4fZCBs1ag4VwXmd6HH12f7dsgYIIV +cbz98MoH7RUwGAPV33QxbImp00LhhjHNE70ZeGz399+XXuRnER5MDoII1jcQCGTQ +qf15RgtjHMNC8S6kPhQLTNktMwKBgQC7TM/t+gfE94CZme/D4ZxDZ488UtVppt1k +KKsE6qqLSkyy0MPmf3xwOakS+cy+AZY8Votx2eAyk2wCq2MhCdvz21ZQZWB5pmWj +vKO74a4xpyPuX2gzlMhX/9y1usNfIvyUjMVTzfEWhrCFWlywctcGXkcruHthM3R9 +QOWzFIUdRwKBgGfEs73U47gkrltP2ODUOtiphfHU1Gc0bJB0b2HLR6vutGxORFdU +pfKFU3/9LkRQzYOyhNj5ekWlwnVWiLtQlmQ6YjZYto606m8snyIKAHBRRaqbQ6hA +5Tu3o/0eiDtnvlZ9OM7rUnY1TcFGQ6hkGXnHBfv1NVL+Zt6/kfIb4JgLAoGBAIZs +M1LNPmQ7aX1TwINp2Rd7LI6TuHyx+HRYx5youqtrMK6pK9+yoWF90H1A8JNxWhyF +1GBqiQBjU4J69JMSm1xhj4n1qA7GwG2KBkziRH14Qk5jBMr4Pe0CQanflzYhSvtm +KHzj8eJD2k5qstkkInR8l0Gmjk4Nes4mFHS5BmwjAoGAaHU+iAIKKZwIl4ta6ih7 +NpKH/oC+dGI8I7EoCwt7uk1y6+k7v3uTWZHS6TimVRaiRnRp21EjhC4WdJ4uKoia +wynq8v3palgKbMPvocp/Ni4XYjqFL9UG7OFY1Bl7N90XyuxGNJNzL3ZCe4L5Cip7 ++cuWKDY8V09Jml8wMEyu1FQ= +-----END PRIVATE KEY----- diff --git a/LDN10/certs/server_cert.crt b/LDN10/certs/server_cert.crt new file mode 100644 index 0000000..ac10eef --- /dev/null +++ b/LDN10/certs/server_cert.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIUEZiP8qpFxBwq/1urH/vY8xLPa30wDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4X +DTI0MDUyNjE1NTcxOFoXDTI1MDUyNjE1NTcxOFowWTELMAkGA1UEBhMCQVUxEzAR +BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 +IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxoKRGOyYRuDCMyd/Q3IHEQXRdJPg/hE5C1yzJGrLyoMjPhLLLFww +GobQE4xCXA/7bzUpVyOHy+1t80YlD4GIiWz+x04U6thsTTh9oMCIK2Uo3lSzyS2W +JINzbT1dQuvt4icgEzcyDYUA6P7rFe+iMFKPxw0h7kPHPtnnpuFsq0SLk7Aopj6a +7TpvxtjSpvcc/D7MLAqAA6u1Ws/JOmdN+4ZD2W4P/t4yiUCzyESxjPYy1DbgLpEr +w82wVcXjBgV82MmtmXZTgcPVNHM1FFXURPCkwOmwjatyRu+S8feBCXJnEfMYrmJB +Kk5AKXkb3viAxAoYokx388tv2YgpknDtCwIDAQABo1MwUTAdBgNVHQ4EFgQUMem3 +SX7Wo2R9gX+BzVQ5rznFsZ0wHwYDVR0jBBgwFoAUMem3SX7Wo2R9gX+BzVQ5rznF +sZ0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEARAsNxVNw5Tsz +6Kh5nm3DhCVbaXjy2jdnFK/Arleay2VXQQaVHf8+9USz6hxmo2qKbf6noY5sXIrO +TAb/Eig2XXEYJth5qIHpNHBY7ccRhrAsMokbSQSlUUz7Ip10AoVDVqwp9P6GWdei +Er2Hgw9JyzaKcbo2rMR/r5TGYnJ4Yg2f0Z5aO9uBCUdqTZvJfHulVEgn+YsCRV90 +Tz4TVleel3vS6Jljqtj6Rie8DnIX9q1bQQjEten6wHKy2eglpp2uJTPSVThxDTrA +7PQBuizGsvPohjBgNx92oOSXIeeJHHPViKb4wTDrTnNPdkK7pKk7uJMGkh6SwhSf +bYnwL9cS+A== +-----END CERTIFICATE----- diff --git a/LDN10/certs/server_private.key b/LDN10/certs/server_private.key new file mode 100644 index 0000000..7895d09 --- /dev/null +++ b/LDN10/certs/server_private.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDGgpEY7JhG4MIz +J39DcgcRBdF0k+D+ETkLXLMkasvKgyM+EsssXDAahtATjEJcD/tvNSlXI4fL7W3z +RiUPgYiJbP7HThTq2GxNOH2gwIgrZSjeVLPJLZYkg3NtPV1C6+3iJyATNzINhQDo +/usV76IwUo/HDSHuQ8c+2eem4WyrRIuTsCimPprtOm/G2NKm9xz8PswsCoADq7Va +z8k6Z037hkPZbg/+3jKJQLPIRLGM9jLUNuAukSvDzbBVxeMGBXzYya2ZdlOBw9U0 +czUUVdRE8KTA6bCNq3JG75Lx94EJcmcR8xiuYkEqTkApeRve+IDEChiiTHfzy2/Z +iCmScO0LAgMBAAECggEABdfH/4zPOp7Y+Hp8I3cSwCyEqsLDh5boL+5tk2/VScOs +YOJaupaID+/R5hFlzqHly7Mr4VW5ZIY7i0KQSrGMXEcqBKHGudbe8TLtd7LTDzvu +BQVHOW+vEKoR1rBMs3CQUuzF4+rm/UDh8vm137Jq+rMjaj93tTSng7EUQXQ3J59S +mgCm48GIuZmTOKd14KrsmKjBUbB15XNqoKsIqIrIBJ3CUvPnmpneztD8jxAd0zm4 +wk9XJ63MZduZmjpNsJ82m1VXPSKHPt2euKYEQTZlNs2dsnrcSYATJKMCgY8ImDpb +LpjnUM1wiIO33b5YsinLFO0Vlxk3ph/VaWa29fK7MQKBgQDnRZTL3fxa8exMIDSK +Jil+BszzikCPdEvNfHtUyC/dR2Jn4MPE3hwGB2rcWmSrj3wPfIoU9gYj8n2rt+gu +HJ3+p6saRE36n1ejZ43hRgbdb+9aVTZT616lFKz3F7PHyASa8pMIZ9O2924Mq+jt +S9HqZvySCE50FORuZvSNYzdk2QKBgQDbvDk8nKxa533Oa36nxdbgLN8SCXcu0Dqa +fJEPgllXCaK9OHgOA3/Dkvt7Ui54eX1TPz4vBGTMrI1FASWDr44U4Rn8xmQmROmH +XQ4VIsJdyiUwZYWbfcGigGglqgTMVM+vEKIIWhkLuyMJfhDagD2lh6GQIeoCXZPb +dgKkMR+igwKBgQCyIICbiQ2uSnkSpRdydDQvEjPXPFu/YfZkfYVMZqefCjU8Bv0h +62SwLBRdRe4VyXznPKfpvxg5pbKviQV2RqpWEnQR1hwtdX79p2u638G32lgDPnCK +sFWEVmlmI0ZgEKmjYkRnC/kgCnEjp2DPLD+xB8NvAqDSfaj3c6rWH13x+QKBgQCW +nqfxR0fRrBqNcxvHbxKCad+iooBiw3NYUAizQ9tvkPhPkjShDn72lXrypnuaM1TX +ymMaoX1i2uifI1EOuji/USmaHnepz9Tv57ZugHwRBC6HxR9XXVVsyW4aWzecxInz +64fWB8RhSS6UJCjzTbJ0E8uIW+bnJjPi3DqlR9LydwKBgQDNKAJeYBuiMQaBpLcj +YA44tTmqtydZbnjxhZ4bnn7/4N9uCKTSmLCDo/J+CbPT9HGImlmx+s72CREZBSAP +doUYM1LT9Iwj8elEmACTaLkcrkM4+qF4wLeUicYxXRcMmyhc38re85PYqfWCdqXs +dKydz9baCWldimI7/soS/fGUVw== +-----END PRIVATE KEY----- diff --git a/LDN10/client.py b/LDN10/client.py new file mode 100644 index 0000000..5374781 --- /dev/null +++ b/LDN10/client.py @@ -0,0 +1,107 @@ +import json +import socket +import struct +import sys +import ssl +import threading +from datetime import datetime + +PORT = 1234 +HEADER_LENGTH = 2 + + +def setup_SSL_context(): + #uporabi samo TLS, ne SSL + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + # certifikat je obvezen + context.verify_mode = ssl.CERT_REQUIRED + #nalozi svoje certifikate + context.load_cert_chain(certfile="certs/janez_cert.crt", keyfile="certs/janez_private.key") + # nalozi certifikate CAjev (samopodp. cert.= svoja CA!) + context.load_verify_locations('certs/server_cert.crt') + # nastavi SSL CipherSuites (nacin kriptiranja) + context.set_ciphers('ECDHE-RSA-AES128-GCM-SHA256') + return context + + +def receive_fixed_length_msg(sock, msglen): + message = b'' + while len(message) < msglen: + chunk = sock.recv(msglen - len(message)) # preberi nekaj bajtov + if chunk == b'': + raise RuntimeError("socket connection broken") + message = message + chunk # pripni prebrane bajte sporocilu + + return message + + +def receive_json(sock): + # preberi glavo sporocila (v prvih 2 bytih je dolzina sporocila) + header = receive_fixed_length_msg(sock, HEADER_LENGTH) + message_length = struct.unpack("!H", header)[0] # pretvori dolzino sporocila v int + + message = None + if message_length > 0: # ce je vse OK + message = receive_fixed_length_msg(sock, message_length) # preberi sporocilo + message = message.decode("utf-8") + message = json.loads(message) + + return message + + +def send_json(sock, data): + data["time"] = datetime.now().strftime("%c") + + # pretvori sporocilo v niz bajtov, uporabi UTF-8 kodno tabelo + encoded_data = json.dumps(data).encode("utf-8") + + # ustvari glavo v prvih 2 bytih je dolzina sporocila (HEADER_LENGTH) + # metoda pack "!H" : !=network byte order, H=unsigned short + header = struct.pack("!H", len(encoded_data)) + + data = header + encoded_data # najprj posljemo dolzino sporocilo, sele nato sporocilo samo + sock.sendall(data) + + +def send_message(sock, message): + send_json(sock, { + "type": "message", + "data": message, + }) + + +# message_receiver funkcija tece v loceni niti +def message_receiver(): + while True: + msg_received = receive_json(sock) + + msg_type = msg_received["type"] + data = msg_received["data"] + time = msg_received["time"] + match msg_type: + case "message": + username = msg_received["username"] + print(f'[{time}] [{username}] : {data}') + case "error": + print(f'Error: {data}') + + +# povezi se na streznik +print("[system] connecting to chat server ...") +my_ssl_ctx = setup_SSL_context() +sock = my_ssl_ctx.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) +sock.connect(("localhost", PORT)) +print("[system] connected!") + +# zazeni message_receiver funkcijo v loceni niti +thread = threading.Thread(target=message_receiver) +thread.daemon = True +thread.start() + +# pocakaj da uporabnik nekaj natipka in poslji na streznik +while True: + try: + msg_send = input("") + send_message(sock, msg_send) + except KeyboardInterrupt: + sys.exit() diff --git a/LDN10/server.py b/LDN10/server.py new file mode 100644 index 0000000..daf46de --- /dev/null +++ b/LDN10/server.py @@ -0,0 +1,165 @@ +import json +import signal +import socket +import struct +import ssl +import threading +from datetime import datetime + +signal.signal(signal.SIGINT, signal.SIG_DFL) + +PORT = 1234 +HEADER_LENGTH = 2 + +def setup_SSL_context(): + #uporabi samo TLS, ne SSL + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + # certifikat je obvezen + context.verify_mode = ssl.CERT_REQUIRED + #nalozi svoje certifikate + context.load_cert_chain(certfile="certs/server_cert.crt", keyfile="certs/server_private.key") + # nalozi certifikate CAjev, ki jim zaupas + # (samopodp. cert. = svoja CA!) + context.load_verify_locations('certs/clients.pem') + # nastavi SSL CipherSuites (nacin kriptiranja) + context.set_ciphers('ECDHE-RSA-AES128-GCM-SHA256') + return context + +def receive_fixed_length_msg(sock, msglen): + message = b'' + while len(message) < msglen: + chunk = sock.recv(msglen - len(message)) # preberi nekaj bajtov + if chunk == b'': + raise RuntimeError("socket connection broken") + message = message + chunk # pripni prebrane bajte sporocilu + + return message + + +def receive_json(sock) -> dict: + # preberi glavo sporocila (v prvih 2 bytih je dolzina sporocila) + header = receive_fixed_length_msg(sock, HEADER_LENGTH) + message_length = struct.unpack("!H", header)[0] # pretvori dolzino sporocila v int + + message = None + if message_length > 0: # ce je vse OK + message = receive_fixed_length_msg(sock, message_length) # preberi sporocilo + message = message.decode("utf-8") + message = json.loads(message) + + return message + + +def send_json(sock, message): + message["time"] = datetime.now().strftime("%c") + encoded_message = json.dumps(message).encode("utf-8") # pretvori sporocilo v niz bajtov, uporabi UTF-8 kodno tabelo + + # ustvari glavo v prvih 2 bytih je dolzina sporocila (HEADER_LENGTH) + # metoda pack "!H" : !=network byte order, H=unsigned short + header = struct.pack("!H", len(encoded_message)) + + message = header + encoded_message # najprj posljemo dolzino sporocilo, slee nato sporocilo samo + sock.sendall(message) + + +def send_error(sock, message): + send_json(sock, { + "type": "error", + "data": message, + }) + + +# funkcija za komunikacijo z odjemalcem (tece v loceni niti za vsakega odjemalca) +def client_thread(client_sock, client_addr): + global clients + global usernames + + cert = client_sock.getpeercert() + for sub in cert['subject']: + for key, value in sub: + if key == 'commonName': + usernames[client_sock] = value + + print("[system] connected with " + client_addr[0] + ":" + str(client_addr[1])) + print("[system] we now have " + str(len(clients)) + " clients") + + try: + + while True: # neskoncna zanka + msg_received = receive_json(client_sock) + msg_type = str(msg_received["type"]) + data = str(msg_received["data"]) + time = str(msg_received["time"]) + + if not msg_received: # ce obstaja sporocilo + break + + match msg_type: + case "message": + username = usernames[client_sock] + if username is None: + username = client_addr[0] + ":" + str(client_addr[1]) + msg_received["username"] = username + + print(f'[{time}] [{username}] : {data}') + + if data.startswith("@"): + [username, *data] = data.split() + username = str(username).replace("@", "") + + cl = [c for c, u in usernames.items() if u == username] + if len(cl) == 0: + send_error(client_sock, "Client with this username does not exist.") + continue + client = cl[0] + + msg_received["data"] = "".join(data) + send_json(client, msg_received) + continue + + for client in clients: + if client == client_sock: + continue + send_json(client, msg_received) + + except: + # tule bi lahko bolj elegantno reagirali, npr. na posamezne izjeme. Trenutno kar pozremo izjemo + pass + + # prisli smo iz neskoncne zanke + with clients_lock: + clients.remove(client_sock) + if client_sock in usernames: + usernames.pop(client_sock) + + print("[system] we now have " + str(len(clients)) + " clients") + client_sock.close() + + +# kreiraj socket +my_ssl_ctx = setup_SSL_context() +server_socket = my_ssl_ctx.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) +server_socket.bind(("localhost", PORT)) +server_socket.listen(1) + +# cakaj na nove odjemalce +print("[system] listening ...") +clients = set() +usernames = dict() +clients_lock = threading.Lock() +while True: + try: + # pocakaj na novo povezavo - blokirajoc klic + client_sock, client_addr = server_socket.accept() + with clients_lock: + clients.add(client_sock) + + thread = threading.Thread(target=client_thread, args=(client_sock, client_addr)) + thread.daemon = True + thread.start() + + except KeyboardInterrupt: + break + +print("[system] closing server socket ...") +server_socket.close() diff --git a/LDN9/dns-transfer.pcapng b/LDN9/dns-transfer.pcapng new file mode 100644 index 0000000..590cb67 Binary files /dev/null and b/LDN9/dns-transfer.pcapng differ diff --git a/LDN9/screenshot.png b/LDN9/screenshot.png new file mode 100644 index 0000000..9b78b38 Binary files /dev/null and b/LDN9/screenshot.png differ