From 3d33f5e00d0f9a640753d8a4de1840138a6995a2 Mon Sep 17 00:00:00 2001 From: icsp Date: Sat, 7 Jun 2025 11:38:26 +0200 Subject: [PATCH 1/2] Enforce user ownership in table existence check. --- .../tabula/repository/table/TableDAO.java | 14 +++++++++----- .../bytestrick/tabula/service/TableService.java | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/backend/src/main/java/com/github/bytestrick/tabula/repository/table/TableDAO.java b/backend/src/main/java/com/github/bytestrick/tabula/repository/table/TableDAO.java index 8e91ed93..57fec164 100644 --- a/backend/src/main/java/com/github/bytestrick/tabula/repository/table/TableDAO.java +++ b/backend/src/main/java/com/github/bytestrick/tabula/repository/table/TableDAO.java @@ -2,6 +2,7 @@ import com.github.bytestrick.tabula.model.table.Table; import com.github.bytestrick.tabula.repository.proxy.table.TableProxy; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.simple.JdbcClient; @@ -85,20 +86,23 @@ public void deleteTable(UUID tableId) { /** - * Check to see if the table exists. + * Checks whether a table with the given ID exists and belongs to the specified user. * - * @param tableId Id to check. - * @return Returns {@code true} if the {@code tableId} is associated with a table. + * @param tableId UUID of the table to check. + * @param userId UUID of the user who should own the table. + * @return {@code true} if a row exists in {@code tbl_table} with {@code id = tableId} + * and {@code user_id = userId}; {@code false} otherwise. */ - public boolean tableExists(UUID tableId) { + public boolean tableExists(UUID tableId, UUID userId) { return jdbcClient.sql(""" SELECT EXISTS( SELECT 1 FROM tbl_table - WHERE id = :tableId + WHERE id = :tableId and user_id = :userId ) """) .param("tableId", tableId) + .param("userId", userId) .query(Boolean.class) .single(); } diff --git a/backend/src/main/java/com/github/bytestrick/tabula/service/TableService.java b/backend/src/main/java/com/github/bytestrick/tabula/service/TableService.java index 5c691f07..439b7781 100644 --- a/backend/src/main/java/com/github/bytestrick/tabula/service/TableService.java +++ b/backend/src/main/java/com/github/bytestrick/tabula/service/TableService.java @@ -145,7 +145,7 @@ private void ensureDataTypeExistsOrThrow(int dataTypeId) { * @throws TableNotFoundException If no table exists for the given {@code tableId}. */ private void ensureTableExistsOrThrow(UUID tableId) { - if (!tableDAO.tableExists(tableId)) { + if (!tableDAO.tableExists(tableId, getAuthUser().getId())) { throw new TableNotFoundException(tableId); } } From 79152026382244de0ae37da1dc92c0ea2a1d0b7b Mon Sep 17 00:00:00 2001 From: icsp Date: Sat, 7 Jun 2025 11:47:45 +0200 Subject: [PATCH 2/2] refactor: rename tableExists to tableExistsForUser and ensureTableExistsOrThrow to ensureTableExistsForAuthUserOrThrow. --- .../tabula/repository/table/TableDAO.java | 3 +- .../tabula/service/TableService.java | 28 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/backend/src/main/java/com/github/bytestrick/tabula/repository/table/TableDAO.java b/backend/src/main/java/com/github/bytestrick/tabula/repository/table/TableDAO.java index 57fec164..8e53dc4c 100644 --- a/backend/src/main/java/com/github/bytestrick/tabula/repository/table/TableDAO.java +++ b/backend/src/main/java/com/github/bytestrick/tabula/repository/table/TableDAO.java @@ -2,7 +2,6 @@ import com.github.bytestrick.tabula.model.table.Table; import com.github.bytestrick.tabula.repository.proxy.table.TableProxy; -import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.simple.JdbcClient; @@ -93,7 +92,7 @@ public void deleteTable(UUID tableId) { * @return {@code true} if a row exists in {@code tbl_table} with {@code id = tableId} * and {@code user_id = userId}; {@code false} otherwise. */ - public boolean tableExists(UUID tableId, UUID userId) { + public boolean tableExistsForUser(UUID tableId, UUID userId) { return jdbcClient.sql(""" SELECT EXISTS( SELECT 1 diff --git a/backend/src/main/java/com/github/bytestrick/tabula/service/TableService.java b/backend/src/main/java/com/github/bytestrick/tabula/service/TableService.java index 439b7781..d7fad7d6 100644 --- a/backend/src/main/java/com/github/bytestrick/tabula/service/TableService.java +++ b/backend/src/main/java/com/github/bytestrick/tabula/service/TableService.java @@ -103,7 +103,7 @@ public TableCreatedDTO createNewTable(TableCreateDTO tableCreateDTO) { @Transactional public String updateTable(UUID tableId, TablePutDTO tablePutDTO) { - ensureTableExistsOrThrow(tableId); + ensureTableExistsForAuthUserOrThrow(tableId); Table table = Table.builder() .id(tableId) @@ -139,13 +139,13 @@ private void ensureDataTypeExistsOrThrow(int dataTypeId) { } /** - * Verifies that a table with the given UUID exists; otherwise throws. + * Verifies that a table with the given UUID exists and belongs to auth user; otherwise throws. * * @param tableId The UUID of the table to check. * @throws TableNotFoundException If no table exists for the given {@code tableId}. */ - private void ensureTableExistsOrThrow(UUID tableId) { - if (!tableDAO.tableExists(tableId, getAuthUser().getId())) { + private void ensureTableExistsForAuthUserOrThrow(UUID tableId) { + if (!tableDAO.tableExistsForUser(tableId, getAuthUser().getId())) { throw new TableNotFoundException(tableId); } } @@ -204,7 +204,7 @@ private void ensureIndexIsWithinTheBoundsOrThrow(int index, int minBounds, int m */ @Transactional public TableContentDTO getTable(UUID tableId) { - ensureTableExistsOrThrow(tableId); + ensureTableExistsForAuthUserOrThrow(tableId); TableProxy table = tableDAO.findTableById(tableId); List content = new ArrayList<>(); @@ -237,7 +237,7 @@ public TableContentDTO getTable(UUID tableId) { */ @Transactional public String deleteTable(UUID tableId) { - ensureTableExistsOrThrow(tableId); + ensureTableExistsForAuthUserOrThrow(tableId); tableDAO.deleteTable(tableId); return "Table deleted successfully"; } @@ -283,7 +283,7 @@ protected RowProxy duplicateRow(UUID tableId, int rowIndex) { */ @Transactional public RowCreatedDTO addNewRow(UUID tableId, RowCreateDTO rowCreateDTO) { - ensureTableExistsOrThrow(tableId); + ensureTableExistsForAuthUserOrThrow(tableId); RowProxy createdRow; List cellsValues = new ArrayList<>(); @@ -357,7 +357,7 @@ protected ColumnProxy duplicateColumn(UUID tableId, int columnIndex) { */ @Transactional public ColumnCreatedDTO addNewColumn(UUID tableId, ColumnCreateDTO columnCreateDTO) { - ensureTableExistsOrThrow(tableId); + ensureTableExistsForAuthUserOrThrow(tableId); ensureDataTypeExistsOrThrow(columnCreateDTO.dataTypeId()); ColumnProxy createdColumn; @@ -410,7 +410,7 @@ public ColumnCreatedDTO addNewColumn(UUID tableId, ColumnCreateDTO columnCreateD */ @Transactional public ColumnPatchedDTO patchHeaderColumn(UUID tableId, UUID columnId, ColumnPatchDTO patchDTO) { - ensureTableExistsOrThrow(tableId); + ensureTableExistsForAuthUserOrThrow(tableId); ensureColumnExistsOrThrow(tableId, columnId); if (patchDTO.dataTypeId() != null) { @@ -450,7 +450,7 @@ public ColumnPatchedDTO patchHeaderColumn(UUID tableId, UUID columnId, ColumnPat */ @Transactional public List updateCellValue(UUID tableId, List cellsPatchDTO) { - ensureTableExistsOrThrow(tableId); + ensureTableExistsForAuthUserOrThrow(tableId); List cellsPatched = new ArrayList<>(); @@ -532,7 +532,7 @@ else if (cellPatchDTO.columnId() != null) { */ @Transactional public ColumnsDeletedDTO deleteColumns(UUID tableId, ColumnsDeleteDTO columnsDeleteDTO) { - ensureTableExistsOrThrow(tableId); + ensureTableExistsForAuthUserOrThrow(tableId); if ((columnDAO.getColumnNumber(tableId) - columnsDeleteDTO.ids().size()) <= 0) throw new AtLeastOneRowAndOneColumn(); @@ -560,7 +560,7 @@ public ColumnsDeletedDTO deleteColumns(UUID tableId, ColumnsDeleteDTO columnsDel */ @Transactional public RowsDeletedDTO deleteRows(UUID tableId, RowsDeleteDTO rowsDeleteDTO) { - ensureTableExistsOrThrow(tableId); + ensureTableExistsForAuthUserOrThrow(tableId); if ((rowDAO.getRowsNumber(tableId) - rowsDeleteDTO.ids().size()) <= 0) throw new AtLeastOneRowAndOneColumn(); @@ -785,7 +785,7 @@ private boolean canMoveRowOrColumn(int fromIndex, int toIndex, int totalAmount) */ @Transactional public MovedRowsOrColumnsDTO moveRowsIndexes(UUID tableId, MovesRowsOrColumnsDTO moveRowsDTO) { - ensureTableExistsOrThrow(tableId); + ensureTableExistsForAuthUserOrThrow(tableId); int rowsAmount = rowDAO.getRowsNumber(tableId); @@ -840,7 +840,7 @@ public MovedRowsOrColumnsDTO moveRowsIndexes(UUID tableId, MovesRowsOrColumnsDTO */ @Transactional public MovedRowsOrColumnsDTO moveColumnsIndexes(UUID tableId, MovesRowsOrColumnsDTO moveColumnsDTO) { - ensureTableExistsOrThrow(tableId); + ensureTableExistsForAuthUserOrThrow(tableId); int columnsAmount = columnDAO.getColumnNumber(tableId);