fix: add CORS headers for Chrome extension + fix Save & Connect button

- Add CORS middleware to server.js allowing chrome-extension:// origins
  so the popup can make authenticated API requests without browser blocking
- Fix popup.js saveSettings(): require password on save, call login() directly
  instead of tryConnect() to avoid password-not-found loop
- Fix init(): open settings panel automatically if no saved token, so users
  know they need to enter credentials after first install or session expiry
- Don't persist password to chrome.storage (security), use remove('token')
  instead of set({token:null}) to properly clear the old session

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Zac Gaetano 2026-04-06 21:30:17 -04:00
parent 08c138ca46
commit 978d447b3d
2 changed files with 34 additions and 7 deletions

View file

@ -12,7 +12,7 @@ let connected = false;
(async function init() {
const stored = await chrome.storage.local.get(['config', 'token', 'mode']);
if (stored.config) config = { ...config, ...stored.config };
if (stored.token) authToken = stored.token;
if (stored.token && stored.token !== null) authToken = stored.token;
if (stored.mode) uploadMode = stored.mode;
document.getElementById('cfg-server').value = config.serverUrl;
@ -20,7 +20,15 @@ let connected = false;
document.getElementById('conn-server').textContent = config.serverUrl.replace(/https?:\/\//, '');
setMode(uploadMode, false);
await tryConnect();
// If we have a saved token, try using it; otherwise open settings
if (authToken) {
await tryConnect();
} else {
// No saved session — open settings panel so user can enter password
document.getElementById('settings-panel').classList.add('open');
setConnStatus('grey', 'Enter credentials in settings below');
}
})();
document.getElementById('settings-toggle').addEventListener('click', () => {
@ -84,16 +92,22 @@ async function saveSettings() {
const username = document.getElementById('cfg-user').value.trim();
const password = document.getElementById('cfg-pass').value;
if (!serverUrl) { showSettingsStatus('Server URL required', 'error'); return; }
if (!username) { showSettingsStatus('Username required', 'error'); return; }
if (!password) { showSettingsStatus('Password required', 'error'); return; }
config = { serverUrl, username, password: password || config.password };
config = { serverUrl, username, password };
authToken = null;
await chrome.storage.local.set({ config, token: null });
connected = false;
// Clear old token and save new config (don't save password to storage for security)
await chrome.storage.local.remove('token');
await chrome.storage.local.set({ config: { serverUrl, username } });
document.getElementById('conn-server').textContent = serverUrl.replace(/https?:\/\//, '');
showSettingsStatus('Saved — connecting…', 'loading');
connected = false;
await tryConnect();
showSettingsStatus('Settings saved', 'success');
await login();
if (connected) {
showSettingsStatus('✅ Connected successfully!', 'success');
}
}
function showSettingsStatus(msg, type) {

View file

@ -231,6 +231,19 @@ const upload = multer({
limits: { fileSize: 50 * 1024 * 1024 * 1024 },
});
// CORS — allow Chrome extensions and browser clients
app.use((req, res, next) => {
const origin = req.headers.origin || "";
// Allow Chrome extensions, localhost, and the configured host
const allowed = origin.startsWith("chrome-extension://") || origin.startsWith("http://localhost") || origin.startsWith("https://localhost");
res.setHeader("Access-Control-Allow-Origin", allowed ? origin : "*");
res.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Content-Type,x-auth-token,Authorization");
res.setHeader("Access-Control-Allow-Credentials", "true");
if (req.method === "OPTIONS") return res.sendStatus(204);
next();
});
app.use((req, res, next) => {
if (req.path === "/" || req.path.endsWith(".html") || req.path.endsWith(".png") || req.path.endsWith(".svg")) {
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate");