Files
memos-chrome-extension/src/settings.html
Paul Spenke 84b3dd69f1 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
2026-03-18 17:55:04 +01:00

75 lines
5.3 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Memos Clipper — Settings</title>
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="settings.css" />
</head>
<body>
<div class="page">
<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">
<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 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 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 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 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 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 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 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 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 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">
<button id="save-defaults-btn" class="w-full bg-emerald-500 hover:bg-emerald-600 text-white font-medium py-2 px-4 rounded-lg shadow-sm transition">Save Defaults</button>
</div>
<div id="defaults-status" class="status hidden p-3 rounded-lg text-sm"></div>
</div>
</main>
</div>
<script src="/settings.js" type="module"></script>
</body>
</html>