Files
inbuxa-admin/src/features/hardening/LegacyProtocolsBanner.tsx
T
jcoffey-dev 11d85cd759 Each tenant's page carries its legacy protocols switch (LP-9 to LP-18)
A card above the tenant form: whether legacy mail protocols are on or off
for the organization, a one-click "Turn legacy protocols back on", and
"Turn off legacy protocols…", which opens -- before anything can change --
the impact panel with the tenant's own people (LP-15), the statement at
tenant scope and the typed confirmation (LP-16, LP-17). The statement reads
"everyone in {organization}" and names no ports and no firewall: a
tenant's switch closes nothing, other tenants share the ports (LP-13).

It reads and turns inbuxa:TenantProtocolPolicy, with the domain
permissions the server checks for it. It shows on the read-only tenant page
too: a tenant administrator reads its tenant without changing it (MT-12)
and may still turn the switch. Turning it back on while the server has
legacy protocols off is refused by the server, and the refusal is shown.

The banner (LP-18) falls back to the tenant's switch where the server's
can't be read -- inside a tenant -- and reads "off for your
organization".

The impact panel, statement and confirmation move to parts.tsx, shared by
Hardening and the tenant card; the statement takes its scope.

Checked by hand against a local server with a tenant, two of its users and
the admin signed in over IMAP: the tenant card's panel lists the tenant's
two users and not the admin; the statement reads "everyone in Example Co"
with no ports or firewall; turning it off makes the tenant's user get "NO
[ALERT] Your organization allows only INBUXA webmail and JMAP apps" over
IMAP; one click turns it back on; Hardening's panel lists all three. Not
checked by hand: the banner as a tenant administrator sees it.
2026-09-21 13:39:56 -07:00

79 lines
2.9 KiB
TypeScript

/*
* SPDX-FileCopyrightText: 2026 Coffey Labs
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
/**
* INBUXA: the banner while legacy mail protocols are off (LP-18), on the
* Security settings and the dashboard. It says nothing when the switch is on,
* when the reader may not see the policy, or when the server has no policy.
*/
import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { ShieldCheck } from 'lucide-react';
import { useAccountStore } from '@/stores/accountStore';
import { fetchProtocolPolicy, fetchTenantPolicy } from './protocolPolicy';
export const LEGACY_PROTOCOLS_VIEW = 'CustomComponent/LegacyProtocols';
export function LegacyProtocolsBanner() {
const { t } = useTranslation();
const canGetServer = useAccountStore((s) => s.hasObjectPermission('sysNetworkListener', 'Get'));
const canGetTenant = useAccountStore((s) => s.hasObjectPermission('sysDomain', 'Get'));
const [off, setOff] = useState<null | 'server' | 'tenant'>(null);
useEffect(() => {
if (!canGetServer && !canGetTenant) return;
const controller = new AbortController();
const signal = controller.signal;
(async () => {
// The server's switch first. Inside a tenant it can't be read, and the
// tenant's own is the one to report (LP-18 at tenant scope).
try {
if (canGetServer) {
const policy = await fetchProtocolPolicy(signal);
if (!signal.aborted) setOff(policy.legacyProtocols === 'disabled' ? 'server' : null);
return;
}
} catch {
// Fall through to the tenant's.
}
try {
if (canGetTenant) {
const policy = await fetchTenantPolicy(null, signal);
if (!signal.aborted) setOff(policy.legacyProtocols === 'disabled' ? 'tenant' : null);
}
} catch {
// A banner is not worth an error: an older server simply has no switch.
}
})();
return () => controller.abort();
}, [canGetServer, canGetTenant]);
if (!off) return null;
return (
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3 text-sm">
<ShieldCheck className="h-4 w-4 shrink-0 text-emerald-600" />
<span>
{t('legacyProtocols.bannerLead', 'Legacy mail protocols are')}{' '}
<strong>{t('legacyProtocols.bannerOff', 'off')}</strong>{' '}
{off === 'server'
? t('legacyProtocols.bannerTail', 'on this server. Only INBUXA webmail and JMAP apps can sign in.')
: t(
'legacyProtocols.bannerTailTenant',
'for your organization. Only INBUXA webmail and JMAP apps can sign in.',
)}
</span>
{off === 'server' && (
<Link to={`/Settings/${LEGACY_PROTOCOLS_VIEW}`} className="font-medium text-primary hover:underline">
{t('legacyProtocols.review', 'Review')}
</Link>
)}
</div>
);
}