feat: protect postbox message content
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from govoplan_core.core.encryption import (
|
||||
ContentProtectionRequest,
|
||||
ContentUnprotectionRequest,
|
||||
ProtectedContent,
|
||||
encryption_content_cipher,
|
||||
)
|
||||
from govoplan_postbox.backend.runtime import get_registry
|
||||
|
||||
|
||||
POSTBOX_PLAINTEXT_PROFILE = "plaintext_v1"
|
||||
POSTBOX_SERVER_ENVELOPE_PROFILE = "server_envelope_v1"
|
||||
|
||||
|
||||
class PostboxContentProtectionError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
def protect_message_body(
|
||||
session: object,
|
||||
*,
|
||||
tenant_id: str,
|
||||
message_id: str,
|
||||
vault_id: str,
|
||||
plaintext: str,
|
||||
actor_id: str,
|
||||
) -> ProtectedContent:
|
||||
capability = encryption_content_cipher(get_registry())
|
||||
if capability is None:
|
||||
raise PostboxContentProtectionError(
|
||||
"Postbox encryption was requested, but Encryption is unavailable."
|
||||
)
|
||||
try:
|
||||
return capability.protect_content(
|
||||
session,
|
||||
request=ContentProtectionRequest(
|
||||
tenant_id=tenant_id,
|
||||
owner_module="postbox",
|
||||
resource_type="postbox_message_body",
|
||||
resource_id=message_id,
|
||||
profile_id=POSTBOX_SERVER_ENVELOPE_PROFILE,
|
||||
vault_id=vault_id,
|
||||
ciphertext_ref=f"postbox-db://messages/{message_id}/body",
|
||||
plaintext=plaintext.encode("utf-8"),
|
||||
policy_decision_ref="postbox:configured-server-envelope:v1",
|
||||
idempotency_key=f"postbox-message:{message_id}:body:v1",
|
||||
actor_id=actor_id,
|
||||
metadata={"content_type": "text/plain;charset=utf-8"},
|
||||
),
|
||||
)
|
||||
except Exception as exc:
|
||||
raise PostboxContentProtectionError(
|
||||
"Postbox message content could not be protected by its configured vault."
|
||||
) from exc
|
||||
|
||||
|
||||
def unprotect_message_body(
|
||||
session: object,
|
||||
*,
|
||||
tenant_id: str,
|
||||
message_id: str,
|
||||
envelope_id: str,
|
||||
ciphertext: bytes,
|
||||
) -> str:
|
||||
capability = encryption_content_cipher(get_registry())
|
||||
if capability is None:
|
||||
raise PostboxContentProtectionError(
|
||||
"This Postbox message is encrypted and Encryption is unavailable."
|
||||
)
|
||||
try:
|
||||
plaintext = capability.unprotect_content(
|
||||
session,
|
||||
request=ContentUnprotectionRequest(
|
||||
tenant_id=tenant_id,
|
||||
owner_module="postbox",
|
||||
resource_type="postbox_message_body",
|
||||
resource_id=message_id,
|
||||
envelope_id=envelope_id,
|
||||
ciphertext=ciphertext,
|
||||
),
|
||||
)
|
||||
return plaintext.decode("utf-8")
|
||||
except Exception as exc:
|
||||
raise PostboxContentProtectionError(
|
||||
"Postbox message content could not be opened with its protection envelope."
|
||||
) from exc
|
||||
|
||||
|
||||
__all__ = [
|
||||
"POSTBOX_PLAINTEXT_PROFILE",
|
||||
"POSTBOX_SERVER_ENVELOPE_PROFILE",
|
||||
"PostboxContentProtectionError",
|
||||
"protect_message_body",
|
||||
"unprotect_message_body",
|
||||
]
|
||||
Reference in New Issue
Block a user