refactor(sync): reuse storage constants instead of redefining

WORKSPACE_METADATA_FILE, LIST_METADATA_FILE and the 64KB frontmatter
cap each existed in two places (storage.rs and sync.rs) with identical
values. parse_frontmatter_for_conflict even repeated the cap as a magic
number with the byte count baked into the error string. Promote the
storage definitions to pub(crate) and import them so any future tweak
(e.g. raising the frontmatter cap) only needs one edit.
This commit is contained in:
Claude 2026-04-25 13:32:08 +00:00
parent ebe09d0afe
commit 69ed27ba44
No known key found for this signature in database
2 changed files with 11 additions and 12 deletions

View file

@ -14,11 +14,11 @@ const MAX_DESCRIPTION_LENGTH: usize = 1_000_000; // 1 MB
/// Maximum allowed length for list names.
const MAX_LIST_NAME_LENGTH: usize = 255;
/// Maximum allowed size for YAML frontmatter (64 KB) to prevent DoS via crafted files.
const MAX_FRONTMATTER_LENGTH: usize = 64 * 1024;
pub(crate) const MAX_FRONTMATTER_LENGTH: usize = 64 * 1024;
/// Workspace root metadata filename.
const WORKSPACE_METADATA_FILE: &str = ".onyx-workspace.json";
pub(crate) const WORKSPACE_METADATA_FILE: &str = ".onyx-workspace.json";
/// Per-list metadata filename.
const LIST_METADATA_FILE: &str = ".listdata.json";
pub(crate) const LIST_METADATA_FILE: &str = ".listdata.json";
/// Task file extension.
const TASK_FILE_EXT: &str = "md";
/// Default version for tasks without a version field (legacy files).

View file

@ -5,7 +5,10 @@ use serde::{Deserialize, Serialize};
use sha2::{Sha256, Digest};
use uuid::Uuid;
use crate::error::{Error, Result};
use crate::storage::{atomic_write, ListMetadata, TaskFrontmatter};
use crate::storage::{
atomic_write, ListMetadata, TaskFrontmatter, LIST_METADATA_FILE, MAX_FRONTMATTER_LENGTH,
WORKSPACE_METADATA_FILE,
};
use crate::webdav::WebDavClient;
/// File-based lock to prevent concurrent sync operations on the same workspace.
@ -404,11 +407,6 @@ pub fn compute_checksum(data: &[u8]) -> String {
format!("{:x}", hasher.finalize())
}
/// Workspace root metadata filename.
const WORKSPACE_METADATA_FILE: &str = ".onyx-workspace.json";
/// Per-list metadata filename.
const LIST_METADATA_FILE: &str = ".listdata.json";
/// Check if a file is syncable: *.md files and metadata files at expected depths.
fn is_syncable(path: &str) -> bool {
let parts: Vec<&str> = path.split('/').collect();
@ -862,10 +860,11 @@ fn parse_frontmatter_for_conflict(content: &str) -> Result<(TaskFrontmatter, Str
.ok_or_else(|| Error::InvalidData("Missing closing frontmatter delimiter".to_string()))?;
let frontmatter_str = lines[1..=end_idx].join("\n");
// Reject oversized frontmatter to prevent DoS via crafted YAML
if frontmatter_str.len() > 64 * 1024 {
if frontmatter_str.len() > MAX_FRONTMATTER_LENGTH {
return Err(Error::InvalidData(format!(
"Frontmatter too large ({} bytes, max 65536)",
frontmatter_str.len()
"Frontmatter too large ({} bytes, max {})",
frontmatter_str.len(),
MAX_FRONTMATTER_LENGTH
)));
}
let frontmatter: TaskFrontmatter = serde_yaml::from_str(&frontmatter_str)