Offer administration only on a device marked as your own
A session signed in without "This is my own device" can no longer administer. The server withholds the account's permissions from it and the JMAP proxy refuses registry methods beyond the account's own, the same gate ADMINISTRATION=0 uses. A borrowed or shared machine is where nobody should be able to reset a password or remove a domain. An administrator in such a session still sees Administration in the account menu, greyed out, with the reason and the fix: sign in again with the box ticked. The server tells that session only that the account administers. The gate now reads the body only when it could name a registry method -- "x: in the text, or a \u escape that could spell one -- so ordinary mail traffic from an untrusted session is forwarded untouched. 1 new string, translated in all nine catalogues, quoting each language's own label for the tickbox; strings falling back to English stay at 16.
This commit is contained in:
@@ -45,6 +45,7 @@ export function AppShell({ children }: { children: ReactNode }) {
|
||||
const appName = useSession((s) => s.session?.ihasmail?.appName) || DEFAULT_APP_NAME;
|
||||
const acctMenu = useMenu();
|
||||
const administers = hasAdministration(usePermissions());
|
||||
const needsOwnDevice = useSession((s) => Boolean(s.session?.ihasmail?.administrationNeedsOwnDevice));
|
||||
/*
|
||||
* "Go to folder" (#233), hosted here rather than in the mail view because
|
||||
* the `g` shortcuts are global: pressing it from the calendar should still
|
||||
@@ -162,6 +163,21 @@ export function AppShell({ children }: { children: ReactNode }) {
|
||||
{/* Only for an account whose Stalwart role manages other accounts.
|
||||
Nobody else is shown an entry that would open onto refusals. */}
|
||||
{administers && <MenuItem icon={<ShieldCheck size={16} />} label={t("Administration")} active={section === "admin"} onClick={() => navigate("/admin")} />}
|
||||
{/* An administrator who signed in without "This is my own device". The
|
||||
server withholds administration from that session, so the entry is
|
||||
shown dead with the reason, rather than gone without one. */}
|
||||
{!administers && needsOwnDevice && (
|
||||
<MenuItem
|
||||
icon={<ShieldCheck size={16} />}
|
||||
disabled
|
||||
label={
|
||||
<>
|
||||
<span style={{ display: "block" }}>{t("Administration")}</span>
|
||||
<span className="hint" style={{ display: "block", whiteSpace: "normal" }}>{t("Only on a device you've marked as your own. Sign in again with “This is my own device” ticked.")}</span>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<MenuItem icon={<RefreshCw size={16} />} label={t("Refresh")} onClick={() => window.location.reload()} />
|
||||
<MenuItem icon={<LogOut size={16} />} label={t("Sign out")} onClick={() => void logout()} />
|
||||
</Popover>
|
||||
|
||||
Reference in New Issue
Block a user