token usage tightened with revocation

This commit is contained in:
2026-08-26 18:17:55 +02:00
parent 1a24d21d0a
commit 4049a197b9
13 changed files with 288 additions and 54 deletions
+63 -13
View File
@@ -13,6 +13,7 @@ const feedLink = document.getElementById('feed-link');
const authWarning = document.getElementById('auth-warning');
const warningSettingsButton = document.getElementById('warning-settings');
const authSession = document.getElementById('auth-session');
const sessionStore = browser.storage.session;
const t = window.linklogI18n;
@@ -42,12 +43,49 @@ function setStatus(message, isError = false) {
}
async function getSettings() {
const result = await browser.storage.local.get([
'backendUrl',
'accessToken',
'tokenExpiresAt',
const [settings, sessionSettings] = await Promise.all([
browser.storage.local.get(['backendUrl', 'username']),
sessionStore.get(['accessToken', 'refreshToken', 'tokenExpiresAt', 'deviceId']),
]);
return result;
return {...settings, ...sessionSettings};
}
async function persistSession(settings) {
await sessionStore.set({
accessToken: settings.accessToken,
refreshToken: settings.refreshToken,
tokenExpiresAt: settings.tokenExpiresAt,
deviceId: settings.deviceId,
});
}
async function clearSession() {
await Promise.all([
sessionStore.remove(['accessToken', 'refreshToken', 'tokenExpiresAt', 'deviceId']),
browser.storage.local.remove(['accessToken', 'tokenType', 'tokenExpiresAt', 'refreshToken', 'deviceId']),
]);
}
async function refreshAccessToken(settings) {
if (!settings.backendUrl || !settings.refreshToken || !settings.deviceId) return null;
try {
const response = await fetch(`${settings.backendUrl}/api/auth/refresh`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({refresh_token: settings.refreshToken, device_id: settings.deviceId}),
});
if (!response.ok) {
await clearSession();
return null;
}
const data = await response.json();
const refreshed = {...settings, accessToken: data.access_token, refreshToken: data.refresh_token,
tokenExpiresAt: data.expires_at, deviceId: data.device_id || settings.deviceId};
await persistSession(refreshed);
return refreshed;
} catch (error) {
return null;
}
}
async function validateSession(settings) {
@@ -57,7 +95,16 @@ async function validateSession(settings) {
headers: {'Authorization': `Bearer ${settings.accessToken}`},
});
if (!response.ok) {
await browser.storage.local.remove(['accessToken', 'tokenType', 'tokenExpiresAt', 'refreshToken']);
if (response.status === 401) {
const refreshed = await refreshAccessToken(settings);
if (refreshed) {
const retry = await fetch(`${refreshed.backendUrl}/api/auth/me`, {
headers: {'Authorization': `Bearer ${refreshed.accessToken}`},
});
if (retry.ok) return await retry.json();
}
}
await clearSession();
return null;
}
return await response.json();
@@ -97,7 +144,7 @@ function showSavedState(message) {
}
async function updateFeedLink() {
const settings = await browser.storage.local.get(['backendUrl', 'username', 'accessToken']);
const settings = await getSettings();
if (!settings.backendUrl || !settings.username || !settings.accessToken) return;
try {
const backend = new URL(settings.backendUrl);
@@ -119,9 +166,10 @@ async function loadExistingTags() {
showSignedOutState();
return;
}
showSignedInState(user, settings.backendUrl);
const response = await fetch(`${settings.backendUrl}/api/tags`, {
headers: {'Authorization': `Bearer ${settings.accessToken}`},
const currentSettings = await getSettings();
showSignedInState(user, currentSettings.backendUrl);
const response = await fetch(`${currentSettings.backendUrl}/api/tags`, {
headers: {'Authorization': `Bearer ${currentSettings.accessToken}`},
});
if (!response.ok) {
if (response.status === 401) {
@@ -212,12 +260,14 @@ async function handleSubmit(event) {
return;
}
const currentSettings = await getSettings();
try {
const response = await fetch(`${backendUrl}/api/links`, {
const response = await fetch(`${currentSettings.backendUrl}/api/links`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'Authorization': `Bearer ${currentSettings.accessToken}`,
},
body: JSON.stringify({
title: titleInput.value,
@@ -240,7 +290,7 @@ async function handleSubmit(event) {
}
const result = await response.json();
const saveMessage = result.duplicate ? t('linkAlreadyExists') : t('linkSaved', backendUrl);
const saveMessage = result.duplicate ? t('linkAlreadyExists') : t('linkSaved', currentSettings.backendUrl);
if (result.plugin_errors?.length) {
const errors = result.plugin_errors.map((error) => `${error.plugin}: ${error.reason}`).join(' ');
showSavedState(`${saveMessage} ${t('publishingErrors', errors)}`);