adminforth 3.24.4 → 3.24.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -286,7 +286,14 @@ async function loadConfig() {
286
286
  publicConfigLoaded.value = true;
287
287
 
288
288
  await initRouter();
289
- if (resp && !resp.loggedIn && route.meta.sidebarAndHeader !== 'none') {
289
+ if (resp?.loggedIn) {
290
+ // the flag the login route guard reads is only ever set by a login, so a 401 can leave it
291
+ // saying "signed out" for a session the server still honours
292
+ userStore.authorize();
293
+ if (route.name === 'login') {
294
+ await router.replace(route.query.next?.toString() || { name: 'home' });
295
+ }
296
+ } else if (resp && route.meta.sidebarAndHeader !== 'none') {
290
297
  // for custom layouts we don't force login, they are allowed to be rendered for anonymous user
291
298
  await handleNotAuthorized();
292
299
  }
@@ -0,0 +1,31 @@
1
+ // The auth cookie is HttpOnly, so the server is the only place that knows whether a session is live.
2
+ export async function hasLiveSession(): Promise<boolean> {
3
+ const baseUrl = (import.meta as any).env?.VITE_ADMINFORTH_PUBLIC_PATH || '';
4
+ try {
5
+ const response = await fetch(`${baseUrl}/adminapi/v1/check_auth`, {
6
+ method: 'POST',
7
+ headers: { 'Content-Type': 'application/json' },
8
+ body: '{}',
9
+ signal: AbortSignal.timeout(5000),
10
+ });
11
+ if (response.status !== 200) {
12
+ return false;
13
+ }
14
+ // a proxy or captive portal can answer 200 with its own page, so the body has to say so too
15
+ return (await response.json().catch(() => null))?.ok === true;
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
20
+
21
+ let inFlight: Promise<boolean> | null = null;
22
+
23
+ /** A 401 can be transient while the cookie is still good. Only worth asking if we thought we were signed in. */
24
+ export async function sessionSurvives401(): Promise<boolean> {
25
+ if (localStorage.getItem('isAuthorized') !== 'true') {
26
+ return false;
27
+ }
28
+ // an outage 401s every call on the page at once, and they all want the same answer
29
+ inFlight ??= hasLiveSession().finally(() => { inFlight = null; });
30
+ return inFlight;
31
+ }
@@ -14,6 +14,7 @@ import { useI18n } from 'vue-i18n';
14
14
  import { onBeforeRouteLeave } from 'vue-router';
15
15
  import { reconnect } from '@/websocket';
16
16
  import { ADMINFORTH_CLIENT_ID_HEADER, getAdminForthClientId } from './clientId';
17
+ import { sessionSurvives401 } from './session';
17
18
 
18
19
 
19
20
 
@@ -103,10 +104,16 @@ async function tryAutologin(autologin: string): Promise<boolean> {
103
104
  return !!coreStore.adminUser;
104
105
  }
105
106
 
106
- export async function handleNotAuthorized() {
107
+ /** @returns false when the session turned out to be alive and nothing was signed out. */
108
+ export async function handleNotAuthorized(): Promise<boolean> {
109
+ // one 401 during a restart must not throw away a session the server still honours
110
+ if (await sessionSurvives401()) {
111
+ return false;
112
+ }
107
113
  useUserStore().unauthorize();
108
114
  useCoreStore().resetAdminUser();
109
115
  await redirectToLogin();
116
+ return true;
110
117
  }
111
118
 
112
119
  export async function redirectToLogin() {
@@ -157,7 +164,10 @@ export async function callApi({path, method, body, headers, silentError = false,
157
164
  try {
158
165
  const r = await fetch(fullPath, options);
159
166
  if (r.status == 401 && !path.includes('/login')) {
160
- await handleNotAuthorized();
167
+ // when the session survived there is no redirect coming, so the failure has to be visible
168
+ if (!await handleNotAuthorized() && !silentError) {
169
+ adminforth.alert({variant:'danger', message: t('Something went wrong, please try again later'),})
170
+ }
161
171
  return null;
162
172
  }
163
173
  return await r.json();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "3.24.4",
3
+ "version": "3.24.6",
4
4
  "description": "OpenSource Agent-Native forth-generation admin panel",
5
5
  "keywords": [
6
6
  "adminforth",