-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.py
411 lines (375 loc) · 20.2 KB
/
main.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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
"""Brainwaves cli client file"""
import getpass
import base64
import json
import argparse
import os
import webbrowser
import time
from encrypt_data import (
generate_keypair,
detect_private_key,
save_private_key,
encrypt_message_symmetrical,
decrypt_message,
generate_sym_key,
detect_sym_key,
detect_public_key,
save_public_key,
)
from client_functions import (
create_token,
get_token,
get_account_info,
get_sym_key,
post_thought,
register_user,
add_user_friends,
get_user_friends,
get_all_users,
get_thoughts_for_user,
wrap_encrypt_sym_key,
upload_keystore,
login_with_token,
log_out,
reset_password,
check_token,
remove_user_friends,
update_rating_for_thought,
get_user_conversation,
post_conversation_message,
delete_user_profile,
delete_user_keys
)
from fastapi import HTTPException
def main():
"""Display the main menu and prompt the user to choose an option."""
# python cli_main.py -s dev FOR DEV SERVER OR python cli_main.py FOR NORMAL USE
argParser = argparse.ArgumentParser()
argParser.add_argument("-s", "--server", help="Dev or live server", type=str, default="live")
args = argParser.parse_args()
if args.server == "dev":
server_url = "http://127.0.0.1:8000/"
else:
server_url = "https://peerbrain.teckhawk.be/"
authenticated = False
print()
print("Welcome to version 0.2 of the Brainwaves P2P client!")
print("-------------------------------------------------------------------")
print(f"The currently set server url is {server_url}")
print("-------------------------------------------------------------------")
print()
print("Please select what you want to do from the menu below.")
#MENU SHOWING WHILE WE ARE NOT LOGGED IN OR AUTHENTICATED WITH TOKEN
if not authenticated:
while authenticated == False:
print("1. Log in to the current server")
print("2. Register account on the current server")
print("3. Change server")
print("4. Reset your password")
print("Q to exit")
choice = input(">> ")
if choice == "1":
try:
if check_token(server_url):
authenticated = True
elif login_with_token(server_url):
authenticated = True
else:
print("---")
print("Inactive user!")
print("---")
except KeyError:
print("---")
print("Username/Password incorrect")
print("---")
elif choice == "2":
username = input("Enter your username: ")
user_email = input("Enter your email address: ")
user_password = getpass.getpass(prompt = "Please enter a password: ")
confirm_password = getpass.getpass(prompt = "Confirm your password: ")
if user_password == confirm_password:
registration_result = register_user(server_url, username.lower(), user_email, user_password)
print()
for key, value in registration_result:
print(f"{key} {value}")
else:
print()
print("Passwords do not match!")
print()
elif choice == "3":
server_url = input("Please enter a new url: ")
elif choice == "4":
print()
password_reset_username = input("Please enter your username: ")
print()
reset_password(server_url, password_reset_username)
print()
elif choice == "Q" or choice=="q":
break
else:
print("Invalid choice")
#MENU SHOWING WHILE WE LOGGED IN OR AUTHENTICATED WITH TOKEN
if authenticated:
while True:
username, email = get_account_info(server_url)#---Making current users username and email available to authenticated user
friends = get_user_friends(server_url)
print("\nMAIN MENU:")
print()
print("\nPlease choose an option:")
print()
print("1. TECHNICAL ACTIONS")
print("2. ACCOUNT ACTIONS")
print("3. LOG OUT")
print("Q to exit")
choice = input(">> ")
if choice == "1":
while True:
print("\TECHNICAL MENU:")
print()
print("\nPlease choose an option:")
print()
print("1. Generate SSH Keypair and symmetrical key(needed to create and read messages/tweets)")
print("B to return to main menu")
sub_choice = input(">> ")
# if sub_choice == "1":
# all_users = get_all_users(server_url)
# print()
# print("---ALL USERS---")
# print()
# for user in all_users:
# print(user)
# print()
if sub_choice == "1":
if detect_private_key() and detect_sym_key() and detect_public_key():
print()
print("Keys already exist, overwriting them will make your account irretrievable!!")
print()
print("Key creation canceled!")
else:
public_key, private_key = generate_keypair()
save_private_key(private_key)
save_public_key(public_key)
symmetric_key = generate_sym_key()
upload_result = upload_keystore(server_url, public_key, symmetric_key)
print("------------------------")
print(upload_result)
print("------------------------")
elif sub_choice == "B" or sub_choice=="b":
print("Returning to main menu...")
break
else:
print("Invalid choice")
elif choice == "2":
#temp storage of the password
user_password=""
while True:
print("\nACCOUNT MENU:")
print()
print("\nPlease choose an option:")
print()
print("1. Check your account details")
print("--------------------------------")
print("2. Create a message")
print("3. Show all messages from a friend")
print("--------------------------------")
print("4. Add a friend")
print("5. Check friends list")
print("6. Remove a friend from your friend list")
print("--------------------------------")
print("7. View your messages singularly.")
print("8. Private conversations(DM)")
print("9. Enable 2FA")
print("10. DELETE USER ACCOUNT")
print("B to return to main menu")
sub_choice = input(">> ")
if sub_choice == "1":
print("---YOUR ACCOUNT DETAILS---")
print()
print(f"Username : {username}")
print(f"Email : {email}")
elif sub_choice == "2":
#---MESSAGE POSTING CODE---#
print()
print(f"POSTING AS >> {username}")
print()
title = input("Please choose a title for your Thought: \n\n>>TITLE: ")
message = input("What would you like to post? : \n\nMESSAGE>>: ")
sym_key, enc_mess = encrypt_message_symmetrical(message)
print()
post_thought(server_url, username, title, enc_mess)
print("Message uploaded successfully!")
elif sub_choice == "3":
get_user_friends(server_url)
print()
base_64_encr_sym_key = bytes(0)
friend_username = str()
#error handling of faulty passwords
try:
while friend_username == str() and isinstance(base_64_encr_sym_key, bytes):
user_password = getpass.getpass(prompt ="Please confirm your password to get your messages: \n\n")
friend_username = input("Please enter the username of the friend that you want to see messages from: \n\n")
while friend_username == "":
print("You didn't provide a username for your friend!\n\n")
friend_username = str()
friend_username += input("Please enter the username of the friend that you want to see messages from: \n\n")
base_64_encr_sym_key = get_sym_key(server_url, user_password, friend_username)
try:
encrypted_sym_key = base64.b64decode(base_64_encr_sym_key)
for thought in get_thoughts_for_user(server_url, friend_username):
print("-------------------------------------------------------")
print(f"TITLE: {thought['title']}")
print()
print(f"RATING: { thought['rating']}")
print()
try:
decrypted_message = decrypt_message(thought["content"].encode("utf-8"), encrypted_sym_key)
print(f"MESSAGE: { decrypted_message}")
except FileNotFoundError as err:
print("Error decrypting message, you may need to generate your keys still!\nError:", err)
except ValueError as err:
print("Please restart the programme to register your keys!\nError:", err)
break
except TypeError as err:
print("Error decrypting the symmetrical key, you may need to generate your keys still, or your password was incorrect!\nError:", err)
except json.decoder.JSONDecodeError as err:
print("Error decoding the symmetrical key, you may need to generate your keys still!\n Error:", err)
print("-------------------------------------------------------")
print()
elif sub_choice == "4":
friend_username = input("Enter your friend's username:")
add_friend_result = add_user_friends(server_url, friend_username)
print("---------------------------")
print(f"Trying to add {friend_username} as a friend. RESULT : {add_friend_result}")
print("---------------------------")
#reloading friends object after adding a friend
friends = get_user_friends(server_url)
elif sub_choice == "5":
print()
print("---Friends---")
print()
for friend in friends:
print(f"- {friend[0]}")
print()
elif sub_choice == "6":
print()
print("---Friends---")
print()
for friend in friends:
print(f"- {friend[0]}")
print()
friend_username = input("Enter the username of the friend you want to remove:")
print()
remove_user_friends(server_url, friend_username)
#reloading friends object after removing a friend
friends = get_user_friends(server_url)
elif sub_choice == "7":
get_user_friends(server_url)
print()
base_64_encr_sym_key = bytes(0)
friend_username = str()
#error handling of faulty passwords
while friend_username == str() and isinstance(base_64_encr_sym_key, bytes):
if user_password == "":
user_password = getpass.getpass(prompt ="Please confirm your password to get your messages:\n\n")
friend_username = input("Please enter the username of the friend that you want to see messages from:\n\n")
while friend_username == "":
print("You didn't provide a username for your friend!\n\n")
friend_username = str()
friend_username += input("Please enter the username of the friend that you want to see messages from:\n\n")
base_64_encr_sym_key = get_sym_key(server_url, user_password, friend_username)
encrypted_sym_key = base64.b64decode(base_64_encr_sym_key)
thoughts = get_thoughts_for_user(server_url, friend_username)
reading = True
if len(thoughts) == 0:
print("No thoughts found for this user.")
else:
while reading:
print("Please choose a thought to read by entering its number or type B to go back:\n")
i = 0
for thought in thoughts:
print(f"{i + 1}. TITLE: {thought['title']}\t RATING: {thought['rating']}")
i += 1
try:
thought_choice = input("\nEnter thought number: ")
if thought_choice == "b" or thought_choice == "B":
reading = False
else:
thought_num = int(thought_choice)
selected_thought = thoughts[thought_num - 1]
print(f"\nTITLE: {selected_thought['title']}")
print(f"RATING: {selected_thought['rating']}\n")
decrypted_message = decrypt_message(selected_thought['content'], encrypted_sym_key)
print(f"MESSAGE: {decrypted_message}\n\n")
key_path = os.path.join(os.path.dirname(__file__), 'keys', 'message.key')
with open(key_path, 'rb') as key_file:
key = str(key_file.read())
update_rating_for_thought(server_url, key)
finished_reading = input("B: Finished reading ")
if finished_reading == "b" or finished_reading == "B":
reading = False
except FileNotFoundError as err:
print("Error decrypting message, you may need to generate your keys still!\nError:", err)
except ValueError as err:
print("Please restart the programme to register your keys!\nError:", err)
except IndexError as err:
print("You selected a non-existant thought number.\nError:", err)
elif sub_choice == "8":
friend_username = input("Please enter your friends username: \n")
get_user_conversation(server_url, friend_username)
print()
message = str()
print("1. Yes")
print("2. No")
choice = int(input(f"Do you want to reply to {friend_username}? "))
if choice == 1:
message += str(input("Enter your message: "))
post_conversation_message(server_url, friend_username, message)
print()
elif sub_choice == "9":
print("Launching 2FA setup in browser...")
token = get_token()
mfa = "https://mfa.peerbrain.net"
mfaurl = f"{mfa}/?token={token}&username={username}"
webbrowser.open(mfaurl)
elif sub_choice == "10":
print("\nYou are about to delete your Peerbrain Account. \
\n\nTHIS ACTION CANNOT BE UNDONE!")
print("\nAre you sure you want to delete your Peerbrain Account? \n")
confirmation = input ("If so, please enter your username below. \n\n")
if confirmation == username:
delete_user_profile(server_url)
delete_user_keys()
log_out()
time.sleep(1)
authenticated == False
print('Your account was successfully deleted! \n')
time.sleep(1)
print("Goodbye!\n\n")
break
else:
break
elif sub_choice == "B" or sub_choice=="b":
print("Returning to main menu...")
break
else:
print("Invalid choice")
elif choice == "3":
log_out()
authenticated == False
break
# file_path = "token.json"
# if os.path.exists(file_path):
# os.remove(file_path)
# print("Logged out successfully!")
#
# break
# else:
# print("You are not logged in!")
elif choice == "Q" or choice=="q":
print("Goodbye!")
break
else:
print("Invalid choice. Please try again.")
if __name__ == "__main__":
main()