diff --git a/cutt/forgotten_password.html b/cutt/forgotten_password.html
new file mode 100644
index 0000000..c1e85f7
--- /dev/null
+++ b/cutt/forgotten_password.html
@@ -0,0 +1,111 @@
+
+
+
+
+ cutt - set password
+
+
+
+
+
+ Hello USER,
+ click on the following link to set yourself a new password.
+
+ reset password
+
+ Cheers,
Julius
+
+
diff --git a/cutt/mail.py b/cutt/mail.py
new file mode 100644
index 0000000..912b084
--- /dev/null
+++ b/cutt/mail.py
@@ -0,0 +1,58 @@
+from email.message import EmailMessage
+from email.utils import formataddr
+import smtplib
+import os
+import ssl
+from dotenv import load_dotenv
+from fastapi import Response, status
+from sqlmodel import Session, select
+from cutt.db import Player, TokenDB, engine
+from cutt.security import set_password_token
+
+P = Player
+
+load_dotenv()
+
+
+def generate_password_link(user: Player):
+ with Session(engine) as session:
+ token = set_password_token(user)
+ if token:
+ session.add(TokenDB(token=token))
+ session.commit()
+ return f"https://cutt.0124816.xyz/setpassword?token={token}"
+
+
+def send_forgotten_password_link(email: str):
+ with Session(engine) as session:
+ user = session.exec(
+ select(P).where(P.email == email, P.disabled != True)
+ ).one_or_none()
+ if user and user.email:
+ link = generate_password_link(user)
+ msg = EmailMessage()
+ msg["Subject"] = "CUTT - reset password"
+ msg["From"] = "CUTT - cool ultimate team tool "
+ msg["To"] = formataddr((user.display_name, user.email))
+ msg.set_content(
+ f"Hello {user.display_name},\nclick on the following link to set yourself a new password.\n\n{link}\n\nCheers,\nJulius"
+ )
+ with open("cutt/forgotten_password.html") as f:
+ html_body = (
+ f.read().replace("USER", user.display_name).replace("LINK", link)
+ )
+ msg.add_alternative(html_body, subtype="html")
+ context = ssl.create_default_context()
+ with smtplib.SMTP(
+ host=os.environ["SMTP_HOST"],
+ port=int(os.environ["SMTP_PORT"]),
+ timeout=20,
+ ) as server:
+ server.starttls(context=context)
+ server.login(os.environ["SMTP_USER"], os.environ["SMTP_PASS"])
+ server.send_message(msg)
+
+ return Response(
+ "a link will be sent to this email, if it belongs to an existing user.",
+ status_code=status.HTTP_200_OK,
+ )
diff --git a/cutt/main.py b/cutt/main.py
index d1b5a4f..0431b93 100644
--- a/cutt/main.py
+++ b/cutt/main.py
@@ -10,6 +10,7 @@ from sqlmodel import (
)
from fastapi.middleware.cors import CORSMiddleware
from cutt.analysis import analysis_router
+from cutt.mail import send_forgotten_password_link
from cutt.security import (
get_current_active_user,
login_for_access_token,
@@ -229,6 +230,9 @@ api_router.include_router(
api_router.include_router(team_router, dependencies=[Depends(get_current_active_user)])
api_router.include_router(analysis_router)
api_router.add_api_route("/token", endpoint=login_for_access_token, methods=["POST"])
+api_router.add_api_route(
+ "/forgotten_password", endpoint=send_forgotten_password_link, methods=["POST"]
+)
api_router.add_api_route("/set_password", endpoint=set_first_password, methods=["POST"])
api_router.add_api_route("/register", endpoint=register, methods=["POST"])
api_router.add_api_route("/logout", endpoint=logout, methods=["POST"])
diff --git a/cutt/security.py b/cutt/security.py
index 519f65b..99da870 100644
--- a/cutt/security.py
+++ b/cutt/security.py
@@ -212,19 +212,17 @@ async def logout(response: Response):
return {"message": "Successfully logged out"}
-def set_password_token(username: str):
- user = get_user(username)
- if user:
- expire = timedelta(days=30)
- token = create_access_token(
- data={
- "sub": "set password",
- "username": username,
- "name": user.display_name,
- },
- expires_delta=expire,
- )
- return token
+def set_password_token(user: Player):
+ expire = timedelta(days=30)
+ token = create_access_token(
+ data={
+ "sub": "set password",
+ "username": user.username,
+ "name": user.display_name,
+ },
+ expires_delta=expire,
+ )
+ return token
def register_token(team_id: int):
diff --git a/forgotten_password.py b/forgotten_password.py
index eb2b31a..18e4559 100644
--- a/forgotten_password.py
+++ b/forgotten_password.py
@@ -7,7 +7,7 @@ from cutt.db import Player, TokenDB, engine
if len(sys.argv) > 1:
with Session(engine) as session:
for p in session.exec(
- select(Player.username).where(Player.username == sys.argv[1].strip())
+ select(Player).where(Player.username == sys.argv[1].strip())
):
print(p)
token = set_password_token(p)