From a7be6b539b30a915e40361ffd0731fa817414828 Mon Sep 17 00:00:00 2001 From: Riad8 Date: Wed, 4 Dec 2024 21:03:24 +0100 Subject: [PATCH 1/6] Add security for score submission with key verification Previously, intercepting requests allowed users to modify scores. Now, an additional security layer with a key mechanism ensures scores cannot be modified with during transmission. --- .../flappybird/endpoints_flappybird.py | 27 ++++++++++++++----- app/modules/flappybird/models_flappybird.py | 4 ++- app/modules/flappybird/schemas_flappybird.py | 3 ++- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/app/modules/flappybird/endpoints_flappybird.py b/app/modules/flappybird/endpoints_flappybird.py index 074116a6e..a7a99bbe9 100644 --- a/app/modules/flappybird/endpoints_flappybird.py +++ b/app/modules/flappybird/endpoints_flappybird.py @@ -1,12 +1,13 @@ import uuid +import hashlib from datetime import UTC, datetime from fastapi import Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from app.core import models_core -from app.core.groups.groups_type import AccountType, GroupType -from app.dependencies import get_db, is_user_a_member, is_user_in +from app.core.groups.groups_type import GroupType +from app.dependencies import get_db, is_user_a_member, is_user_a_member_of from app.modules.flappybird import ( cruds_flappybird, models_flappybird, @@ -14,10 +15,20 @@ ) from app.types.module import Module +def genKey(score: int) -> int: + """ Generates a key based on the score of the player. """ + data = f"{score}" + + hash_bytes = hashlib.sha256(data.encode()).digest() + key = int.from_bytes(hash_bytes[:4], byteorder="big") + + return key + + module = Module( root="flappybird", tag="Flappy Bird", - default_allowed_account_types=[AccountType.student], + default_allowed_groups_ids=[GroupType.student], ) @@ -95,25 +106,27 @@ async def create_flappybird_score( id=score_id, user_id=user.id, value=flappybird_score.value, + key=flappybird_score.key, creation_time=creation_time, ) db_flappybird_best_score = models_flappybird.FlappyBirdBestScore( id=score_id, user_id=user.id, value=flappybird_score.value, + key=flappybird_score.key, creation_time=creation_time, ) personal_best = await cruds_flappybird.get_flappybird_personal_best_by_user_id( user_id=user.id, db=db, ) - if personal_best is None: + if personal_best is None and genKey(flappybird_score.value) == flappybird_score.key: await cruds_flappybird.create_flappybird_best_score( flappybird_best_score=db_flappybird_best_score, db=db, ) else: - if personal_best.value < flappybird_score.value: + if personal_best.value < flappybird_score.value and genKey(flappybird_score.value) == flappybird_score.key: await cruds_flappybird.update_flappybird_best_score( user_id=user.id, best_score=flappybird_score.value, @@ -133,6 +146,6 @@ async def create_flappybird_score( async def remove_flappybird_score( targeted_user_id: str, db: AsyncSession = Depends(get_db), - user: models_core.CoreUser = Depends(is_user_in(GroupType.admin)), + user: models_core.CoreUser = Depends(is_user_a_member_of(GroupType.admin)), ): - await cruds_flappybird.delete_flappybird_best_score(db=db, user_id=targeted_user_id) + await cruds_flappybird.delete_flappybird_best_score(db=db, user_id=targeted_user_id) \ No newline at end of file diff --git a/app/modules/flappybird/models_flappybird.py b/app/modules/flappybird/models_flappybird.py index 5077c7a04..1266dc084 100644 --- a/app/modules/flappybird/models_flappybird.py +++ b/app/modules/flappybird/models_flappybird.py @@ -14,6 +14,7 @@ class FlappyBirdScore(Base): user_id: Mapped[str] = mapped_column(ForeignKey("core_user.id")) user: Mapped[CoreUser] = relationship("CoreUser", init=False) value: Mapped[int] + key: Mapped[int] creation_time: Mapped[datetime] @@ -24,4 +25,5 @@ class FlappyBirdBestScore(Base): user_id: Mapped[str] = mapped_column(ForeignKey("core_user.id")) user: Mapped[CoreUser] = relationship("CoreUser", init=False) value: Mapped[int] - creation_time: Mapped[datetime] + key: Mapped[int] + creation_time: Mapped[datetime] \ No newline at end of file diff --git a/app/modules/flappybird/schemas_flappybird.py b/app/modules/flappybird/schemas_flappybird.py index 37f752cff..821b975d0 100644 --- a/app/modules/flappybird/schemas_flappybird.py +++ b/app/modules/flappybird/schemas_flappybird.py @@ -8,6 +8,7 @@ class FlappyBirdScoreBase(BaseModel): value: int + key: int class FlappyBirdScore(FlappyBirdScoreBase): @@ -25,4 +26,4 @@ class FlappyBirdScoreCompleteFeedBack(FlappyBirdScore): A score with its position in the best players leaderboard """ - position: int + position: int \ No newline at end of file From d2b0105c1f4411f39f9547e61be5540db14107c9 Mon Sep 17 00:00:00 2001 From: Riad8 Date: Wed, 4 Dec 2024 21:13:14 +0100 Subject: [PATCH 2/6] Updated is_user_a_member_of() to is_user_in(). --- app/modules/flappybird/endpoints_flappybird.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/modules/flappybird/endpoints_flappybird.py b/app/modules/flappybird/endpoints_flappybird.py index a7a99bbe9..f715f01d0 100644 --- a/app/modules/flappybird/endpoints_flappybird.py +++ b/app/modules/flappybird/endpoints_flappybird.py @@ -6,8 +6,8 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.core import models_core -from app.core.groups.groups_type import GroupType -from app.dependencies import get_db, is_user_a_member, is_user_a_member_of +from app.core.groups.groups_type import AccountType, GroupType +from app.dependencies import get_db, is_user_a_member, is_user_in from app.modules.flappybird import ( cruds_flappybird, models_flappybird, @@ -24,11 +24,10 @@ def genKey(score: int) -> int: return key - module = Module( root="flappybird", tag="Flappy Bird", - default_allowed_groups_ids=[GroupType.student], + default_allowed_account_types=[AccountType.student], ) @@ -146,6 +145,6 @@ async def create_flappybird_score( async def remove_flappybird_score( targeted_user_id: str, db: AsyncSession = Depends(get_db), - user: models_core.CoreUser = Depends(is_user_a_member_of(GroupType.admin)), + user: models_core.CoreUser = Depends(is_user_in(GroupType.admin)), ): await cruds_flappybird.delete_flappybird_best_score(db=db, user_id=targeted_user_id) \ No newline at end of file From 1f93bf26402412c7dfe81826e932fd1f1761f449 Mon Sep 17 00:00:00 2001 From: Riad8 Date: Wed, 4 Dec 2024 21:27:27 +0100 Subject: [PATCH 3/6] Formatting code --- app/modules/flappybird/endpoints_flappybird.py | 8 ++++---- app/modules/flappybird/models_flappybird.py | 2 +- app/modules/flappybird/schemas_flappybird.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/modules/flappybird/endpoints_flappybird.py b/app/modules/flappybird/endpoints_flappybird.py index f715f01d0..59d50c252 100644 --- a/app/modules/flappybird/endpoints_flappybird.py +++ b/app/modules/flappybird/endpoints_flappybird.py @@ -1,5 +1,5 @@ -import uuid import hashlib +import uuid from datetime import UTC, datetime from fastapi import Depends, HTTPException @@ -18,10 +18,10 @@ def genKey(score: int) -> int: """ Generates a key based on the score of the player. """ data = f"{score}" - + hash_bytes = hashlib.sha256(data.encode()).digest() key = int.from_bytes(hash_bytes[:4], byteorder="big") - + return key module = Module( @@ -147,4 +147,4 @@ async def remove_flappybird_score( db: AsyncSession = Depends(get_db), user: models_core.CoreUser = Depends(is_user_in(GroupType.admin)), ): - await cruds_flappybird.delete_flappybird_best_score(db=db, user_id=targeted_user_id) \ No newline at end of file + await cruds_flappybird.delete_flappybird_best_score(db=db, user_id=targeted_user_id) diff --git a/app/modules/flappybird/models_flappybird.py b/app/modules/flappybird/models_flappybird.py index 1266dc084..cfe561bdb 100644 --- a/app/modules/flappybird/models_flappybird.py +++ b/app/modules/flappybird/models_flappybird.py @@ -26,4 +26,4 @@ class FlappyBirdBestScore(Base): user: Mapped[CoreUser] = relationship("CoreUser", init=False) value: Mapped[int] key: Mapped[int] - creation_time: Mapped[datetime] \ No newline at end of file + creation_time: Mapped[datetime] diff --git a/app/modules/flappybird/schemas_flappybird.py b/app/modules/flappybird/schemas_flappybird.py index 821b975d0..f30bd18b6 100644 --- a/app/modules/flappybird/schemas_flappybird.py +++ b/app/modules/flappybird/schemas_flappybird.py @@ -26,4 +26,4 @@ class FlappyBirdScoreCompleteFeedBack(FlappyBirdScore): A score with its position in the best players leaderboard """ - position: int \ No newline at end of file + position: int From c5595a69c466416aa29e4f4a0dab5d644abb4c79 Mon Sep 17 00:00:00 2001 From: Riad8 Date: Wed, 4 Dec 2024 21:31:35 +0100 Subject: [PATCH 4/6] Formatting code --- app/modules/flappybird/endpoints_flappybird.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/modules/flappybird/endpoints_flappybird.py b/app/modules/flappybird/endpoints_flappybird.py index 59d50c252..f46554f21 100644 --- a/app/modules/flappybird/endpoints_flappybird.py +++ b/app/modules/flappybird/endpoints_flappybird.py @@ -15,6 +15,7 @@ ) from app.types.module import Module + def genKey(score: int) -> int: """ Generates a key based on the score of the player. """ data = f"{score}" From a61fd20c8965881bb1e74832326bcaf3282b5dc5 Mon Sep 17 00:00:00 2001 From: Riad8 Date: Thu, 5 Dec 2024 18:24:27 +0100 Subject: [PATCH 5/6] Updated the requirements to synchronize with the main branch Removed the 'key' column from the database models. Improved the key verification logic. --- app/modules/flappybird/endpoints_flappybird.py | 11 +++++++---- app/modules/flappybird/models_flappybird.py | 2 -- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/modules/flappybird/endpoints_flappybird.py b/app/modules/flappybird/endpoints_flappybird.py index f46554f21..d3d94854c 100644 --- a/app/modules/flappybird/endpoints_flappybird.py +++ b/app/modules/flappybird/endpoints_flappybird.py @@ -102,31 +102,34 @@ async def create_flappybird_score( # And get the current date and time creation_time = datetime.now(UTC) + if genKey(flappybird_score.value) != flappybird_score.key: + raise HTTPException( + status_code=400, detail="Invalid key for the provided score" + ) + db_flappybird_score = models_flappybird.FlappyBirdScore( id=score_id, user_id=user.id, value=flappybird_score.value, - key=flappybird_score.key, creation_time=creation_time, ) db_flappybird_best_score = models_flappybird.FlappyBirdBestScore( id=score_id, user_id=user.id, value=flappybird_score.value, - key=flappybird_score.key, creation_time=creation_time, ) personal_best = await cruds_flappybird.get_flappybird_personal_best_by_user_id( user_id=user.id, db=db, ) - if personal_best is None and genKey(flappybird_score.value) == flappybird_score.key: + if personal_best is None: await cruds_flappybird.create_flappybird_best_score( flappybird_best_score=db_flappybird_best_score, db=db, ) else: - if personal_best.value < flappybird_score.value and genKey(flappybird_score.value) == flappybird_score.key: + if personal_best.value < flappybird_score.value: await cruds_flappybird.update_flappybird_best_score( user_id=user.id, best_score=flappybird_score.value, diff --git a/app/modules/flappybird/models_flappybird.py b/app/modules/flappybird/models_flappybird.py index cfe561bdb..5077c7a04 100644 --- a/app/modules/flappybird/models_flappybird.py +++ b/app/modules/flappybird/models_flappybird.py @@ -14,7 +14,6 @@ class FlappyBirdScore(Base): user_id: Mapped[str] = mapped_column(ForeignKey("core_user.id")) user: Mapped[CoreUser] = relationship("CoreUser", init=False) value: Mapped[int] - key: Mapped[int] creation_time: Mapped[datetime] @@ -25,5 +24,4 @@ class FlappyBirdBestScore(Base): user_id: Mapped[str] = mapped_column(ForeignKey("core_user.id")) user: Mapped[CoreUser] = relationship("CoreUser", init=False) value: Mapped[int] - key: Mapped[int] creation_time: Mapped[datetime] From 7d8a492223f0193a98bb46693660e20f1e503c46 Mon Sep 17 00:00:00 2001 From: Riad8 Date: Thu, 5 Dec 2024 18:34:53 +0100 Subject: [PATCH 6/6] Formatting the code --- app/modules/flappybird/endpoints_flappybird.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/modules/flappybird/endpoints_flappybird.py b/app/modules/flappybird/endpoints_flappybird.py index d3d94854c..ecaff2ab8 100644 --- a/app/modules/flappybird/endpoints_flappybird.py +++ b/app/modules/flappybird/endpoints_flappybird.py @@ -17,7 +17,7 @@ def genKey(score: int) -> int: - """ Generates a key based on the score of the player. """ + """Generates a key based on the score of the player.""" data = f"{score}" hash_bytes = hashlib.sha256(data.encode()).digest() @@ -25,6 +25,7 @@ def genKey(score: int) -> int: return key + module = Module( root="flappybird", tag="Flappy Bird", @@ -104,7 +105,8 @@ async def create_flappybird_score( if genKey(flappybird_score.value) != flappybird_score.key: raise HTTPException( - status_code=400, detail="Invalid key for the provided score" + status_code=400, + detail="Invalid key for the provided score", ) db_flappybird_score = models_flappybird.FlappyBirdScore(