From c5eef007aa9ef1f9bf0e334833ebfcf26e5a9884 Mon Sep 17 00:00:00 2001 From: BlenderDumbass Date: Sun, 24 Nov 2024 23:28:19 +0200 Subject: [PATCH] First fully functional website --- icons/user_link.png | Bin 0 -> 5028 bytes icons/user_new.png | Bin 0 -> 4889 bytes modules/Account.py | 109 +++++++++++++ modules/Common.py | 5 +- modules/Help.py | 16 ++ modules/Legacy.py | 7 + modules/Render.py | 381 +++++++++++++++++++++++++++++++++++++++++--- modules/Run.py | 15 ++ modules/Set.py | 3 +- run.py | 4 + 10 files changed, 514 insertions(+), 26 deletions(-) create mode 100644 icons/user_link.png create mode 100644 icons/user_new.png create mode 100644 modules/Account.py diff --git a/icons/user_link.png b/icons/user_link.png new file mode 100644 index 0000000000000000000000000000000000000000..f62c2778543f26acd1cbeeda817a0a214a3f66a5 GIT binary patch literal 5028 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 literal 0 HcmV?d00001 diff --git a/icons/user_new.png b/icons/user_new.png new file mode 100644 index 0000000000000000000000000000000000000000..2aec0da4b7ed88ad9539e9df853931ee687a5115 GIT binary patch literal 4889 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 Ihi4Z52gZHVp8x;= literal 0 HcmV?d00001 diff --git a/modules/Account.py b/modules/Account.py new file mode 100644 index 0000000..141685d --- /dev/null +++ b/modules/Account.py @@ -0,0 +1,109 @@ +# AGPL 3 or any later version +# (C) J.Y.Amihud ( Blender Dumbass ) + + +import os +import sys +import json +import random +import hashlib +import urllib.parse + +from datetime import datetime +from getpass import getpass + +from modules import Set +from modules import markdown +from modules.Common import * + + +def Load(name): + + folder = Set.Folder()+"/accounts/" + try: + with open(folder+name+".json") as o: + return json.load(o) + except: + return {} + +def Save(account): + + name = account.get("username", "") + folder = Set.Folder()+"/accounts/" + + try: + with open(folder+name+".json", "w") as save: + json.dump(account, save, indent=4) + + except Exception as e: + print(clr["bold"]+clr["tdrd"]+"Error:"+clr["norm"]+" Cannot save account!", e) + +def Account(): + + if len(sys.argv) < 3: + from modules import Help + Help.Accounts() + + if "--list" in sys.argv: + List() + + elif "--add" in sys.argv: + try: + account = sys.argv[ sys.argv.index("--add") + 1] + if "--" in account: 1/0 # Failing this for the error message. + Add(account) + + except Exception as e: + print(clr["bold"]+clr["tdrd"]+"Error:"+clr["norm"]+" Account name wasn't specified!") + print('Use: $ python3 run.py --account --add blenderdumbass') + + elif "--edit" in sys.argv: + try: + account = sys.argv[ sys.argv.index("--edit") + 1] + if "--" in account: 1/0 # Failing this for the error message. + Edit(account) + + except Exception as e: + print(clr["bold"]+clr["tdrd"]+"Error:"+clr["norm"]+" Account name wasn't specified!") + print('Use: $ python3 run.py --account --edit blenderdumbass') + + +def List(): + + folder = Set.Folder()+"/accounts" + for account in os.listdir(folder): + if account.endswith(".json"): + print(account.replace(".json", "")) + +def Add(name): + + # Adds a new account. + + account = Load(name) + if account: + print(clr["bold"]+clr["tdrd"]+"Error:"+clr["norm"]+" Account already exists.") + + account = { + "username":name, + "bio":"", + "invite_codes":{}, + "invited":[], + "invited_by":"", + "password":hashlib.sha512(getpass("Account's Password: ").encode("utf-8")).hexdigest(), + "title":name, + "email":"", + "website":"", + "mastodon":"", + "matrix":"", + "sessions":{} + } + + + Save(account) + + print(clr["bold"]+clr["tbyl"]+name+clr["norm"]+" is added."+clr["norm"]) + +def Edit(name): + + folder = Set.Folder()+"/accounts/" + os.system("nano "+folder+name+".json") diff --git a/modules/Common.py b/modules/Common.py index c53b26c..128821d 100644 --- a/modules/Common.py +++ b/modules/Common.py @@ -52,7 +52,10 @@ def Simplify(text, extrasimple=True): good = "QWERTYUIOPLKJHGFDSAZXCVBNMqwertyuiopasdfghjklzxcvbnm.1234567890-_:* " - if extrasimple: + if extrasimple == "file": + good = "QWERTYUIOPLKJHGFDSAZXCVBNMqwertyuiopasdfghjklzxcvbnm.1234567890-_" + + elif extrasimple: good = "qwertyuiopasdfghjklzxcvbnm.1234567890-_:" text = text.lower() diff --git a/modules/Help.py b/modules/Help.py index 8ebdf7f..49a0dfb 100644 --- a/modules/Help.py +++ b/modules/Help.py @@ -10,9 +10,13 @@ def Help(): print() print(clr["tdyl"]+"--help"+clr["norm"]+" - Prints this Help Page.") print(clr["tdyl"]+"--run"+clr["norm"]+" - Run the server.") + print() print(clr["tdyl"]+"--set"+clr["norm"]+" - Use for changing settings.") + print(clr["tdyl"]+"--account"+clr["norm"]+" - Manage Accounts.") + print() print(clr["tdyl"]+"--config"+clr["norm"]+" - Edit config file directly, bypassing --set.") print(clr["tdyl"]+"--folder"+clr["norm"]+" - Open the folder of the website's data.") + print() print(clr["tdyl"]+"--transfer"+clr["norm"]+"- Transfers legacy website data to the new format.") print() @@ -32,3 +36,15 @@ def Set(): print(clr["tdyl"]+"--add_tab"+clr["norm"]+" - Adds a category of articles.") print(clr["tdyl"]+"--edit_tab"+clr["norm"]+" - Edit the config of a category.") print() + +def Accounts(): + + print() + print(clr["bold"]+" BDServer Account Help "+clr["norm"]) + print() + print(" Account is used to manage website's accounts.") + print() + print(clr["tdyl"]+"--add"+clr["norm"]+" - Add a new account.") + print(clr["tdyl"]+"--list"+clr["norm"]+" - List accounts.") + print() + diff --git a/modules/Legacy.py b/modules/Legacy.py index 8a199bf..ae50801 100644 --- a/modules/Legacy.py +++ b/modules/Legacy.py @@ -139,6 +139,13 @@ def Transfer(location): account = accounts[username] + # We are updating the invites + invite_codes = account.pop("invite_codes") + account["invite_codes"] = {} + + for code in invite_codes: + account["invite_codes"][code] = "Unknown" + # We are adding some new stuff to accounts account["title"] = username # Visible title diff --git a/modules/Render.py b/modules/Render.py index 2f922b8..cf81642 100644 --- a/modules/Render.py +++ b/modules/Render.py @@ -138,6 +138,22 @@ def moderates(moderator, user): if moderator == user: return True + + if rank(moderator, Accounts) < rank(user, Accounts): + return True + +def rank(account, Accounts=None): + + if not Accounts: + Accounts = accounts() + + if account not in Accounts: + return 1000000 + + if not Accounts[account].get("invited_by") or Accounts[account].get("invited_by") == account: + return 0 + + return 1 + rank(Accounts[account].get("invited_by"), Accounts) def articles(tab): @@ -530,8 +546,16 @@ def AccountPage(server, account): html = html + '
' html = html + '
' - html = html +"

"+Accounts.get(account, {}).get("title", account)+"

" + html = html +"

"+Accounts.get(account, {}).get("title", account)+"

" + # Rank + + Rank = rank(account) + html = html + Button("Rank "+str(Rank), "", icon="analytics") + + + html = html + '
' + # Website website = Safe(Accounts.get(account, {}).get("website" , "")) @@ -561,16 +585,19 @@ def AccountPage(server, account): if mastodon: # It could be mastodon url and not handle. - if "/" in mastodon: - mastodon = mastodon.replace("https://", "").replace("http://", "") - mastodon = mastodon.split("/")[1]+"@"+mastodon.split("/")[0] + try: + if "/" in mastodon: + mastodon = mastodon.replace("https://", "").replace("http://", "") + mastodon = mastodon.split("/")[1]+"@"+mastodon.split("/")[0] - mastolink = "https://"+mastodon[1:].split("@")[1]+"/@"+mastodon[1:].split("@")[0] - - html = html + '
' - html = html + '' - html = html + ' '+mastodon+'' - html = html + '
' + mastolink = "https://"+mastodon[1:].split("@")[1]+"/@"+mastodon[1:].split("@")[0] + + html = html + '
' + html = html + '' + html = html + ' '+mastodon+'' + html = html + '
' + except: + pass # Matrix @@ -593,11 +620,11 @@ def AccountPage(server, account): html = html + '
' - html = html + '
' - html = html +"
Invited by:
"+User(Accounts.get(account, {}).get("invited_by", account))+"
" - - - html = html + '
' + invited_by = Accounts.get(account, {}).get("invited_by", "") + if invited_by: + html = html + '
' + html = html +"
Invited by:
"+User(invited_by)+"
" + html = html + '
' bio = Safe(Accounts.get(account, {}).get("bio" , "")) if bio: @@ -670,13 +697,17 @@ def LoginPage(server): html = html + """ +
+ +
+
- +
-
+
- Don't have an account? Register. +
+ +
+ Don't have an account?
""" + html = html + Button("Register", "/register", icon="user_new") + + send(server, html, 200) - html = html + '' +def RegisterPage(server): + user = validate(server.cookie) + + config = Set.Load() + Accounts = accounts() + f = Set.Folder() + + code = server.parsed.get("code", [""])[0] + userexists = server.parsed.get("userexists", [""])[0] + wrongcode = server.parsed.get("wrongcode", [""])[0] + + # Generating + html = head(title = "Login", + description = "Login", + config = config + ) + + html = html + Button(config.get("title", "My Website"), "/", image=config.get("favicon", "/icon/internet")) + + html = html + '
' + + + html = html + """ + +
+ +
+ +
+ """ + + if wrongcode: + html = html + "Invalid Invite Code.

" + + if not code and not user: + html = html + """ + + + + + """ + username = "" + + else: + for account in Accounts: + if code in Accounts[account].get("invite_codes", []): + username = Simplify(Accounts[account]["invite_codes"][code], "file") + + html = html + '
Invited by:

' + html = html + User(account)+'
' + html = html + '' + + break + + + if not user: + + + if userexists: + html = html + "Username is taken.

" + + html = html + """ + +
+ +
+ + + """ + + elif code: + html = html + "Share this page with those you invited." + + else: + html = html + "
You already registered and logged in." + + html = html + """ + + +
+ +
+ +
+ + Have an account?
+ """ + html = html + Button("Login", "/login", icon="unlock") + + send(server, html, 200) def SettingsPage(server): user = validate(server.cookie) + + if not user: + Redirect(server, "/login") + return + config = Set.Load() # Generating @@ -757,12 +891,71 @@ def SettingsPage(server):
-
- """ + # Current Logged in Sessions + + sessions = user.get("sessions", {}) + + html = html + '
' + html = html + '

Active Sessions

' + for cookie in sessions: + + session = sessions[cookie] + + CancelButton = Button("Log Out", "/log_out?cookie="+cookie, icon="cancel") + if server.cookie == cookie: + html = html + '
' + else: + html = html + '
' + html = html + ''+CancelButton + + html = html + '

' + html = html + '
' + html = html + '
' + + # Invites and Invite codes + + invite_codes = user.get("invite_codes", {}) + + html = html + '
' + html = html + '

Invites

' + + for code in invite_codes: + + nick = invite_codes[code] + + Open = "" + if code == server.parsed.get("code", [""])[0]: + Open = "open" + + html = html + '
' + html = html + ''+nick + html = html + '
' + html = html + '' + html = html + '' + html = html + Button("Share Link", "/register?code="+code, icon="link") + html = html + Button("Cancel", "/cancel_invite?code="+code, icon="cancel") + html = html + '
' + + html = html + """ + +
+ + + + + +
+ + """ + send(server, html, 200) + ### @@ -1078,7 +1271,7 @@ def LoginButton(server): if not user: html = html + '' - html = html + ' Login' + html = html + ' Login' html = html + '' else: @@ -1161,10 +1354,109 @@ def Login(server): Redirect(server, "/") +def Register(server): + + # If by mistake we are logged in + user = validate(server.cookie) + if user: + Redirect(server, "/register") + + username = Simplify(server.parsed.get("user_name", [""])[0], "file") + code = server.parsed.get("code", [""])[0] + password = server.parsed.get("password" , [""])[0] + hashed = hashlib.sha512(password.encode("utf-8")).hexdigest() + + Accounts = accounts() + + # We avoid username swappage + if username in Accounts or not username: + if code: + Redirect(server, "/register?code="+code+"&userexists=True#user_name") + else: + Redirect(server, "/register?userexists=True#user_name") + return + + # Validating the invite code + + invited_by = "" + for account in Accounts: + if code in Accounts[account].get("invite_codes", []): + invited_by = account + break + + if not invited_by: + Redirect(server, "/register?wrongcode=True") + return + + # Now we can finally make our account. + + # New account first + account = { + "username":username, + "bio":"", + "invite_codes":{}, + "invited":[], + "invited_by":invited_by, + "password":hashed, + "title":username, + "email":"", + "website":"", + "mastodon":"", + "matrix":"", + "sessions":{ + server.cookie:server.headers.get("User-Agent") + } + } + + f = Set.Folder() + folder = f+"/accounts" + + with open(folder+"/"+username+".json", "w") as save: + json.dump(account, save, indent=4) + + # Now the invitor changes + + account = Accounts[invited_by] + del account["invite_codes"][code] + account["invited"].append(username) + + with open(folder+"/"+account.get("username", "")+".json", "w") as save: + json.dump(account, save, indent=4) + + Redirect(server, "/settings") + +def LogOut(server): + + user = validate(server.cookie) + cookie = server.parsed.get("cookie", [""])[0] + + # This might be an attack. So we don't want that. + if cookie not in user.get("sessions",{}): + Redirect(server, "/") + return + + del user["sessions"][cookie] + + f = Set.Folder() + folder = f+"/accounts" + with open(folder+"/"+user.get("username", "")+".json", "w") as save: + json.dump(user, save, indent=4) + + # If the user logged out this session + if cookie == server.cookie: + Redirect(server, "/") + + else: + Redirect(server, "/settings#sessions") + + def UpdateAccount(server): user = validate(server.cookie) - + if not user: + Redirect(server, "/login") + return + keys = [ "title", "avatar", @@ -1259,6 +1551,14 @@ def DoComment(server): else: number = int(number) if moderates(user.get("username"), article["comments"]["comments"][number]["username"]): + + # Making sure moderators done get credit for small edits + # in comments. + + originalcommet = article["comments"]["comments"][number] + if originalcommet.get("username") in Accounts: + comment["username"] = originalcommet["username"] + article["comments"]["comments"][number] = comment @@ -1311,3 +1611,36 @@ def DeleteComment(server): redirect = "#comments" Redirect(server, url+redirect) + +def CancelInvite(server): + + user = validate(server.cookie) + code = server.parsed.get("code", [""])[0] + if user: + del user["invite_codes"][code] + f = Set.Folder() + folder = f+"/accounts" + with open(folder+"/"+user.get("username", "")+".json", "w") as save: + json.dump(user, save, indent=4) + Redirect(server, "/settings#invites") + + else: + Redirect(server, "/") + +def CreateInvite(server): + + user = validate(server.cookie) + nick = server.parsed.get("nick", [""])[0] + if not nick: nick = "Unknown" + code = RandString() + if user: + user["invite_codes"][code] = nick + + f = Set.Folder() + folder = f+"/accounts" + with open(folder+"/"+user.get("username", "")+".json", "w") as save: + json.dump(user, save, indent=4) + Redirect(server, "/settings?code="+code+"#invite_"+code) + + else: + Redirect(server, "/") diff --git a/modules/Run.py b/modules/Run.py index 254b06f..bbfd6ba 100644 --- a/modules/Run.py +++ b/modules/Run.py @@ -74,6 +74,9 @@ class handler(BaseHTTPRequestHandler): elif self.path[1:].startswith("login"): Render.LoginPage(self) + elif self.path[1:].startswith("register"): + Render.RegisterPage(self) + elif self.path[1:].startswith("settings"): Render.SettingsPage(self) @@ -86,9 +89,21 @@ class handler(BaseHTTPRequestHandler): elif self.path[1:].startswith("update_account"): Render.UpdateAccount(self) + elif self.path[1:].startswith("create_invite"): + Render.CreateInvite(self) + + elif self.path[1:].startswith("cancel_invite"): + Render.CancelInvite(self) + + elif self.path[1:].startswith("log_out"): + Render.LogOut(self) + elif self.path[1:].startswith("do_login"): Render.Login(self) + elif self.path[1:].startswith("do_register"): + Render.Register(self) + elif self.path.startswith("/graph/"): url = self.path[6:] if "?" in url: url = url[:url.find("?")] diff --git a/modules/Set.py b/modules/Set.py index 84c73c4..315eb6e 100644 --- a/modules/Set.py +++ b/modules/Set.py @@ -45,7 +45,7 @@ def Save(data): try: with open(Folder()+"/config.json", "w") as save: - json.dump(data, save, indent=4, sort_keys=True) + json.dump(data, save, indent=4) except Exception as e: print(clr["bold"]+clr["tdrd"]+"Error:"+clr["norm"]+" Cannot save config!", e) @@ -221,3 +221,4 @@ def SetFavicon(filename): Save(config) print("New favicon is set at "+clr["bold"]+Folder()+"/pictures/favicon.png"+clr["norm"]) + diff --git a/run.py b/run.py index a9d8c70..35d3df7 100644 --- a/run.py +++ b/run.py @@ -15,6 +15,10 @@ elif "--set" in sys.argv: from modules import Set Set.Set() +elif "--account" in sys.argv: + from modules import Account + Account.Account() + elif "--config" in sys.argv: from modules import Set data = Set.Load() # Making sure