-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.py
134 lines (110 loc) · 4.68 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
from flask import Flask, render_template, request, redirect, jsonify
from client.client_socket import ClientSocket
from server.server_socket import ServerSocket
import logging
import sys
from argon2 import PasswordHasher
import os
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
ph = PasswordHasher()
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///./db.sqlite'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=False
db = SQLAlchemy(app)
class Message(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), nullable=False)
message = db.Column(db.String(500), nullable=False)
timestamp=db.Column(db.DateTime, nullable=False,
default=datetime.utcnow)
def __repr__(self):
return str(self.username)
db.drop_all()
db.create_all()
# to log errors on heroku console for easier debug
app.logger.addHandler(logging.StreamHandler(sys.stdout))
app.logger.setLevel(logging.ERROR)
def get_open_port():
"""
Function to find open port which is not in use at the moment..
We Find it by:
* Giving it empty IP and PORT 0 so that i finds everything by itself
* Use s.getsockname()[1] to get port which is occupied by current socket object
* Close the socket by s.close()
* return the port so that SERVER and CLIENT can connect on it
"""
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", 0))
s.listen(1)
port = s.getsockname()[1]
s.close()
return port
# Getting open Port
open_port = get_open_port()
server = ServerSocket(open_port,db,Message)
# list of usernames to prevent duplicate usernames
users = []
# Dictionary of username to its respective client socket to access its socket later
connsDict = {}
# Dictionary of User to their passwordHash They enter while Login
userKeys = {}
@app.route('/', methods=['GET', "POST"])
def login(name="login"):
global userKeys, connsDict, users
s = ""
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('pass')
passwordHash = ph.hash(password)
if len(username) and len(username) < 32:
if username in users and username.isalnum:
# if passwordHash matches then redirect to chat of that person
if ph.verify(userKeys.get(username), password):
return redirect(f'/chat/{username}')
else:
return render_template('login.html', name=name, mystring="username already taken.. and the password also doesn't match for login")
clientSocket = ClientSocket(open_port, username,Message.query.all())
clientSocket.connect()
users.append(username)
connsDict[username] = clientSocket
userKeys[username] = passwordHash
return redirect(f'/chat/{username}')
else:
s = "length of username should be between 1 and 32 and only alphanumeric characters allowed"
return render_template('login.html', name=name, mystring=s)
@app.route('/chat/<string:username>/', methods=['GET', "POST"])
def chat(username, name="chat"):
if request.method == 'POST':
msg = request.form.get('msg')
# accessing client for a username ans sending message using it
connsDict[username].sendMsg(msg)
return render_template('chatPage.html', name=name, messages=connsDict[username].MsgList, passwordHash=userKeys[username], username=username,latency=os.getenv("LATENCY"))
@app.route('/chat/<string:username>/chat_list/')
def getChatList(username):
if username in connsDict:
# returning messages list without authentication as
# it is single room for all and everyone can access the chats by joining the room
timeStamps=[i.timestamp for i in Message.query.all()]
return jsonify([connsDict.get(username).MsgList,timeStamps])
@app.route('/leave/<string:username>/', methods=["GET", "POST"])
def leave_room(username):
global connsDict, userKeys, users
passwordHash = request.form.get("passwordHash")
if userKeys[username] == passwordHash:
conn = connsDict.get(username)
conn.sendMsg(username+" left the chat..")
conn.close_client()
users.remove(username)
connsDict.pop(username, None)
userKeys.pop(username, None)
return redirect('/')
else:
return "Password didn't Match"
@app.route('/history/<string:username>/')
def history(username):
timeStamps=[i.timestamp for i in Message.query.all()]
return render_template("history.html",timestamps=timeStamps,messages=Message.query.all(),username=username)
if __name__ == "__main__":
app.run(threaded=True)