summaryrefslogtreecommitdiffstats
path: root/docs/superpowers/plans
AgeCommit message (Collapse)AuthorFilesLines
6 hoursdocs: scope the document-load exemption to an exact URLDanilo M.1-3/+22
The interceptor previously trusted the whole qtmaildir: scheme, so a hostile message body referencing qtmaildir://anything would have been allowed. That made the interceptor's correctness depend on the scheme handler in a different, later task. It now trusts only the exact base URL passed to setHtml() and fails closed when none is set. Records the resulting obligation on MessageView to call setDocumentUrl() with that same URL. Also corrects the attachment path guard to a separator-aware comparison and notes that it is unreachable defence-in-depth: safeFilename() runs first, so no caller-supplied name can reach it. A test driving saveTo() expecting refusal cannot pass; test safeFilename() instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6 hoursfix: make attachment path-containment guard separator-awareDanilo M.1-5/+20
Attachment::saveTo()'s escape guard compared paths with a bare QString::startsWith(), which is not a path-boundary test: "/tmp/safe-evil" textually starts with "/tmp/safe", so a sibling directory whose name merely extends the target's name would incorrectly pass as contained within it. Extract the check into Attachment::isPathInsideDirectory(), comparing QDir::cleanPath()'d absolute paths and requiring an exact match or a prefix ending at a '/' boundary. Not exploitable today since safeFilename() always reduces the name to a bare basename before saveTo() builds the target, so the guard is unreachable via saveTo()'s public interface; comments on both now say so plainly instead of implying it is currently load-bearing. Add pathInsideDirectoryRejectsSiblingPrefix, testing the guard directly (independent of safeFilename(), which would mask a broken guard by never producing an escaping path), and safeFilenameStripsPathComponents, testing the sanitiser that actually stops traversal today.
6 hoursfeat: add Config with account, query, and sync parsingDanilo M.1-6/+6
Accounts use [account.work] rather than [account/work]: QSettings' INI backend treats "/" as its own hierarchical group separator, so a literal slash in a section header parses as a nested group and trips QSettings::FormatError, silently breaking childGroups() enumeration. A dot carries no such meaning and keeps the format flat. Saved-query order is alphabetical (QSettings::childKeys() sorts), not file order; documented in code and tests rather than left to a false assumption.
6 hoursdocs: fold full thread rendering and batch tagging into spec and planDanilo M.1-86/+515
Both were narrowed in the first draft and are now in scope. Newsletter threads make whole-thread rendering fundamental, and bulk archive is the main thing a GUI buys over neomutt. Two consequences fell out of thread rendering and are recorded in both documents. The thread renders as one document in one web view rather than one view per message, since a view each would spawn a Chromium render process each. Sharing a document makes cid: references collide when two messages use the same Content-ID, which is common across newsletters from one sender, so every reference is namespaced to cid:<prefix>!<id>. Deciding which messages render expanded needs the query, so loadThread now intersects it with the thread and MessageRef carries a matched flag. Batch tagging resolves thread ids to message ids on the worker in one combined query. Undo stores thread ids and re-resolves, staying correct after the selection moves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6 hoursdocs: add qtmaildir v1 implementation planDanilo M.1-0/+3988
Fourteen TDD tasks building from pure-logic units outward: keymap, config, MIME parsing, and the request interceptor are fully tested first, then the notmuch layer, then the UI that wires them together. Seven test binaries, up from the three the spec named; config, htmlbuilder, thread model, and sync each earned one. NotmuchWorker stays untested by design, with Task 13 as the compensating manual checklist against a real database. Two narrowings from the spec are recorded rather than silently dropped: thread rendering shows the newest message instead of a flat list of all messages, and tagging applies to the loaded thread rather than every selected one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>