hdx-python-api 6.7.4__tar.gz → 6.7.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/PKG-INFO +3 -3
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/pyproject.toml +2 -2
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/_version.py +2 -2
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/resource.py +30 -2
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_resource.py +38 -0
- hdx_python_api-6.7.6/uv.lock +3203 -0
- hdx_python_api-6.7.4/uv.lock +0 -2309
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/.github/workflows/publish.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/.github/workflows/run-python-tests.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/.gitignore +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/.pre-commit-config.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/CLAUDE.md +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/LICENSE +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/README.md +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/documentation/.readthedocs.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/documentation/index.md +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/documentation/mkdocs.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/__init__.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/configuration.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/hdx_base_configuration.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/locations.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/remotehdx.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/utilities/__init__.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/utilities/date_helper.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/utilities/filestore_helper.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/utilities/hdx_error_handler.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/utilities/hdx_state.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/utilities/hdx_stats.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/api/utilities/url_utils.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/__init__.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/activity.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/dataset.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/hdxobject.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/location.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/organization.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/resource_matcher.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/resource_view.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/showcase.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/user.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/data/vocabulary.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/facades/__init__.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/facades/infer_arguments.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/facades/keyword_arguments.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/src/hdx/facades/simple.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/__init__.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/Accepted_Tags.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/CKAN/hdx_dataset_static.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/Tag_Mapping.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/Tag_Mapping_ChainRuleError.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/empty.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_base_config.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_base_config.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_config.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_config.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_dataset_static.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_dataset_static.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_datasource_topline.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_datasource_topline.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_email_configuration.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_email_configuration.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_missing_site_config.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_organization_static.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_organization_static.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_resource_static.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_resource_static.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_resource_view_static.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_resource_view_static.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_showcase_static.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_showcase_static.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_user_static.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_user_static.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_vocabulary_static.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/hdx_vocabulary_static.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/project_configuration.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/project_configuration.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/user_agent_config.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/user_agent_config2.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/user_agent_config3.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/config/user_agent_config_wrong.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/dataset_search_results.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/download_gen_resource/conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/download_gen_resource/min_qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/download_gen_resource/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/download_gen_resource/test_data_no_data.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/download_gen_resource/test_data_no_years.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/empty.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/gen_resource/conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/gen_resource/min_qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/gen_resource/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/gen_resource/test_data_no_data.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/gen_resource/test_data_no_years.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/location/location_list_all_fields.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/location/location_show_results.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/organization/organization_list_all_fields.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/organization/organization_show_results.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/qc_from_rows/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/qc_from_rows/qc_conflict_data_alg_one_col.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/resource_formats.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/showcase_all_search_results.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/size_hash/ACLED-All-Africa-File_20170101-to-20170708.xlsx +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/state/analysis_dates.txt +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/state/last_build_date.txt +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/test_data.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/test_data.zip +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/dem_data_zwe.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/dem_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/expected_resources_to_update.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/opri_data_zwe.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/opri_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/opri_metadata_zwe.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/qc_sdg_data_zwe.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/sdg_data_zwe.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/sdg_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/sdg_metadata_zwe.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/unesco_dataset.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_dataset_resources/unesco_update_dataset.json +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_logic/update_logic_resources.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/fixtures/update_logic/update_logic_resources_new.yaml +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/__init__.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/api/__init__.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/api/test_ckan.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/api/test_configuration.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/api/test_locations.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/api/utilities/__init__.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/api/utilities/test_filestore_helper.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/api/utilities/test_hdx_error_handler.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/api/utilities/test_hdx_state.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/api/utilities/test_hdx_stats.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/api/utilities/test_url_utils.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/conftest.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/__init__.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_activity.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_dataset_add_hapi_error.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_dataset_core.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_dataset_noncore.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_dataset_resource_generation.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_location.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_organization.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_resource_view.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_showcase.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_update_dataset_resources.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_update_logic.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_user.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/data/test_vocabulary.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/facades/__init__.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/facades/test_infer_arguments.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/facades/test_keyword_arguments.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/tests/hdx/facades/test_simple.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/workingexample/my_code.py +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/workingexample/my_resource.csv +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/workingexample/my_resource.xlsx +0 -0
- {hdx_python_api-6.7.4 → hdx_python_api-6.7.6}/workingexample/run.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hdx-python-api
|
|
3
|
-
Version: 6.7.
|
|
3
|
+
Version: 6.7.6
|
|
4
4
|
Summary: HDX Python API for interacting with the Humanitarian Data Exchange
|
|
5
5
|
Project-URL: Homepage, https://github.com/OCHA-DAP/hdx-python-api
|
|
6
6
|
Author: Michael Rans
|
|
@@ -28,8 +28,8 @@ Requires-Python: >=3.10
|
|
|
28
28
|
Requires-Dist: ckanapi>=4.11
|
|
29
29
|
Requires-Dist: defopt>=7.0.0
|
|
30
30
|
Requires-Dist: email-validator
|
|
31
|
-
Requires-Dist: hdx-python-country>=4.2.
|
|
32
|
-
Requires-Dist: hdx-python-utilities>=4.2.
|
|
31
|
+
Requires-Dist: hdx-python-country>=4.2.5
|
|
32
|
+
Requires-Dist: hdx-python-utilities>=4.2.4
|
|
33
33
|
Requires-Dist: makefun
|
|
34
34
|
Requires-Dist: requests
|
|
35
35
|
Provides-Extra: docs
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '6.7.
|
|
22
|
-
__version_tuple__ = version_tuple = (6, 7,
|
|
21
|
+
__version__ = version = '6.7.6'
|
|
22
|
+
__version_tuple__ = version_tuple = (6, 7, 6)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -4,13 +4,15 @@ import json
|
|
|
4
4
|
import logging
|
|
5
5
|
from collections.abc import Iterator, Sequence
|
|
6
6
|
from datetime import datetime
|
|
7
|
-
from pathlib import Path
|
|
7
|
+
from pathlib import Path, PureWindowsPath
|
|
8
8
|
from typing import Any, Optional
|
|
9
|
+
from urllib.parse import urlsplit
|
|
9
10
|
|
|
10
11
|
from hdx.utilities.dateparse import now_utc, now_utc_notz, parse_date
|
|
11
12
|
from hdx.utilities.downloader import Download
|
|
12
13
|
from hdx.utilities.file_hashing import get_size_and_hash
|
|
13
14
|
from hdx.utilities.retriever import Retrieve
|
|
15
|
+
from hdx.utilities.session import get_session
|
|
14
16
|
from hdx.utilities.uuid import is_valid_uuid
|
|
15
17
|
|
|
16
18
|
import hdx.api.utilities.url_utils
|
|
@@ -755,6 +757,22 @@ class Resource(HDXObject):
|
|
|
755
757
|
logger.debug(result)
|
|
756
758
|
return resources
|
|
757
759
|
|
|
760
|
+
@staticmethod
|
|
761
|
+
def _get_safe_filename(filename: str) -> str:
|
|
762
|
+
"""Strip any directory components (/ or \\) from a filename built from
|
|
763
|
+
resource metadata so downloads cannot be written outside the folder
|
|
764
|
+
|
|
765
|
+
Args:
|
|
766
|
+
filename: Filename to make safe
|
|
767
|
+
|
|
768
|
+
Returns:
|
|
769
|
+
Filename without directory components
|
|
770
|
+
"""
|
|
771
|
+
safe_filename = PureWindowsPath(filename).name
|
|
772
|
+
if safe_filename in ("", ".", ".."):
|
|
773
|
+
raise HDXError(f"Invalid filename {filename} for download!")
|
|
774
|
+
return safe_filename
|
|
775
|
+
|
|
758
776
|
def _download_file(
|
|
759
777
|
self,
|
|
760
778
|
url: str,
|
|
@@ -773,7 +791,17 @@ class Resource(HDXObject):
|
|
|
773
791
|
Returns:
|
|
774
792
|
Path to downloaded file
|
|
775
793
|
"""
|
|
776
|
-
|
|
794
|
+
# Only send the HDX API key to the HDX site, not to external resource URLs
|
|
795
|
+
hdx_site_url = self.configuration.get_hdx_site_url()
|
|
796
|
+
if urlsplit(url)[:2] == urlsplit(hdx_site_url)[:2]:
|
|
797
|
+
session = hdx.api.utilities.url_utils.get_ckan_ready_session(
|
|
798
|
+
self.configuration
|
|
799
|
+
)
|
|
800
|
+
else:
|
|
801
|
+
session = get_session(
|
|
802
|
+
full_agent=self.configuration.get_user_agent(), use_env=False
|
|
803
|
+
)
|
|
804
|
+
filename = self._get_safe_filename(filename)
|
|
777
805
|
with Download(session=session) as downloader:
|
|
778
806
|
if retriever:
|
|
779
807
|
downloader = retriever.clone(downloader)
|
|
@@ -1225,6 +1225,44 @@ class TestResource:
|
|
|
1225
1225
|
with pytest.raises(DownloadError):
|
|
1226
1226
|
resource2.download()
|
|
1227
1227
|
|
|
1228
|
+
def test_download_security(self, configuration, read, monkeypatch):
|
|
1229
|
+
downloads = []
|
|
1230
|
+
|
|
1231
|
+
def download_file(self, url, folder=None, filename=None, path=None, **kwargs):
|
|
1232
|
+
downloads.append((self.session.headers.get("Authorization"), filename))
|
|
1233
|
+
return Path(folder or "tmp") / filename
|
|
1234
|
+
|
|
1235
|
+
monkeypatch.setattr(Download, "download_file", download_file)
|
|
1236
|
+
Configuration.read().set_api_key("12345")
|
|
1237
|
+
resource = Resource.read_from_hdx("74b74ae1-df0c-4716-829f-4f939a046811")
|
|
1238
|
+
resource.download()
|
|
1239
|
+
site_url = resource.configuration.get_hdx_site_url()
|
|
1240
|
+
resource["url"] = f"{site_url}/dataset/x/resource/y/download/a.csv"
|
|
1241
|
+
resource.download()
|
|
1242
|
+
resource["url"] = site_url.replace("https://", "http://")
|
|
1243
|
+
resource.download()
|
|
1244
|
+
assert downloads == [
|
|
1245
|
+
(None, "MyResource1.csv"),
|
|
1246
|
+
("12345", "MyResource1.csv"),
|
|
1247
|
+
(None, "MyResource1.csv"),
|
|
1248
|
+
]
|
|
1249
|
+
|
|
1250
|
+
downloads.clear()
|
|
1251
|
+
resource["name"] = "/home/user/.bashrc"
|
|
1252
|
+
resource.download()
|
|
1253
|
+
resource["name"] = "..\\..\\evil"
|
|
1254
|
+
resource.download_datastore()
|
|
1255
|
+
resource["name"] = "evil"
|
|
1256
|
+
resource["format"] = "csv/../../x"
|
|
1257
|
+
resource.download()
|
|
1258
|
+
assert [filename for _, filename in downloads] == [
|
|
1259
|
+
".bashrc.csv",
|
|
1260
|
+
"evil.csv",
|
|
1261
|
+
"x",
|
|
1262
|
+
]
|
|
1263
|
+
with pytest.raises(HDXError):
|
|
1264
|
+
Resource._get_safe_filename("a/..")
|
|
1265
|
+
|
|
1228
1266
|
def test_download_datastore(self, configuration, read, monkeypatch):
|
|
1229
1267
|
downloads = []
|
|
1230
1268
|
|