mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-12-19 10:54:06 -06:00
Address comments from Copilot
This commit is contained in:
parent
127e5c3c03
commit
b4494595d6
@ -47,10 +47,10 @@ Plugin.Encrypt({
|
||||
- `algorithm`: Encryption algorithm to use
|
||||
- `"aes-256-cbc"` (default): AES-256 in CBC mode
|
||||
- `"aes-256-gcm"`: AES-256 in GCM mode (authenticated encryption)
|
||||
- `"aes-256-ecb"`: AES-256 in ECB mode (not recommended)
|
||||
- `ttl`: Time-to-live for cached passwords in seconds (default: 7 days)
|
||||
- `message`: Default message shown on encrypted pages
|
||||
- `encryptedFolders`: Configure folder-level encryption
|
||||
- Key length is automatically inferred from the algorithm (e.g., 256-bit = 32 bytes)
|
||||
- `encryptedFolders`: Object mapping folder paths to passwords or configuration objects for folder-level encryption
|
||||
- `ttl`: Time-to-live for cached passwords in seconds (default: 604800 = 7 days, set to 0 for session-only)
|
||||
- `message`: Message to be displayed in the decryption page
|
||||
|
||||
## How Configuration Works
|
||||
|
||||
|
||||
@ -98,6 +98,7 @@ const decryptWithPassword = async (
|
||||
if (showError) throw new Error("decryption-failed")
|
||||
return false
|
||||
} catch (decryptError) {
|
||||
console.error("Decryption failed:", decryptError)
|
||||
if (showError) showLoading(container, false)
|
||||
if (showError) throw new Error("decryption-failed")
|
||||
return false
|
||||
@ -136,7 +137,6 @@ const decryptWithPassword = async (
|
||||
}
|
||||
|
||||
function updateTitle(container: HTMLElement | null) {
|
||||
console.log(container)
|
||||
if (container) {
|
||||
const span = container.querySelector(".article-title-icon") as HTMLElement
|
||||
if (span) {
|
||||
|
||||
@ -44,6 +44,7 @@ const fetchContentCache: Map<FullSlug, Element[]> = new Map()
|
||||
const contextWindowWords = 30
|
||||
const numSearchResults = 8
|
||||
const numTagResults = 5
|
||||
const RENDER_DELAY_MS = 100
|
||||
|
||||
const tokenizeTerm = (term: string) => {
|
||||
const tokens = term.split(/\s+/).filter((t) => t.trim() !== "")
|
||||
@ -395,7 +396,7 @@ async function setupSearch(searchElement: Element, currentSlug: FullSlug, data:
|
||||
(a, b) => b.innerHTML.length - a.innerHTML.length,
|
||||
)
|
||||
highlights[0]?.scrollIntoView({ block: "start" })
|
||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||
await new Promise((resolve) => setTimeout(resolve, RENDER_DELAY_MS))
|
||||
|
||||
dispatchRenderEvent(previewInner)
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ export const Description: QuartzTransformerPlugin<Partial<Options>> = (userOpts)
|
||||
return [
|
||||
() => {
|
||||
return async (tree: HTMLRoot, file) => {
|
||||
if (file.data?.encrypted && file.data.encryptionConfig) {
|
||||
if (file.data.encryptionConfig) {
|
||||
file.data.description =
|
||||
file.data.encryptionConfig.message ||
|
||||
i18n(ctx.cfg.configuration.locale).components.encryption.encryptedDescription
|
||||
|
||||
@ -143,16 +143,22 @@ function getConfigurationForPath(
|
||||
/**
|
||||
* Validates the plugin configuration
|
||||
*/
|
||||
function validateConfig(config: PluginConfig): void {
|
||||
function validateConfig(config: EncryptionConfig, file: VFile | null = null): void {
|
||||
let suffixedPath = ""
|
||||
|
||||
if (file && file.data && file.data.relativePath) {
|
||||
suffixedPath = `(in file: ${file.data.relativePath})`
|
||||
}
|
||||
|
||||
if (!SUPPORTED_ALGORITHMS.includes(config.algorithm)) {
|
||||
throw new Error(
|
||||
`[EncryptPlugin] Unsupported encryption algorithm: ${config.algorithm}. ` +
|
||||
`Supported algorithms: ${SUPPORTED_ALGORITHMS.join(", ")}`,
|
||||
`Supported algorithms: ${SUPPORTED_ALGORITHMS.join(", ")} ${suffixedPath}`,
|
||||
)
|
||||
}
|
||||
|
||||
if (config.ttl <= 0) {
|
||||
throw new Error(`[EncryptPlugin] TTL must be a positive number`)
|
||||
if (config.ttl < 0) {
|
||||
throw new Error(`[EncryptPlugin] TTL cannot be negative. ${suffixedPath}`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,9 +174,6 @@ export const Encrypt: QuartzTransformerPlugin<PluginOptions> = (userOpts) => {
|
||||
encryptedFolders: userOpts?.encryptedFolders ?? {},
|
||||
}
|
||||
|
||||
// Validate configuration
|
||||
validateConfig(pluginConfig)
|
||||
|
||||
// Pre-process folder configurations for efficient lookup
|
||||
const folderConfigs = createFolderConfigHierarchy(pluginConfig.encryptedFolders, pluginConfig)
|
||||
|
||||
@ -241,6 +244,8 @@ export const Encrypt: QuartzTransformerPlugin<PluginOptions> = (userOpts) => {
|
||||
if (!config) {
|
||||
return
|
||||
}
|
||||
// Validate configuration
|
||||
validateConfig(config, file)
|
||||
|
||||
file.data.encryptionConfig = config
|
||||
file.data.hash = await hashString(config.password)
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
// =============================================================================
|
||||
// TYPES AND INTERFACES
|
||||
// =============================================================================
|
||||
export const SUPPORTED_ALGORITHMS = ["aes-256-cbc", "aes-256-gcm", "aes-256-ecb"] as const
|
||||
export const SUPPORTED_ALGORITHMS = ["aes-256-cbc", "aes-256-gcm"] as const
|
||||
|
||||
export type SupportedEncryptionAlgorithm = (typeof SUPPORTED_ALGORITHMS)[number]
|
||||
|
||||
@ -88,7 +85,7 @@ export function base64Encode(data: string): string {
|
||||
return Buffer.from(data).toString("base64")
|
||||
} else {
|
||||
// Browser environment
|
||||
return btoa(unescape(encodeURIComponent(data)))
|
||||
return btoa(encodeURIComponent(data))
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,16 +95,17 @@ export function base64Decode(data: string): string {
|
||||
return Buffer.from(data, "base64").toString()
|
||||
} else {
|
||||
// Browser environment
|
||||
return decodeURIComponent(escape(atob(data)))
|
||||
return decodeURIComponent(atob(data))
|
||||
}
|
||||
}
|
||||
|
||||
// Utility functions for array buffer conversions
|
||||
export function hexToArrayBuffer(hex: string): ArrayBuffer {
|
||||
if (!hex) return new ArrayBuffer(0)
|
||||
|
||||
const bytes = new Uint8Array(hex.length / 2)
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = parseInt(hex.substr(i * 2, 2), 16)
|
||||
bytes[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16)
|
||||
}
|
||||
return bytes.buffer
|
||||
}
|
||||
@ -209,8 +207,7 @@ export async function encryptContent(
|
||||
}
|
||||
|
||||
// Generate random salt for encryption
|
||||
const initializationVector =
|
||||
algorithm === "aes-256-ecb" ? new Uint8Array(16) : crypto.getRandomValues(new Uint8Array(16)) // Zero IV for ECB simulation
|
||||
const initializationVector = crypto.getRandomValues(new Uint8Array(16))
|
||||
|
||||
// Create encryption hash and derive key
|
||||
const encryptionHashData = await hashString(password)
|
||||
@ -251,16 +248,6 @@ export async function encryptContent(
|
||||
key,
|
||||
contentBuffer,
|
||||
)
|
||||
} else if (algorithm === "aes-256-ecb") {
|
||||
// ECB simulation using CBC with zero IV
|
||||
encryptedBuffer = await crypto.subtle.encrypt(
|
||||
{
|
||||
name: "AES-CBC",
|
||||
iv: initializationVector, // Zero IV for ECB simulation
|
||||
},
|
||||
key,
|
||||
contentBuffer,
|
||||
)
|
||||
} else {
|
||||
throw new Error("Unsupported algorithm: " + algorithm)
|
||||
}
|
||||
@ -274,10 +261,7 @@ export async function encryptContent(
|
||||
const result: EncryptionResult = {
|
||||
encryptedContent: arrayBufferToHex(encryptedBuffer),
|
||||
encryptionSalt: encryptionHashData.salt,
|
||||
}
|
||||
|
||||
if (algorithm !== "aes-256-ecb") {
|
||||
result.iv = arrayBufferToHex(initializationVector.buffer)
|
||||
iv: arrayBufferToHex(initializationVector.buffer as ArrayBuffer),
|
||||
}
|
||||
|
||||
if (authTag) {
|
||||
@ -339,18 +323,6 @@ export async function decryptContent(
|
||||
key,
|
||||
ciphertext,
|
||||
)
|
||||
} else if (config.algorithm === "aes-256-ecb") {
|
||||
// ECB simulation using CBC with zero IV
|
||||
const zeroInitializationVector = new ArrayBuffer(16)
|
||||
|
||||
decryptedBuffer = await crypto.subtle.decrypt(
|
||||
{
|
||||
name: "AES-CBC",
|
||||
iv: zeroInitializationVector,
|
||||
},
|
||||
key,
|
||||
ciphertext,
|
||||
)
|
||||
} else {
|
||||
throw new Error("Unsupported algorithm: " + config.algorithm)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user