fix: a worksheet a lesson downloads comes back as a tab
Some Wonder Ink lesson links are a download rather than a page: the server sends the PDF as an attachment, so there is nothing for a tab to show and the file lands on disk. In this room that is the same as it not arriving. There is no file manager, no application launcher and no downloads bar, on purpose, and a teacher is not going to open a maintenance terminal to print a Christmas tree. 0.2.1 downloaded the worksheet, said so in a notification, and left it somewhere unreachable. Found on the canary machine with a real lesson. So a download that completes, and really is a PDF, opens as another tab. Rendering is the engine's own viewer — the same PDFium Chrome uses — so there is no second rendering library and no separate application. That was verified against a completed local file rather than assumed from the remote case: PdfViewerEnabled was already on, and a local file: URL is a different question. WHAT IS REFUSED. A completed download is not a usable worksheet. HTML that a server called .pdf, an empty file, an unreadable one: all refused on the first five bytes rather than on the name, because the alternative is a blank tab that says nothing. An interrupted download says it did not finish and to try again — and that needed stateChanged rather than isFinishedChanged, which is not emitted for an interrupted download at all. Connected to the obvious signal, this said nothing whatsoever about a worksheet that failed to arrive, which is the one case a teacher most needs told about. Measured. WHICH LOCAL FILES. Exactly the ones the window opened itself. Opening a worksheet adds one resolved path to a list, and the page's acceptNavigationRequest refuses every file: URL that is not on it. Chromium already refuses to let a remote page reach file: — verified with a link, a location.href, and a link to a worksheet that had been downloaded but not opened by the shell, all refused — so this is the second lock rather than the only one. It is here because the first one is somebody else's. Two Qt defaults are turned off beside it: LocalContentCanAccessFileUrls, which is on by default and would let a local document read other local documents, and its remote counterpart. Print to File is removed from the print dialog, because choosing it enables a path with a "..." button, which is a file chooser, in a room whose whole design is that there is no file chooser. The PDF viewer's own menus were audited: two-page view, annotations, present, properties, and nothing that opens or saves anywhere a teacher chooses. AND THE BROWSER IS NOT INVOLVED. The handler is connected to Wonder Ink's own profile, so it only ever sees downloads that started in a Wonder Ink tab. Nothing inspects a filename, nothing watches a directory, and Chrome — a separate application with a separate profile — is untouched: classroom-browser and the Chrome policies are byte-identical to stable 0.2.0. Worksheets go to ~/Downloads/Wonder Ink, which is tidiness and mostly the security argument: it is the only place one can come from. Only PDFs. Anything else downloads, says so, and is still unreachable; that limitation and two small follow-ups are written down rather than built, and nothing downloaded is ever executed. Measured from the package on a rebooted machine, and again on one upgraded from the published 0.2.1: the click-to-tab workflow end to end, a name with spaces and brackets, multi-page navigation, printing to Elmer, closing the worksheet without closing the lesson, and the four refusals. 120 convergence checks and 24 worksheet checks pass on both. Cookies are still session-only, the Present-view autoplay fix still works, fullscreen still comes back maximised, and there is still no address bar and no new-tab button. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
55a5aa3c99
commit
5f2a9098c1
@@ -267,6 +267,72 @@ check("Wonder Ink is not told twice",
|
||||
check("the clock is sized by the bar, not by a number",
|
||||
'autoFontAndSize", true' in layout and "fontSize" not in layout)
|
||||
|
||||
print()
|
||||
print("8. a lesson's worksheets come back as tabs")
|
||||
# The workflow itself is driven against a running session; these are the
|
||||
# properties of it that can be asserted from the source, and each one is
|
||||
# something whose absence was a bug at some point in the lab.
|
||||
check("worksheets land in Wonder Ink's own directory",
|
||||
'DOWNLOADS = Path(' in wonderink and '"Wonder Ink"' in wonderink)
|
||||
check("a finished PDF is opened as a tab",
|
||||
"def open_worksheet" in wonderink and "def open_pdf" in wonderink)
|
||||
check("and only after its contents are checked",
|
||||
'PDF_MAGIC = b"%PDF-"' in wonderink and "head != PDF_MAGIC" in wonderink)
|
||||
# isFinishedChanged is never emitted for an interrupted download, which
|
||||
# was measured: a worksheet that did not arrive said nothing at all.
|
||||
check("terminal states are read from stateChanged, not isFinishedChanged",
|
||||
"download.stateChanged.connect" in wonderink
|
||||
and "isFinishedChanged.connect" not in wonderink)
|
||||
check("an interrupted download says so",
|
||||
"DownloadInterrupted" in wonderink and "interruptReasonString" in wonderink)
|
||||
check("the path is made into a URL rather than concatenated",
|
||||
"QUrl.fromLocalFile" in wonderink)
|
||||
|
||||
print()
|
||||
print("8b. and opening them does not open the machine")
|
||||
check("a navigation guard decides every local file",
|
||||
"def acceptNavigationRequest" in wonderink and "url.isLocalFile()" in wonderink)
|
||||
check("which consults a list of paths the window itself opened",
|
||||
"def may_open" in wonderink and "self._openable" in wonderink)
|
||||
check("local documents may not read other local documents",
|
||||
"LocalContentCanAccessFileUrls, False" in wonderink)
|
||||
check("nor reach the network",
|
||||
"LocalContentCanAccessRemoteUrls, False" in wonderink)
|
||||
check("there is no file chooser behind the print dialog",
|
||||
"PrintDialogOption.PrintToFile, False" in wonderink)
|
||||
check("nothing downloaded is executed",
|
||||
"subprocess" not in wonderink.split("def notify")[0]
|
||||
and "QDesktopServices" not in wonderink
|
||||
and "xdg-open" not in wonderink)
|
||||
check("and no general file browser was added",
|
||||
"QFileDialog" not in wonderink)
|
||||
|
||||
print()
|
||||
print("8c. Wonder Ink and the browser stay apart")
|
||||
# The download handler belongs to the Wonder Ink window and is fed by the
|
||||
# Wonder Ink profile. Nothing watches a directory, and nothing asks where
|
||||
# a file came from by looking at its name.
|
||||
check("downloads are handled through Wonder Ink's own profile",
|
||||
"profile.downloadRequested.connect(window.on_download)" in wonderink)
|
||||
check("no directory watcher",
|
||||
"QFileSystemWatcher" not in wonderink and "inotify" not in wonderink)
|
||||
check("the browser is not touched by any of it",
|
||||
"wonderink" not in browser.lower().replace("wonder ink", "")
|
||||
or "Wonder Ink is a separate application" in browser)
|
||||
check("and Chrome's download policy is still unmentioned",
|
||||
not any(k.lower().startswith("download") for k in chrome_policy))
|
||||
|
||||
print()
|
||||
print("8d. the 0.2.1 behaviour it must not regress")
|
||||
check("cookies are still session-only",
|
||||
"NoPersistentCookies" in wonderink)
|
||||
check("the Present-view autoplay fix is still there",
|
||||
"PlaybackRequiresUserGesture, False" in wonderink)
|
||||
check("fullscreen still returns to a maximised window",
|
||||
"WindowFullScreen" in wonderink)
|
||||
check("still no new-tab button or address bar",
|
||||
"setCornerWidget" not in wonderink and "QLineEdit" not in wonderink)
|
||||
|
||||
print()
|
||||
print("7b. the disc player is decided before a session starts")
|
||||
layout_unit = (root / "systemd/layout/ekklesia-classroom-layout.service").read_text()
|
||||
|
||||
Reference in New Issue
Block a user