start convertion to channels websocket and start using django sessions

This commit is contained in:
2024-08-22 20:37:48 +02:00
parent 7b4ef96081
commit 62e2281c69
24 changed files with 549 additions and 16 deletions

View File

@ -4,14 +4,19 @@ RUN apt update
RUN apt upgrade -y
RUN apt install -y python3 python3-pip postgresql-client
RUN pip3 install django psycopg "channels[daphne]"
RUN pip3 install requests django psycopg "channels[daphne]"
ARG DB_HOST=;
ARG DB_NAME=;
ARG DB_USERNAME=;
ARG DB_PASSWORD=;
ARG SECRET_42=;
ARG SECRET_42=;
ENV DB_HOST=${DB_HOST}
ENV PYTHONUNBUFFERED=1
ENV UID_42=${UID_42}
ENV SECRET_42=${SECRET_42}
RUN mkdir -p /var/www/djangoserver/
RUN mkdir -p /var/www/djangoserver/static/

View File

@ -12,6 +12,7 @@ import os
from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import path
from django.core.asgi import get_asgi_application
from channels.sessions import SessionMiddlewareStack
from .websocket import WebsocketHandler
@ -21,5 +22,5 @@ django = get_asgi_application()
application = ProtocolTypeRouter({
"http": django,
"websocket":URLRouter({path("ws",WebsocketHandler.as_asgi())})
"websocket":SessionMiddlewareStack(URLRouter({path("ws",WebsocketHandler.as_asgi())}))
})

View File

@ -129,3 +129,10 @@ STATIC_URL = 'static/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
ASGI_APPLICATION = 'server.asgi.applicatio'
SESSION_SAVE_EVERY_REQUEST = True
SESSION_COOKIE_NAME = 'sessionid'
SESSION_COOKIE_SECURE = False
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
SESSION_EXPIRE_AT_BROWSER_CLOSE = False

View File

@ -0,0 +1,75 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# createAccount.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/09 08:08:00 by edbernar #+# #+# #
# Updated: 2024/08/22 19:13:09 by tomoron ### ########.fr #
# #
# **************************************************************************** #
from .login import userList
import random
import re
pattern = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_]).+$'
# {'username': 'Kumita', 'mail': 'eddydhj@gmail.com', 'password': '3b19482535d1ab2f4e3c629c4e3e5e2d6af0a5f5280be190726a4c3be518a475'}
async def createAccount(socket, content):
try:
content["mail"] = content["mail"].lower()
if (content["mail"].find('@') == -1 or content["mail"].find('.') == -1):
await socket.sendError("Invalid mail", 9006)
return
if (content["username"].find(' ') != -1):
await socket.sendError("Username must not contain spaces", 9007)
return
if (len(content["username"]) < 3):
await socket.sendError("Username must be at least 3 characters long", 9008)
return
if (len(content["username"]) > 20):
await socket.sendError("Username must be at most 20 characters long", 9009)
return
if (content["username"].find(' ') != -1):
await socket.sendError("Username must not contain spaces", 9011)
return
if (content["username"].isalnum() == False):
await socket.sendError("Username must contain only letters and numbers", 9012)
return
if (len(content["password"]) < 8):
await socket.sendError("Password must be at least 8 characters long", 9013)
return
if (bool(re.match(pattern, content["password"]))):
await socket.sendError("Password must contain at least one lowercase letter, one uppercase letter and one special character", 9014)
return
if (content["password"].find(content["username"]) != -1):
await socket.sendError("Password must not contain the username", 9015)
return
# |Tom| Au lieu d'utiliser userList, faire une requête à la base de donnée pour savoir si on a un utilisateur avec cet email ou cet username
if (content["mail"] in userList):
await socket.sendError("Mail already used", 9016)
return
if (content["username"] in userList):
await socket.sendError("Username already used", 9017)
return
content["token"] = generateToken()
while (True):
content["id"] = random.randint(1000000, 9999999)
if (content["id"] not in userList):
break
userList.append(content)
await socket.send({"type": "create_account", "content": "Account created"})
except Exception as e:
await socket.sendError("Error create account", 9005, e)
def generateToken():
list = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
token = ""
for i in range(0, 35):
token += list[random.randint(0, len(list) - 1)]
return token

View File

@ -0,0 +1,69 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# getPrivateListMessage.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 22:53:14 by edbernar #+# #+# #
# Updated: 2024/08/22 19:13:09 by tomoron ### ########.fr #
# #
# **************************************************************************** #
import random
listMessage = {
"type": "private_list_message",
"content": [
{
"from": 0,
"content": "",
"date": "10:05 31/07/2024"
},
{
"from": 0,
"content": "",
"date": "10:05 31/07/2024"
},
{
"from": 0,
"content": "",
"date": "10:06 31/07/2024"
},
{
"from": 0,
"content": "",
"date": "10:06 31/07/2024"
},
{
"from": 0,
"content": "",
"date": "10:45 31/07/2024"
},
{
"from": 0,
"content": "",
"date": "10:46 31/07/2024"
}
]
}
def generate_random_string():
char = "abcdefghijklmnopqrstuvwxyz 123456789"
string = ""
for i in range(20):
string += char[random.randint(0, len(char) - 1)]
return string
async def getPrivateListMessage(socket, content):
# |TOM| Requete pour avoir la liste des messages privés grace à l'id de l'utilisateur
copyListMessage = listMessage.copy()
for message in copyListMessage["content"]:
if (random.randint(1, 10) % 2 == 0):
message["from"] = 9999999
else:
message["from"] = content["id"]
message["content"] = generate_random_string()
await socket.send(copyListMessage)

View File

@ -0,0 +1,60 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# getPrivateListUser.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 15:10:23 by edbernar #+# #+# #
# Updated: 2024/08/22 19:13:09 by tomoron ### ########.fr #
# #
# **************************************************************************** #
import asyncio
import json
data = [
{
"name": "Nessundorma",
"status": "online",
"pfp": "https://wallpapers-clan.com/wp-content/uploads/2023/05/cool-pfp-02.jpg",
"id": 145564
},
{
"name": "Succotash",
"status": "offline",
"pfp": "https://i.pinimg.com/200x/28/75/96/287596f98304bf1adc2c411619ae8fef.jpg",
"id": 256981
},
{
"name": "Astropower",
"status": "online",
"pfp": "https://ashisheditz.com/wp-content/uploads/2024/03/cool-anime-pfp-demon-slayer-HD.jpg",
"id": 301547
},
{
"name": "Assaultive",
"status": "offline",
"pfp": "https://i1.sndcdn.com/artworks-1Li0JIJrQGlojD3y-AEiNkw-t500x500.jpg",
"id": 432448
},
{
"name": "Redshock",
"status": "offline",
"pfp": "https://cdn.pfps.gg/pfps/7094-boy-pfp.png",
"id": 543211
},
{
"name": "Parley",
"status": "offline",
"pfp": "https://pbs.twimg.com/media/EscE6ckU0AA-Uhe.png",
"id": 654123
}
]
async def getPrivateListUser(socket, content=None):
# |TOM| Faire une requête à la base de données pour récupérer la liste des
# utilisateurs qui doivent apparaitre dans la liste du chat privé
# (ceux qui ont eu conversation avec l'utilisateur)
# Si user existe pas, faire ça : await socket.sendError("User not found", 9008)
await socket.send({"type": "private_list_user", "content": data})

View File

@ -0,0 +1,110 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# login.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 08:10:38 by edbernar #+# #+# #
# Updated: 2024/08/22 19:12:23 by tomoron ### ########.fr #
# #
# **************************************************************************** #
from .login42.login42 import main42login
import requests
import json
import os
# Les requêtes de login peuvent être de 3 types:
# <-- {"type" : "login", "content" : {"type": "byToken", "token": "123456"}}
# <-- {"type" : "login", "content" : {"type": "byPass", "mail": "aaa@a.com", "pass": "dasd"}}
# <-- {"type" : "login", "content" : {"type": "by42", "token": "1dsa23dsa456"}}
# --> {"type" : "login", "content" : {"username": "". "token": "", "id": 0}}
userList = [
{
"username": "Eddy",
"token": "54dsadw8f4a6w5f4a62s4f984fa62f4as65",
"mail": "aaaaa",
"password": "ed968e840d10d2d313a870bc131a4e2c311d7ad09bdf32b3418147221f51a6e2", # not hashed : aaaaa
"id": 2135421,
"id42": -1
},
{
"username": "Hugo",
"token": "dsa4d6sa4sa1hfd1jhgk6g4k21bn65m4nb4",
"mail": "bbbbb",
"password": "bbbbb",
"id": 9892154,
"id42": -1
},
{
"username": "Mathis",
"token": "8cb1qjlfndc12mn2l1mn654xzkkhad54cxz",
"mail": "ccccc",
"password": "6304fbfe2b22557c34c42a70056616786a733b3d09fb326308c813d6ab712ec0", # not hashed : ccccc
"id": 2371234,
"id42": -1
},
{
"username": "Tom",
"token": "poiuygfvbdsv5c21vcxvcxhgbjqnkmds546",
"mail": "ddddd",
"password": "ddddd",
"id": 6423457,
"id42": -1
}
]
async def loginByToken(socket, content):
# |TOM| Requete pour savoir si le token est valide
for user in userList:
if (user["token"] == content["token"]):
jsonVar = {"type": "login", "content": {"username": user["username"], "token": user["token"], "id": user["id"]}}
socket.username = jsonVar["content"]["username"]
socket.token = jsonVar["content"]["token"]
socket.id = jsonVar["content"]["id"]
await socket.send(jsonVar)
return
jsonVar = {"type": "error", "content": "Invalid token", "code": 9001}
await socket.send(json.dumps(jsonVar))
async def loginByPass(socket, content):
# |TOM| Requete pour savoir si le mail et le mot de passe sont valides
# et créer un token si celui-ci n'existe pas
for user in userList:
if (user["mail"] == content["mail"] and user["password"] == content["password"]):
jsonVar = {"type": "login", "content": {"username": user["username"], "token": user["token"], "id": user["id"]}}
socket.username = jsonVar["content"]["username"]
socket.token = jsonVar["content"]["token"]
socket.id = jsonVar["content"]["id"]
await socket.send(jsonVar)
return
await socket.send({"type": "error", "content": "Invalid username or password", "code": 9007})
async def loginBy42(socket, content):
# |TOM| Requete pour récuperer les informations de l'utilisateur selon l'intra de la personne
# et créer un token si celui-ci n'existe pas
try:
await main42login(socket, content, userList)
except Exception as e:
await socket.sendError("Invalid 42 token", 9010, e)
async def login(socket, content):
# |TOM| Faire 3 types de requêtes:
# - byToken: Récupérer les informations de l'utilisateur en fonction de son token
# - byPass: Récupérer les informations de l'utilisateur en fonction de mail et de son mot de passe
# - by42: Récupérer les informations de l'utilisateur en fonction de son token42 (qui sera different du token)
try:
if (content["type"] == "byToken"):
await loginByToken(socket, content)
elif (content["type"] == "byPass"):
await loginByPass(socket, content)
elif (content["type"] == "by42"):
await loginBy42(socket, content)
else:
await socket.sendError("Invalid login type", 9006)
except Exception as e:
await socket.sendError("Invalid request", 9005, e)

View File

@ -0,0 +1,72 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# login42.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/09 09:32:17 by edbernar #+# #+# #
# Updated: 2024/08/22 19:13:31 by tomoron ### ########.fr #
# #
# **************************************************************************** #
import requests
import json
import os
UID42 = os.environ.get("UID_42")
SECRET42 = os.environ.get("SECRET_42")
TOKENURL = 'https://api.intra.42.fr/oauth/token'
INFOURL = 'https://api.intra.42.fr/v2/me'
REDIRECT = 'http://127.0.0.1:5500/site/'
# |Eddy| Changer le redirect quand il y aura un vrai serveur
access_token = ""
if (UID42 == None or SECRET42 == None):
print("Please set the environment variables uid and secret")
exit()
async def main42login(socket, content, userList):
global access_token
print(content['token'])
data = {
'grant_type': 'authorization_code',
'client_id': UID42,
'client_secret': SECRET42,
'code': content['token'],
'redirect_uri': REDIRECT
}
response = requests.post(TOKENURL, data=data)
if (response.status_code != 200):
raise Exception(f"Problem with the request (access_token {response.status_code})")
response = response.json()
headers = {
'Authorization': f'Bearer {response["access_token"]}',
}
response = requests.get(INFOURL, headers=headers)
if (response.status_code != 200):
raise Exception(f"Problem with the request (user info {response.status_code})")
response = response.json()
# |Tom| Au lieu d'utiliser userList, faire une requête à la base de donnée pour savoir si on a un utilisateur avec cet id42
i = 0
while (i < len(userList)):
if (userList[i]['id42'] == response['id']):
break
i += 1
if (i == len(userList)):
await socket.sendError("Not user registered with this 42 account", 9011)
return
else:
await socket.send({
"type": "login",
"content": {
"username": userList[i]['username'],
"token": userList[i]['token'],
"id": userList[i]['id']
}
})

View File

@ -0,0 +1,35 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# sendPrivateMessage.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/04 13:44:11 by edbernar #+# #+# #
# Updated: 2024/08/22 19:13:31 by tomoron ### ########.fr #
# #
# **************************************************************************** #
from datetime import datetime
async def sendPrivateMessage(socket, content):
# |Tom| Requete pour vérifier si l'user existe
# Si user existe pas, faire ça : await socket.sendError("User not found", 9008)
# Sinon l'ajouter à la base de données
# |Eddy| Si user existe, envoyer le message privé aux deux personnes concernées
# sachant que le receveur doit être connecté. Dans le cas contraire, uniquement
# l'envoyeur recevra le message.
try:
time = content["time"]
time = datetime.strptime(time, "%Y-%m-%dT%H:%M:%S.%fZ")
time = time.strftime("%H:%M %d/%m/%Y")
jsonVar = {"type": "new_private_message", "content": {
"from": content["from"],
"channel": content["to"],
"content": content["content"],
"date": time
}}
await socket.send(jsonVar)
except Exception as e:
await socket.sendError("Invalid message sent", 9009, e)

View File

@ -2,4 +2,8 @@ from django.http import HttpResponse
from .models import User
def index(request):
if(request.session.get("visited", False)):
print("already visited")
request.session["visited"] = True
return HttpResponse("AAAAAAAAAAAAAAAAAAAAAAA")

View File

@ -1,13 +1,112 @@
from channels.generic.websocket import WebsocketConsumer
import json
from .typeRequets.getPrivateListMessage import getPrivateListMessage
from .typeRequets.getPrivateListUser import getPrivateListUser
from .typeRequets.sendPrivateMessage import sendPrivateMessage
from .typeRequets.createAccount import createAccount
from .typeRequets.login import login
typeRequest = ["login", "get_private_list_user", "get_private_list_message",
"send_private_message", "create_account"]
functionRequest = [login, getPrivateListUser, getPrivateListMessage,
sendPrivateMessage, createAccount]
from random import randint
class WebsocketHandler(WebsocketConsumer):
debugMode = True
session = None
def connect(self):
print("new client")
self.accept()
print("AAAAAAAAAAAAA")
print(self.scope["session"].get("number"))
if(self.scope["session"].get("number") == None):
self.scope["session"]["number"] = randint(0,2147483647)
self.scope["session"].save()
print("new number : ", self.scope["session"].get("number"))
else:
print("remembered number : ", self.scope["session"].get("number"))
def disconnect(self, close_code):
print("CCCCCCCCCCCCCC")
print("you can go, we never wanted you anyway")
def receive(self, message):
print("BBBBBBBBBBBB")
self.send(text_data=json.dumps({"AAAAA":"received"}))
def receive(self, text_data):
print(self.scope["session"].get("number"))
print("someone is talking")
try:
jsonRequest = json.loads(text_data)
except json.JSONDecodeError:
self.sendError("Invalid JSON", 9002)
return
try:
self.printDebug(jsonRequest, 0)
if (jsonRequest["type"] in typeRequest):
if (jsonRequest["type"] == "login" or jsonRequest["type"] == "create_account"):
functionRequest[typeRequest.index(jsonRequest["type"])](self, jsonRequest["content"])
else:
if (self.verifyToken(jsonRequest["token"]) == False):
return
functionRequest[typeRequest.index(jsonRequest["type"])](self, jsonRequest["content"])
else:
self.sendError("Invalid type", 9004)
except Exception as e:
self.sendError("Invalid request", 9005, e)
def sendError(self, message, code, error=None):
try:
jsonVar = {"type": "error", "content": message, "code": code}
self.printDebug(jsonVar, 2, error)
self.send(text_data=json.dumps(jsonVar))
except Exception as e:
if (self.debugMode):
print("\033[0;31m|------ Error in sendError ------|\033[0;0m")
print(e)
def printDebug(self, request, typeRequest, error=None):
try:
if (self.debugMode and typeRequest == 0):
print("\033[0;34m|----- New received request -----|\033[0;0m")
#print("User :", self.username)
#print("Token :", self.token)
#print("Id :", self.id)
try:
print("Var type :", type(request["type"]))
print("Type :", request["type"])
except:
pass
try:
print("Content type :", request["content"])
except:
pass
elif (self.debugMode and typeRequest == 1):
print("\033[0;32m|------- New sent request -------|\033[0;0m")
#print("To :", self.username)
#print("Id :", self.id)
try:
print("Var type :", type(request["type"]))
print("Type :", request["type"])
except:
pass
try:
print("Content :", request["content"])
except:
pass
if ("type" not in request or "content" not in request):
print("Warning : not usual json format")
elif (self.debugMode and typeRequest == 2):
print("\033[0;31m|------------- Error ------------|\033[0;0m")
#print("User :", self.username)
#print("Token :", self.token)
#print("Id :", self.id)
print("Error message :", request["content"])
print("Error code :", request["code"])
if (error != None):
print("Error python :", error)
print("File :", error.__traceback__.tb_frame.f_globals["__file__"])
print("Line :", error.__traceback__.tb_lineno)
except Exception as e:
print("\033[0;31m|------ Error in printDebug -----|\033[0;0m")
print(e)

View File

@ -0,0 +1,120 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# User.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 15:54:14 by edbernar #+# #+# #
# Updated: 2024/08/22 19:12:27 by tomoron ### ########.fr #
# #
# **************************************************************************** #
import websockets
import asyncio
import json
connected_clients = []
class User():
debugMode = True
websocket = None
username = ""
token = ""
id = -1
def __init__(self, websocket):
if (self.debugMode):
print("\033[42m|------ New user Connected ------|\033[1;0m")
self.websocket = websocket
connected_clients.append(self)
def __del__(self):
if (self.debugMode):
print("\033[43m|------ User disconnected -------|\033[1;0m")
print("User :", self.username)
print("Id :", self.id)
async def sendError(self, message, code, error=None):
try:
jsonVar = {"type": "error", "content": message, "code": code}
self.printDebug(jsonVar, 2, error)
await self.websocket.send(json.dumps(jsonVar))
except:
if (self.debugMode):
print("\033[0;31m|------ Error in sendError ------|\033[0;0m")
try:
if (type(content) == dict):
self.printDebug(content, 1)
await self.websocket.send(json.dumps(content))
else:
self.printDebug(json.loads(content), 1)
await self.websocket.send(content)
except Exception as e:
if (self.debugMode):
print("\033[0;31m|--------- Error in send --------|\033[0;0m")
print("Error message :", e)
async def verifyToken(self, token):
try:
if (self.token != token or self.token == ""):
await self.sendError("Invalid token", 9001)
return False
return True
except:
if (self.debugMode):
print("\033[0;31m|----- Error in verifyToken -----|\033[0;0m")
def printDebug(self, request, typeRequest, error=None):
try:
if (self.debugMode and typeRequest == 0):
print("\033[0;34m|----- New received request -----|\033[0;0m")
print("User :", self.username)
print("Token :", self.token)
print("Id :", self.id)
try:
print("Var type :", type(request["type"]))
print("Type :", request["type"])
except:
pass
try:
print("Content type :", request["content"])
except:
pass
elif (self.debugMode and typeRequest == 1):
print("\033[0;32m|------- New sent request -------|\033[0;0m")
print("To :", self.username)
print("Id :", self.id)
try:
print("Var type :", type(request["type"]))
print("Type :", request["type"])
except:
pass
try:
print("Content :", request["content"])
except:
pass
if ("type" not in request or "content" not in request):
print("Warning : not usual json format")
elif (self.debugMode and typeRequest == 2):
print("\033[0;31m|------------- Error ------------|\033[0;0m")
print("User :", self.username)
print("Token :", self.token)
print("Id :", self.id)
print("Error message :", request["content"])
print("Error code :", request["code"])
if (error != None):
print("Error python :", error)
print("File :", error.__traceback__.tb_frame.f_globals["__file__"])
print("Line :", error.__traceback__.tb_lineno)
except:
print("\033[0;31m|------ Error in printDebug -----|\033[0;0m")
async def close(self):
try:
await self.websocket.close()
except:
pass

View File

@ -0,0 +1,65 @@
**************************************************************************** #
# #
# ::: :::::::: #
# main.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 08:10:40 by edbernar #+# #+# #
# Updated: 2024/08/22 15:54:03 by tomoron ### ########.fr #
# #
# **************************************************************************** #
from typeRequets.getPrivateListMessage import getPrivateListMessage
from typeRequets.getPrivateListUser import getPrivateListUser
from typeRequets.sendPrivateMessage import sendPrivateMessage
from typeRequets.createAccount import createAccount
from typeRequets.login import login
from Class.User import User, connected_clients
import websockets
import asyncio
import json
# Todo (Eddy):
# - verifier que l'utilisateur n'est pas déjà connecté pour éviter les doublons
# Todo (Tom) :
# - Mettre des pages temporaires accesibles qu'on envoie par mail pour confirmer le compte
typeRequest = ["login", "get_private_list_user", "get_private_list_message",
"send_private_message", "create_account"]
functionRequest = [login, getPrivateListUser, getPrivateListMessage,
sendPrivateMessage, createAccount]
async def handler(websocket, path):
userClass = User(websocket)
try:
async for resquet in userClass.websocket:
try:
jsonRequest = json.loads(resquet)
except json.JSONDecodeError:
await userClass.sendError("Invalid JSON", 9002)
continue
try:
userClass.printDebug(jsonRequest, 0)
if (jsonRequest["type"] in typeRequest):
if (jsonRequest["type"] == "login" or jsonRequest["type"] == "create_account"):
await functionRequest[typeRequest.index(jsonRequest["type"])](userClass, jsonRequest["content"])
else:
if (await userClass.verifyToken(jsonRequest["token"]) == False):
continue
await functionRequest[typeRequest.index(jsonRequest["type"])](userClass, jsonRequest["content"])
else:
await userClass.sendError("Invalid type", 9004)
except Exception as e:
await userClass.sendError("Invalid request", 9005, e)
except websockets.ConnectionClosed:
pass
await userClass.close()
connected_clients.remove(userClass)
start_server = websockets.serve(handler, "localhost", 8000, subprotocols=['123456'])
asyncio.get_event_loop().run_until_complete(start_server)
print("Server started")
asyncio.get_event_loop().run_forever()

View File

@ -0,0 +1,75 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# createAccount.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/09 08:08:00 by edbernar #+# #+# #
# Updated: 2024/08/10 12:37:49 by edbernar ### ########.fr #
# #
# **************************************************************************** #
from typeRequets.login import userList
import random
import re
pattern = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_]).+$'
# {'username': 'Kumita', 'mail': 'eddydhj@gmail.com', 'password': '3b19482535d1ab2f4e3c629c4e3e5e2d6af0a5f5280be190726a4c3be518a475'}
async def createAccount(userClass, content):
try:
content["mail"] = content["mail"].lower()
if (content["mail"].find('@') == -1 or content["mail"].find('.') == -1):
await userClass.sendError("Invalid mail", 9006)
return
if (content["username"].find(' ') != -1):
await userClass.sendError("Username must not contain spaces", 9007)
return
if (len(content["username"]) < 3):
await userClass.sendError("Username must be at least 3 characters long", 9008)
return
if (len(content["username"]) > 20):
await userClass.sendError("Username must be at most 20 characters long", 9009)
return
if (content["username"].find(' ') != -1):
await userClass.sendError("Username must not contain spaces", 9011)
return
if (content["username"].isalnum() == False):
await userClass.sendError("Username must contain only letters and numbers", 9012)
return
if (len(content["password"]) < 8):
await userClass.sendError("Password must be at least 8 characters long", 9013)
return
if (bool(re.match(pattern, content["password"]))):
await userClass.sendError("Password must contain at least one lowercase letter, one uppercase letter and one special character", 9014)
return
if (content["password"].find(content["username"]) != -1):
await userClass.sendError("Password must not contain the username", 9015)
return
# |Tom| Au lieu d'utiliser userList, faire une requête à la base de donnée pour savoir si on a un utilisateur avec cet email ou cet username
if (content["mail"] in userList):
await userClass.sendError("Mail already used", 9016)
return
if (content["username"] in userList):
await userClass.sendError("Username already used", 9017)
return
content["token"] = generateToken()
while (True):
content["id"] = random.randint(1000000, 9999999)
if (content["id"] not in userList):
break
userList.append(content)
await userClass.send({"type": "create_account", "content": "Account created"})
except Exception as e:
await userClass.sendError("Error create account", 9005, e)
def generateToken():
list = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
token = ""
for i in range(0, 35):
token += list[random.randint(0, len(list) - 1)]
return token

View File

@ -0,0 +1,69 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# getPrivateListMessage.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 22:53:14 by edbernar #+# #+# #
# Updated: 2024/08/06 23:32:08 by edbernar ### ########.fr #
# #
# **************************************************************************** #
import random
listMessage = {
"type": "private_list_message",
"content": [
{
"from": 0,
"content": "",
"date": "10:05 31/07/2024"
},
{
"from": 0,
"content": "",
"date": "10:05 31/07/2024"
},
{
"from": 0,
"content": "",
"date": "10:06 31/07/2024"
},
{
"from": 0,
"content": "",
"date": "10:06 31/07/2024"
},
{
"from": 0,
"content": "",
"date": "10:45 31/07/2024"
},
{
"from": 0,
"content": "",
"date": "10:46 31/07/2024"
}
]
}
def generate_random_string():
char = "abcdefghijklmnopqrstuvwxyz 123456789"
string = ""
for i in range(20):
string += char[random.randint(0, len(char) - 1)]
return string
async def getPrivateListMessage(userClass, content):
# |TOM| Requete pour avoir la liste des messages privés grace à l'id de l'utilisateur
copyListMessage = listMessage.copy()
for message in copyListMessage["content"]:
if (random.randint(1, 10) % 2 == 0):
message["from"] = 9999999
else:
message["from"] = content["id"]
message["content"] = generate_random_string()
await userClass.send(copyListMessage)

View File

@ -0,0 +1,61 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# getPrivateListUser.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 15:10:23 by edbernar #+# #+# #
# Updated: 2024/08/05 16:36:53 by edbernar ### ########.fr #
# #
# **************************************************************************** #
import websockets
import asyncio
import json
data = [
{
"name": "Nessundorma",
"status": "online",
"pfp": "https://wallpapers-clan.com/wp-content/uploads/2023/05/cool-pfp-02.jpg",
"id": 145564
},
{
"name": "Succotash",
"status": "offline",
"pfp": "https://i.pinimg.com/200x/28/75/96/287596f98304bf1adc2c411619ae8fef.jpg",
"id": 256981
},
{
"name": "Astropower",
"status": "online",
"pfp": "https://ashisheditz.com/wp-content/uploads/2024/03/cool-anime-pfp-demon-slayer-HD.jpg",
"id": 301547
},
{
"name": "Assaultive",
"status": "offline",
"pfp": "https://i1.sndcdn.com/artworks-1Li0JIJrQGlojD3y-AEiNkw-t500x500.jpg",
"id": 432448
},
{
"name": "Redshock",
"status": "offline",
"pfp": "https://cdn.pfps.gg/pfps/7094-boy-pfp.png",
"id": 543211
},
{
"name": "Parley",
"status": "offline",
"pfp": "https://pbs.twimg.com/media/EscE6ckU0AA-Uhe.png",
"id": 654123
}
]
async def getPrivateListUser(userClass, content=None):
# |TOM| Faire une requête à la base de données pour récupérer la liste des
# utilisateurs qui doivent apparaitre dans la liste du chat privé
# (ceux qui ont eu conversation avec l'utilisateur)
# Si user existe pas, faire ça : await userClass.sendError("User not found", 9008)
await userClass.send({"type": "private_list_user", "content": data})

View File

@ -0,0 +1,110 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# login.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 08:10:38 by edbernar #+# #+# #
# Updated: 2024/08/10 15:59:54 by edbernar ### ########.fr #
# #
# **************************************************************************** #
from typeRequets.login42.login42 import main42login
import requests
import json
import os
# Les requêtes de login peuvent être de 3 types:
# <-- {"type" : "login", "content" : {"type": "byToken", "token": "123456"}}
# <-- {"type" : "login", "content" : {"type": "byPass", "mail": "aaa@a.com", "pass": "dasd"}}
# <-- {"type" : "login", "content" : {"type": "by42", "token": "1dsa23dsa456"}}
# --> {"type" : "login", "content" : {"username": "". "token": "", "id": 0}}
userList = [
{
"username": "Eddy",
"token": "54dsadw8f4a6w5f4a62s4f984fa62f4as65",
"mail": "aaaaa",
"password": "ed968e840d10d2d313a870bc131a4e2c311d7ad09bdf32b3418147221f51a6e2", # not hashed : aaaaa
"id": 2135421,
"id42": -1
},
{
"username": "Hugo",
"token": "dsa4d6sa4sa1hfd1jhgk6g4k21bn65m4nb4",
"mail": "bbbbb",
"password": "bbbbb",
"id": 9892154,
"id42": -1
},
{
"username": "Mathis",
"token": "8cb1qjlfndc12mn2l1mn654xzkkhad54cxz",
"mail": "ccccc",
"password": "6304fbfe2b22557c34c42a70056616786a733b3d09fb326308c813d6ab712ec0", # not hashed : ccccc
"id": 2371234,
"id42": -1
},
{
"username": "Tom",
"token": "poiuygfvbdsv5c21vcxvcxhgbjqnkmds546",
"mail": "ddddd",
"password": "ddddd",
"id": 6423457,
"id42": -1
}
]
async def loginByToken(userClass, content):
# |TOM| Requete pour savoir si le token est valide
for user in userList:
if (user["token"] == content["token"]):
jsonVar = {"type": "login", "content": {"username": user["username"], "token": user["token"], "id": user["id"]}}
userClass.username = jsonVar["content"]["username"]
userClass.token = jsonVar["content"]["token"]
userClass.id = jsonVar["content"]["id"]
await userClass.send(jsonVar)
return
jsonVar = {"type": "error", "content": "Invalid token", "code": 9001}
await userClass.send(json.dumps(jsonVar))
async def loginByPass(userClass, content):
# |TOM| Requete pour savoir si le mail et le mot de passe sont valides
# et créer un token si celui-ci n'existe pas
for user in userList:
if (user["mail"] == content["mail"] and user["password"] == content["password"]):
jsonVar = {"type": "login", "content": {"username": user["username"], "token": user["token"], "id": user["id"]}}
userClass.username = jsonVar["content"]["username"]
userClass.token = jsonVar["content"]["token"]
userClass.id = jsonVar["content"]["id"]
await userClass.send(jsonVar)
return
await userClass.send({"type": "error", "content": "Invalid username or password", "code": 9007})
async def loginBy42(userClass, content):
# |TOM| Requete pour récuperer les informations de l'utilisateur selon l'intra de la personne
# et créer un token si celui-ci n'existe pas
try:
await main42login(userClass, content, userList)
except Exception as e:
await userClass.sendError("Invalid 42 token", 9010, e)
async def login(userClass, content):
# |TOM| Faire 3 types de requêtes:
# - byToken: Récupérer les informations de l'utilisateur en fonction de son token
# - byPass: Récupérer les informations de l'utilisateur en fonction de mail et de son mot de passe
# - by42: Récupérer les informations de l'utilisateur en fonction de son token42 (qui sera different du token)
try:
if (content["type"] == "byToken"):
await loginByToken(userClass, content)
elif (content["type"] == "byPass"):
await loginByPass(userClass, content)
elif (content["type"] == "by42"):
await loginBy42(userClass, content)
else:
await userClass.sendError("Invalid login type", 9006)
except Exception as e:
await userClass.sendError("Invalid request", 9005, e)

View File

@ -0,0 +1,72 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# login42.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/09 09:32:17 by edbernar #+# #+# #
# Updated: 2024/08/10 16:06:09 by edbernar ### ########.fr #
# #
# **************************************************************************** #
import requests
import json
import os
UID42 = os.environ.get("uid")
SECRET42 = os.environ.get("secret")
TOKENURL = 'https://api.intra.42.fr/oauth/token'
INFOURL = 'https://api.intra.42.fr/v2/me'
REDIRECT = 'http://127.0.0.1:5500/site/'
# |Eddy| Changer le redirect quand il y aura un vrai serveur
access_token = ""
if (UID42 == None or SECRET42 == None):
print("Please set the environment variables uid and secret")
exit()
async def main42login(userClass, content, userList):
global access_token
print(content['token'])
data = {
'grant_type': 'authorization_code',
'client_id': UID42,
'client_secret': SECRET42,
'code': content['token'],
'redirect_uri': REDIRECT
}
response = requests.post(TOKENURL, data=data)
if (response.status_code != 200):
raise Exception(f"Problem with the request (access_token {response.status_code})")
response = response.json()
headers = {
'Authorization': f'Bearer {response["access_token"]}',
}
response = requests.get(INFOURL, headers=headers)
if (response.status_code != 200):
raise Exception(f"Problem with the request (user info {response.status_code})")
response = response.json()
# |Tom| Au lieu d'utiliser userList, faire une requête à la base de donnée pour savoir si on a un utilisateur avec cet id42
i = 0
while (i < len(userList)):
if (userList[i]['id42'] == response['id']):
break
i += 1
if (i == len(userList)):
await userClass.sendError("Not user registered with this 42 account", 9011)
return
else:
await userClass.send({
"type": "login",
"content": {
"username": userList[i]['username'],
"token": userList[i]['token'],
"id": userList[i]['id']
}
})

View File

@ -0,0 +1,35 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# sendPrivateMessage.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/08/04 13:44:11 by edbernar #+# #+# #
# Updated: 2024/08/04 15:48:24 by edbernar ### ########.fr #
# #
# **************************************************************************** #
from datetime import datetime
async def sendPrivateMessage(userClass, content):
# |Tom| Requete pour vérifier si l'user existe
# Si user existe pas, faire ça : await userClass.sendError("User not found", 9008)
# Sinon l'ajouter à la base de données
# |Eddy| Si user existe, envoyer le message privé aux deux personnes concernées
# sachant que le receveur doit être connecté. Dans le cas contraire, uniquement
# l'envoyeur recevra le message.
try:
time = content["time"]
time = datetime.strptime(time, "%Y-%m-%dT%H:%M:%S.%fZ")
time = time.strftime("%H:%M %d/%m/%Y")
jsonVar = {"type": "new_private_message", "content": {
"from": content["from"],
"channel": content["to"],
"content": content["content"],
"date": time
}}
await userClass.send(jsonVar)
except Exception as e:
await userClass.sendError("Invalid message sent", 9009, e)