From 851c106a99063f520cfc598011e23ed62b73e581 Mon Sep 17 00:00:00 2001 From: birjd002 Date: Sun, 24 May 2026 22:07:23 +0930 Subject: [PATCH 1/9] fix: return string instead of error object Testing if this works first before applying. --- client/src/routes/standardUser/ReportHistory.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/routes/standardUser/ReportHistory.js b/client/src/routes/standardUser/ReportHistory.js index 4f925b5b..b20b4367 100644 --- a/client/src/routes/standardUser/ReportHistory.js +++ b/client/src/routes/standardUser/ReportHistory.js @@ -102,9 +102,9 @@ const AIHealthPrediction = ({}) => { }) .then((res) => res.json()) .then((data) => setReportData(data)) - .catch((err) => console.log(err)); + .catch(() => console.error("Failed to delete report data.")); } catch (err) { - console.log(err); + console.error("Failed to delete report data."); } // Reload reports fetchReportDates(); From 53456be057b376eb518162c38078fc734315e965 Mon Sep 17 00:00:00 2001 From: birjd002 Date: Mon, 25 May 2026 00:46:16 +0930 Subject: [PATCH 2/9] fix: resolve leakage of information in logger message conflict --- client/src/components/Navbar.js | 1 - .../components/administrator/AccountApprovalTable.js | 4 ++-- client/src/components/administrator/AuditLogTable.js | 2 +- .../components/administrator/UserManagementTable.js | 10 +++++----- .../src/components/authentication/CreatePatientForm.js | 2 +- .../src/components/authentication/RegistrationForm.js | 4 ++-- .../src/components/healthReport/BloodReportUpload.js | 2 +- .../components/healthReport/DownloadReportButton.js | 2 +- .../src/components/healthReport/GenerateReportForm.js | 4 ++-- .../src/components/healthReport/MerchantReportForm.js | 8 ++++---- client/src/routes/merchant/MerchantReports.js | 6 +++--- client/src/routes/merchant/PatientManagement.js | 4 ++-- client/src/routes/standardUser/HealthAnalytics.js | 3 +-- client/src/routes/standardUser/ReportHistory.js | 5 ++--- client/src/routes/standardUser/UserSettings.js | 2 +- 15 files changed, 28 insertions(+), 31 deletions(-) diff --git a/client/src/components/Navbar.js b/client/src/components/Navbar.js index 8a9d3eb4..56d223a0 100644 --- a/client/src/components/Navbar.js +++ b/client/src/components/Navbar.js @@ -198,7 +198,6 @@ const NavBar = ({ role }) => { function handleOpenSettings(e) { setOpenMenu(e.currentTarget); - console.log(openMenu); } function handleCloseSettings() { diff --git a/client/src/components/administrator/AccountApprovalTable.js b/client/src/components/administrator/AccountApprovalTable.js index 9d2ae3b8..8e72883c 100644 --- a/client/src/components/administrator/AccountApprovalTable.js +++ b/client/src/components/administrator/AccountApprovalTable.js @@ -25,7 +25,7 @@ const AccountApprovalTable = ({}) => { }) .then((data) => setUserData(data)) .catch((err) => { - console.log(err); + console.error("Failed to fetch merchant data."); }); }; @@ -49,7 +49,7 @@ const AccountApprovalTable = ({}) => { fetchMerchants(); }) .catch((err) => { - console.log(err); + console.error("Failed to validate merchant account."); }); }; diff --git a/client/src/components/administrator/AuditLogTable.js b/client/src/components/administrator/AuditLogTable.js index 7e4c241e..fef4864b 100644 --- a/client/src/components/administrator/AuditLogTable.js +++ b/client/src/components/administrator/AuditLogTable.js @@ -80,7 +80,7 @@ const AuditLogTable = () => { setLoading(false); }) .catch((err) => { - console.log(err); + console.error("Failed to fetch log data."); setLoading(false); }); }; diff --git a/client/src/components/administrator/UserManagementTable.js b/client/src/components/administrator/UserManagementTable.js index 4c28ac26..6924ccad 100644 --- a/client/src/components/administrator/UserManagementTable.js +++ b/client/src/components/administrator/UserManagementTable.js @@ -84,7 +84,7 @@ const UserManagementTable = () => { setLoading(false); }) .catch((err) => { - console.log(err); + console.error("Failed to fetch user data."); setLoading(false); }); }; @@ -114,7 +114,7 @@ const UserManagementTable = () => { }) .then((data) => setRoleData(data)) .catch((err) => { - console.log(err); + console.error("Failed to fetch role data."); }); }, [API_BASE]); @@ -128,7 +128,7 @@ const UserManagementTable = () => { }) .then((data) => setClinicData(data)) .catch(() => { - console.log("Failed to fetch Clinics"); + console.error("Failed to fetch clinic data."); }); }, [API_BASE]); @@ -170,7 +170,7 @@ const UserManagementTable = () => { setNewRole(null); setRowSelectionModel({ type: "include", ids: new Set() }); } catch (err) { - console.log(err); + console.error("Failed to process request."); } }; @@ -204,7 +204,7 @@ const UserManagementTable = () => { setUserToDelete(null); setRowSelectionModel({ type: "include", ids: new Set() }); // Reset the checkbox after deletion. } catch (error) { - console.error("Delete user error:", error); + console.error("Failed to delete user."); setSnackbar({ open: true, message: error.message, severity: "error" }); } }; diff --git a/client/src/components/authentication/CreatePatientForm.js b/client/src/components/authentication/CreatePatientForm.js index ee30e215..153017eb 100644 --- a/client/src/components/authentication/CreatePatientForm.js +++ b/client/src/components/authentication/CreatePatientForm.js @@ -181,7 +181,7 @@ const CreatePatientForm = () => { return response.json(); }) .catch((err) => { - console.log("An error has occurred"); + console.error("An error has occurred."); }); setIsLoading(false); } diff --git a/client/src/components/authentication/RegistrationForm.js b/client/src/components/authentication/RegistrationForm.js index 748feac8..69ee8747 100644 --- a/client/src/components/authentication/RegistrationForm.js +++ b/client/src/components/authentication/RegistrationForm.js @@ -77,7 +77,7 @@ const RegistrationForm = () => { }) .then((res) => res.json()) .then((data) => setClinicList(data)) - .catch((err) => console.log("An error has occurred")); + .catch((err) => console.error("An error has occurred.")); }, []); function updateGivenName(e) { @@ -281,7 +281,7 @@ const RegistrationForm = () => { setShowFailMessage(false); }) .catch((error) => { - console.log(error); + console.error("User reigstration requeset failed."); }); setIsLoading(false); } diff --git a/client/src/components/healthReport/BloodReportUpload.js b/client/src/components/healthReport/BloodReportUpload.js index cecdfffa..0c9d7af1 100644 --- a/client/src/components/healthReport/BloodReportUpload.js +++ b/client/src/components/healthReport/BloodReportUpload.js @@ -28,7 +28,7 @@ const BloodReportUpload = ({ onChange }) => { const file = e.target.files[0]; await pdfToText(file) .then((text) => onChange?.(extractPatientInfoAsDict(text))) - .catch((error) => console.error(error)); + .catch((error) => console.error("Failed to process blood report.")); } function extractPatientInfoAsDict(text) { diff --git a/client/src/components/healthReport/DownloadReportButton.js b/client/src/components/healthReport/DownloadReportButton.js index d7c14104..96c0e9a4 100644 --- a/client/src/components/healthReport/DownloadReportButton.js +++ b/client/src/components/healthReport/DownloadReportButton.js @@ -56,7 +56,7 @@ const DownloadReportButton = ({ saveAs(blob, fileName); if (onError) onError?.(null); // Clear previous errors on success } catch (error) { - console.error("Failed to download report:", error); + console.error("Failed to download report."); if (onError) onError(error.message); } }; diff --git a/client/src/components/healthReport/GenerateReportForm.js b/client/src/components/healthReport/GenerateReportForm.js index 65070815..3e2ce540 100644 --- a/client/src/components/healthReport/GenerateReportForm.js +++ b/client/src/components/healthReport/GenerateReportForm.js @@ -121,7 +121,7 @@ const GenerateReportForm = () => { setWorkingStatus(data.workingStatus); setRace(data.race); } catch (err) { - console.log("Failed to fetch patient data."); + console.error("Failed to fetch patient data."); } } fetchPatientData(); @@ -355,7 +355,7 @@ const GenerateReportForm = () => { navigate("/report-history"); // Route the user to the Health prediction page after submission }) .catch((error) => { - console.log("An error has occurred"); + console.error("An error has occurred."); }); } diff --git a/client/src/components/healthReport/MerchantReportForm.js b/client/src/components/healthReport/MerchantReportForm.js index 21512891..bf470211 100644 --- a/client/src/components/healthReport/MerchantReportForm.js +++ b/client/src/components/healthReport/MerchantReportForm.js @@ -135,7 +135,7 @@ const MerchantReportForm = () => { setPatientName(name.name); } }) - .catch((err) => console.log(err)); + .catch((err) => console.error("Failed to fetch patient names.")); }, []); function handleChangeCondition(e) { @@ -170,7 +170,7 @@ const MerchantReportForm = () => { setWorkingStatus(data.workingStatus); setRace(data.race); } catch (err) { - console.log("Failed to fetch patient data."); + console.error("Failed to fetch patient data."); } } fetchPatientData(); @@ -374,7 +374,7 @@ const MerchantReportForm = () => { return response.json(); }) .catch((error) => { - console.log("Something went wrong."); + console.error("Failed to process request."); }); navigate("/merchant-reports"); setIsLoading(false); @@ -437,7 +437,7 @@ const MerchantReportForm = () => { }); // Route the user to the Health prediction page after submission }) .catch((error) => { - console.log("Something went wrong"); + console.error("Failed to process request."); }); } const HiddenInput = styled("input")({ diff --git a/client/src/routes/merchant/MerchantReports.js b/client/src/routes/merchant/MerchantReports.js index c0d7d42e..1ee5552f 100644 --- a/client/src/routes/merchant/MerchantReports.js +++ b/client/src/routes/merchant/MerchantReports.js @@ -82,7 +82,7 @@ const MerchantReports = ({}) => { } }) .catch((err) => { - console.log(err); + console.error("Failed to fetch report data."); }, []); } @@ -102,7 +102,7 @@ const MerchantReports = ({}) => { }) .then((res) => res.json()) .then((data) => setReportData(data)) - .catch((err) => console.log(err)); + .catch((err) => console.error("Failed to fetch report health data.")); }, [selectedDate]); // Delete report data @@ -127,7 +127,7 @@ const MerchantReports = ({}) => { setReportDates(patientReports); setSelectedDate(patientReports[0]); } catch (err) { - console.log(err); + console.error("Failed to delete report data."); } // Close Dialog setDeleteDialogOpen(false); diff --git a/client/src/routes/merchant/PatientManagement.js b/client/src/routes/merchant/PatientManagement.js index fbf6a874..07877580 100644 --- a/client/src/routes/merchant/PatientManagement.js +++ b/client/src/routes/merchant/PatientManagement.js @@ -159,7 +159,7 @@ const PatientManagement = () => { setLoading(false); }) .catch((err) => { - console.log("An error has occurred"); + console.error("An error has occurred."); setLoading(false); }); }; @@ -171,7 +171,7 @@ const PatientManagement = () => { }) .then((response) => response.json()) .catch((err) => { - console.log("An error has occurred"); + console.error("An error has occurred."); }); fetchPatients(); setDeleteDialogOpen(false); diff --git a/client/src/routes/standardUser/HealthAnalytics.js b/client/src/routes/standardUser/HealthAnalytics.js index db46f3d5..015cf17b 100644 --- a/client/src/routes/standardUser/HealthAnalytics.js +++ b/client/src/routes/standardUser/HealthAnalytics.js @@ -82,10 +82,9 @@ const HealthAnalytics = () => { throw new Error("Network response was not ok"); } const data = await response.json(); - //console.log("Fetched data:", data); // Log fetched data setHealthData(data); } catch (error) { - console.error("Failed to fetch health analytics data:", error); + console.error("Failed to fetch health analytics data."); } }; diff --git a/client/src/routes/standardUser/ReportHistory.js b/client/src/routes/standardUser/ReportHistory.js index b20b4367..d613ad51 100644 --- a/client/src/routes/standardUser/ReportHistory.js +++ b/client/src/routes/standardUser/ReportHistory.js @@ -63,11 +63,10 @@ const AIHealthPrediction = ({}) => { setReportDates(data); if (data.length > 0) { setSelectedDate(data[0]); - console.log("The selected date is: " + selectedDate); } }) .catch((err) => { - console.log(err); + console.error("Failed to fetch health data dates."); }); } @@ -87,7 +86,7 @@ const AIHealthPrediction = ({}) => { }) .then((res) => res.json()) .then((data) => setReportData(data)) - .catch((err) => console.log(err)); + .catch((err) => console.error("Failed to fetch report data.")); }, [selectedDate]); // Delete report data diff --git a/client/src/routes/standardUser/UserSettings.js b/client/src/routes/standardUser/UserSettings.js index 866d0f85..29129d86 100644 --- a/client/src/routes/standardUser/UserSettings.js +++ b/client/src/routes/standardUser/UserSettings.js @@ -153,7 +153,7 @@ const UserSettings = () => { return response.json(); }) .catch((error) => { - console.log("Failed to change password"); + console.error("Failed to change password."); }); } From 58b6e3af169c794401a8d5a60d90eded5ee3ada7 Mon Sep 17 00:00:00 2001 From: birjd002 Date: Mon, 25 May 2026 01:09:42 +0930 Subject: [PATCH 3/9] fix: resolve information exposure through an exception conflict --- server/routers/health_prediction.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/server/routers/health_prediction.py b/server/routers/health_prediction.py index 6a68803f..28eb6f86 100644 --- a/server/routers/health_prediction.py +++ b/server/routers/health_prediction.py @@ -7,6 +7,7 @@ from sqlalchemy.orm import Session import csv import codecs +import logging from ..utils.database import get_db from ..models.dbmodels import HealthData, Prediction, Recommendation, UserAccount, UserPatientAccess, Patient, LogEventType @@ -15,6 +16,8 @@ from ..utils.audit_log import write_audit_log +logger = logging.getLogger(__name__) + # HealthData class HealthDataInput(CamelModel): age: int @@ -233,8 +236,9 @@ async def predict(data: HealthDataInput, request: Request, db_conn: Session = De db_conn=db_conn, health_data_id=int(_hd_id)) else: recommendations = {"error": "Missing HealthDataID"} - except Exception as e: - recommendations = {"error": str(e)} + except Exception: + logger.error("Health recommendations failed to generate.") + recommendations = None # Persist recommendations when available exercise_rec = None @@ -539,8 +543,9 @@ async def merchant_predict(data: MerchantHealthDataInput, request: Request, db_c db_conn=db_conn, health_data_id=int(_hd_id)) else: recommendations = {"error": "Missing HealthDataID"} - except Exception as e: - recommendations = {"error": str(e)} + except Exception: + logger.error("Health recommendations failed to generate.") + recommendations = None # Persist recommendations when available exercise_rec = None From 8e08924ddbe68a0742d35ed8344821795eca5c63 Mon Sep 17 00:00:00 2001 From: birjd002 Date: Mon, 25 May 2026 01:24:36 +0930 Subject: [PATCH 4/9] fix: resolve usage of hard-coded secret conflict --- load-tests/scenarios/admin.js | 8 +++++--- load-tests/scenarios/merchant.js | 9 ++++++--- load-tests/scenarios/user.js | 9 ++++++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/load-tests/scenarios/admin.js b/load-tests/scenarios/admin.js index 7088e7d7..c96ee9a2 100644 --- a/load-tests/scenarios/admin.js +++ b/load-tests/scenarios/admin.js @@ -2,14 +2,16 @@ import http from 'k6/http'; import { check, sleep } from 'k6'; -const BASE_URL = 'http://localhost:8000'; +const BASE_URL = __ENV.BASEURL || 'http://localhost:8000'; +const TEST_EMAIL = __ENV.TEST_EMAIL || 'SHP_Admin@example.com' +const TEST_PASSWORD = __ENV.TEST_PASSWORD || 'password12345678' export default function () { // Test login. let loginResult = http.post(`${BASE_URL}/login`, JSON.stringify({ - email: 'SHP_Admin@example.com', - password: 'password12345678', + email: TEST_EMAIL, + password: TEST_PASSWORD, }), { headers: { 'Content-Type': 'application/json' }, }); diff --git a/load-tests/scenarios/merchant.js b/load-tests/scenarios/merchant.js index 163fb320..5c93efe2 100644 --- a/load-tests/scenarios/merchant.js +++ b/load-tests/scenarios/merchant.js @@ -1,15 +1,18 @@ import http from "k6/http"; import { check, sleep } from "k6"; -const BASE_URL = "http://localhost:8000"; + +const BASE_URL = __ENV.BASEURL || 'http://localhost:8000'; +const TEST_EMAIL = __ENV.TEST_EMAIL || 'service@example.com' +const TEST_PASSWORD = __ENV.TEST_PASSWORD || 'thisismypassword' export default function () { // Test login. let loginResult = http.post( `${BASE_URL}/login`, JSON.stringify({ - email: "service@example.com", - password: "thisismypassword", + email: TEST_EMAIL, + password: TEST_PASSWORD, }), { headers: { "Content-Type": "application/json" }, diff --git a/load-tests/scenarios/user.js b/load-tests/scenarios/user.js index 4e2b0941..9b5088ce 100644 --- a/load-tests/scenarios/user.js +++ b/load-tests/scenarios/user.js @@ -1,15 +1,18 @@ import http from "k6/http"; import { check, sleep } from "k6"; -const BASE_URL = "http://localhost:8000"; + +const BASE_URL = __ENV.BASEURL || 'http://localhost:8000'; +const TEST_EMAIL = __ENV.TEST_EMAIL || 'audrey.young@example.com' +const TEST_PASSWORD = __ENV.TEST_PASSWORD || 'whyaretherebirds' export default function () { // Test login. let loginResult = http.post( `${BASE_URL}/login`, JSON.stringify({ - email: "audrey.young@example.com", - password: "whyaretherebirds", + email: TEST_EMAIL, + password: TEST_PASSWORD, }), { headers: { "Content-Type": "application/json" }, From 868da074228ac339c6aadee2b4cdfd205cfbccad Mon Sep 17 00:00:00 2001 From: birjd002 Date: Mon, 25 May 2026 01:39:21 +0930 Subject: [PATCH 5/9] fix: remove default credential values --- load-tests/scenarios/admin.js | 4 ++-- load-tests/scenarios/merchant.js | 4 ++-- load-tests/scenarios/user.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/load-tests/scenarios/admin.js b/load-tests/scenarios/admin.js index c96ee9a2..1b758e45 100644 --- a/load-tests/scenarios/admin.js +++ b/load-tests/scenarios/admin.js @@ -3,8 +3,8 @@ import { check, sleep } from 'k6'; const BASE_URL = __ENV.BASEURL || 'http://localhost:8000'; -const TEST_EMAIL = __ENV.TEST_EMAIL || 'SHP_Admin@example.com' -const TEST_PASSWORD = __ENV.TEST_PASSWORD || 'password12345678' +const TEST_EMAIL = __ENV.TEST_EMAIL; +const TEST_PASSWORD = __ENV.TEST_PASSWORD; export default function () { // Test login. diff --git a/load-tests/scenarios/merchant.js b/load-tests/scenarios/merchant.js index 5c93efe2..fe537e53 100644 --- a/load-tests/scenarios/merchant.js +++ b/load-tests/scenarios/merchant.js @@ -3,8 +3,8 @@ import { check, sleep } from "k6"; const BASE_URL = __ENV.BASEURL || 'http://localhost:8000'; -const TEST_EMAIL = __ENV.TEST_EMAIL || 'service@example.com' -const TEST_PASSWORD = __ENV.TEST_PASSWORD || 'thisismypassword' +const TEST_EMAIL = __ENV.TEST_EMAIL; +const TEST_PASSWORD = __ENV.TEST_PASSWORD; export default function () { // Test login. diff --git a/load-tests/scenarios/user.js b/load-tests/scenarios/user.js index 9b5088ce..6b042f38 100644 --- a/load-tests/scenarios/user.js +++ b/load-tests/scenarios/user.js @@ -3,8 +3,8 @@ import { check, sleep } from "k6"; const BASE_URL = __ENV.BASEURL || 'http://localhost:8000'; -const TEST_EMAIL = __ENV.TEST_EMAIL || 'audrey.young@example.com' -const TEST_PASSWORD = __ENV.TEST_PASSWORD || 'whyaretherebirds' +const TEST_EMAIL = __ENV.TEST_EMAIL; +const TEST_PASSWORD = __ENV.TEST_PASSWORD; export default function () { // Test login. From b72fd8d2d65d6ae5e6b29c469b74c6ed7acf98aa Mon Sep 17 00:00:00 2001 From: birjd002 Date: Mon, 25 May 2026 14:52:18 +0930 Subject: [PATCH 6/9] fix: resolve observable timing discrepancy conflict --- .../authentication/PasswordInputField.js | 2 +- .../authentication/RegistrationForm.js | 21 ++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/client/src/components/authentication/PasswordInputField.js b/client/src/components/authentication/PasswordInputField.js index d85347cf..8438c532 100644 --- a/client/src/components/authentication/PasswordInputField.js +++ b/client/src/components/authentication/PasswordInputField.js @@ -95,7 +95,7 @@ const PasswordInputField = ({ if (!isAltered && !showRequired) { return null; } - if (password.length === 0 || password === null || showRequired) { + if (password.length < 1 || password === null || showRequired) { return "*Required"; } diff --git a/client/src/components/authentication/RegistrationForm.js b/client/src/components/authentication/RegistrationForm.js index 69ee8747..4a20999f 100644 --- a/client/src/components/authentication/RegistrationForm.js +++ b/client/src/components/authentication/RegistrationForm.js @@ -80,6 +80,17 @@ const RegistrationForm = () => { .catch((err) => console.error("An error has occurred.")); }, []); + function stringEqual(a, b) { + if (a.length !== b.length) { + return false; + } + let diff = 0; + for (let i = 0; i < a.length; i++) { + diff |= a.charCodeAt(i) ^ b.charCodeAt(i); + } + return diff === 0; + } + function updateGivenName(e) { const isNameValid = e.target.value !== ""; setGivenNameState({ isValid: isNameValid, name: e.target.value }); @@ -134,7 +145,7 @@ const RegistrationForm = () => { const confirmPasswordInput = e.target.value; setConfirmPassword(confirmPasswordInput); setAlertPasswordsDontMatch( - confirmPasswordInput !== passwordState.password || + !stringEqual(confirmPasswordInput, passwordState.password) || confirmPasswordInput === "", ); } @@ -182,7 +193,7 @@ const RegistrationForm = () => { setAlertPasswordRequired(passwordState === null); setAlertPasswordsDontMatch( passwordState === null || - confirmPassword !== passwordState.password || + !stringEqual(confirmPassword, passwordState.password) || confirmPassword === "", ); setAlertGenderRequired(genderState === ""); @@ -194,7 +205,7 @@ const RegistrationForm = () => { setAlertPasswordRequired(passwordState === null); setAlertPasswordsDontMatch( passwordState === null || - confirmPassword !== passwordState.password || + !stringEqual(confirmPassword, passwordState.password) || confirmPassword === "", ); setAlertClinicRequired(clinicState === ""); @@ -214,7 +225,7 @@ const RegistrationForm = () => { (phoneState === null || phoneState.isValid) && passwordState !== null && passwordState.isValid && - passwordState.password === confirmPassword + stringEqual(passwordState.password, confirmPassword) ); } @@ -225,7 +236,7 @@ const RegistrationForm = () => { (phoneState === null || phoneState.isValid) && passwordState !== null && passwordState.isValid && - passwordState.password === confirmPassword && + stringEqual(passwordState.password, confirmPassword) && clinicState !== "" ); } From 921983e1fe4d5fcaae39c28b886f8c594344d062 Mon Sep 17 00:00:00 2001 From: birjd002 Date: Mon, 25 May 2026 15:04:57 +0930 Subject: [PATCH 7/9] chore: move xor func to util folder used by UserSettings and RegistrationForm --- .../authentication/RegistrationForm.js | 12 +----------- client/src/routes/standardUser/UserSettings.js | 4 +++- client/src/utils/stringEqual.js | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 client/src/utils/stringEqual.js diff --git a/client/src/components/authentication/RegistrationForm.js b/client/src/components/authentication/RegistrationForm.js index 4a20999f..5ebf184e 100644 --- a/client/src/components/authentication/RegistrationForm.js +++ b/client/src/components/authentication/RegistrationForm.js @@ -26,6 +26,7 @@ import PasswordInputField from "../authentication/PasswordInputField"; import EmailInputField from "../authentication/EmailInputField"; import PhoneInputField from "../authentication/PhoneInputField"; import Logo from "../../assets/WellAiLogoTR.png"; +import { stringEqual } from "../../utils/stringEqual"; const FULL_NAME_MAX_LENGTH = 255; const ACCOUNT_TYPES = Object.freeze({ @@ -80,17 +81,6 @@ const RegistrationForm = () => { .catch((err) => console.error("An error has occurred.")); }, []); - function stringEqual(a, b) { - if (a.length !== b.length) { - return false; - } - let diff = 0; - for (let i = 0; i < a.length; i++) { - diff |= a.charCodeAt(i) ^ b.charCodeAt(i); - } - return diff === 0; - } - function updateGivenName(e) { const isNameValid = e.target.value !== ""; setGivenNameState({ isValid: isNameValid, name: e.target.value }); diff --git a/client/src/routes/standardUser/UserSettings.js b/client/src/routes/standardUser/UserSettings.js index 29129d86..ee888b2b 100644 --- a/client/src/routes/standardUser/UserSettings.js +++ b/client/src/routes/standardUser/UserSettings.js @@ -22,6 +22,8 @@ import ConfirmationDialog from "../../components/dialog/confirmationDialog"; import { useNavigate } from "react-router-dom"; import { UserContext } from "../../utils/UserContext"; import PhoneInputField from "../../components/authentication/PhoneInputField"; +import { stringEqual } from "../../utils/stringEqual"; + /** * A page that provides the tools for a user to securely update their @@ -517,7 +519,7 @@ const UserSettings = () => { const Password = () => { const mismatch = passwordData.confirmPassword && - passwordData.newPassword !== passwordData.confirmPassword; + !stringEqual(passwordData.newPassword, passwordData.confirmPassword); const disabled = !passwordData.currentPassword || !passwordData.newPassword || mismatch; return ( diff --git a/client/src/utils/stringEqual.js b/client/src/utils/stringEqual.js new file mode 100644 index 00000000..019f51cf --- /dev/null +++ b/client/src/utils/stringEqual.js @@ -0,0 +1,18 @@ +/** + * Compares two strings in constant time using XOR. + * + * @param {string} a - The first string to compare + * @param {string} b - The second string to compare + * + * @returns {boolean} True if the strings are equal, false otherwise + */ +export function stringEqual(a, b) { + if (a.length !== b.length) { + return false; + } + let diff = 0; + for (let i = 0; i < a.length; i++) { + diff |= a.charCodeAt(i) ^ b.charCodeAt(i); + } + return diff === 0; +} From 618dcc3c9f7be7b72681ed8daa7f05210698830a Mon Sep 17 00:00:00 2001 From: birjd002 Date: Mon, 25 May 2026 15:16:37 +0930 Subject: [PATCH 8/9] fix: add bearer suppression comment to non-vulnerable code --- server/routers/authentication.py | 1 + server/tools/generate_dummy_data.py | 1 + 2 files changed, 2 insertions(+) diff --git a/server/routers/authentication.py b/server/routers/authentication.py index 271f9205..c6208535 100644 --- a/server/routers/authentication.py +++ b/server/routers/authentication.py @@ -334,6 +334,7 @@ async def login(request: Request, response: Response, user_cred: LoginCredential cookie_settings = _cookie_security_settings(request) + # bearer:disable python_django_cookies response.set_cookie( key='auth_token', value=token, diff --git a/server/tools/generate_dummy_data.py b/server/tools/generate_dummy_data.py index d7c6c11b..4384d30e 100644 --- a/server/tools/generate_dummy_data.py +++ b/server/tools/generate_dummy_data.py @@ -76,6 +76,7 @@ class UserRoleID(Enum): def load_names_csv(filename: str): '''Loads all the names in the CSV file to use in the dummy data''' + # bearer:disable python_lang_path_traversal with open(filename, encoding="utf-8") as csv_file: csv_reader = csvReader(csv_file, delimiter=',') for row in csv_reader: From 3a75ef1a4f881efb0bc6a682cf3b3521b7712cf5 Mon Sep 17 00:00:00 2001 From: birjd002 Date: Mon, 25 May 2026 18:00:36 +0930 Subject: [PATCH 9/9] fix: replace length and null check with false check --- client/src/components/authentication/PasswordInputField.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/authentication/PasswordInputField.js b/client/src/components/authentication/PasswordInputField.js index 8438c532..308d7856 100644 --- a/client/src/components/authentication/PasswordInputField.js +++ b/client/src/components/authentication/PasswordInputField.js @@ -95,7 +95,7 @@ const PasswordInputField = ({ if (!isAltered && !showRequired) { return null; } - if (password.length < 1 || password === null || showRequired) { + if (!password || showRequired) { return "*Required"; }