-
Notifications
You must be signed in to change notification settings - Fork 58
/
web.py
245 lines (231 loc) · 9.67 KB
/
web.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# -*- coding: utf-8 -*-
import core
from flask import Blueprint, render_template, redirect, request, session, make_response, Response, stream_with_context
import bcrypt
import logging
import threading
import time
import tools
import requests
log = logging.getLogger()
db = None
start_time = None
configuration_data = None
socketio = None
web = Blueprint('web', __name__, template_folder='templates')
@web.route("/signup")
def signup():
"""
Render signup template
:return:
"""
log.info(":WEB:/signup")
return render_template("signup.html")
def update_loop(session_id, sid):
"""
:param session_id: W.I.L.L session id
:param sid: Flask session id
Update thread that will emit socket.io updates to the user while they're connected
:return:
"""
while session_id in core.sessions.keys():
try:
session_data = core.sessions[session_id]
except KeyError:
#Session ended while loop was sleeping
break
session_updates = session_data["updates"]
while not session_updates.empty():
update = session_updates.get()
log.debug("Pushing update {0}".format(update))
socketio.emit('update', update, room=sid)
time.sleep(1)
log.info(":{0}:Ending updates for finished session".format(session_id))
def disconnect_session():
"""
:param session_id:
End the webapp session and the update thread on the users disconnect from the page
:return:
"""
log.info(":SOCKET:disconnect")
session_id = session["session_id"]
if session_id in core.sessions.keys():
log.info(":{0}:Session disconnected".format(session_id))
#del core.sessions[session_id]
else:
log.debug(":{0}:Session id wasn't found in core.sessions".format(session_id))
@web.route("/settings", methods=["GET"])
def settings_page():
"""
Render the settings template
:return:
"""
log.info(":WEB:/settings")
if "username" in session.keys():
if "logged-in" in session.keys():
if session["logged-in"]:
session["user"] = db["users"].find_one(username=session["username"])
if session["user"]:
return render_template("settings.html")
return redirect("/")
def get_updates(data):
"""
:param data: socket.io data about the update thread:
Authenticate and start the update thread
:return:
"""
log.info(":SOCKET:get_updates")
session_id = data["session_id"]
if session_id:
if session_id in core.sessions.keys():
#If the session id is valid
log.debug("{1}:Subscribing client {0} to updates for session_id".format(
request.environ["REMOTE_ADDR"], session_id
))
#Keep running this loop while the session is active
log.info(":{0}:Starting update loop".format(session_id))
update_thread = threading.Thread(target=update_loop, args=(session_id, request.sid))
update_thread.start()
else:
log.debug("Session id {0} is invalid".format(session_id))
socketio.emit("update", {"value": "Error, invalid session id"})
else:
socketio.emit("update", {"value": "Error, couldn't find session id in update request"})
@web.route("/login", methods=["POST"])
def login():
"""
:param username:
:param password:
:return Login data:
"""
response = {"type": None, "text": None, "data": {}}
try:
username = str(request.form["username"])
password = request.form["password"]
if all(tools.check_string(x) for x in [username, password]):
user_table = db["users"].find_one(username=username)
db_hash = user_table["password"]
if bcrypt.checkpw(password.encode('utf8'), db_hash.encode('utf8')):
log.info(":{0}:Logged in user".format(username))
#Generate user token
session["logged-in"] = True
session["username"] = username
user_token = tools.get_user_token(username)
db['users'].upsert({"username":username, "user_token":user_token}, ['username'])
response["type"] = "success"
response["text"] = "Authentication successful"
response["data"].update({"user_token":user_token})
else:
response["type"] = "error"
response["text"] = "Invalid username/password"
else:
response["type"] = "error"
response["text"] = "Invalid input, allowed characters are {0}".format(tools.valid_chars)
except KeyError:
response["type"] = "error"
response["text"] = "Couldn't find username and password in request data"
resp = make_response(redirect("/"))
if response["type"] == "success":
log.info(":{0}:Setting cookies for username and user token".format(username))
session["username"] = username
session["user_token"] = response["data"]["user_token"]
return resp
@web.route("/", methods=["GET", "POST"])
def main():
"""
Render the webapp index.html template
:return index template:
"""
log.info(":WEB:/")
if "username" in session.keys():
username = session["username"]
else:
username = None
if username:
log.info(":{0}:Found username cookies".format(username))
log.debug("Setting session data")
if "logged-in" not in session.keys():
session["logged-in"] = False
session["welcome-message"] = "Welcome to W.I.L.L"
if configuration_data["debug"]:
session["debug_http"] = True
session["first-command"] = True
if username:
user_table = db["users"].find_one(username=username)
if "user_token" in user_table.keys() and "user_token" in session.keys():
user_token = session["user_token"]
if user_table["user_token"] == user_token:
log.info(":{0}:User authenticated via user_token in cookies".format(username))
new_token = tools.get_user_token(username)
db["users"].upsert({"username":username, "user_token": new_token}, ['username'])
session["logged-in"] = True
user_first_name = user_table["first_name"]
session["welcome-message"] = "Welcome back {0}".format(user_first_name)
if "session_id" in session.keys() and session["session_id"] in core.sessions.keys():
session_id = session["session_id"]
else:
session_id = tools.gen_session(username, "WEB", db)
session["session_id"] = session_id
session["user_token"] = new_token
log.info(":{0}:Generated session id for user {1}".format(
session_id, username
))
resp = make_response(render_template('index.html'))
return resp
else:
log.debug("User tokens don't match.\n{0}\n{1}".format(request.cookies.get("user_token"),
db["users"].find_one(username=username)["user_token"]))
session["logged-in"] = False
else:
log.debug("Couldn't find user token in cookies")
session["logged-in"] = False
else:
log.debug("Couldn't find username in cookies")
session["logged-in"] = False
#If the cookies aren't found
return render_template('index.html')
@web.route('/admin/<path>', methods=["GET"])
def report(path):
"""
Render template for admin-only reporting page or bounce a non admin user back to /
:param session:
:return report template:
"""
log.info(":WEB:/admin/{0}".format(path))
if "username" in session.keys() and "logged-in" in session.keys() and session["logged-in"]:
user_table = db["users"].find_one(username=session["username"])
if user_table:
if user_table["admin"]:
#Get the session_data
session["commands-processed"] = core.processed_commands
time_str = start_time
session["start-time"] = start_time
users_online = 0
users_processed = []
for session_id in core.sessions:
session_data = core.sessions[session_id]
session_user = session_data["username"]
if session_user not in users_processed:
users_processed.append(str(session_user))
users_online+=1
session["users-online"] = users_online
session["active-sessions"] = len(core.sessions)
session["errors"] = core.error_num
session["success"] = core.success_num
session["users-list"] = users_processed
if path == "report":
return render_template('report.html')
elif path == "logging":
if "log_proxy" in configuration_data.keys():
req = requests.get(configuration_data["log_proxy"], stream=True)
return Response(stream_with_context(req.iter_content()), content_type=req.headers['content-type'])
else:
return redirect("/")
elif path == "db":
if "db_proxy" in configuration_data.keys():
req = requests.get(configuration_data["db_proxy"], stream=True)
return Response(stream_with_context(req.iter_content()),
content_type=req.headers['content-type'])
else:
return redirect("/")
return redirect("/")