Tweak offline mode detection (#1404)

This commit is contained in:
Leendert de Borst
2025-12-13 12:32:50 +01:00
parent ee853b830b
commit caabcdbe10
3 changed files with 43 additions and 20 deletions

View File

@@ -9,6 +9,7 @@ import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
import type { EncryptionKeyDerivationParams } from '@/utils/dist/core/models/metadata';
import type { VaultResponse } from '@/utils/dist/core/models/webapi';
import { EncryptionUtility } from '@/utils/EncryptionUtility';
import { ApiAuthError } from '@/utils/types/errors/ApiAuthError';
import { NetworkError } from '@/utils/types/errors/NetworkError';
import { VaultVersionIncompatibleError } from '@/utils/types/errors/VaultVersionIncompatibleError';
import type { VaultUploadResponse } from '@/utils/types/messaging/VaultUploadResponse';
@@ -303,6 +304,11 @@ export const useVaultSync = (): { syncVault: (options?: VaultSyncOptions) => Pro
return false;
}
// Check if it's an auth error (session expired) - logout is already triggered by WebApiService
if (err instanceof ApiAuthError) {
return false;
}
// Check if it's a network error - enter offline mode if we have a local vault
if (err instanceof NetworkError) {
if (dbContext.dbAvailable) {

View File

@@ -81,24 +81,34 @@ const Unlock: React.FC = () => {
* Returns { online: boolean, error: string | null }
*/
const checkStatus = async () : Promise<{ online: boolean; error: string | null }> => {
const statusResponse = await webApi.getStatus();
try {
const statusResponse = await webApi.getStatus();
// Server is offline (network error) - this is OK for unlock, we can use local vault
if (statusResponse.serverVersion === '0.0.0') {
setIsInitialLoading(false);
await dbContext.setIsOffline(true);
return { online: false, error: null };
}
const statusError = webApi.validateStatusResponse(statusResponse);
if (statusError !== null) {
await app.logout(t('common.errors.' + statusError));
return { online: false, error: statusError };
}
// Server is offline - this is OK for unlock, we can use local vault
if (statusResponse.serverVersion === '0.0.0') {
setIsInitialLoading(false);
await dbContext.setIsOffline(true);
return { online: false, error: null };
await dbContext.setIsOffline(false);
return { online: true, error: null };
} catch {
/**
* Non-network errors (e.g., session expired, auth failures) are thrown by getStatus().
* The logout event is already emitted by the WebApiService, so we just return an error
* and don't set offline mode since the server is reachable.
*/
setIsInitialLoading(false);
return { online: false, error: 'sessionExpired' };
}
const statusError = webApi.validateStatusResponse(statusResponse);
if (statusError !== null) {
await app.logout(t('common.errors.' + statusError));
return { online: false, error: statusError };
}
setIsInitialLoading(false);
await dbContext.setIsOffline(false);
return { online: true, error: null };
};
/**

View File

@@ -3,6 +3,7 @@ import type { StatusResponse } from '@/utils/dist/core/models/webapi';
import { logoutEventEmitter } from '@/events/LogoutEventEmitter';
import { AppInfo } from "./AppInfo";
import { ApiAuthError } from './types/errors/ApiAuthError';
import { NetworkError } from './types/errors/NetworkError';
import { storage } from '#imports';
@@ -72,13 +73,13 @@ export class WebApiService {
});
if (!retryResponse.ok) {
throw new Error('Request failed after token refresh');
throw new ApiAuthError('Request failed after token refresh');
}
return parseJson ? retryResponse.json() : retryResponse as unknown as T;
} else {
logoutEventEmitter.emit('auth.errors.sessionExpired');
throw new Error('Session expired');
throw new ApiAuthError('Session expired');
}
}
@@ -211,15 +212,21 @@ export class WebApiService {
/**
* Calls the status endpoint to check if the auth tokens are still valid, app is supported and the vault is up to date.
* Returns offline indicator (serverVersion: '0.0.0') for network failures and server errors (5xx, 404, etc.).
* Auth errors (ApiAuthError) are re-thrown to be handled appropriately (e.g., trigger logout).
*/
public async getStatus(): Promise<StatusResponse> {
try {
return await this.get<StatusResponse>('Auth/status');
} catch {
} catch (error) {
/**
* If the status endpoint is not available, return a default status response which will trigger
* a logout and error message.
* Only re-throw ApiAuthError (session expired, auth failures).
* All other errors (NetworkError, HTTP 5xx, 404, etc.) indicate the server
* is unreachable or misconfigured, so return offline indicator.
*/
if (error instanceof ApiAuthError) {
throw error;
}
return {
clientVersionSupported: true,
serverVersion: '0.0.0',