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