Add message frontmatter, field. Encrypted the encrypt docs for PoC

This commit is contained in:
Yigit Colakoglu 2025-07-30 20:42:32 +02:00
parent 2533c5b01a
commit ff83a93588
7 changed files with 49 additions and 8 deletions

View File

@ -2,6 +2,9 @@
title: "Encrypt" title: "Encrypt"
tags: tags:
- plugin/transformer - plugin/transformer
encrypt: true
encrypt_message: '^ Password is "quartz"'
password: "quartz"
--- ---
This plugin enables content encryption for sensitive pages in your Quartz site. It uses AES encryption with password-based access control, allowing you to protect specific pages or entire folders with passwords. This plugin enables content encryption for sensitive pages in your Quartz site. It uses AES encryption with password-based access control, allowing you to protect specific pages or entire folders with passwords.
@ -63,6 +66,7 @@ Use frontmatter to encrypt individual pages or override folder passwords:
title: "My Secret Page" title: "My Secret Page"
encrypt: true encrypt: true
password: "page-specific-password" password: "page-specific-password"
encrypt_message: "Sorry, this one is only for my eyes,"
--- ---
This content will be encrypted and require a password to view. This content will be encrypted and require a password to view.
``` ```
@ -73,6 +77,7 @@ The plugin recognizes these frontmatter fields:
- `encrypt`: Set to `true` to enable encryption for this page - `encrypt`: Set to `true` to enable encryption for this page
- `password`: The password required to decrypt this page - `password`: The password required to decrypt this page
- `encrypt_message`: Message to be shown on the unlock page.
If a page is in an encrypted folder but has its own `password` field, the page-specific password will be used instead of the folder password. If a page is in an encrypted folder but has its own `password` field, the page-specific password will be used instead of the folder password.

View File

@ -66,6 +66,11 @@ Quartz supports the following frontmatter:
- `date` - `date`
- encrypt - encrypt
- `encrypt` - `encrypt`
- `encrypted`
- encryptMessage
- `encrypt_message`
- `encryptMessage`
- `encrypt-message`
- password - password
- `password` - `password`

View File

@ -32,7 +32,6 @@
} }
.encryption-notice p { .encryption-notice p {
margin: 0 0 1.5rem 0;
color: var(--gray); color: var(--gray);
line-height: 1.4; line-height: 1.4;
font-size: 0.95rem; font-size: 0.95rem;
@ -151,3 +150,13 @@
font-size: 16px; /* Prevent zoom on iOS */ font-size: 16px; /* Prevent zoom on iOS */
} }
} }
.encrypted-message-footnote {
color: var(--gray);
font-size: 0.85rem;
opacity: 0.8;
text-align: center;
width: 100%;
font-style: italic;
margin: 0;
}

View File

@ -59,7 +59,7 @@ function generateRSSFeed(cfg: GlobalConfiguration, idx: ContentIndexMap, limit?:
<title>${escapeHTML(content.title)}</title> <title>${escapeHTML(content.title)}</title>
<link>https://${joinSegments(base, encodeURI(slug))}</link> <link>https://${joinSegments(base, encodeURI(slug))}</link>
<guid>https://${joinSegments(base, encodeURI(slug))}</guid> <guid>https://${joinSegments(base, encodeURI(slug))}</guid>
<description><![CDATA[ ${content.encrypted ? content.description : (content.richContent ?? content.description)} ]]></description> <description><![CDATA[ ${content.richContent ?? content.description} ]]></description>
<pubDate>${content.date?.toUTCString()}</pubDate> <pubDate>${content.date?.toUTCString()}</pubDate>
</item>` </item>`
@ -111,9 +111,10 @@ export const ContentIndex: QuartzEmitterPlugin<Partial<Options>> = (opts) => {
links: file.data.links ?? [], links: file.data.links ?? [],
tags: file.data.frontmatter?.tags ?? [], tags: file.data.frontmatter?.tags ?? [],
content: file.data.text ?? "", content: file.data.text ?? "",
richContent: opts?.rssFullHtml richContent:
? escapeHTML(toHtml(tree as Root, { allowDangerousHtml: true })) !file.data.encrypted && opts?.rssFullHtml
: undefined, ? escapeHTML(toHtml(tree as Root, { allowDangerousHtml: true }))
: undefined,
date: date, date: date,
description: file.data.description ?? "", description: file.data.description ?? "",
encrypted: file.data.encrypted, encrypted: file.data.encrypted,

View File

@ -30,9 +30,9 @@ export const Description: QuartzTransformerPlugin<Partial<Options>> = (userOpts)
() => { () => {
return async (tree: HTMLRoot, file) => { return async (tree: HTMLRoot, file) => {
if (file.data?.encrypted) { if (file.data?.encrypted) {
file.data.description = i18n( file.data.description =
ctx.cfg.configuration.locale, file.data.encryptMessage ||
).components.encryption.encryptedDescription i18n(ctx.cfg.configuration.locale).components.encryption.encryptedDescription
return return
} }

View File

@ -146,6 +146,10 @@ export const EncryptPlugin: QuartzTransformerPlugin<Partial<Options>> = (userOpt
} }
file.data.encrypted = true file.data.encrypted = true
file.data.password = password
if (file.data?.frontmatter?.encryptMessage) {
file.data.encryptMessage = file.data.frontmatter.encryptMessage as string
}
if (file.data?.frontmatter?.title) { if (file.data?.frontmatter?.title) {
file.data.frontmatter.title = `🔒 ${file.data.frontmatter.title}` file.data.frontmatter.title = `🔒 ${file.data.frontmatter.title}`
@ -171,6 +175,7 @@ export const EncryptPlugin: QuartzTransformerPlugin<Partial<Options>> = (userOpt
// Encrypt the content // Encrypt the content
const encryptedContent = encryptContent(htmlContent, password, opts) const encryptedContent = encryptContent(htmlContent, password, opts)
console.log(file.data)
// Create a new tree with encrypted content placeholder // Create a new tree with encrypted content placeholder
const encryptedTree = fromHtml( const encryptedTree = fromHtml(
@ -182,6 +187,7 @@ export const EncryptPlugin: QuartzTransformerPlugin<Partial<Options>> = (userOpt
<div class="decrypt-form"> <div class="decrypt-form">
<input type="password" class="decrypt-password" placeholder="${t.enterPassword}" /> <input type="password" class="decrypt-password" placeholder="${t.enterPassword}" />
<button class="decrypt-button">${t.decrypt}</button> <button class="decrypt-button">${t.decrypt}</button>
${file.data.encryptMessage ? `<p class="encrypted-message-footnote">${file.data.encryptMessage}</p>` : ""}
</div> </div>
<div class="decrypt-loading"> <div class="decrypt-loading">
<div class="loading-spinner"></div> <div class="loading-spinner"></div>
@ -228,5 +234,7 @@ export const EncryptPlugin: QuartzTransformerPlugin<Partial<Options>> = (userOpt
declare module "vfile" { declare module "vfile" {
interface DataMap { interface DataMap {
encrypted: boolean encrypted: boolean
encryptMessage?: string
password?: string
} }
} }

View File

@ -118,6 +118,19 @@ export const FrontMatter: QuartzTransformerPlugin<Partial<Options>> = (userOpts)
if (socialImage) data.socialImage = socialImage if (socialImage) data.socialImage = socialImage
const encrypted = coalesceAliases(data, ["encrypted", "encrypt"])
if (encrypted) data.encrypt = true
const password = coalesceAliases(data, ["password"])
if (password) data.password = password
const encryptMessage = coalesceAliases(data, [
"encryptMessage",
"encrypt_message",
"encrypt-message",
])
if (encryptMessage) data.encryptMessage = encryptMessage
// Remove duplicate slugs // Remove duplicate slugs
const uniqueSlugs = [...new Set(allSlugs)] const uniqueSlugs = [...new Set(allSlugs)]
allSlugs.splice(0, allSlugs.length, ...uniqueSlugs) allSlugs.splice(0, allSlugs.length, ...uniqueSlugs)