mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-01-29 16:32:32 -05:00
Add server version check (#541)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
|
||||
@@ -9,13 +9,15 @@ import { useAuth } from '../context/AuthContext';
|
||||
const GlobalStateChangeHandler: React.FC = () => {
|
||||
const authContext = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const lastLoginState = useRef(authContext.isLoggedIn);
|
||||
|
||||
/**
|
||||
* Listen for auth logged in changes and redirect to home page if logged in state changes to handle logins and logouts.
|
||||
*/
|
||||
useEffect(() => {
|
||||
// Only navigate when auth state changes and we're not already on home page
|
||||
if (window.location.pathname !== '/index.html' && window.location.pathname !== '/') {
|
||||
// Only navigate when auth state is different from the last state we acted on.
|
||||
if (lastLoginState.current !== authContext.isLoggedIn) {
|
||||
lastLoginState.current = authContext.isLoggedIn;
|
||||
navigate('/');
|
||||
}
|
||||
}, [authContext.isLoggedIn]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
@@ -10,7 +10,6 @@ import ReloadButton from '../components/ReloadButton';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import LoadingSpinner from '../components/LoadingSpinner';
|
||||
import { useMinDurationLoading } from '../hooks/useMinDurationLoading';
|
||||
import { AppInfo } from '../../shared/AppInfo';
|
||||
|
||||
/**
|
||||
* Credentials list page.
|
||||
@@ -38,15 +37,9 @@ const CredentialsList: React.FC = () => {
|
||||
|
||||
// Do status check first to ensure the extension is (still) supported.
|
||||
const statusResponse = await webApi.getStatus();
|
||||
console.log('CredentialsList: statusResponse', statusResponse);
|
||||
if (!statusResponse.clientVersionSupported) {
|
||||
authContext.logout('This version of the AliasVault browser extension is outdated. Please update your browser extension to the latest version.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if server version is supported by this client.
|
||||
if (!AppInfo.isServerVersionSupported(statusResponse.serverVersion)) {
|
||||
authContext.logout('The AliasVault server needs to be updated to a newer version in order to use this browser extension. Please contact support if you need help.');
|
||||
const statusError = webApi.validateStatusResponse(statusResponse);
|
||||
if (statusError !== null) {
|
||||
authContext.logout(statusError);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,29 +38,20 @@ const Home: React.FC = () => {
|
||||
// Show loading state if not fully initialized or when about to redirect to credentials.
|
||||
if (!isFullyInitialized || (isFullyInitialized && !requireLoginOrUnlock)) {
|
||||
// Global loading spinner will be shown by the parent component.
|
||||
console.log('Home: not fully initialized');
|
||||
return null;
|
||||
}
|
||||
|
||||
setIsInitialLoading(false);
|
||||
|
||||
if (!isAuthenticated) {
|
||||
console.log('Home: not authenticated');
|
||||
return <Login />;
|
||||
}
|
||||
|
||||
if (!isDatabaseAvailable) {
|
||||
console.log('isFullyInitialized', isFullyInitialized);
|
||||
console.log('isAuthenticated', isAuthenticated);
|
||||
console.log('isDatabaseAvailable', isDatabaseAvailable);
|
||||
console.log('isInlineUnlockMode', isInlineUnlockMode);
|
||||
console.log('requireLoginOrUnlock', requireLoginOrUnlock);
|
||||
console.log('Home: not database available');
|
||||
return <Unlock />;
|
||||
}
|
||||
|
||||
if (isInlineUnlockMode) {
|
||||
console.log('Home: inline unlock mode');
|
||||
return <UnlockSuccess onClose={() => setIsInlineUnlockMode(false)} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -167,7 +167,6 @@ const Login: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// All is good. Store auth info which is required to make requests to the web API.
|
||||
await authContext.setAuthTokens(credentials.username, validationResponse.token.token, validationResponse.token.refreshToken);
|
||||
|
||||
|
||||
@@ -28,9 +28,11 @@ const Unlock: React.FC = () => {
|
||||
* Make status call to API which acts as health check.
|
||||
*/
|
||||
const checkStatus = async () : Promise<void> => {
|
||||
const status = await webApi.getStatus();
|
||||
if (!status.clientVersionSupported) {
|
||||
authContext.logout('The browser extension is outdated. Please update to the latest version.');
|
||||
const statusResponse = await webApi.getStatus();
|
||||
const statusError = webApi.validateStatusResponse(statusResponse);
|
||||
if (statusError !== null) {
|
||||
authContext.logout(statusError);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -45,10 +45,10 @@ export async function handleSyncVault(
|
||||
sendResponse: (response: any) => void
|
||||
) : Promise<void> {
|
||||
const webApi = new WebApiService(() => {});
|
||||
const response = await webApi.getStatus();
|
||||
|
||||
if (!response.clientVersionSupported) {
|
||||
sendResponse({ success: false, error: 'The browser extension is outdated. Please update to the latest version.' });
|
||||
const statusResponse = await webApi.getStatus();
|
||||
const statusError = webApi.validateStatusResponse(statusResponse);
|
||||
if (statusError !== null) {
|
||||
sendResponse({ success: false, error: statusError });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ export async function handleSyncVault(
|
||||
'vaultRevisionNumber'
|
||||
]);
|
||||
|
||||
if (response.vaultRevision > result.vaultRevisionNumber) {
|
||||
if (statusResponse.vaultRevision > result.vaultRevisionNumber) {
|
||||
// Retrieve the latest vault from the server.
|
||||
const vaultResponse = await webApi.get<VaultResponse>('Vault');
|
||||
|
||||
|
||||
@@ -2,14 +2,20 @@
|
||||
* AppInfo class which contains information about the application version.
|
||||
*/
|
||||
export class AppInfo {
|
||||
// Current extension version - should be updated with each release.
|
||||
/**
|
||||
* The current extension version. This should be updated with each release of the extension.
|
||||
*/
|
||||
public static readonly VERSION = '0.12.0';
|
||||
|
||||
// Minimum supported AliasVault server (API) version. If the server version is below this, the
|
||||
// client will throw an error stating that the server should be updated.
|
||||
public static readonly MIN_SERVER_VERSION = '0.13.0';
|
||||
/**
|
||||
* The minimum supported AliasVault server (API) version. If the server version is below this, the
|
||||
* client will throw an error stating that the server should be updated.
|
||||
*/
|
||||
public static readonly MIN_SERVER_VERSION = '0.12.0-dev';
|
||||
|
||||
// Minimum supported AliasVault client vault version.
|
||||
/**
|
||||
* The minimum supported AliasVault client vault version.
|
||||
*/
|
||||
public static readonly MIN_VAULT_VERSION = '1.4.1';
|
||||
|
||||
/*
|
||||
@@ -65,8 +71,7 @@ export class AppInfo {
|
||||
if (part1 < part2) return false;
|
||||
}
|
||||
|
||||
// If core versions are equal, check pre-release versions
|
||||
// No pre-release > pre-release
|
||||
// If core versions are equal, check pre-release versions.
|
||||
if (!preRelease1 && preRelease2) return true;
|
||||
if (preRelease1 && !preRelease2) return false;
|
||||
if (!preRelease1 && !preRelease2) return true;
|
||||
|
||||
@@ -218,6 +218,21 @@ export class WebApiService {
|
||||
return await this.get<StatusResponse>('Auth/status');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the status response and returns an error message if validation fails.
|
||||
*/
|
||||
public validateStatusResponse(statusResponse: StatusResponse): string | null {
|
||||
if (!statusResponse.clientVersionSupported) {
|
||||
return 'This version of the AliasVault browser extension is outdated. Please update your browser extension to the latest version.';
|
||||
}
|
||||
|
||||
if (!AppInfo.isServerVersionSupported(statusResponse.serverVersion)) {
|
||||
return 'The AliasVault server needs to be updated to a newer version in order to use this browser extension. Please contact support if you need help.';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the vault response and returns an error message if validation fails
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { AppInfo } from '../AppInfo';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
|
||||
describe('AppInfo', () => {
|
||||
describe('isVersionSupported', () => {
|
||||
it('should support exact version match', () => {
|
||||
|
||||
@@ -25,12 +25,12 @@ public static class AppInfo
|
||||
/// <summary>
|
||||
/// Gets the minor version number.
|
||||
/// </summary>
|
||||
public const int VersionMinor = 11;
|
||||
public const int VersionMinor = 12;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the patch version number.
|
||||
/// </summary>
|
||||
public const int VersionPatch = 1;
|
||||
public const int VersionPatch = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of minimum supported client versions that the WebApi supports.
|
||||
|
||||
Reference in New Issue
Block a user