83 lines
3.4 KiB
TypeScript
83 lines
3.4 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import {
|
|
Button,
|
|
DismissibleAlert,
|
|
hasScope,
|
|
useGuardedNavigate,
|
|
usePlatformModuleInstalled
|
|
} from "@govoplan/core-webui";
|
|
import type { ApiSettings, AuthInfo } from "../../../types";
|
|
import {
|
|
getCampaignArchiveEncryptionPolicy,
|
|
type CampaignArchiveEncryptionPolicy
|
|
} from "../../../api/campaigns";
|
|
|
|
export const UNAVAILABLE_ARCHIVE_POLICY: CampaignArchiveEncryptionPolicy = {
|
|
available: false,
|
|
allowed_password_encryption_methods: ["aes"],
|
|
allowed_password_delivery_channels: ["separate_mail", "sms", "letter", "phone", "in_person"],
|
|
policy_hash: "",
|
|
source_path: [],
|
|
reason: "Archive-encryption policy is loading. Legacy ZipCrypto remains blocked.",
|
|
diagnostics: [],
|
|
legacy_label: "Legacy ZipCrypto — Windows-compatible, weak encryption"
|
|
};
|
|
|
|
export default function CampaignArchiveEncryptionPolicyNotice({
|
|
settings,
|
|
auth,
|
|
campaignId,
|
|
onPolicyChange
|
|
}: {
|
|
settings: ApiSettings;
|
|
auth: AuthInfo;
|
|
campaignId: string;
|
|
onPolicyChange?: (policy: CampaignArchiveEncryptionPolicy) => void;
|
|
}) {
|
|
const navigate = useGuardedNavigate();
|
|
const policyInstalled = usePlatformModuleInstalled("policy");
|
|
const [policy, setPolicy] = useState(UNAVAILABLE_ARCHIVE_POLICY);
|
|
const [loading, setLoading] = useState(true);
|
|
const [refresh, setRefresh] = useState(0);
|
|
const allowed = policy.available && policy.allowed_password_encryption_methods.includes("zip_standard");
|
|
const canReadPolicy = policyInstalled && hasScope(auth, "admin:policies:read");
|
|
const canUseLegacy = hasScope(auth, "campaigns:archive:use_legacy_zipcrypto");
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
setLoading(true);
|
|
setPolicy(UNAVAILABLE_ARCHIVE_POLICY);
|
|
void getCampaignArchiveEncryptionPolicy(settings, campaignId)
|
|
.then((loaded) => { if (!cancelled) setPolicy(loaded); })
|
|
.catch((cause) => {
|
|
if (!cancelled) setPolicy({
|
|
...UNAVAILABLE_ARCHIVE_POLICY,
|
|
reason: cause instanceof Error ? cause.message : String(cause)
|
|
});
|
|
})
|
|
.finally(() => { if (!cancelled) setLoading(false); });
|
|
return () => { cancelled = true; };
|
|
}, [campaignId, refresh, settings.accessToken, settings.apiBaseUrl, settings.apiKey]);
|
|
|
|
useEffect(() => { onPolicyChange?.(policy); }, [onPolicyChange, policy]);
|
|
|
|
return <DismissibleAlert tone={allowed ? "warning" : "info"} dismissible={false} compact>
|
|
<strong>{policy.legacy_label}</strong>: {policy.reason}
|
|
{policy.source_path.length > 0 && <p>{policy.source_path.map((step) => step.label).join(" → ")}</p>}
|
|
<p>i18n:govoplan-campaign.archive_policy_enable_guidance</p>
|
|
{!canUseLegacy && <p>i18n:govoplan-campaign.archive_policy_permission_missing</p>}
|
|
{!policyInstalled && <p>i18n:govoplan-campaign.archive_policy_module_missing</p>}
|
|
{canReadPolicy && <Button
|
|
helpContextId="campaign.archive-encryption"
|
|
helpModuleId="campaigns"
|
|
onClick={() => navigate("/admin?section=system-campaign-archive-encryption")}
|
|
>i18n:govoplan-campaign.archive_policy_open_system</Button>}
|
|
{canReadPolicy && <Button
|
|
onClick={() => navigate("/admin?section=tenant-campaign-archive-encryption")}
|
|
>i18n:govoplan-campaign.archive_policy_open_tenant</Button>}
|
|
<Button disabled={loading} onClick={() => setRefresh((value) => value + 1)}>
|
|
i18n:govoplan-campaign.archive_policy_reload
|
|
</Button>
|
|
</DismissibleAlert>;
|
|
}
|