* Replace /api/v1/resources with /api/v1/attachments for image uploads
* Upload attachments as JSON with base64-encoded content field
* After memo creation, link each attachment via PATCH /api/v1/attachments/{id}
* Rewrite markdown image URLs to use /file/attachments/{id} pattern
* Fix XSS: sanitize marked.parse output with a DOM-based allowlist sanitizer
* Fix SSRF: validate img.src scheme (http/https only) before fetching
* Fix stack overflow: use chunked base64 encoding for large images
* Update CLAUDE.md to document new attachment flow
3.0 KiB
3.0 KiB
CLAUDE.md
Project Overview
Memos Clipper is a Chrome Extension (Manifest V3) that clips web pages or text selections and saves them to a Memos instance in Markdown format.
Architecture
Three-part Chrome extension:
src/content.js— Content script injected into pages; extracts HTML and converts it to Markdownsrc/popup.html/src/popup.js— Main popup UI: editor, preview, image gallery, send buttonsrc/settings.html/src/settings.js— Options page: Memos URL, API token, defaultssrc/background.js— Service worker (minimal; onInstalled listener only)
Tech Stack
- Runtime: Chrome MV3 (Manifest V3)
- Language: Vanilla JavaScript (ES6+), no frontend framework
- Styling: Tailwind CSS v4 + PostCSS + Autoprefixer; CSS variables for theming; dark mode via
prefers-color-scheme - Markdown: Custom HTML→Markdown converter in
content.js;marked.min.jsfor preview rendering - Build: Vite v8 with
vite-plugin-static-copy
Build & Development
npm install # Install dependencies
npm run dev # Dev server with hot reload
npm run build # Production build → dist/
npm run preview # Preview built output
Load the extension in Chrome: Extensions → Load unpacked → select dist/
Key Implementation Details
API Integration
- Memos API v1:
/api/v1/memos,/api/v1/attachments - Requires Memos v0.22+
- Bearer token auth via
chrome.storage.sync - Attachment flow: upload via
POST /api/v1/attachments(JSON + base64content), create memo, then link each attachment to the memo viaPATCH /api/v1/attachments/{id}with{ memo: "memos/{id}" }
Content Extraction
- Removes boilerplate: nav, ads, sidebars, cookie banners (45+ selectors)
- Supports full-page and selection-only modes
- Converts: headings, lists, tables, code blocks, links, images, blockquotes
Image Handling
- Filters images smaller than 32px (icons/tracking pixels)
- Deduplicates images
- Supports data URIs
- Uploads images as attachments (
POST /api/v1/attachments) with base64-encoded content - After memo creation, links each attachment to the memo via
PATCH /api/v1/attachments/{id} - Attachment file URL pattern:
{memosUrl}/file/attachments/{id}
Storage
chrome.storage.syncfor cross-device settings (URL, token, defaults)
Project Structure
src/
├── manifest.json # MV3 config (permissions, entry points)
├── popup.html/.js/.css # Main extension popup
├── settings.html/.js/.css # Options page
├── content.js # Page content extractor
├── background.js # Service worker
├── marked.min.js # Bundled Markdown renderer
└── icons/ # 16, 32, 48, 128px PNG icons
dist/ # Build output (gitignored)
vite.config.js
package.json
Permissions
activeTab,scripting,storage- Host permissions:
<all_urls>(needed for cross-origin image fetching and API calls)