mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-11 16:52:38 +02:00
feat(obsidian_plugin): validate binary attachments and enforce MIME type checks
This commit is contained in:
parent
3b9be79d65
commit
e84dc87c5b
9 changed files with 275 additions and 40 deletions
|
|
@ -16,10 +16,10 @@ export class AttachmentsConfirmModal extends Modal {
|
|||
this.contentEl.empty();
|
||||
|
||||
new Setting(this.contentEl).setDesc(
|
||||
"Syncing attachments (images, PDFs, and other non-Markdown files) can make indexing slower, especially on large vaults.",
|
||||
"Syncing attachments (images & PDFs) can make indexing slower, especially on large vaults."
|
||||
);
|
||||
new Setting(this.contentEl).setDesc(
|
||||
"You can disable this anytime in settings if syncing becomes too slow.",
|
||||
"Syncing attachments can make indexing slower on large vaults. You can disable this anytime.",
|
||||
);
|
||||
|
||||
new Setting(this.contentEl)
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ export class SurfSenseSettingTab extends PluginSettingTab {
|
|||
new Setting(containerEl)
|
||||
.setName("Sync interval")
|
||||
.setDesc(
|
||||
"How often to check for changes made outside Obsidian. Set to off to only sync manually.",
|
||||
"How often to check for changes made outside Obsidian.",
|
||||
)
|
||||
.addDropdown((drop) => {
|
||||
const options: Array<[number, string]> = [
|
||||
|
|
@ -205,7 +205,7 @@ export class SurfSenseSettingTab extends PluginSettingTab {
|
|||
new Setting(containerEl)
|
||||
.setName("Include attachments")
|
||||
.setDesc(
|
||||
"Also sync non-Markdown files such as images and PDFs.",
|
||||
"Also sync non-Markdown files such as images and PDFs. Other file types are skipped.",
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
|
|
@ -231,7 +231,7 @@ export class SurfSenseSettingTab extends PluginSettingTab {
|
|||
new Setting(containerEl)
|
||||
.setName("Sync only on WiFi")
|
||||
.setDesc(
|
||||
"Pause automatic syncing on cellular. Note: only Android can detect network type — on iOS this toggle has no effect.",
|
||||
"Pause automatic syncing on cellular. Note: only Android can detect network type, on iOS this toggle has no effect.",
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
|
|
|
|||
|
|
@ -393,7 +393,7 @@ export class SyncEngine {
|
|||
ctime: file.stat.ctime,
|
||||
is_binary: true,
|
||||
binary_base64: binaryBase64,
|
||||
mime_type: mimeTypeFromExtension(file.extension),
|
||||
mime_type: mimeTypeFor(file.extension),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -560,9 +560,10 @@ export class SyncEngine {
|
|||
|
||||
private shouldTrack(file: TAbstractFile): boolean {
|
||||
if (!isTFile(file)) return false;
|
||||
if (this.isMarkdown(file)) return true;
|
||||
const settings = this.deps.getSettings();
|
||||
if (!settings.includeAttachments && !this.isMarkdown(file)) return false;
|
||||
return true;
|
||||
if (!settings.includeAttachments) return false;
|
||||
return ALLOWED_ATTACHMENT_EXTENSIONS.has(file.extension.toLowerCase());
|
||||
}
|
||||
|
||||
private isExcluded(path: string, settings: SyncEngineSettings): boolean {
|
||||
|
|
@ -599,23 +600,29 @@ function arrayBufferToBase64(buf: ArrayBuffer): string {
|
|||
return btoa(binary);
|
||||
}
|
||||
|
||||
function mimeTypeFromExtension(extension: string): string | undefined {
|
||||
const ext = extension.toLowerCase();
|
||||
const mimeByExt: Record<string, string> = {
|
||||
pdf: "application/pdf",
|
||||
png: "image/png",
|
||||
jpg: "image/jpeg",
|
||||
jpeg: "image/jpeg",
|
||||
gif: "image/gif",
|
||||
webp: "image/webp",
|
||||
svg: "image/svg+xml",
|
||||
txt: "text/plain",
|
||||
csv: "text/csv",
|
||||
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
};
|
||||
return mimeByExt[ext];
|
||||
/** Source of truth for the attachment whitelist. Mirrors ATTACHMENT_MIME_TYPES on the backend. */
|
||||
export const MIME_BY_EXTENSION = {
|
||||
pdf: "application/pdf",
|
||||
png: "image/png",
|
||||
jpg: "image/jpeg",
|
||||
jpeg: "image/jpeg",
|
||||
gif: "image/gif",
|
||||
webp: "image/webp",
|
||||
svg: "image/svg+xml",
|
||||
txt: "text/plain",
|
||||
} as const satisfies Record<string, string>;
|
||||
|
||||
export const ALLOWED_ATTACHMENT_EXTENSIONS: ReadonlySet<string> = new Set(
|
||||
Object.keys(MIME_BY_EXTENSION),
|
||||
);
|
||||
|
||||
function mimeTypeFor(extension: string): string {
|
||||
const ext = extension.toLowerCase() as keyof typeof MIME_BY_EXTENSION;
|
||||
const mime = MIME_BY_EXTENSION[ext];
|
||||
if (!mime) {
|
||||
throw new Error(`Unsupported attachment extension: .${extension}`);
|
||||
}
|
||||
return mime;
|
||||
}
|
||||
|
||||
function formatRelative(ts: number): string {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export interface RenameItem {
|
|||
|
||||
export type QueueItem = UpsertItem | DeleteItem | RenameItem;
|
||||
|
||||
export interface NotePayload {
|
||||
interface NotePayloadBase {
|
||||
vault_id: string;
|
||||
path: string;
|
||||
name: string;
|
||||
|
|
@ -85,15 +85,23 @@ export interface NotePayload {
|
|||
size: number;
|
||||
mtime: number;
|
||||
ctime: number;
|
||||
/** Non-markdown attachment marker; enables backend ETL path. */
|
||||
is_binary?: boolean;
|
||||
/** Base64-encoded file bytes for binary attachments. */
|
||||
binary_base64?: string;
|
||||
/** Optional MIME type hint for backend parsers. */
|
||||
mime_type?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface MarkdownNotePayload extends NotePayloadBase {
|
||||
is_binary?: false;
|
||||
}
|
||||
|
||||
export interface BinaryNotePayload extends NotePayloadBase {
|
||||
/** Non-markdown attachment marker; enables backend ETL path. */
|
||||
is_binary: true;
|
||||
/** Base64-encoded file bytes for binary attachments. */
|
||||
binary_base64: string;
|
||||
/** Canonical MIME type for the extension; required by the backend. */
|
||||
mime_type: string;
|
||||
}
|
||||
|
||||
export type NotePayload = MarkdownNotePayload | BinaryNotePayload;
|
||||
|
||||
export interface HeadingRef {
|
||||
heading: string;
|
||||
level: number;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue