| Age | Commit message (Collapse) | Author | Files | Lines |
|
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.
|
|
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.
|
|
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>
|
|
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>
|