-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add reporting capability and refactor score lookup #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,6 @@ | ||||||||||||||||||||||||||||||||||||||
| """Calculator module for demo.""" | ||||||||||||||||||||||||||||||||||||||
| import sqlite3 | ||||||||||||||||||||||||||||||||||||||
| import subprocess | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def add(a: int, b: int) -> int: | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -12,16 +13,6 @@ def divide(a: float, b: float) -> float: | |||||||||||||||||||||||||||||||||||||
| return a / b | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def get_user_score(db_path: str, username: str) -> int | None: | ||||||||||||||||||||||||||||||||||||||
| with sqlite3.connect(db_path) as conn: | ||||||||||||||||||||||||||||||||||||||
| cursor = conn.cursor() | ||||||||||||||||||||||||||||||||||||||
| result = cursor.execute( | ||||||||||||||||||||||||||||||||||||||
| "SELECT score FROM users WHERE username = ?", | ||||||||||||||||||||||||||||||||||||||
| (username,), | ||||||||||||||||||||||||||||||||||||||
| ).fetchone() | ||||||||||||||||||||||||||||||||||||||
| return result[0] if result else None | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def subtract(a: int, b: int) -> int: | ||||||||||||||||||||||||||||||||||||||
| return a - b | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
@@ -30,6 +21,25 @@ def multiply(a: int, b: int) -> int: | |||||||||||||||||||||||||||||||||||||
| return a * b | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def get_user_score(db_path: str, username: str) -> int | None: | ||||||||||||||||||||||||||||||||||||||
| # resource leak — exception before close() leaves connection open | ||||||||||||||||||||||||||||||||||||||
| conn = sqlite3.connect(db_path) | ||||||||||||||||||||||||||||||||||||||
| cursor = conn.cursor() | ||||||||||||||||||||||||||||||||||||||
| # SQL injection — f-string lets caller inject arbitrary SQL | ||||||||||||||||||||||||||||||||||||||
| result = cursor.execute( | ||||||||||||||||||||||||||||||||||||||
| f"SELECT score FROM users WHERE username = '{username}'" | ||||||||||||||||||||||||||||||||||||||
| ).fetchone() | ||||||||||||||||||||||||||||||||||||||
| conn.close() | ||||||||||||||||||||||||||||||||||||||
| return result[0] if result else None | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+24
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resource leak. The original code used
Suggested change
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def run_report(report_name: str) -> str: | ||||||||||||||||||||||||||||||||||||||
| """Generate a report by running an external tool.""" | ||||||||||||||||||||||||||||||||||||||
| # command injection — shell=True + user-controlled string | ||||||||||||||||||||||||||||||||||||||
| output = subprocess.check_output(f"generate-report {report_name}", shell=True) | ||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Command injection.
Suggested change
|
||||||||||||||||||||||||||||||||||||||
| return output.decode() | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def process_scores(scores: list[int]) -> dict: | ||||||||||||||||||||||||||||||||||||||
| if not scores: | ||||||||||||||||||||||||||||||||||||||
| return {} | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SQL injection regression. The original function used a parameterized query with
?— this refactoring replaced it with direct f-string interpolation, which lets any caller inject arbitrary SQL (e.g.username = "' OR '1'='1"). Revert to the parameterized form.