1111from deta import Deta
1212from dotenv import load_dotenv
1313import os
14- from tools import hashing , dnsverify
14+ from tools import hashing , dnsverify , htmlgen
1515from datetime import datetime , timedelta
1616import sentry_sdk
1717import requests
5353# FUNCTION AND CLASS DECLARATION ###############################
5454
5555def createtoken (data : dict , expires_delta : Optional [timedelta ] = None ):
56+ """
57+ Creates JWT token
58+ """
59+
5660 to_encode = data .copy ()
5761 if expires_delta :
5862 expire = datetime .utcnow () + expires_delta
@@ -63,6 +67,10 @@ def createtoken(data: dict, expires_delta: Optional[timedelta] = None):
6367 return encoded_jwt
6468
6569def get_current_user (access_token : Optional [str ] = Cookie (None )):
70+ """
71+ Gets current user by JWT token
72+ """
73+
6674 if access_token is None :
6775 #raise HTTPException(status_code=401, detail="Unauthorized. Authentication failed.")
6876 return None
@@ -80,6 +88,10 @@ def get_current_user(access_token: Optional[str] = Cookie(None)):
8088 return site ["key" ]
8189
8290def verifycaptcha (response : str ):
91+ """
92+ Verifies that hCaptcha result is valid
93+ """
94+
8395 data = {"secret" : str (os .getenv ("CAPTCHA_SECRET" )), "response" : response }
8496 r = requests .post ("https://hcaptcha.com/siteverify" , data = data )
8597 if r .status_code == 200 and json .loads (r .text )["success" ] == True :
@@ -114,8 +126,19 @@ def privacy(request: Request):
114126 return templates .TemplateResponse ("privacy.html" , {"request" : request })
115127
116128@app .get ("/login" )
117- def login (request : Request ):
118- return templates .TemplateResponse ("login.html" , {"request" : request })
129+ def login (request : Request , error : Optional [str ] = None ):
130+ if error == None :
131+ popup = ""
132+ elif error == "auth" :
133+ popup = htmlgen .loginalert ("Wrong domain/password." )
134+ elif error == "captcha" :
135+ popup = htmlgen .loginalert ("Captcha failed." )
136+ elif error == "locked" :
137+ popup = htmlgen .loginalert ("This account was locked. Contact support for further details." )
138+ else :
139+ popup = htmlgen .loginalert ("Login error." )
140+
141+ return templates .TemplateResponse ("login.html" , {"request" : request , "login_alert" : popup })
119142
120143@app .get ("/signup" )
121144def signup (request : Request ):
@@ -149,23 +172,27 @@ def dashboard(request: Request, key: str = Depends(get_current_user)):
149172"""
150173@app .post ("/login/auth" )
151174def loginauth (response : Response , username : str = Form (...), password : str = Form (...), captcha : str = Form (None , alias = "h-captcha-response" )):
175+ """
176+ Handles user authentication
177+ """
178+
152179 domain = username
153180 if captcha is None :
154- raise HTTPException ( status_code = 401 , detail = "Unauthorized. Captcha failed." )
181+ return RedirectResponse ( url = f"/login?error=captcha" , status_code = status . HTTP_303_SEE_OTHER )
155182 else :
156183 if verifycaptcha (captcha ) is False :
157- raise HTTPException ( status_code = 401 , detail = "Unauthorized. Captcha failed." )
184+ return RedirectResponse ( url = f"/login?error=captcha" , status_code = status . HTTP_303_SEE_OTHER )
158185
159186 try :
160187 site = sitesdb .fetch ({"domain" : domain }).items [0 ]
161188 except IndexError :
162- raise HTTPException ( status_code = 401 , detail = "Unauthorized. Authentication failed." )
189+ return RedirectResponse ( url = f"/login?error=auth" , status_code = status . HTTP_303_SEE_OTHER )
163190
164191 if hashing .verifypw (site ["password" ], password ) is False :
165- raise HTTPException ( status_code = 401 , detail = "Unauthorized. Authentication failed." )
192+ return RedirectResponse ( url = f"/login?error=auth" , status_code = status . HTTP_303_SEE_OTHER )
166193
167194 if site ["locked" ] is True :
168- raise HTTPException ( status_code = 401 , detail = "This account was locked. Contact support for further details." )
195+ return RedirectResponse ( url = f"/login?error=locked" , status_code = status . HTTP_303_SEE_OTHER )
169196
170197 access_token_expires = timedelta (minutes = ACCESS_TOKEN_EXPIRE_MINUTES )
171198 access_token = createtoken (
@@ -178,12 +205,20 @@ def loginauth(response: Response, username: str = Form(...), password: str = For
178205
179206@app .get ("/logout" )
180207def logout (response : Response , key : str = Depends (get_current_user )):
208+ """
209+ Logs out user
210+ """
211+
181212 response = RedirectResponse (url = "/login" , status_code = status .HTTP_303_SEE_OTHER )
182213 response .delete_cookie (key = "access_token" )
183214 return response
184215
185216@app .post ("/login/create" )
186217def create (username : str = Form (...), password : str = Form (...), captcha : str = Form (None , alias = "h-captcha-response" )):
218+ """
219+ Creates a new user
220+ """
221+
187222 if captcha is None :
188223 raise HTTPException (status_code = 401 , detail = "Unauthorized. Captcha failed." )
189224 else :
@@ -226,6 +261,10 @@ def create(username: str = Form(...), password: str = Form(...), captcha: str =
226261
227262@app .post ("/login/reset" )
228263def loginreset (username : str = Form (...), captcha : str = Form (None , alias = "h-captcha-response" )):
264+ """
265+ Handles password resets
266+ """
267+
229268 domain = username
230269 try :
231270 site = sitesdb .fetch ({"domain" : domain }).items [0 ]
@@ -246,6 +285,10 @@ def loginreset(username: str = Form(...), captcha: str = Form(None, alias="h-cap
246285
247286@app .get ("/login/reset/check" )
248287def loginresetcheck (key : str ):
288+ """
289+ Checks if the correct TXT DNS record to reset the user's password is set
290+ """
291+
249292 verification = dnsverify .verify (key )
250293 if verification is None :
251294 raise HTTPException (status_code = 404 , detail = "Reset key not found" )
@@ -257,6 +300,10 @@ def loginresetcheck(key: str):
257300
258301@app .post ("/login/reset/set" )
259302def loginset (key : str , password : str = Form (...)):
303+ """
304+ Sets a new account password
305+ """
306+
260307 verification = dnsverify .get (key )
261308 if verification is None :
262309 raise HTTPException (status_code = 404 , detail = "Reset key not found" )
@@ -276,6 +323,10 @@ def loginset(key: str, password: str = Form(...)):
276323
277324@app .get ("/forgot/2" )
278325def forgot2 (request : Request , key : str ):
326+ """
327+ Displays fogot (step 2) page
328+ """
329+
279330 verification = dnsverify .get (key )
280331 if verification is None :
281332 raise HTTPException (status_code = 404 , detail = "Reset key not found" )
@@ -288,6 +339,10 @@ def forgot2(request: Request, key: str):
288339
289340@app .get ("/forgot/3" )
290341def forgot3 (request : Request , key : str ):
342+ """
343+ Displays fogot (step 3) page
344+ """
345+
291346 verification = dnsverify .get (key )
292347 dt = datetime .now ()
293348 if verification is None :
@@ -313,6 +368,10 @@ def forgot3(request: Request, key: str):
313368
314369@app .get ("/api/{key}/widget.js" )
315370def widgetjs (key : str ):
371+ """
372+ Creates and serves widget for site
373+ """
374+
316375 # add site key to widget code
317376 site = sitesdb .get (key )
318377 if site is False or site is None :
@@ -329,6 +388,10 @@ def widgetjs(key: str):
329388
330389@app .get ("/api/{key}/report/{feedback}" )
331390def getfeedback (key : str , feedback : str , origin : Optional [str ] = Header (None )):
391+ """
392+ Receives and stores feedback reported from the widget
393+ """
394+
332395 site = sitesdb .get (key )
333396 if not site :
334397 raise HTTPException (status_code = 404 , detail = "Site key not found" )
@@ -378,6 +441,10 @@ def getfeedback(key: str, feedback: str, origin: Optional[str] = Header(None)):
378441
379442@app .post ("/api/settings" )
380443def widgetsettings (key : str = Depends (get_current_user ), text : str = Form (...)):
444+ """
445+ Changes account settings
446+ """
447+
381448 site = sitesdb .get (key )
382449 if site is False :
383450 raise HTTPException (status_code = 404 , detail = "Site key not found" )
@@ -389,6 +456,10 @@ def widgetsettings(key: str = Depends(get_current_user), text: str = Form(...)):
389456
390457@app .get ("/api/clear" )
391458def clearwidget (key : str = Depends (get_current_user )):
459+ """
460+ Clears the account's feedback
461+ """
462+
392463 site = sitesdb .get (key )
393464 if site is False :
394465 raise HTTPException (status_code = 404 , detail = "Site key not found" )
@@ -403,6 +474,10 @@ def clearwidget(key: str = Depends(get_current_user)):
403474
404475@app .get ("/api/delete" )
405476def deletewidget (key : str = Depends (get_current_user )):
477+ """
478+ Deletes the account
479+ """
480+
406481 site = sitesdb .get (key )
407482 if site is False :
408483 raise HTTPException (status_code = 404 , detail = "Site key not found" )
0 commit comments