Fix security bugs and migrate image uploads to /api/v1/attachments
* 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
This commit is contained in:
@@ -8,64 +8,58 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<header class="p-6 border-b border-gray-100 bg-white">
|
||||
<header class="p-6 border-b border-gray-100 dark:border-gray-800 bg-white dark:bg-[#1a1a1f]">
|
||||
<div class="logo flex items-center space-x-3 text-2xl font-bold text-emerald-500">
|
||||
<svg viewBox="0 0 32 32" fill="none" width="32" height="32" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="32" height="32" rx="8" fill="currentColor"/>
|
||||
<path d="M11 9C11 8.44772 11.4477 8 12 8H20C20.5523 8 21 8.44772 21 9V23C21 23.5523 20.5523 24 20 24H12C11.4477 24 11 23.5523 11 23V9Z" fill="white"/>
|
||||
<path d="M14 12H18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M14 15H18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M14 18H16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<span>Memos Clipper Settings</span>
|
||||
<img src="icons/icon48.png" width="32" height="32" alt="Memos Logo">
|
||||
<span class="dark:text-gray-200">Memos Clipper Settings</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="max-w-3xl mx-auto p-6 space-y-8">
|
||||
<div class="card bg-white rounded-xl shadow-sm border border-gray-100 p-6 space-y-6">
|
||||
<h2 class="text-xl font-semibold text-gray-800 border-b pb-2">Connection</h2>
|
||||
<div class="card bg-white dark:bg-[#1a1a1f] rounded-xl shadow-sm border border-gray-100 dark:border-gray-800 p-6 space-y-6">
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200 border-b dark:border-gray-800 pb-2">Connection</h2>
|
||||
<label class="block space-y-2">
|
||||
<span class="text-sm font-medium text-gray-700">Memos Instance URL</span>
|
||||
<input type="url" id="memos-url" placeholder="https://memos.example.com" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-emerald-100 focus:border-emerald-400 outline-none transition" />
|
||||
<small class="block text-xs text-gray-400">The base URL of your usememos instance (no trailing slash)</small>
|
||||
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Memos Instance URL</span>
|
||||
<input type="url" id="memos-url" placeholder="https://memos.example.com" class="w-full px-4 py-2 border border-gray-200 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-emerald-100 dark:focus:ring-emerald-900/30 dark:bg-transparent dark:text-inherit outline-none transition" />
|
||||
<small class="block text-xs text-gray-400 dark:text-gray-500">The base URL of your usememos instance (no trailing slash)</small>
|
||||
</label>
|
||||
<label class="block space-y-2">
|
||||
<span class="text-sm font-medium text-gray-700">API Token</span>
|
||||
<input type="password" id="api-token" placeholder="Your access token" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-emerald-100 focus:border-emerald-400 outline-none transition" />
|
||||
<small class="block text-xs text-gray-400">Settings → Account → Access Tokens in your Memos instance</small>
|
||||
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">API Token</span>
|
||||
<input type="password" id="api-token" placeholder="Your access token" class="w-full px-4 py-2 border border-gray-200 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-emerald-100 dark:focus:ring-emerald-900/30 dark:bg-transparent dark:text-inherit outline-none transition" />
|
||||
<small class="block text-xs text-gray-400 dark:text-gray-500">Settings → Account → Access Tokens in your Memos instance</small>
|
||||
</label>
|
||||
<div class="actions flex space-x-3 pt-2">
|
||||
<button id="test-btn" class="secondary flex-1 bg-gray-50 hover:bg-gray-100 text-gray-700 font-medium py-2 px-4 rounded-lg border border-gray-200 transition">Test Connection</button>
|
||||
<button id="test-btn" class="secondary flex-1 bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300 font-medium py-2 px-4 rounded-lg border border-gray-200 dark:border-gray-700 transition">Test Connection</button>
|
||||
<button id="save-btn" class="flex-1 bg-emerald-500 hover:bg-emerald-600 text-white font-medium py-2 px-4 rounded-lg shadow-sm transition">Save Settings</button>
|
||||
</div>
|
||||
<div id="status" class="status hidden p-3 rounded-lg text-sm"></div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-white rounded-xl shadow-sm border border-gray-100 p-6 space-y-6">
|
||||
<h2 class="text-xl font-semibold text-gray-800 border-b pb-2">Defaults</h2>
|
||||
<div class="card bg-white dark:bg-[#1a1a1f] rounded-xl shadow-sm border border-gray-100 dark:border-gray-800 p-6 space-y-6">
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200 border-b dark:border-gray-800 pb-2">Defaults</h2>
|
||||
<label class="block space-y-2">
|
||||
<span class="text-sm font-medium text-gray-700">Default visibility</span>
|
||||
<select id="visibility" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-emerald-100 focus:border-emerald-400 outline-none bg-white transition">
|
||||
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Default visibility</span>
|
||||
<select id="visibility" class="w-full px-4 py-2 border border-gray-200 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-emerald-100 dark:focus:ring-emerald-900/30 bg-white dark:bg-transparent dark:text-inherit outline-none transition">
|
||||
<option value="PRIVATE">Private</option>
|
||||
<option value="PROTECTED">Protected</option>
|
||||
<option value="PUBLIC">Public</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="block space-y-2">
|
||||
<span class="text-sm font-medium text-gray-700">Default clip mode</span>
|
||||
<select id="clip-mode" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-emerald-100 focus:border-emerald-400 outline-none bg-white transition">
|
||||
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Default clip mode</span>
|
||||
<select id="clip-mode" class="w-full px-4 py-2 border border-gray-200 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-emerald-100 dark:focus:ring-emerald-900/30 bg-white dark:bg-transparent dark:text-inherit outline-none transition">
|
||||
<option value="page">Full page (article extraction)</option>
|
||||
<option value="selection">Selection only</option>
|
||||
</select>
|
||||
</label>
|
||||
<div class="space-y-3 pt-2">
|
||||
<label class="flex items-center space-x-3 cursor-pointer group">
|
||||
<input type="checkbox" id="include-images" checked class="w-4 h-4 text-emerald-500 border-gray-300 rounded focus:ring-emerald-400 transition" />
|
||||
<span class="text-sm text-gray-700 group-hover:text-gray-900 transition">Upload page images as attachments</span>
|
||||
<input type="checkbox" id="include-images" checked class="w-4 h-4 text-emerald-500 border-gray-300 dark:border-gray-700 rounded focus:ring-emerald-400 transition" />
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300 group-hover:text-gray-900 dark:group-hover:text-gray-100 transition">Upload page images as attachments</span>
|
||||
</label>
|
||||
<label class="flex items-center space-x-3 cursor-pointer group">
|
||||
<input type="checkbox" id="include-tags" class="w-4 h-4 text-emerald-500 border-gray-300 rounded focus:ring-emerald-400 transition" />
|
||||
<span class="text-sm text-gray-700 group-hover:text-gray-900 transition">Automatically add #clipped tag</span>
|
||||
<input type="checkbox" id="include-tags" class="w-4 h-4 text-emerald-500 border-gray-300 dark:border-gray-700 rounded focus:ring-emerald-400 transition" />
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300 group-hover:text-gray-900 dark:group-hover:text-gray-100 transition">Automatically add #clipped tag</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="actions pt-4">
|
||||
|
||||
Reference in New Issue
Block a user