diff --git a/db/create_users.sql b/db/create_users.sql index 0c1c4b2..bb522d6 100644 --- a/db/create_users.sql +++ b/db/create_users.sql @@ -5,4 +5,7 @@ INSERT INTO "sessions" ("token", "userid", "validuntil") VALUES ('test2', 1, '2025-04-30'); INSERT INTO "clients" ("name") VALUES - ('1.54'); \ No newline at end of file + ('1.54'); + +INSERT INTO "user" ("name", "api_access", "password") VALUES + ('sepp', True, '473287f8298dba7163a897908958f7c0eae733e25d2e027992ea2edc9bed2fa8'); -- PASSWORD: string diff --git a/webservice/README.md b/webservice/README.md index 98c0229..cd89eba 100644 --- a/webservice/README.md +++ b/webservice/README.md @@ -2,6 +2,8 @@ Developer Mode starten: fastapi dev webservice.py +SHA256 Hash generieren: echo -n "string" | shasum -a 256 + ## Error Table | Errorcode | Type | Definition | diff --git a/webservice/crypto.py b/webservice/crypto.py new file mode 100644 index 0000000..aece48a --- /dev/null +++ b/webservice/crypto.py @@ -0,0 +1,11 @@ +# crypto.py +import hashlib +import secrets + +def hash_password(password: str) -> str: + """Generiert einen SHA-256 Hash des gegebenen Passworts.""" + return hashlib.sha256(password.encode()).hexdigest() + +def generate_new_token(length: int = 32) -> str: + """Generiert einen neuen sicheren Token.""" + return secrets.token_hex(length) # Erzeugt einen sicheren Token \ No newline at end of file diff --git a/webservice/dbfunctions.py b/webservice/dbfunctions.py index 607c762..2e379b7 100644 --- a/webservice/dbfunctions.py +++ b/webservice/dbfunctions.py @@ -50,4 +50,10 @@ def check_api_access(db: Session, token: str) -> bool: user = db.query(User).filter(User.id == session.userid).first() # Überprüfe, ob api_access True ist - return user.api_access if user else False # Gibt True oder False zurück \ No newline at end of file + return user.api_access if user else False # Gibt True oder False zurück + +def save_token_to_db(db: Session, token: str, user_id: int, valid_until: datetime): + new_session = SessionModel(token=token, validuntil=valid_until, userid=user_id) + db.add(new_session) + db.commit() + db.refresh(new_session) \ No newline at end of file diff --git a/webservice/models.py b/webservice/models.py index ad890d9..648d778 100644 --- a/webservice/models.py +++ b/webservice/models.py @@ -7,6 +7,10 @@ class MessageOnly(BaseModel): message: str timestamp: datetime = Field(default_factory=datetime.now) +class TokenResponse(BaseModel): + token: str + validuntil: datetime + class User(SQLModel, table=True): __tablename__ = "user" id: int = Field(default=None, primary_key=True) diff --git a/webservice/webservice.py b/webservice/webservice.py index e994ea0..ed54e90 100644 --- a/webservice/webservice.py +++ b/webservice/webservice.py @@ -2,18 +2,20 @@ # INP21b - Timo Weber & Michael von Ah ################ IMPORTS ################ -from fastapi import FastAPI, Depends, HTTPException, Header +from fastapi import FastAPI, Depends, HTTPException, Header, Body from sqlmodel import Session -from dbfunctions import save_sensor_data, get_client_id_by_name, validate_token_with_access, engine -from models import SensorDataIn, SensorData, MessageOnly +from dbfunctions import save_sensor_data, get_client_id_by_name, validate_token_with_access, engine, save_token_to_db +from models import SensorDataIn, SensorData, MessageOnly, User, TokenResponse, Session as SessionModel +from datetime import datetime, timedelta +from crypto import hash_password, generate_new_token ################ API ################ app = FastAPI( - title="M241-M245-BBZW-Horizon", + title="BBZW-Horizon", description="BBZW-Horizon", summary="BBZW-Horizon", - version="0.0.1" + version="0.0.2" ) # DB Session @@ -51,4 +53,32 @@ async def saveNewSensorData( return MessageOnly(message="Sensor data saved successfully.") except Exception as error: - raise HTTPException(status_code=500, detail=str(error)) \ No newline at end of file + raise HTTPException(status_code=500, detail=str(error)) + +@app.post("/user/new-session", response_model=TokenResponse, tags=["auth"]) +async def generate_token( + username: str = Body(...), + password: str = Body(...), + db: Session = Depends(get_db), +): + # Überprüfe, ob der Benutzer existiert + user = db.query(User).filter(User.name == username).first() + if not user: + raise HTTPException(status_code=404, detail="User not found") + + # Überprüfe das Passwort + if user.password != hash_password(password): + raise HTTPException(status_code=401, detail="Incorrect password") + + # Erstelle einen neuen Token + new_token = generate_new_token() # Generiere den Token + valid_until = datetime.now() + timedelta(days=30) # Setze das Datum auf 30 Tage in der Zukunft + + # Speichere den neuen Token in der Datenbank + new_session = SessionModel(token=new_token, validuntil=valid_until, userid=user.id) + db.add(new_session) + db.commit() + db.refresh(new_session) + + # Rückgabe des Tokens und des Ablaufdatums + return TokenResponse(token=new_token, validuntil=valid_until) \ No newline at end of file