rnotes-online/browser-extension/options.js

180 lines
5.4 KiB
JavaScript

const DEFAULT_HOST = 'https://rnotes.online';
// --- Helpers ---
function decodeToken(token) {
try {
const payload = JSON.parse(atob(token.split('.')[1]));
if (payload.exp && payload.exp * 1000 < Date.now()) {
return null;
}
return payload;
} catch {
return null;
}
}
function showStatus(message, type) {
const el = document.getElementById('status');
el.textContent = message;
el.className = `status ${type}`;
if (type === 'success') {
setTimeout(() => { el.className = 'status'; }, 3000);
}
}
// --- Auth UI ---
async function updateAuthUI() {
const { encryptid_token } = await chrome.storage.local.get(['encryptid_token']);
const claims = encryptid_token ? decodeToken(encryptid_token) : null;
const authStatus = document.getElementById('authStatus');
const loginSection = document.getElementById('loginSection');
const loggedInSection = document.getElementById('loggedInSection');
if (claims) {
const username = claims.username || claims.sub?.slice(0, 20) || 'Authenticated';
authStatus.textContent = `Signed in as ${username}`;
authStatus.className = 'auth-status authed';
loginSection.style.display = 'none';
loggedInSection.style.display = 'block';
} else {
authStatus.textContent = 'Not signed in';
authStatus.className = 'auth-status not-authed';
loginSection.style.display = 'block';
loggedInSection.style.display = 'none';
}
}
async function populateNotebooks() {
const { encryptid_token } = await chrome.storage.local.get(['encryptid_token']);
if (!encryptid_token) return;
const host = document.getElementById('host').value.replace(/\/+$/, '') || DEFAULT_HOST;
try {
const response = await fetch(`${host}/api/notebooks`, {
headers: { 'Authorization': `Bearer ${encryptid_token}` },
});
if (!response.ok) return;
const notebooks = await response.json();
const select = document.getElementById('defaultNotebook');
// Clear existing options (keep first)
while (select.options.length > 1) {
select.remove(1);
}
for (const nb of notebooks) {
const option = document.createElement('option');
option.value = nb.id;
option.textContent = nb.title;
select.appendChild(option);
}
// Restore saved default
const { lastNotebookId } = await chrome.storage.local.get(['lastNotebookId']);
if (lastNotebookId) {
select.value = lastNotebookId;
}
} catch (err) {
console.error('Failed to load notebooks:', err);
}
}
// --- Load settings ---
async function loadSettings() {
const result = await chrome.storage.sync.get(['rnotesHost']);
document.getElementById('host').value = result.rnotesHost || DEFAULT_HOST;
await updateAuthUI();
await populateNotebooks();
}
// --- Event handlers ---
// Open rNotes sign-in
document.getElementById('openSigninBtn').addEventListener('click', () => {
const host = document.getElementById('host').value.replace(/\/+$/, '') || DEFAULT_HOST;
chrome.tabs.create({ url: `${host}/auth/signin?extension=true` });
});
// Save token
document.getElementById('saveTokenBtn').addEventListener('click', async () => {
const tokenInput = document.getElementById('tokenInput').value.trim();
if (!tokenInput) {
showStatus('Please paste a token', 'error');
return;
}
const claims = decodeToken(tokenInput);
if (!claims) {
showStatus('Invalid or expired token', 'error');
return;
}
await chrome.storage.local.set({ encryptid_token: tokenInput });
document.getElementById('tokenInput').value = '';
showStatus(`Signed in as ${claims.username || claims.sub}`, 'success');
await updateAuthUI();
await populateNotebooks();
});
// Logout
document.getElementById('logoutBtn').addEventListener('click', async () => {
await chrome.storage.local.remove(['encryptid_token']);
showStatus('Signed out', 'success');
await updateAuthUI();
});
// Save settings
document.getElementById('saveBtn').addEventListener('click', async () => {
const host = document.getElementById('host').value.trim().replace(/\/+$/, '');
const notebookId = document.getElementById('defaultNotebook').value;
await chrome.storage.sync.set({ rnotesHost: host || DEFAULT_HOST });
await chrome.storage.local.set({ lastNotebookId: notebookId });
showStatus('Settings saved', 'success');
});
// Test connection
document.getElementById('testBtn').addEventListener('click', async () => {
const host = document.getElementById('host').value.trim().replace(/\/+$/, '') || DEFAULT_HOST;
const { encryptid_token } = await chrome.storage.local.get(['encryptid_token']);
try {
const headers = {};
if (encryptid_token) {
headers['Authorization'] = `Bearer ${encryptid_token}`;
}
const response = await fetch(`${host}/api/notebooks`, { headers });
if (response.ok) {
const data = await response.json();
showStatus(`Connected! Found ${data.length || 0} notebooks.`, 'success');
} else if (response.status === 401) {
showStatus('Connected but not authenticated. Sign in first.', 'error');
} else {
showStatus(`Connection failed: ${response.status}`, 'error');
}
} catch (err) {
showStatus(`Cannot connect: ${err.message}`, 'error');
}
});
// Default notebook change
document.getElementById('defaultNotebook').addEventListener('change', async (e) => {
await chrome.storage.local.set({ lastNotebookId: e.target.value });
});
// Init
document.addEventListener('DOMContentLoaded', loadSettings);