140 lines
3.8 KiB
Python
Executable File
140 lines
3.8 KiB
Python
Executable File
|
|
#!/usr/bin/env python3
|
|
|
|
from os import environ
|
|
from typing import Optional, Tuple
|
|
from datetime import datetime
|
|
from redis import Redis
|
|
from hashlib import sha256
|
|
from functools import reduce
|
|
|
|
s = datetime.now()
|
|
NO_REMOTE_IDENTITY_MSG = """User identity hash not available.
|
|
In MeshChat: use the fingerprint button in the top right to send the identification information.
|
|
In NomadNet: Save node, click on it, go to <Info> and select "Identify when connecting"."""
|
|
|
|
FORBIDDEN_INPUT = [
|
|
"[",
|
|
"`",
|
|
"\n"
|
|
]
|
|
|
|
MENU_ITEMS = [
|
|
("Home", "/page/index.mu]"),
|
|
("Status", "/page/status.mu"),
|
|
("Shoutbox", "/page/chat.mu]")
|
|
]
|
|
|
|
ADMIN_IDENTITIES = [
|
|
"e6c72573bb91d48338dbcc57d0223b81",
|
|
"70c9608c9a0f4ae895f7fab406554e1c"
|
|
]
|
|
BGCOLOR = "`F333`BDDD"
|
|
MENUBGCOLOR = "`FEEE`B333"
|
|
|
|
def is_admin() -> bool:
|
|
remote_identity = environ.get("remote_identity", None)
|
|
if remote_identity is None:
|
|
return False
|
|
return remote_identity in ADMIN_IDENTITIES
|
|
|
|
def sanitize_input(text: str) -> str:
|
|
return reduce(lambda a, b: a.replace(b, ""), FORBIDDEN_INPUT, text)
|
|
|
|
def check_password(password: str) -> bool:
|
|
expected = '34a77e61000b2ba1f56201332ef64d93f9cdc60e63ab48bc255102586ef7e592'
|
|
gotten = sha256(f"hswrosalt{password}".encode('utf-8'), usedforsecurity=True).hexdigest()
|
|
return expected == gotten
|
|
|
|
def check_name(username: str) -> bool:
|
|
if len(username) >= 16:
|
|
return False
|
|
return all(map(lambda c: c.isalnum(), username))
|
|
|
|
def get_login_info() -> Tuple[Optional[str], Optional[str]]:
|
|
"""Returns [login_name, error]"""
|
|
remote_identity = environ.get("remote_identity", None)
|
|
if remote_identity is None:
|
|
return (None, NO_REMOTE_IDENTITY_MSG)
|
|
r = Redis(host='localhost', port=6379, db=0)
|
|
login = r.get(f'login_info_{remote_identity}')
|
|
if login is None:
|
|
return (None, None)
|
|
return (login.decode('utf-8'), None)
|
|
|
|
def login(username: str) -> Optional[str]:
|
|
"""Returns err"""
|
|
remote_identity = environ.get("remote_identity", None)
|
|
if remote_identity is None:
|
|
return NO_REMOTE_IDENTITY_MSG
|
|
if not check_name(username):
|
|
return "Username should only contain alphanumeric characters and have at most 16 characters."
|
|
r = Redis(host='localhost', port=6379, db=0)
|
|
r.set(f'login_info_{remote_identity}', username)
|
|
return None
|
|
|
|
def logout():
|
|
remote_identity = environ.get("remote_identity", None)
|
|
if remote_identity is None:
|
|
return
|
|
r = Redis(host='localhost', port=6379, db=0)
|
|
r.delete(f'login_info_{remote_identity}')
|
|
|
|
|
|
def login_button() -> str:
|
|
l = get_login_info()
|
|
if l[0] is None:
|
|
return "[`[Identify`:/page/login.mu`]]"
|
|
else:
|
|
return f"Welcome, {l[0]} | [`[Forget`:/page/logout.mu`]]"
|
|
|
|
def render_menu_item(active_title: Optional[str]) -> str:
|
|
def f(current: Tuple[str, str]) -> str:
|
|
current_title = current[0]
|
|
href = current[1]
|
|
retval = " "
|
|
if current_title == active_title:
|
|
retval += "`!"
|
|
retval += f"`[{current_title}`:{href}`]"
|
|
if current_title == active_title:
|
|
retval += "`!"
|
|
return retval + " "
|
|
return f
|
|
|
|
def render_menu(title: Optional[str] = None) -> str:
|
|
LEFT_MARGIN = 2
|
|
retval = "\n`l" + " "*LEFT_MARGIN
|
|
retval += "│".join(map(render_menu_item(title), MENU_ITEMS))
|
|
retval += "\n"
|
|
return retval
|
|
|
|
|
|
def header(title: Optional[str] = None):
|
|
ftitle = ""
|
|
if title is not None:
|
|
ftitle = ": `i" + title
|
|
print(f"""`F000`BFB1
|
|
`c
|
|
|
|
`r {login_button()}
|
|
`l `!Hackerspace`!Wrocław{ftitle}
|
|
`a
|
|
|
|
|
|
`a
|
|
``
|
|
{MENUBGCOLOR}
|
|
`c
|
|
{render_menu(title)}
|
|
{BGCOLOR}""")
|
|
|
|
def reset_colors() -> str:
|
|
print(BGCOLOR)
|
|
|
|
def footer():
|
|
print(f"\n{BGCOLOR}`r Rendered in: {(datetime.now()-s).total_seconds()}s")
|
|
print(f"{datetime.now()}")
|
|
|
|
if __name__ == "__main__":
|
|
pass
|