Summary
bases-page generates a page for every .base file on disk, without consulting the publish filters. On a site using explicit-publish, a base file publishes even though nothing opted it in, and there is no way to opt it out.
canvas-page has the same defect, in the same shape.
Cause
Both page types read the raw file listing rather than the filtered content they are handed:
// bases-page
ctx.allFiles.filter((fp) => fp.endsWith(".base"))
// canvas-page
ctx.allFiles.filter((fp) => fp.endsWith(".canvas"))
ctx.allFiles is the glob of everything on disk, populated in build.ts before filterContent runs. The dispatcher already passes the filtered set in as generate({ content, cfg, ctx }), so the information needed is available -- it is just not the source used.
Why there is no opt-out
publish: true cannot solve this from either end:
- A
.base file is YAML describing views. It has no frontmatter block, so there is nowhere to write the field. Same for .canvas. - Nothing would read it if there were. Neither package references publish, and explicit-publish filters content before the emitter phase, whereas these pages are created during it.
The generated page cannot be encrypted either
On a site using encrypted-pages, the leaked page is served in the clear. Encryption cannot reach it, for two independent reasons:
- Virtual pages are constructed with a fixed
frontmatter: { title, tags: [] } in the dispatcher, so the password field can never be present regardless of what the source file contains. - Encryption runs from htmlPlugins, in the transformer phase, which has already completed by the time the dispatcher creates these pages.
Confirmed by building: the generated .base page carries no data-encrypted attribute, and every note title and URL in it is readable without the password.
Impact
On a private site this publishes a page nobody marked for publication. In my case a base file listing every note in a section rendered as a standalone, unencrypted page at its vault path, exposing note titles and URLs on a site where every real page is password protected, and revealing the vault's internal folder structure that custom permalinks otherwise keep off the site.
Reproduced for canvas by dropping an unreferenced .canvas with no frontmatter into a content folder: it published as an unencrypted page.
The only workarounds are ignorePatterns or moving the file out of the content tree. Both also make the file unavailable to ![[embeds]] in published notes, so a base cannot currently be embedded without also being published standalone.
Suggested fix
Derive the file list from the content argument rather than ctx.allFiles, so a base or canvas publishes on the same terms as the notes around it.
Failing that, an option to restrict generation to files referenced by published pages would cover the embedding case, which is the common one, and would resolve the embed-or-publish tradeoff above.
Environment
- Quartz 5.0.0
@quartz-community/bases-page 0.2.2
@quartz-community/canvas-page 0.1.0
@quartz-community/encrypted-pages 0.1.1
- filters:
remove-draft, explicit-publish
Filing here rather than on canvas-page since the fix is the same one line in both; happy to open a matching issue there if you would prefer them tracked separately.
Related: jackyzha0/quartz#2531 reports the same shape of problem for attachments, which bypass explicit-publish in the builtin Assets emitter.
Summary
bases-pagegenerates a page for every.basefile on disk, without consulting the publish filters. On a site usingexplicit-publish, a base file publishes even though nothing opted it in, and there is no way to opt it out.canvas-pagehas the same defect, in the same shape.Cause
Both page types read the raw file listing rather than the filtered content they are handed:
ctx.allFilesis the glob of everything on disk, populated inbuild.tsbeforefilterContentruns. The dispatcher already passes the filtered set in asgenerate({ content, cfg, ctx }), so the information needed is available -- it is just not the source used.Why there is no opt-out
publish: truecannot solve this from either end:.basefile is YAML describing views. It has no frontmatter block, so there is nowhere to write the field. Same for.canvas. - Nothing would read it if there were. Neither package referencespublish, andexplicit-publishfilterscontentbefore the emitter phase, whereas these pages are created during it.The generated page cannot be encrypted either
On a site using
encrypted-pages, the leaked page is served in the clear. Encryption cannot reach it, for two independent reasons:frontmatter: { title, tags: [] }in the dispatcher, so thepasswordfield can never be present regardless of what the source file contains. - Encryption runs fromhtmlPlugins, in the transformer phase, which has already completed by the time the dispatcher creates these pages.Confirmed by building: the generated
.basepage carries nodata-encryptedattribute, and every note title and URL in it is readable without the password.Impact
On a private site this publishes a page nobody marked for publication. In my case a base file listing every note in a section rendered as a standalone, unencrypted page at its vault path, exposing note titles and URLs on a site where every real page is password protected, and revealing the vault's internal folder structure that custom permalinks otherwise keep off the site.
Reproduced for canvas by dropping an unreferenced
.canvaswith no frontmatter into a content folder: it published as an unencrypted page.The only workarounds are
ignorePatternsor moving the file out of the content tree. Both also make the file unavailable to![[embeds]]in published notes, so a base cannot currently be embedded without also being published standalone.Suggested fix
Derive the file list from the
contentargument rather thanctx.allFiles, so a base or canvas publishes on the same terms as the notes around it.Failing that, an option to restrict generation to files referenced by published pages would cover the embedding case, which is the common one, and would resolve the embed-or-publish tradeoff above.
Environment
@quartz-community/bases-page0.2.2@quartz-community/canvas-page0.1.0@quartz-community/encrypted-pages0.1.1remove-draft,explicit-publishFiling here rather than on
canvas-pagesince the fix is the same one line in both; happy to open a matching issue there if you would prefer them tracked separately.Related: jackyzha0/quartz#2531 reports the same shape of problem for attachments, which bypass
explicit-publishin the builtinAssetsemitter.