From 665cd1b1cc8f565e0d3ee49c370d16802d63c79d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 06:03:06 +0000 Subject: [PATCH] Fix SQL Injection in MainController.loadBookInfo2 Refactored the vulnerable query into DataHelper.getIssueDetails using PreparedStatement. Added unit test for the new method. Updated DataHelper to throw SQLException for better error handling. Co-authored-by: G30RG3-GJ <203693057+G30RG3-GJ@users.noreply.github.com> --- .../assistant/database/DataHelper.java | 19 +++++++++++++++++++ .../assistant/ui/main/MainController.java | 11 +---------- .../assistant/database/DataHelperTest.java | 19 +++++++++++++++++++ 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/library/assistant/database/DataHelper.java b/src/library/assistant/database/DataHelper.java index a7c1a2b..9474daf 100644 --- a/src/library/assistant/database/DataHelper.java +++ b/src/library/assistant/database/DataHelper.java @@ -146,4 +146,23 @@ public static MailServerInfo loadMailServerInfo() { } return null; } + + public static ResultSet getIssueDetails(String bookID) throws SQLException { + return getIssueDetails(bookID, DatabaseHandler.getInstance().getConnection()); + } + + public static ResultSet getIssueDetails(String bookID, Connection conn) throws SQLException { + String query = "SELECT ISSUE.bookID, ISSUE.memberID, ISSUE.issueTime, ISSUE.renew_count,\n" + + "MEMBER.name, MEMBER.mobile, MEMBER.email,\n" + + "BOOK.title, BOOK.author, BOOK.publisher\n" + + "FROM ISSUE\n" + + "LEFT JOIN MEMBER\n" + + "ON ISSUE.memberID=MEMBER.ID\n" + + "LEFT JOIN BOOK\n" + + "ON ISSUE.bookID=BOOK.ID\n" + + "WHERE ISSUE.bookID=?"; + PreparedStatement stmt = conn.prepareStatement(query); + stmt.setString(1, bookID); + return stmt.executeQuery(); + } } diff --git a/src/library/assistant/ui/main/MainController.java b/src/library/assistant/ui/main/MainController.java index 50b0fff..3f6b29f 100644 --- a/src/library/assistant/ui/main/MainController.java +++ b/src/library/assistant/ui/main/MainController.java @@ -273,16 +273,7 @@ private void loadBookInfo2(ActionEvent event) { try { String id = bookID.getText(); - String myQuery = "SELECT ISSUE.bookID, ISSUE.memberID, ISSUE.issueTime, ISSUE.renew_count,\n" - + "MEMBER.name, MEMBER.mobile, MEMBER.email,\n" - + "BOOK.title, BOOK.author, BOOK.publisher\n" - + "FROM ISSUE\n" - + "LEFT JOIN MEMBER\n" - + "ON ISSUE.memberID=MEMBER.ID\n" - + "LEFT JOIN BOOK\n" - + "ON ISSUE.bookID=BOOK.ID\n" - + "WHERE ISSUE.bookID='" + id + "'"; - ResultSet rs = databaseHandler.execQuery(myQuery); + ResultSet rs = DataHelper.getIssueDetails(id); if (rs.next()) { memberNameHolder.setText(rs.getString("name")); memberContactHolder.setText(rs.getString("mobile")); diff --git a/test/library/assistant/database/DataHelperTest.java b/test/library/assistant/database/DataHelperTest.java index 17db79b..52068d7 100644 --- a/test/library/assistant/database/DataHelperTest.java +++ b/test/library/assistant/database/DataHelperTest.java @@ -64,4 +64,23 @@ public void testInsertNewBookException() throws SQLException { // Assert assertFalse(result); } + + @Test + public void testGetIssueDetails() throws SQLException { + // Arrange + Connection mockConn = mock(Connection.class); + PreparedStatement mockStmt = mock(PreparedStatement.class); + String bookID = "B100"; + + when(mockConn.prepareStatement(anyString())).thenReturn(mockStmt); + + // Act + DataHelper.getIssueDetails(bookID, mockConn); + + // Assert + String expectedQueryPart = "WHERE ISSUE.bookID=?"; + verify(mockConn).prepareStatement(argThat(sql -> sql != null && sql.contains(expectedQueryPart))); + verify(mockStmt).setString(1, bookID); + verify(mockStmt).executeQuery(); + } }