Working logic to redirect to sessions
Build LinkLog Development Image / development-image (push) Successful in 12s

This commit is contained in:
2026-08-26 16:11:11 +02:00
parent 0287305884
commit 6772bf7107
11 changed files with 122 additions and 4 deletions
+42
View File
@@ -849,6 +849,12 @@ Change the title of the field “One-time password” to “One-time password (w
### Assistant outcome ### Assistant outcome
Updated the OTP field label in the English, Spanish, German, French, and Dutch extension locale catalogs to clarify that the code is needed only when OTP is configured. Updated the OTP field label in the English, Spanish, German, French, and Dutch extension locale catalogs to clarify that the code is needed only when OTP is configured.
### User
The plugin settings still show `emailLabel`; make that `email` as the title for the email field.
### Assistant outcome
Added the missing `emailLabel` and `emailPlaceholder` messages to every extension locale. The English field now resolves to `Email` instead of displaying the localization key.
### User ### User
For the new password in the user setting add a validation field to make sure they are the same before submitting. For the new password in the user setting add a validation field to make sure they are the same before submitting.
@@ -914,3 +920,39 @@ Remove the “New primary email address” functionality and keep only selecting
### Assistant outcome ### Assistant outcome
Removed the replacement-email workflow entirely. Added cleanup migration 14 for its unused table; verified alternatives remain the only addresses eligible for primary selection. Removed the replacement-email workflow entirely. Added cleanup migration 14 for its unused table; verified alternatives remain the only addresses eligible for primary selection.
### User
When the user is logged in, the web plugin should not display “Please sign in to use LinkLog.”
### Assistant outcome
Removed the authenticated-state warning flash by hiding the popup sign-in warning in the initial markup. The popup reveals it only after the session check confirms that no valid bearer session is available.
### User
When the user is signed in, the plugin should not display “Please sign in to use LinkLog.” or the settings link.
### Assistant outcome
Updated popup session detection to validate the stored bearer token through `/api/auth/me` before hiding the sign-in warning and revealing capture fields. Expired or invalid sessions now keep the warning and settings action visible.
### User
The plugin still does not behave as expected and still shows that the user should sign in.
### Assistant outcome
Centralized popup session validation, ensured valid bearer sessions hide the sign-in warning, and cleared stale credentials when the backend rejects a session. The capture form is shown only after successful validation.
### User
In the popup show that the user has logged in.
### Assistant outcome
Added a localized authenticated-session indicator to the Firefox popup, showing the returned username and backend URL after successful session validation. It remains hidden for signed-out or invalid sessions.
### User
The popup still shows the sign-in block even though the authenticated session text is displayed; show the block only when signed out.
### Assistant outcome
Made popup authentication states mutually exclusive using the DOM `hidden` property. Authenticated sessions now always hide the sign-in block, while signed-out sessions hide the session text and show only the warning block.
### User
The authenticated session text and sign-in block are still shown together.
### Assistant outcome
Made popup state transitions defensive by synchronizing both `hidden` attributes and CSS classes. Non-authentication tag-loading errors no longer switch the popup to signed-out state; only a rejected session does. Added `display: none !important` guards for both authentication blocks.
+7
View File
@@ -147,6 +147,7 @@
138. When the user is not logged in then the plugin should just display no form fields but warn the user that they have to log in with a link to settings. 138. When the user is not logged in then the plugin should just display no form fields but warn the user that they have to log in with a link to settings.
139. Remove DEFAULT_BACKEND setting in the plugin. 139. Remove DEFAULT_BACKEND setting in the plugin.
140. Change the title of the field "One-time password" to "One-time password (when configured)". 140. Change the title of the field "One-time password" to "One-time password (when configured)".
157. The plugin settings still show 'emailLabel'; make that 'email' as title for the email field.
141. Remove any leading and trailing spaces when entering fields in the settings page of the plugin. 141. Remove any leading and trailing spaces when entering fields in the settings page of the plugin.
142. Do a full security audit document in what you have done in detail in Security-audit.md 142. Do a full security audit document in what you have done in detail in Security-audit.md
143. Address issue 1. and improve password storage 143. Address issue 1. and improve password storage
@@ -164,6 +165,12 @@
152. Make sure an email can only be selected when it has been validated. 152. Make sure an email can only be selected when it has been validated.
153. Remove the entire "New primary email address" block; keep only selecting an existing alternative as primary. 153. Remove the entire "New primary email address" block; keep only selecting an existing alternative as primary.
155. Remove the “New primary email address” functionality and keep only selecting an existing alternative as primary. 155. Remove the “New primary email address” functionality and keep only selecting an existing alternative as primary.
158. When the user is logged in the webplugin should not display "Please sign in to use LinkLog."
156. When the user is signed in the plugin should not display "Please sign in to use LinkLog." and the link to the settings
159. The plugin still does not behave as expected. It still shows that the user should sign in.
160. In the popup show that the user has logged in.
161. The popup still shows the sign-in block even though the authenticated session text is displayed; show the block only when signed out.
162. The authenticated session text and sign-in block are still shown together.
## Future entries ## Future entries
Binary file not shown.
+2
View File
@@ -15,6 +15,8 @@
"openSettings": {"message": "Einstellungen öffnen"}, "openSettings": {"message": "Einstellungen öffnen"},
"signOut": {"message": "Abmelden"}, "signOut": {"message": "Abmelden"},
"backendUrlLabel": {"message": "Backend-URL"}, "backendUrlLabel": {"message": "Backend-URL"},
"emailLabel": {"message": "E-Mail"},
"emailPlaceholder": {"message": "alice@example.com"},
"usernameLabel": {"message": "Benutzername"}, "usernameLabel": {"message": "Benutzername"},
"usernamePlaceholder": {"message": "alice"}, "usernamePlaceholder": {"message": "alice"},
"passwordLabel": {"message": "Passwort"}, "passwordLabel": {"message": "Passwort"},
@@ -47,6 +47,12 @@
"backendUrlLabel": { "backendUrlLabel": {
"message": "Backend URL" "message": "Backend URL"
}, },
"emailLabel": {
"message": "Email"
},
"emailPlaceholder": {
"message": "alice@example.com"
},
"usernameLabel": { "usernameLabel": {
"message": "Username" "message": "Username"
}, },
+2
View File
@@ -15,6 +15,8 @@
"openSettings": {"message": "Abrir configuración"}, "openSettings": {"message": "Abrir configuración"},
"signOut": {"message": "Cerrar sesión"}, "signOut": {"message": "Cerrar sesión"},
"backendUrlLabel": {"message": "URL del servidor"}, "backendUrlLabel": {"message": "URL del servidor"},
"emailLabel": {"message": "Correo electrónico"},
"emailPlaceholder": {"message": "alice@example.com"},
"usernameLabel": {"message": "Nombre de usuario"}, "usernameLabel": {"message": "Nombre de usuario"},
"usernamePlaceholder": {"message": "alice"}, "usernamePlaceholder": {"message": "alice"},
"passwordLabel": {"message": "Contraseña"}, "passwordLabel": {"message": "Contraseña"},
+2
View File
@@ -15,6 +15,8 @@
"openSettings": {"message": "Ouvrir les paramètres"}, "openSettings": {"message": "Ouvrir les paramètres"},
"signOut": {"message": "Se déconnecter"}, "signOut": {"message": "Se déconnecter"},
"backendUrlLabel": {"message": "URL du serveur"}, "backendUrlLabel": {"message": "URL du serveur"},
"emailLabel": {"message": "E-mail"},
"emailPlaceholder": {"message": "alice@example.com"},
"usernameLabel": {"message": "Nom dutilisateur"}, "usernameLabel": {"message": "Nom dutilisateur"},
"usernamePlaceholder": {"message": "alice"}, "usernamePlaceholder": {"message": "alice"},
"passwordLabel": {"message": "Mot de passe"}, "passwordLabel": {"message": "Mot de passe"},
+2
View File
@@ -15,6 +15,8 @@
"openSettings": {"message": "Instellingen openen"}, "openSettings": {"message": "Instellingen openen"},
"signOut": {"message": "Uitloggen"}, "signOut": {"message": "Uitloggen"},
"backendUrlLabel": {"message": "Backend-URL"}, "backendUrlLabel": {"message": "Backend-URL"},
"emailLabel": {"message": "E-mail"},
"emailPlaceholder": {"message": "alice@example.com"},
"usernameLabel": {"message": "Gebruikersnaam"}, "usernameLabel": {"message": "Gebruikersnaam"},
"usernamePlaceholder": {"message": "alice"}, "usernamePlaceholder": {"message": "alice"},
"passwordLabel": {"message": "Wachtwoord"}, "passwordLabel": {"message": "Wachtwoord"},
+15
View File
@@ -149,6 +149,16 @@ button {
color: #f38ba8; color: #f38ba8;
} }
.auth-session {
margin-bottom: 10px;
border: 1px solid #585b70;
border-radius: 8px;
padding: 8px 10px;
color: #94e2d5;
font-size: 0.8rem;
overflow-wrap: anywhere;
}
#auth-warning { #auth-warning {
display: grid; display: grid;
gap: 8px; gap: 8px;
@@ -162,6 +172,11 @@ button {
display: none; display: none;
} }
#auth-session[hidden],
#auth-warning[hidden] {
display: none !important;
}
.extension-footer { .extension-footer {
margin-top: 16px; margin-top: 16px;
color: #7f849c; color: #7f849c;
+2 -1
View File
@@ -15,7 +15,8 @@
</header> </header>
<div id="status" class="status hidden" aria-live="polite"></div> <div id="status" class="status hidden" aria-live="polite"></div>
<div id="auth-warning" class="status error" aria-live="polite"> <div id="auth-session" class="auth-session" hidden aria-live="polite"></div>
<div id="auth-warning" class="status error" hidden aria-live="polite">
<span data-i18n="authRequired">Please sign in to use LinkLog.</span> <span data-i18n="authRequired">Please sign in to use LinkLog.</span>
<button type="button" id="warning-settings" class="secondary" data-i18n="openSettings">Open settings</button> <button type="button" id="warning-settings" class="secondary" data-i18n="openSettings">Open settings</button>
</div> </div>
+42 -3
View File
@@ -12,6 +12,7 @@ const newTagsInput = document.getElementById('new-tags');
const feedLink = document.getElementById('feed-link'); const feedLink = document.getElementById('feed-link');
const authWarning = document.getElementById('auth-warning'); const authWarning = document.getElementById('auth-warning');
const warningSettingsButton = document.getElementById('warning-settings'); const warningSettingsButton = document.getElementById('warning-settings');
const authSession = document.getElementById('auth-session');
const t = window.linklogI18n; const t = window.linklogI18n;
@@ -31,13 +32,36 @@ async function getSettings() {
return result; return result;
} }
async function validateSession(settings) {
if (!settings.backendUrl || !settings.accessToken) return null;
try {
const response = await fetch(`${settings.backendUrl}/api/auth/me`, {
headers: {'Authorization': `Bearer ${settings.accessToken}`},
});
if (!response.ok) {
await browser.storage.local.remove(['accessToken', 'tokenType', 'tokenExpiresAt', 'refreshToken']);
return null;
}
return await response.json();
} catch (error) {
return null;
}
}
function showSignedOutState() { function showSignedOutState() {
form.classList.add('hidden'); form.classList.add('hidden');
authSession.hidden = true;
authSession.classList.add('hidden');
authWarning.hidden = false;
authWarning.classList.remove('hidden'); authWarning.classList.remove('hidden');
} }
function showSignedInState() { function showSignedInState(user, backendUrl) {
authWarning.hidden = true;
authWarning.classList.add('hidden'); authWarning.classList.add('hidden');
authSession.textContent = t('loggedInAt', [user.username || user.email, backendUrl]);
authSession.hidden = false;
authSession.classList.remove('hidden');
form.classList.remove('hidden'); form.classList.remove('hidden');
} }
@@ -59,12 +83,20 @@ async function loadExistingTags() {
showSignedOutState(); showSignedOutState();
return; return;
} }
showSignedInState(); const user = await validateSession(settings);
if (!user) {
showSignedOutState();
return;
}
showSignedInState(user, settings.backendUrl);
const response = await fetch(`${settings.backendUrl}/api/tags`, { const response = await fetch(`${settings.backendUrl}/api/tags`, {
headers: {'Authorization': `Bearer ${settings.accessToken}`}, headers: {'Authorization': `Bearer ${settings.accessToken}`},
}); });
if (!response.ok) { if (!response.ok) {
if (response.status === 401) showSignedOutState(); if (response.status === 401) {
showSignedOutState();
return;
}
existingTags.textContent = t('loadTagsFailed'); existingTags.textContent = t('loadTagsFailed');
return; return;
} }
@@ -124,6 +156,13 @@ async function handleSubmit(event) {
return; return;
} }
if (!await validateSession(settings)) {
showSignedOutState();
setStatus(t('sessionExpired'), true);
browser.runtime.openOptionsPage();
return;
}
try { try {
const response = await fetch(`${backendUrl}/api/links`, { const response = await fetch(`${backendUrl}/api/links`, {
method: 'POST', method: 'POST',