Block local file paths at Campaign server boundaries
This commit is contained in:
@@ -107,6 +107,7 @@ from govoplan_campaign.backend.persistence.campaigns import (
|
||||
validate_campaign_version,
|
||||
)
|
||||
from govoplan_campaign.backend.integrations import files_integration
|
||||
from govoplan_campaign.backend.path_security import CampaignPathSecurityError, assert_server_safe_campaign_paths
|
||||
from govoplan_campaign.backend.campaign.loader import load_campaign_json
|
||||
from govoplan_campaign.backend.attachments.resolver import resolve_campaign_attachments
|
||||
from govoplan_core.security.time import utc_now
|
||||
@@ -373,6 +374,8 @@ def _campaign_version_detail_response(
|
||||
return CampaignVersionDetailResponse.model_validate(version)
|
||||
except LockedCampaignVersionError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(exc)) from exc
|
||||
except CampaignPathSecurityError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail=str(exc)) from exc
|
||||
except CampaignPersistenceError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
||||
except Exception as exc:
|
||||
@@ -1487,6 +1490,8 @@ def fork_version_for_edit(
|
||||
)
|
||||
except LockedCampaignVersionError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(exc)) from exc
|
||||
except CampaignPathSecurityError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail=str(exc)) from exc
|
||||
except CampaignPersistenceError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
||||
|
||||
@@ -3203,6 +3208,7 @@ def _attachment_preview_for_version(
|
||||
include_unlinked_candidates: bool,
|
||||
) -> CampaignAttachmentPreviewResponse:
|
||||
files = files_integration()
|
||||
assert_server_safe_campaign_paths(raw, managed_files_available=files.available)
|
||||
with files.prepared_campaign_snapshot(
|
||||
session,
|
||||
tenant_id=principal.tenant_id,
|
||||
@@ -3352,15 +3358,18 @@ def preview_campaign_attachments(
|
||||
raw = payload.campaign_json if isinstance(payload.campaign_json, dict) else version.raw_json
|
||||
raw = raw if isinstance(raw, dict) else {}
|
||||
_require_mail_profile_use_if_needed(principal, raw)
|
||||
return _attachment_preview_for_version(
|
||||
session,
|
||||
principal,
|
||||
campaign=campaign,
|
||||
version=version,
|
||||
raw=raw,
|
||||
include_unmatched=payload.include_unmatched,
|
||||
include_unlinked_candidates=payload.include_unlinked_candidates,
|
||||
)
|
||||
try:
|
||||
return _attachment_preview_for_version(
|
||||
session,
|
||||
principal,
|
||||
campaign=campaign,
|
||||
version=version,
|
||||
raw=raw,
|
||||
include_unmatched=payload.include_unmatched,
|
||||
include_unlinked_candidates=payload.include_unlinked_candidates,
|
||||
)
|
||||
except CampaignPathSecurityError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.post("/{campaign_id}/versions/{version_id}/attachments/link-matches", response_model=CampaignAttachmentLinkMatchesResponse)
|
||||
|
||||
Reference in New Issue
Block a user