Skip to content

Commit

Permalink
Add status call to unlock page, fix redirect bug (#541)
Browse files Browse the repository at this point in the history
  • Loading branch information
lanedirt committed Feb 12, 2025
1 parent 0862aa6 commit 47201b5
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const CredentialsList: React.FC = () => {
const checkStatus = async (): Promise<void> => {
if (!dbContext?.sqliteClient) return;

const statusResponse = await webApi.get('Auth/status') as StatusResponse;
const statusResponse = await webApi.getStatus();
if (!statusResponse.supported) {
authContext.logout('This version of the AliasVault browser extension is outdated. Please update to the latest version.');
return;
Expand Down
20 changes: 15 additions & 5 deletions browser-extensions/chrome/src/app/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,44 @@ import UnlockSuccess from './UnlockSuccess';
import { useNavigate } from 'react-router-dom';
import { useDb } from '../context/DbContext';
import { useLoading } from '../context/LoadingContext';
import { useWebApi } from '../context/WebApiContext';

/**
* Home page that shows the correct page based on the user's authentication state.
*/
const Home: React.FC = () => {
const { isLoggedIn } = useAuth();
const authContext = useAuth();
const dbContext = useDb();
const navigate = useNavigate();
const webApi = useWebApi();
const { setIsInitialLoading } = useLoading();
const [isInlineUnlockMode, setIsInlineUnlockMode] = useState(false);
const needsUnlock = (!authContext.isLoggedIn && authContext.isInitialized) || (!dbContext.dbAvailable && dbContext.dbInitialized);
const initialized = authContext.isInitialized && dbContext.dbInitialized;
const needsUnlock = initialized && (!authContext.isLoggedIn || !dbContext.dbAvailable);

useEffect(() => {
// Detect if the user is coming from the unlock page with mode=inline_unlock
const urlParams = new URLSearchParams(window.location.search);
const isInlineUnlockMode = urlParams.get('mode') === 'inline_unlock';
setIsInlineUnlockMode(isInlineUnlockMode);

if (isLoggedIn && !needsUnlock && !isInlineUnlockMode) {
// Do a status check to see if the auth tokens are still valid, if not, redirect to the login page.
const checkStatus = async () => {
const status = await webApi.get('Status');
if (status.status !== 0) {
authContext.logout();
}
};

if (initialized && !needsUnlock) {
navigate('/credentials', { replace: true });
}
}, [isLoggedIn, needsUnlock, isInlineUnlockMode, navigate]);
}, [initialized,needsUnlock, isInlineUnlockMode, navigate]);

// Set initial loading state to false once the page is loaded until here.
setIsInitialLoading(false);

if (!isLoggedIn) {
if (!authContext.isLoggedIn) {
return <Login />;
}

Expand Down
15 changes: 13 additions & 2 deletions browser-extensions/chrome/src/app/pages/Unlock.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { useDb } from '../context/DbContext';
import { useAuth } from '../context/AuthContext';
import { useWebApi } from '../context/WebApiContext';
Expand All @@ -23,13 +23,25 @@ const Unlock: React.FC = () => {
const [error, setError] = useState<string | null>(null);
const { showLoading, hideLoading } = useLoading();

useEffect(() => {
const checkStatus = async () => {
const status = await webApi.getStatus();
if (!status.supported) {
authContext.logout('The browser extension is outdated. Please update to the latest version.');
}
};

checkStatus();
}, [webApi, authContext]);

/**
* Handle submit
*/
const handleSubmit = async (e: React.FormEvent) : Promise<void> => {
e.preventDefault();
setError(null);
showLoading();

try {
// 1. Initiate login to get salt and server ephemeral
const loginResponse = await srpUtil.initiateLogin(authContext.username!);
Expand Down Expand Up @@ -84,7 +96,6 @@ const Unlock: React.FC = () => {
finally {
hideLoading();
}

};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ export async function handleSyncVault(
) : Promise<void> {
const webApi = new WebApiService(() => {});
await webApi.initializeBaseUrl();
const response = await webApi.get('Auth/status') as StatusResponse;
const response = await webApi.getStatus();

if (!response.supported) {
sendResponse({ success: false, error: 'Browser extension is not supported. Please update to the latest version.' });
sendResponse({ success: false, error: 'The browser extension is outdated. Please update to the latest version.' });
return;
}

Expand Down
26 changes: 16 additions & 10 deletions browser-extensions/chrome/src/shared/WebApiService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AppInfo } from "./AppInfo";
import { StatusResponse } from "./types/webapi/StatusResponse";
import { VaultResponse } from "./types/webapi/VaultResponse";

type RequestInit = globalThis.RequestInit;
Expand All @@ -15,8 +16,6 @@ type TokenResponse = {
* Service class for interacting with the web API.
*/
export class WebApiService {
private baseUrl: string = '';

/**
* Constructor for the WebApiService class.
*
Expand All @@ -25,17 +24,15 @@ export class WebApiService {
public constructor(
private handleLogout: () => void
) {
// Load the API URL from storage when service is initialized
this.initializeBaseUrl();
// Remove initialization of baseUrl
}

/**
* Initialize the base URL for the API from settings.
* Get the base URL for the API from settings.
*/
public async initializeBaseUrl() : Promise<void> {
private async getBaseUrl(): Promise<string> {
const result = await chrome.storage.local.get(['apiUrl']);
// Trim trailing slash if present
this.baseUrl = (result.apiUrl || 'https://app.aliasvault.net/api').replace(/\/$/, '') + '/v1/';
return (result.apiUrl || 'https://app.aliasvault.net/api').replace(/\/$/, '') + '/v1/';
}

/**
Expand All @@ -46,7 +43,8 @@ export class WebApiService {
options: RequestInit = {},
parseJson: boolean = true
): Promise<T> {
const url = this.baseUrl + endpoint;
const baseUrl = await this.getBaseUrl();
const url = baseUrl + endpoint;
const headers = new Headers(options.headers || {});

// Add authorization header if we have an access token
Expand Down Expand Up @@ -107,7 +105,8 @@ export class WebApiService {
}

try {
const response = await fetch(`${this.baseUrl}Auth/refresh`, {
const baseUrl = await this.getBaseUrl();
const response = await fetch(`${baseUrl}Auth/refresh`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down Expand Up @@ -191,6 +190,13 @@ export class WebApiService {
}, false);
}

/**
* Calls the status endpoint to check if the auth tokens are still valid, app is supported and the vault is up to date.
*/
public async getStatus(): Promise<StatusResponse> {
return await this.get('Auth/status') as StatusResponse;
}

/**
* Validates the vault response and returns an error message if validation fails
*/
Expand Down

0 comments on commit 47201b5

Please sign in to comment.