Refuse to save a script we only partly read
The transport fix stops the truncation that caused #76, but the save path had no answer for a baseline that arrives incomplete. It is neither unknown nor empty, so every existing guard passes it through: it parses into a shorter rule list that looks exactly like a script with fewer rules, and saving writes that back over the real one. Check the script against the shape the generator emits instead. Every rule comment parses, every enabled rule has an if and a closed body under it, every block ends with a blank line. Structural rather than a re-serialize-and-compare, so a script written by an older version whose serializer differed is still editable. The rule editor reports a short script as unreadable rather than showing the rules that happened to parse, since a list that looks complete over a script that is not is the most dangerous thing it could offer. A cut at the end of a complete rule block is still a valid shorter script and cannot be told apart from one; that residual is the proxy's to cover.
This commit is contained in:
@@ -33,17 +33,19 @@ export function FilterFromMessageDialog({ email, mailboxId, onClose }: { email:
|
||||
}
|
||||
if (!ready) return <Dialog open onClose={onClose} title="Create filter" size="sm"><Spinner /></Dialog>;
|
||||
|
||||
const { rules, loaded } = sieve.rules();
|
||||
const { rules, loaded, damage } = sieve.rules();
|
||||
if (rules === null) {
|
||||
return (
|
||||
<Dialog open onClose={onClose} title="Create filter" size="sm" footer={<button className="btn" onClick={onClose}>Close</button>}>
|
||||
{/*
|
||||
Two different situations, and telling them apart matters: one is
|
||||
permanent and one is a reload away. Saying "written by hand" when the
|
||||
script merely failed to fetch sends someone looking for a problem
|
||||
they do not have.
|
||||
Three different situations, and telling them apart matters: one is
|
||||
permanent and two are a reload away. Saying "written by hand" when the
|
||||
script merely failed to fetch -- or arrived in part -- sends someone
|
||||
looking for a problem they do not have.
|
||||
*/}
|
||||
{loaded ? (
|
||||
{damage ? (
|
||||
<p>Your filter script {damage}, so only part of it arrived. Adding a rule would write that part back over the whole thing. Reload the page and try again.</p>
|
||||
) : loaded ? (
|
||||
<p>Your active Sieve script was written by hand, so rules can't be added automatically. Open <b>Settings → Filters & rules</b> to edit the script or switch to managed rules.</p>
|
||||
) : (
|
||||
<p>Your filter script couldn't be read just now, so adding a rule would risk overwriting it. Reload the page and try again.</p>
|
||||
|
||||
@@ -45,7 +45,7 @@ const RULE_MIME = "application/x-ihasmail-sieve-rule";
|
||||
|
||||
function RulesEditor() {
|
||||
const sieve = useSieve();
|
||||
const { script, rules, content } = sieve.rules();
|
||||
const { script, rules, content, damage } = sieve.rules();
|
||||
const [local, setLocal] = useState<SieveRule[] | null>(null);
|
||||
const [editing, setEditing] = useState<SieveRule | null>(null);
|
||||
const [saving, setSaving] = useState(false);
|
||||
@@ -80,6 +80,19 @@ function RulesEditor() {
|
||||
}
|
||||
};
|
||||
|
||||
// Before the hand-written branch: a script that arrived in part is not a
|
||||
// script someone chose to write themselves, and the way out of it is a reload
|
||||
// rather than the "start with rules" button below, which would write over it.
|
||||
if (damage) {
|
||||
return (
|
||||
<div className="warn-box">
|
||||
<div className="row gap-8" style={{ marginBottom: 8 }}><AlertTriangle size={18} /> <b>Only part of your filter script arrived.</b></div>
|
||||
<p style={{ margin: "0 0 8px" }}>It {damage}, so the rules in it can't be shown or edited — saving what did arrive would write it back over the rest. Reload the page to try again. Your rules are still on the server; nothing here has changed them.</p>
|
||||
<button className="btn" onClick={() => window.location.reload()}>Reload</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (rules === null) {
|
||||
return (
|
||||
<div className="warn-box">
|
||||
|
||||
Reference in New Issue
Block a user