180 lines
5.4 KiB
JavaScript
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);
|