-
Notifications
You must be signed in to change notification settings - Fork 0
/
user_settings.mu
executable file
·419 lines (409 loc) · 23.1 KB
/
user_settings.mu
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
410
411
412
413
414
415
416
417
418
419
#!/usr/bin/env python3
# nomadForum - a forum on the NomadNetwork
# Copyright (C) 2023-2024 AutumnSpark1226
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import os
import sys
import string
from argon2.exceptions import VerificationError
from argon2 import PasswordHasher
import main
import notify
def list_connections():
query_results = main.query_database(f"SELECT remote_id, allow_login, send_notifications, public, conn_id, verified FROM connections WHERE username = '{username}'")
for result in query_results:
print(f">>Identity: {main.decrypt(result[0])}")
if result[5] == 1:
if result[1] == 1:
print(f" Autologin: enabled `Ff22`_`[disable`:{main.page_path}/user_settings.mu`action=disable_autologin|value={result[4]}|source_link_id={link_id}]`_`f")
elif result[1] == 0:
print(f" Autologin: disabled `Ff22`_`[enable`:{main.page_path}/user_settings.mu`action=enable_autologin|value={result[4]}|source_link_id={link_id}]`_`f")
if result[2] == 1 and main.notifications_enabled:
print(f" Notifications: enabled `Ff22`_`[disable`:{main.page_path}/user_settings.mu`action=disable_notifications|value={result[4]}|source_link_id={link_id}]`_`f")
elif result[2] == 0 and main.notifications_enabled:
print(f" Notifications: disabled `Ff22`_`[enable`:{main.page_path}/user_settings.mu`action=enable_notifications|value={result[4]}|source_link_id={link_id}]`_`f")
if result[3] == 1:
print(f" Show on profile: enabled `Ff22`_`[disable`:{main.page_path}/user_settings.mu`action=disable_public|value={result[4]}|source_link_id={link_id}]`_`f")
elif result[3] == 0:
print(f" Show on profile: disabled `Ff22`_`[enable`:{main.page_path}/user_settings.mu`action=enable_public|value={result[4]}|source_link_id={link_id}]`_`f")
else:
print(" This identity is not verified yet.")
print(f" Verification code: `B444`<8|verification_code`>`b `Ff22`_`[Submit`:{main.page_path}/user_settings.mu`*|action=verify_connection|value={result[4]}|source_link_id={link_id}]`_`f")
print(f" `Ff22`_`[Remove`:{main.page_path}/user_settings.mu`action=remove_connection|value={result[4]}|source_link_id={link_id}]`_`f")
print()
def print_fields():
print(f">Settings Username: {username}")
print()
print(">>Pofile")
profile_data = main.query_database(f"SELECT display_name, about, default_styling, show_online FROM users WHERE username = '{username}'")[0]
display_name = profile_data[0].replace(">", "\\>")
print(f" Display name: `B444`<display_name`{display_name}>`b")
about = profile_data[1].replace("None", "").replace(">", "\\>").replace("\n", "$newline$")
print(f" About: `B444`<about`{about}>`b")
print(" $newline$ creates a new line. You can just use enter and it will be automatically replaced.")
print(f" `Ff22`_`[Save`:{main.page_path}/user_settings.mu`*|action=change_profile|source_link_id={link_id}]`_`f")
if profile_data[3] == 1:
print(f" Show online status: enabled `Ff22`_`[disable`:{main.page_path}/user_settings.mu`action=disable_online|source_link_id={link_id}]`_`f")
elif profile_data[3] == 0:
print(f" Show online status: disabled `Ff22`_`[enable`:{main.page_path}/user_settings.mu`action=enable_online|source_link_id={link_id}]`_`f")
print(f" `Ff22`_`[Visit your profile`:{main.page_path}/profile.mu`username={username}]`_`f")
print()
print(">>Default post styling")
default_styling = profile_data[2].replace("None", "").replace(">", "\\>").replace("\n", "$newline$")
print(f" Default post styling: `B444`<default_styling`{default_styling}>`b")
print(" $newline$ creates a new line. You can just use enter and it will be automatically replaced.")
print(f" `Ff22`_`[Save`:{main.page_path}/user_settings.mu`*|action=change_default_styling|source_link_id={link_id}]`_`f")
print()
list_connections()
print(">>Password")
if main.decrypt(main.query_database(f"SELECT password FROM users WHERE username = '{username}'")[0][0]) == "$nopassword$":
print(" Disabled")
print(" Set new password: `B444`<!|password`>`b")
print(" Confirm password: `B444`<!|password_confirm`>`b")
main.execute_sql(f"DELETE FROM verification_codes WHERE use_type = 'enable_password' AND username = '{username}'")
verification_code = main.get_verification_code()
main.execute_sql(f"INSERT INTO verification_codes (username, code, use_type, use_id, creation_time) VALUES ('{username}', '{main.encrypt(verification_code)}', 'enable_password', '{link_id}', unixepoch())")
print(f" Confirm this action by typing: '{verification_code}'")
print(f" Code: `B444`<8|confirmation_enable_password`>`b `Ff22`_`[Enable password`:{main.page_path}/user_settings.mu`*|action=enable_password|source_link_id={link_id}]`_`f")
else:
print(f" Enabled")
print(" Current password: `B444`<!|password_current`>`b")
print(f" `Ff22`_`[Disable password`:{main.page_path}/user_settings.mu`*|action=disable_password|source_link_id={link_id}]`_`f")
print(" Update password: `B444`<!|password`>`b")
print(" Confirm password: `B444`<!|password_confirm`>`b")
print(f" `Ff22`_`[Change password`:{main.page_path}/user_settings.mu`*|action=change_password|source_link_id={link_id}]`_`f")
print()
print(">>Other actions")
if main.notifications_enabled:
print(f" Add identity: `B444`<33|identity`>`b `Ff22`_`[Submit`:{main.page_path}/user_settings.mu`*|action=add_identity|source_link_id={link_id}]`_`f")
print(" Enter the identity and NOT the LXMF address here.")
print(f" `Ff22`_`[Subscription settings`:{main.page_path}/subscription_settings.mu]`_`f")
print(f" `Ff22`_`[Delete your account`:{main.page_path}/delete_account.mu]`_`f")
try:
link_id, remote_identity = main.handle_ids()
main.print_header(link_id, reload=True)
action = ""
value = ""
password = ""
password_confirm = ""
password_current = ""
display_name = ""
about = ""
verification_code = ""
identity = ""
default_styling = ""
confirmation_enable_password = ""
for env_variable in os.environ:
if env_variable == "var_action":
action = os.environ[env_variable]
elif env_variable == "var_value":
value = os.environ[env_variable]
elif env_variable == "field_password":
password = os.environ[env_variable]
elif env_variable == "field_password_confirm":
password_confirm = os.environ[env_variable]
elif env_variable == "field_password_current":
password_current = os.environ[env_variable]
elif env_variable == "field_display_name":
display_name = os.environ[env_variable]
elif env_variable == "field_about":
about = os.environ[env_variable]
elif env_variable == "field_verification_code":
verification_code = os.environ[env_variable]
elif env_variable == "field_identity":
identity = os.environ[env_variable]
elif env_variable == "field_default_styling":
default_styling = os.environ[env_variable]
elif env_variable == "field_confirmation_enable_password":
confirmation_enable_password = os.environ[env_variable]
query_result = main.query_database(f"SELECT username FROM users WHERE link_id = '{link_id}'")
if len(query_result) != 1:
print(">You are not logged in.")
else:
if action != "":
main.verify_link_id()
username = query_result[0][0]
if action == "remove_connection":
if not value.isdigit():
print("something went wrong...")
main.close_database(write_changes=False)
sys.exit(0)
query = main.query_database(f"SELECT allow_login FROM connections WHERE conn_id = {value} AND username = '{username}' ")
if len(query) != 1:
print("something went wrong...")
print(f"`Ff22`_`[Reload`:{main.page_path}/user_settings.mu]`_`f")
main.close_database()
sys.exit(0)
elif query[0][0] == 1:
print(">This identity is used for logging in. You can't remove it. (Disable autologin first.)")
print()
print_fields()
elif query[0][0] == 0:
main.execute_sql(f"DELETE FROM connections WHERE conn_id = {value} AND allow_login = 0 AND username = '{username}'")
print(">The identity has been removed.")
print()
print_fields()
else:
print("something went wrong...")
main.close_database(write_changes=False)
sys.exit(0)
elif action == "disable_autologin":
if not value.isdigit():
print("something went wrong...")
main.close_database(write_changes=False)
sys.exit(0)
if main.decrypt(main.query_database(f"SELECT password FROM users WHERE username = '{username}'")[0][0]) == "$nopassword$" and main.decrypt(main.query_database(f"SELECT remote_id FROM connections WHERE conn_id = {value}")[0][0]) == remote_identity:
print(">Deactivating autologin would lock you out of your account and is not permitted.")
print()
print_fields()
else:
main.execute_sql(f"UPDATE connections SET allow_login = 0 WHERE conn_id = {value} AND allow_login = 1 AND username = '{username}' AND verified = 1")
print(">Autologin disabled.")
print()
print_fields()
elif action == "enable_autologin":
if not value.isdigit():
print("something went wrong...")
main.close_database(write_changes=False)
sys.exit(0)
main.execute_sql(f"UPDATE connections SET allow_login = 1 WHERE conn_id = {value} AND allow_login = 0 AND username = '{username}' AND verified = 1")
print(">Autologin enabled.")
print()
print_fields()
elif action == "enable_notifications" and main.notifications_enabled:
if not value.isdigit():
print("something went wrong...")
main.close_database(write_changes=False)
sys.exit(0)
main.execute_sql(f"UPDATE connections SET send_notifications = 1 WHERE conn_id = {value} AND send_notifications = 0 AND username = '{username}' AND verified = 1")
identity = main.decrypt(main.query_database(f"SELECT remote_id FROM connections WHERE conn_id = {value}")[0][0])
try:
notify.add_notification([identity, "Notifications are now enabled on this address."])
print(">Notifications enabled.")
except:
print(">Could not send notification.")
print()
print_fields()
elif action == "disable_notifications" and main.notifications_enabled:
if not value.isdigit():
print("something went wrong...")
main.close_database(write_changes=False)
sys.exit(0)
main.execute_sql(f"UPDATE connections SET send_notifications = 0 WHERE conn_id = {value} AND send_notifications = 1 AND username = '{username}' AND verified = 1")
print(">Notifications disabled.")
print()
print_fields()
elif action == "enable_public":
if not value.isdigit():
print("something went wrong...")
main.close_database(write_changes=False)
sys.exit(0)
main.execute_sql(f"UPDATE connections SET public = 1 WHERE conn_id = {value} AND public = 0 AND username = '{username}' AND verified = 1")
print(">This identity will be shown on your profile.")
print()
print_fields()
elif action == "disable_public":
if not value.isdigit():
print("something went wrong...")
main.close_database(write_changes=False)
sys.exit(0)
main.execute_sql(f"UPDATE connections SET public = 0 WHERE conn_id = {value} AND public = 1 AND username = '{username}' AND verified = 1")
print(">This identity will not be shown on your profile.")
print()
print_fields()
elif action == "enable_online":
main.execute_sql(f"UPDATE users SET show_online = 1 WHERE username = '{username}' AND show_online = 0")
print(">Your online status will be shown.")
print()
print_fields()
elif action == "disable_online":
main.execute_sql(f"UPDATE users SET show_online = 0 WHERE username = '{username}' AND show_online = 1")
print(">Your online status will be hidden.")
print()
print_fields()
elif action == "disable_password":
query_result = main.query_database(f"SELECT conn_id, remote_id FROM connections WHERE username = '{username}' AND allow_login = 1 AND verified = 1")
remote_id_found = False
for data in query_result:
if main.decrypt(data[1]) == remote_identity:
remote_id_found = True
break
if remote_id_found:
hasher = PasswordHasher()
hashed_password = main.decrypt(main.query_database(f"SELECT password FROM users WHERE username = '{username}'")[0][0])
try:
hasher.verify(hashed_password, password_current)
except VerificationError:
print(">You entered a wrong password.\n")
print_fields()
main.close_database(write_changes=False)
exit(0)
main.execute_sql("UPDATE users SET password = '" + main.encrypt("$nopassword$") + f"' WHERE link_id = '{link_id}' AND username = '{username}'")
print(">Your password has been disabled.")
print()
print_fields()
else:
print(">Disabling your password would lock you out of your account and is not permitted.")
print()
print_fields()
elif action == "enable_password":
query_result = main.query_database(f"SELECT code FROM verification_codes WHERE use_type = 'enable_password' AND use_id = '{link_id}' AND username = '{username}'")
if len(query_result) != 1:
print(">Verification error\n")
print_fields()
main.close_database(write_changes=False)
exit(0)
else:
verification_code = main.decrypt(query_result[0][0])
if confirmation_enable_password != verification_code:
print(">Verification error\n")
print_fields()
main.close_database()
exit(0)
main.execute_sql(f"DELETE FROM verification_codes WHERE use_type = 'enable_password' AND use_id = '{link_id}' AND username = '{username}'")
query_result = main.query_database("SELECT username, remote_id FROM connections WHERE allow_login = 1")
remote_id_found = False
for data in query_result:
if main.decrypt(data[1]) == remote_identity and data[0] == username:
remote_id_found = True
break
if remote_id_found:
if len(password) < 8:
print(">Your password must be at least 8 characters long.\n")
print_fields()
main.close_database()
sys.exit(0)
elif len(password) > 512 or len(password_confirm) > 512:
print(">Long passwords are good, but that is just too long.\n")
print_fields()
main.close_database()
sys.exit(0)
hasher = PasswordHasher()
hashed_password = hasher.hash(password)
try:
hasher.verify(hashed_password, password_confirm)
except VerificationError:
print(">The entered passwords do not match.\n")
print_fields()
main.close_database(write_changes=False)
sys.exit(0)
prepared_password = main.encrypt(hashed_password)
main.execute_sql(f"UPDATE users SET password = '{prepared_password}' WHERE link_id = '{link_id}' AND username = '{username}'")
print(">Your password has been enabled.")
print()
print_fields()
else:
print(">Verification failed")
print()
print_fields()
elif action == "change_password":
if len(password) < 8:
print(">Your password must be at least 8 characters long.\n")
print_fields()
main.close_database(write_changes=False)
sys.exit(0)
elif len(password) > 512 or len(password_confirm) > 512 or len(password_current) > 512:
print(">Long passwords are good, but that is just too long.\n")
print_fields()
main.close_database()
sys.exit(0)
hasher = PasswordHasher()
hashed_password = main.decrypt(main.query_database(f"SELECT password FROM users WHERE username = '{username}'")[0][0])
try:
hasher.verify(hashed_password, password_current)
except VerificationError:
print(">You entered a wrong password.\n")
print_fields()
main.close_database(write_changes=False)
exit(0)
hasher = PasswordHasher()
hashed_password = hasher.hash(password)
try:
hasher.verify(hashed_password, password_confirm)
except VerificationError:
print(">The entered passwords do not match.\n")
print_fields()
main.close_database(write_changes=False)
sys.exit(0)
prepared_password = main.encrypt(hashed_password)
main.execute_sql(f"UPDATE users SET password = '{prepared_password}' WHERE link_id = '{link_id}' AND username = '{username}'")
print(">Your password has been changed.")
print()
print_fields()
elif action == "change_profile":
if display_name == "" or len(display_name) > 256:
main.execute_sql(f"UPDATE users SET display_name = username WHERE username = '{username}'")
else:
display_name = main.prepare_display_name(display_name, username)
main.execute_sql(f"UPDATE users SET display_name = '{display_name}' WHERE username = '{username}'")
if about == "" or len(about) >= 4096:
main.execute_sql(f"UPDATE users SET about = 'None' WHERE username = '{username}'")
else:
about = main.prepare_content(about)
main.execute_sql(f"UPDATE users SET about = '{about}' WHERE username = '{username}'")
print(">Your profile has been updated.")
print()
print_fields()
elif action == "change_default_styling":
if default_styling == "" or len(default_styling) >= 256:
main.execute_sql(f"UPDATE users SET default_styling = 'None' WHERE username = '{username}'")
else:
default_styling = main.prepare_content(default_styling)
main.execute_sql(f"UPDATE users SET default_styling = '{default_styling}' WHERE username = '{username}'")
print(">Your default styling has been updated.")
print()
print_fields()
elif action == "verify_connection":
if len(verification_code) == 7 and verification_code.replace("-", "").isnumeric() and verification_code[3] == "-" and value.isnumeric():
query_result = main.query_database(f"SELECT remote_id FROM connections WHERE conn_id = {value}")
if len(query_result) == 1:
requested_remote_id = main.decrypt(query_result[0][0])
possible_remote_ids = main.query_database(f"SELECT code_id, code, use_id FROM verification_codes WHERE username = '{username}' AND use_type = 'add_lxmf' AND try_counter < 3")
for verified_remote_id in possible_remote_ids:
if main.decrypt(verified_remote_id[2]) == requested_remote_id:
if main.decrypt(verified_remote_id[1]) == verification_code:
main.execute_sql(f"UPDATE connections SET verified = 1 WHERE username = '{username}' AND conn_id = {value}")
main.execute_sql(f"DELETE FROM verification_codes WHERE code_id = '{verified_remote_id[0]}'")
print(">Connection verified\n")
else:
main.execute_sql(f"UPDATE verification_codes SET try_counter = (try_counter + 1) WHERE code_id = '{verified_remote_id[0]}'")
main.purge()
print(">Could not verify connection\n")
break
else:
print(">Could not verify connection\n")
else:
print(">Could not verify connection\n")
print_fields()
elif action == "add_identity":
if len(identity) == 32 and set(identity).issubset(set(string.hexdigits)):
query_result = main.query_database("SELECT remote_id FROM connections")
for data in query_result:
if identity == main.decrypt(data[0]):
print(">Could not add identity\n")
print_fields()
main.close_database()
exit(0)
main.generate_verification(username, "add_lxmf", main.encrypt(identity), identity)
main.execute_sql(f"INSERT INTO connections (username, remote_id, verified) VALUES ('{username}', '{main.encrypt(identity)}', 0)")
print(">A verification code has been sent. Please enter enter it to verify this identity.\n")
else:
print(">Could not add identity\n")
print_fields()
else:
print_fields()
main.close_database()
except:
print("An error occured")