Skip to content

Bases (and canvases) publish without opt-in, and cannot be encrypted #11

Description

@archifont

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions