|
8 | 8 | from openpyxl import Workbook, load_workbook |
9 | 9 | from openpyxl.styles import Font, PatternFill |
10 | 10 | from openpyxl.utils.exceptions import InvalidFileException |
11 | | -from openpyxl.worksheet.views import Pane |
| 11 | +from openpyxl.worksheet.views import Pane, SheetView |
12 | 12 |
|
13 | 13 | from src.sharepoint_excel import SharePointExcelParser |
14 | 14 |
|
@@ -1300,3 +1300,92 @@ def test_include_frozen_rows_with_merged_cells(self): |
1300 | 1300 | assert sheet_data["rows"][0][0]["coordinate"] == "A1" |
1301 | 1301 | assert sheet_data["rows"][0][0]["merged"]["is_top_left"] is True |
1302 | 1302 | assert sheet_data["rows"][0][0]["merged"]["range"] == "A1:B1" |
| 1303 | + |
| 1304 | + def test_frozen_rows_dos_mitigation_exceeds_limit(self): |
| 1305 | + """frozen_rowsが上限を超えた場合は0にリセットされて処理が続行されること(DoS対策)""" |
| 1306 | + # 異常に大きなfrozen_rowsを持つExcelファイルを作成 |
| 1307 | + wb = Workbook() |
| 1308 | + ws = wb.active |
| 1309 | + ws.title = "TestSheet" |
| 1310 | + ws["A1"] = "Header" |
| 1311 | + ws["A2"] = "Data" |
| 1312 | + |
| 1313 | + # 異常に大きなfrozen_rowsを設定(openpyxl内部でpane.ySplitに直接設定) |
| 1314 | + pane = Pane() |
| 1315 | + pane.ySplit = 200 # デフォルト上限(100)を超える値 |
| 1316 | + pane.xSplit = 0 |
| 1317 | + pane.topLeftCell = "A201" |
| 1318 | + pane.state = "frozen" |
| 1319 | + |
| 1320 | + sheet_view = SheetView(pane=pane) |
| 1321 | + ws.views.sheetView[0] = sheet_view |
| 1322 | + |
| 1323 | + excel_bytes = BytesIO() |
| 1324 | + wb.save(excel_bytes) |
| 1325 | + excel_bytes.seek(0) |
| 1326 | + |
| 1327 | + self.mock_download_client.download_file.return_value = excel_bytes.getvalue() |
| 1328 | + |
| 1329 | + parser = SharePointExcelParser(self.mock_download_client) |
| 1330 | + |
| 1331 | + # frozen_rowsが上限を超えているが、リセットされて処理が続行される |
| 1332 | + result_json = parser.parse_to_json("test.xlsx") |
| 1333 | + result = json.loads(result_json) |
| 1334 | + |
| 1335 | + # frozen_rowsが0にリセットされている |
| 1336 | + sheet_data = result["sheets"][0] |
| 1337 | + assert sheet_data["frozen_rows"] == 0 |
| 1338 | + assert sheet_data["frozen_cols"] == 0 |
| 1339 | + # freeze_panes情報は含まれない |
| 1340 | + assert "freeze_panes" not in sheet_data |
| 1341 | + |
| 1342 | + @patch("src.sharepoint_excel.config.excel_max_frozen_rows", 50) |
| 1343 | + def test_frozen_rows_dos_mitigation_within_limit(self): |
| 1344 | + """frozen_rowsが上限以内の場合は正常に処理されること""" |
| 1345 | + # 上限以内のfrozen_rowsを持つExcelファイルを作成 |
| 1346 | + excel_bytes = self._create_frozen_rows_excel("A3") # frozen_rows=2 |
| 1347 | + self.mock_download_client.download_file.return_value = excel_bytes |
| 1348 | + |
| 1349 | + parser = SharePointExcelParser(self.mock_download_client) |
| 1350 | + |
| 1351 | + # 正常に処理される(エラーが発生しない) |
| 1352 | + result_json = parser.parse_to_json("test.xlsx") |
| 1353 | + result = json.loads(result_json) |
| 1354 | + |
| 1355 | + # frozen_rowsが正しく取得されている |
| 1356 | + sheet_data = result["sheets"][0] |
| 1357 | + assert sheet_data["frozen_rows"] == 2 |
| 1358 | + |
| 1359 | + @patch("src.sharepoint_excel.config.excel_max_frozen_rows", 150) |
| 1360 | + def test_frozen_rows_dos_mitigation_custom_limit(self): |
| 1361 | + """カスタム上限値が正しく適用されること""" |
| 1362 | + # カスタム上限(150)以内のfrozen_rowsを持つExcelファイルを作成 |
| 1363 | + wb = Workbook() |
| 1364 | + ws = wb.active |
| 1365 | + ws.title = "TestSheet" |
| 1366 | + ws["A1"] = "Header" |
| 1367 | + |
| 1368 | + # frozen_rows=120を設定(カスタム上限150以内) |
| 1369 | + pane = Pane() |
| 1370 | + pane.ySplit = 120 |
| 1371 | + pane.xSplit = 0 |
| 1372 | + pane.topLeftCell = "A121" |
| 1373 | + pane.state = "frozen" |
| 1374 | + |
| 1375 | + sheet_view = SheetView(pane=pane) |
| 1376 | + ws.views.sheetView[0] = sheet_view |
| 1377 | + |
| 1378 | + excel_bytes = BytesIO() |
| 1379 | + wb.save(excel_bytes) |
| 1380 | + excel_bytes.seek(0) |
| 1381 | + |
| 1382 | + self.mock_download_client.download_file.return_value = excel_bytes.getvalue() |
| 1383 | + |
| 1384 | + parser = SharePointExcelParser(self.mock_download_client) |
| 1385 | + |
| 1386 | + # カスタム上限(150)以内なので正常に処理される |
| 1387 | + result_json = parser.parse_to_json("test.xlsx") |
| 1388 | + result = json.loads(result_json) |
| 1389 | + |
| 1390 | + sheet_data = result["sheets"][0] |
| 1391 | + assert sheet_data["frozen_rows"] == 120 |
0 commit comments