mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-03-06 15:58:09 -05:00
Refactor browser extension to use shared types, add import order lint rules (#900)
This commit is contained in:
committed by
Leendert de Borst
parent
c6d7d16b27
commit
22acea0e35
@@ -105,8 +105,51 @@ export default [
|
||||
],
|
||||
"react-hooks/exhaustive-deps": "warn",
|
||||
"react/jsx-no-constructed-context-values": "error",
|
||||
"import/no-unresolved": "error",
|
||||
},
|
||||
"import/no-unresolved": [
|
||||
"error",
|
||||
{
|
||||
ignore: ['^#imports$'] // Ignore virtual imports from WXT which are not resolved by the typescript compiler
|
||||
}
|
||||
],
|
||||
"import/order": [
|
||||
"error",
|
||||
{
|
||||
"groups": [
|
||||
"builtin", // Node "fs", "path", etc.
|
||||
"external", // "react", "lodash", etc.
|
||||
"internal", // Aliased paths like "@/utils"
|
||||
"parent", // "../"
|
||||
"sibling", // "./"
|
||||
"index", // "./index"
|
||||
"object", // import 'foo'
|
||||
"type" // import type ...
|
||||
],
|
||||
"pathGroups": [
|
||||
{
|
||||
pattern: "@/entrypoints/**",
|
||||
group: "internal",
|
||||
position: "before"
|
||||
},
|
||||
{
|
||||
pattern: "@/utils/**",
|
||||
group: "internal",
|
||||
position: "before"
|
||||
},
|
||||
{
|
||||
pattern: "@/hooks/**",
|
||||
group: "internal",
|
||||
position: "before"
|
||||
}
|
||||
],
|
||||
"pathGroupsExcludedImportTypes": ["builtin"],
|
||||
"newlines-between": "always",
|
||||
"alphabetize": {
|
||||
order: "asc",
|
||||
caseInsensitive: true
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { defineBackground } from '#imports';
|
||||
import { onMessage, sendMessage } from "webext-bridge/background";
|
||||
|
||||
import { setupContextMenus } from '@/entrypoints/background/ContextMenu';
|
||||
import { handleCheckAuthStatus, handleClearVault, handleCreateIdentity, handleGetCredentials, handleGetDefaultEmailDomain, handleGetDefaultIdentityLanguage, handleGetDerivedKey, handleGetPasswordSettings, handleGetVault, handleStoreVault, handleSyncVault } from '@/entrypoints/background/VaultMessageHandler';
|
||||
import { handleOpenPopup, handlePopupWithCredential, handleToggleContextMenu } from '@/entrypoints/background/PopupMessageHandler';
|
||||
import { storage, browser } from '#imports';
|
||||
import { handleCheckAuthStatus, handleClearVault, handleCreateIdentity, handleGetCredentials, handleGetDefaultEmailDomain, handleGetDefaultIdentityLanguage, handleGetDerivedKey, handleGetPasswordSettings, handleGetVault, handleStoreVault, handleSyncVault } from '@/entrypoints/background/VaultMessageHandler';
|
||||
|
||||
import { GLOBAL_CONTEXT_MENU_ENABLED_KEY } from '@/utils/Constants';
|
||||
|
||||
import { defineBackground, storage, browser } from '#imports';
|
||||
|
||||
export default defineBackground({
|
||||
/**
|
||||
* This is the main entry point for the background script.
|
||||
@@ -32,7 +34,7 @@ export default defineBackground({
|
||||
if (isContextMenuEnabled) {
|
||||
setupContextMenus();
|
||||
}
|
||||
|
||||
|
||||
// Listen for custom commands
|
||||
try {
|
||||
browser.commands.onCommand.addListener(async (command) => {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { sendMessage } from 'webext-bridge/background';
|
||||
import { browser } from "#imports";
|
||||
import { type Browser } from '@wxt-dev/browser';
|
||||
import { sendMessage } from 'webext-bridge/background';
|
||||
|
||||
import { PasswordGenerator } from '@/utils/shared/password-generator';
|
||||
|
||||
import { browser } from "#imports";
|
||||
|
||||
/**
|
||||
* Setup the context menus.
|
||||
*/
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { browser } from '#imports';
|
||||
import { BoolResponse } from '@/utils/types/messaging/BoolResponse';
|
||||
|
||||
import { setupContextMenus } from './ContextMenu';
|
||||
|
||||
import { browser } from '#imports';
|
||||
|
||||
/**
|
||||
* Handle opening the popup.
|
||||
*/
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { storage } from 'wxt/utils/storage';
|
||||
|
||||
import { EncryptionUtility } from '@/utils/EncryptionUtility';
|
||||
import type { Vault, VaultResponse, VaultPostResponse } from '@/utils/shared/models';
|
||||
import { SqliteClient } from '@/utils/SqliteClient';
|
||||
import { WebApiService } from '@/utils/WebApiService';
|
||||
import { Vault } from '@/utils/types/webapi/Vault';
|
||||
import { VaultResponse } from '@/utils/types/webapi/VaultResponse';
|
||||
import { VaultPostResponse } from '@/utils/types/webapi/VaultPostResponse';
|
||||
import { BoolResponse as messageBoolResponse } from '@/utils/types/messaging/BoolResponse';
|
||||
import { VaultResponse as messageVaultResponse } from '@/utils/types/messaging/VaultResponse';
|
||||
import { CredentialsResponse as messageCredentialsResponse } from '@/utils/types/messaging/CredentialsResponse';
|
||||
import { StringResponse as stringResponse } from '@/utils/types/messaging/StringResponse';
|
||||
import { PasswordSettingsResponse as messagePasswordSettingsResponse } from '@/utils/types/messaging/PasswordSettingsResponse';
|
||||
import { StringResponse as stringResponse } from '@/utils/types/messaging/StringResponse';
|
||||
import { VaultResponse as messageVaultResponse } from '@/utils/types/messaging/VaultResponse';
|
||||
import { WebApiService } from '@/utils/WebApiService';
|
||||
|
||||
/**
|
||||
* Check if the user is logged in and if the vault is locked.
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import '@/entrypoints/contentScript/style.css';
|
||||
import { FormDetector } from '@/utils/formDetector/FormDetector';
|
||||
import { isAutoShowPopupEnabled, openAutofillPopup, removeExistingPopup } from '@/entrypoints/contentScript/Popup';
|
||||
import { injectIcon, popupDebounceTimeHasPassed, validateInputField } from '@/entrypoints/contentScript/Form';
|
||||
import { onMessage } from "webext-bridge/content-script";
|
||||
|
||||
import { injectIcon, popupDebounceTimeHasPassed, validateInputField } from '@/entrypoints/contentScript/Form';
|
||||
import { isAutoShowPopupEnabled, openAutofillPopup, removeExistingPopup } from '@/entrypoints/contentScript/Popup';
|
||||
|
||||
import { FormDetector } from '@/utils/formDetector/FormDetector';
|
||||
import { BoolResponse as messageBoolResponse } from '@/utils/types/messaging/BoolResponse';
|
||||
|
||||
import { defineContentScript } from '#imports';
|
||||
import { createShadowRootUi } from '#imports';
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { openAutofillPopup } from '@/entrypoints/contentScript/Popup';
|
||||
|
||||
import { FormDetector } from '@/utils/formDetector/FormDetector';
|
||||
import { FormFiller } from '@/utils/formDetector/FormFiller';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
import { openAutofillPopup } from '@/entrypoints/contentScript/Popup';
|
||||
|
||||
/**
|
||||
* Global timestamp to track popup debounce time.
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import { storage } from '#imports';
|
||||
import { sendMessage } from 'webext-bridge/content-script';
|
||||
import { fillCredential } from '@/entrypoints/contentScript/Form';
|
||||
|
||||
import { filterCredentials } from '@/entrypoints/contentScript/Filter';
|
||||
import { fillCredential } from '@/entrypoints/contentScript/Form';
|
||||
|
||||
import { DISABLED_SITES_KEY, TEMPORARY_DISABLED_SITES_KEY, GLOBAL_AUTOFILL_POPUP_ENABLED_KEY, VAULT_LOCKED_DISMISS_UNTIL_KEY, LAST_CUSTOM_EMAIL_KEY, LAST_CUSTOM_USERNAME_KEY } from '@/utils/Constants';
|
||||
import { FormDetector } from '@/utils/formDetector/FormDetector';
|
||||
import { CreateIdentityGenerator } from '@/utils/shared/identity-generator';
|
||||
import { CreatePasswordGenerator, PasswordGenerator } from '@/utils/shared/password-generator';
|
||||
import { SqliteClient } from '@/utils/SqliteClient';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
import { CredentialsResponse } from '@/utils/types/messaging/CredentialsResponse';
|
||||
import { PasswordSettingsResponse } from '@/utils/types/messaging/PasswordSettingsResponse';
|
||||
import { SqliteClient } from '@/utils/SqliteClient';
|
||||
import { StringResponse } from '@/utils/types/messaging/StringResponse';
|
||||
import { FormDetector } from '@/utils/formDetector/FormDetector';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
import { DISABLED_SITES_KEY, TEMPORARY_DISABLED_SITES_KEY, GLOBAL_AUTOFILL_POPUP_ENABLED_KEY, VAULT_LOCKED_DISMISS_UNTIL_KEY, LAST_CUSTOM_EMAIL_KEY, LAST_CUSTOM_USERNAME_KEY } from '@/utils/Constants';
|
||||
|
||||
import { storage } from '#imports';
|
||||
|
||||
/**
|
||||
* WeakMap to store event listeners for popup containers
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { HashRouter as Router, Routes, Route } from 'react-router-dom';
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
|
||||
import Header from '@/entrypoints/popup/components/Layout/Header';
|
||||
import BottomNav from '@/entrypoints/popup/components/Layout/BottomNav';
|
||||
import AuthSettings from '@/entrypoints/popup/pages/AuthSettings';
|
||||
import CredentialsList from '@/entrypoints/popup/pages/CredentialsList';
|
||||
import EmailsList from '@/entrypoints/popup/pages/EmailsList';
|
||||
import LoadingSpinner from '@/entrypoints/popup/components/LoadingSpinner';
|
||||
import Home from '@/entrypoints/popup/pages/Home';
|
||||
import CredentialDetails from '@/entrypoints/popup/pages/CredentialDetails';
|
||||
import EmailDetails from '@/entrypoints/popup/pages/EmailDetails';
|
||||
import Settings from '@/entrypoints/popup/pages/Settings';
|
||||
|
||||
import GlobalStateChangeHandler from '@/entrypoints/popup/components/GlobalStateChangeHandler';
|
||||
import BottomNav from '@/entrypoints/popup/components/Layout/BottomNav';
|
||||
import Header from '@/entrypoints/popup/components/Layout/Header';
|
||||
import LoadingSpinner from '@/entrypoints/popup/components/LoadingSpinner';
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
|
||||
import AuthSettings from '@/entrypoints/popup/pages/AuthSettings';
|
||||
import CredentialDetails from '@/entrypoints/popup/pages/CredentialDetails';
|
||||
import CredentialsList from '@/entrypoints/popup/pages/CredentialsList';
|
||||
import EmailDetails from '@/entrypoints/popup/pages/EmailDetails';
|
||||
import EmailsList from '@/entrypoints/popup/pages/EmailsList';
|
||||
import Home from '@/entrypoints/popup/pages/Home';
|
||||
import Logout from '@/entrypoints/popup/pages/Logout';
|
||||
import Settings from '@/entrypoints/popup/pages/Settings';
|
||||
|
||||
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
|
||||
import '@/entrypoints/popup/style.css';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
|
||||
import SqliteClient from '@/utils/SqliteClient';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
|
||||
type CredentialCardProps = {
|
||||
credential: Credential;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React from 'react';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
|
||||
import { FormInputCopyToClipboard } from '@/entrypoints/popup/components/FormInputCopyToClipboard';
|
||||
|
||||
import { IdentityHelperUtils } from '@/utils/shared/identity-generator';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
|
||||
type AliasBlockProps = {
|
||||
credential: Credential;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import { EmailPreview } from '@/entrypoints/popup/components/EmailPreview';
|
||||
|
||||
type EmailBlockProps = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
|
||||
import SqliteClient from '@/utils/SqliteClient';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
|
||||
type HeaderBlockProps = {
|
||||
credential: Credential;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React from 'react';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
|
||||
import { FormInputCopyToClipboard } from '@/entrypoints/popup/components/FormInputCopyToClipboard';
|
||||
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
|
||||
type LoginCredentialsBlockProps = {
|
||||
credential: Credential;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { TotpCode } from '@/utils/types/TotpCode';
|
||||
import * as OTPAuth from 'otpauth';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
|
||||
import { TotpCode } from '@/utils/types/TotpCode';
|
||||
|
||||
type TotpBlockProps = {
|
||||
credentialId: string;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import HeaderBlock from './HeaderBlock';
|
||||
import EmailBlock from './EmailBlock';
|
||||
import TotpBlock from './TotpBlock';
|
||||
import LoginCredentialsBlock from './LoginCredentialsBlock';
|
||||
import AliasBlock from './AliasBlock';
|
||||
import EmailBlock from './EmailBlock';
|
||||
import HeaderBlock from './HeaderBlock';
|
||||
import LoginCredentialsBlock from './LoginCredentialsBlock';
|
||||
import NotesBlock from './NotesBlock';
|
||||
import TotpBlock from './TotpBlock';
|
||||
|
||||
export {
|
||||
HeaderBlock,
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { storage } from '#imports';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { EncryptionUtility } from '@/utils/EncryptionUtility';
|
||||
import { MailboxEmail } from '@/utils/types/webapi/MailboxEmail';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
|
||||
import { AppInfo } from '@/utils/AppInfo';
|
||||
import { EncryptionUtility } from '@/utils/EncryptionUtility';
|
||||
import type { MailboxEmail } from '@/utils/shared/models';
|
||||
|
||||
import { storage } from '#imports';
|
||||
|
||||
type EmailPreviewProps = {
|
||||
email: string;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import { ClipboardCopyService } from '@/entrypoints/popup/utils/ClipboardCopyService';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import React from 'react';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import { storage } from '#imports';
|
||||
|
||||
import { UserMenu } from '@/entrypoints/popup/components/Layout/UserMenu';
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
|
||||
import { AppInfo } from '@/utils/AppInfo';
|
||||
|
||||
import { storage } from '#imports';
|
||||
|
||||
/**
|
||||
* Header props.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { storage } from '#imports';
|
||||
|
||||
import { AppInfo } from '@/utils/AppInfo';
|
||||
|
||||
import { storage } from '#imports';
|
||||
|
||||
/**
|
||||
* Component for displaying the login server information.
|
||||
*/
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import React, { createContext, useContext, useState, useEffect, useMemo, useCallback } from 'react';
|
||||
import { storage } from '#imports';
|
||||
import { sendMessage } from 'webext-bridge/popup';
|
||||
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
|
||||
import { VAULT_LOCKED_DISMISS_UNTIL_KEY } from '@/utils/Constants';
|
||||
|
||||
import { storage } from '#imports';
|
||||
|
||||
type AuthContextType = {
|
||||
isLoggedIn: boolean;
|
||||
isInitialized: boolean;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { createContext, useContext, useState, useEffect, useCallback, useMemo } from 'react';
|
||||
import { sendMessage } from 'webext-bridge/popup';
|
||||
import SqliteClient from '@/utils/SqliteClient';
|
||||
import { VaultResponse } from '@/utils/types/webapi/VaultResponse';
|
||||
|
||||
import EncryptionUtility from '@/utils/EncryptionUtility';
|
||||
import type { VaultResponse } from '@/utils/shared/models';
|
||||
import SqliteClient from '@/utils/SqliteClient';
|
||||
import { VaultResponse as messageVaultResponse } from '@/utils/types/messaging/VaultResponse';
|
||||
|
||||
type DbContextType = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { createContext, useContext, useState, useMemo } from 'react';
|
||||
|
||||
import LoadingSpinnerFullScreen from '@/entrypoints/popup/components/LoadingSpinnerFullScreen';
|
||||
|
||||
type LoadingContextType = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { createContext, useContext, useState, useMemo, useEffect, useCallback } from 'react';
|
||||
|
||||
import { storage } from '#imports';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||
import { WebApiService } from '@/utils/WebApiService';
|
||||
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
|
||||
import { WebApiService } from '@/utils/WebApiService';
|
||||
|
||||
const WebApiContext = createContext<WebApiService | null>(null);
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
|
||||
import { AppInfo } from '@/utils/AppInfo';
|
||||
import type { VaultResponse } from '@/utils/shared/models';
|
||||
|
||||
/**
|
||||
* Utility function to ensure a minimum time has elapsed for an operation
|
||||
*/
|
||||
const withMinimumDelay = async <T>(
|
||||
operation: () => Promise<T>,
|
||||
minDelayMs: number,
|
||||
initialSync: boolean
|
||||
): Promise<T> => {
|
||||
if (!initialSync) {
|
||||
return operation();
|
||||
}
|
||||
|
||||
const startTime = Date.now();
|
||||
const result = await operation();
|
||||
const elapsedTime = Date.now() - startTime;
|
||||
|
||||
if (elapsedTime < minDelayMs) {
|
||||
await new Promise(resolve => setTimeout(resolve, minDelayMs - elapsedTime));
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
type VaultSyncOptions = {
|
||||
initialSync?: boolean;
|
||||
onSuccess?: (hasNewVault: boolean) => void;
|
||||
onError?: (error: string) => void;
|
||||
onStatus?: (message: string) => void;
|
||||
onOffline?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to sync the vault with the server.
|
||||
*/
|
||||
export const useVaultSync = () : {
|
||||
syncVault: (options?: VaultSyncOptions) => Promise<boolean>;
|
||||
} => {
|
||||
const authContext = useAuth();
|
||||
const dbContext = useDb();
|
||||
const webApi = useWebApi();
|
||||
|
||||
const syncVault = useCallback(async (options: VaultSyncOptions = {}) => {
|
||||
const { initialSync = false, onSuccess, onError, onStatus, onOffline } = options;
|
||||
|
||||
try {
|
||||
const { isLoggedIn } = await authContext.initializeAuth();
|
||||
|
||||
if (!isLoggedIn) {
|
||||
// Not authenticated, return false immediately
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check app status and vault revision
|
||||
onStatus?.('Checking vault updates');
|
||||
const statusResponse = await withMinimumDelay(
|
||||
() => webApi.getStatus(),
|
||||
300,
|
||||
initialSync
|
||||
);
|
||||
|
||||
if (statusResponse.serverVersion === '0.0.0') {
|
||||
// Server is not available, go into offline mode
|
||||
onOffline?.();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!statusResponse.clientVersionSupported) {
|
||||
const statusError = 'This version of the AliasVault mobile app is not supported by the server anymore. Please update your app to the latest version.';
|
||||
onError?.(statusError);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AppInfo.isServerVersionSupported(statusResponse.serverVersion)) {
|
||||
const statusError = 'The AliasVault server needs to be updated to a newer version in order to use this mobile app. Please contact support if you need help.';
|
||||
onError?.(statusError);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get here, it means we have a valid connection to the server.
|
||||
* TODO: browser extension does not support offline mode yet.
|
||||
* authContext.setOfflineMode(false);
|
||||
*/
|
||||
|
||||
// Compare vault revisions
|
||||
const vaultMetadata = await dbContext.getVaultMetadata();
|
||||
const vaultRevisionNumber = vaultMetadata?.vaultRevisionNumber ?? 0;
|
||||
|
||||
if (statusResponse.vaultRevision > vaultRevisionNumber) {
|
||||
onStatus?.('Syncing updated vault');
|
||||
const vaultResponseJson = await withMinimumDelay(
|
||||
() => webApi.get<VaultResponse>('Vault'),
|
||||
1000,
|
||||
initialSync
|
||||
);
|
||||
|
||||
const vaultError = webApi.validateVaultResponse(vaultResponseJson as VaultResponse);
|
||||
if (vaultError) {
|
||||
// Only logout if it's an authentication error, not a network error
|
||||
if (vaultError.includes('authentication') || vaultError.includes('unauthorized')) {
|
||||
await webApi.logout(vaultError);
|
||||
onError?.(vaultError);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: browser extension does not support offline mode yet.
|
||||
* For other errors, go into offline mode
|
||||
* authContext.setOfflineMode(true);
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await dbContext.initializeDatabase(vaultResponseJson as VaultResponse);
|
||||
onSuccess?.(true);
|
||||
return true;
|
||||
} catch {
|
||||
// Vault could not be decrypted, throw an error
|
||||
throw new Error('Vault could not be decrypted, if problem persists please logout and login again.');
|
||||
}
|
||||
}
|
||||
|
||||
await withMinimumDelay(
|
||||
() => Promise.resolve(onSuccess?.(false)),
|
||||
300,
|
||||
initialSync
|
||||
);
|
||||
return false;
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : 'Unknown error during vault sync';
|
||||
console.error('Vault sync error:', err);
|
||||
|
||||
/*
|
||||
* Check if it's a network error
|
||||
* TODO: browser extension does not support offline mode yet.
|
||||
*/
|
||||
/*
|
||||
* if (errorMessage.includes('network') || errorMessage.includes('timeout')) {
|
||||
*authContext.setOfflineMode(true);
|
||||
*return true;
|
||||
*}
|
||||
*/
|
||||
|
||||
onError?.(errorMessage);
|
||||
return false;
|
||||
}
|
||||
}, [authContext, dbContext, webApi]);
|
||||
|
||||
return { syncVault };
|
||||
};
|
||||
@@ -1,10 +1,12 @@
|
||||
import ReactDOM from 'react-dom/client';
|
||||
|
||||
import App from '@/entrypoints/popup/App';
|
||||
import { AuthProvider } from '@/entrypoints/popup/context/AuthContext';
|
||||
import { WebApiProvider } from '@/entrypoints/popup/context/WebApiContext';
|
||||
import { DbProvider } from '@/entrypoints/popup/context/DbContext';
|
||||
import { LoadingProvider } from '@/entrypoints/popup/context/LoadingContext';
|
||||
import { ThemeProvider } from '@/entrypoints/popup/context/ThemeContext';
|
||||
import { WebApiProvider } from '@/entrypoints/popup/context/WebApiContext';
|
||||
|
||||
import { setupExpandedMode } from '@/utils/ExpandedMode';
|
||||
|
||||
// Run before React initializes to ensure the popup is always a fixed width except for when explicitly expanded.
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { AppInfo } from '@/utils/AppInfo';
|
||||
import { storage } from '#imports';
|
||||
import { GLOBAL_AUTOFILL_POPUP_ENABLED_KEY, DISABLED_SITES_KEY, VAULT_LOCKED_DISMISS_UNTIL_KEY } from '@/utils/Constants';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
import { AppInfo } from '@/utils/AppInfo';
|
||||
import { GLOBAL_AUTOFILL_POPUP_ENABLED_KEY, DISABLED_SITES_KEY, VAULT_LOCKED_DISMISS_UNTIL_KEY } from '@/utils/Constants';
|
||||
|
||||
import { storage } from '#imports';
|
||||
|
||||
type ApiOption = {
|
||||
label: string;
|
||||
value: string;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
|
||||
|
||||
import {
|
||||
HeaderBlock,
|
||||
EmailBlock,
|
||||
@@ -11,6 +9,10 @@ import {
|
||||
AliasBlock,
|
||||
NotesBlock
|
||||
} from '@/entrypoints/popup/components/CredentialDetails';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
|
||||
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
|
||||
/**
|
||||
* Credential details page.
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { sendMessage } from 'webext-bridge/popup';
|
||||
|
||||
import CredentialCard from '@/entrypoints/popup/components/CredentialCard';
|
||||
import LoadingSpinner from '@/entrypoints/popup/components/LoadingSpinner';
|
||||
import ReloadButton from '@/entrypoints/popup/components/ReloadButton';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
import { VaultResponse } from '@/utils/types/webapi/VaultResponse';
|
||||
import ReloadButton from '@/entrypoints/popup/components/ReloadButton';
|
||||
import LoadingSpinner from '@/entrypoints/popup/components/LoadingSpinner';
|
||||
|
||||
import type { VaultResponse } from '@/utils/shared/models';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
|
||||
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
|
||||
import CredentialCard from '@/entrypoints/popup/components/CredentialCard';
|
||||
|
||||
/**
|
||||
* Credentials list page.
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { Email } from '@/utils/types/webapi/Email';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
|
||||
import LoadingSpinner from '@/entrypoints/popup/components/LoadingSpinner';
|
||||
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
|
||||
import EncryptionUtility from '@/utils/EncryptionUtility';
|
||||
import { Attachment } from '@/utils/types/webapi/Attachment';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
import ConversionUtility from '@/entrypoints/popup/utils/ConversionUtility';
|
||||
|
||||
import EncryptionUtility from '@/utils/EncryptionUtility';
|
||||
import type { Attachment, Email } from '@/utils/shared/models';
|
||||
|
||||
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
|
||||
|
||||
/**
|
||||
* Email details page.
|
||||
*/
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { MailboxBulkRequest, MailboxBulkResponse } from '@/utils/types/webapi/MailboxBulk';
|
||||
import { MailboxEmail } from '@/utils/types/webapi/MailboxEmail';
|
||||
|
||||
import LoadingSpinner from '@/entrypoints/popup/components/LoadingSpinner';
|
||||
import ReloadButton from '@/entrypoints/popup/components/ReloadButton';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
import LoadingSpinner from '@/entrypoints/popup/components/LoadingSpinner';
|
||||
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
|
||||
|
||||
import EncryptionUtility from '@/utils/EncryptionUtility';
|
||||
import ReloadButton from '@/entrypoints/popup/components/ReloadButton';
|
||||
import type { MailboxBulkRequest, MailboxBulkResponse, MailboxEmail } from '@/utils/shared/models';
|
||||
|
||||
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
|
||||
|
||||
/**
|
||||
* Emails list page.
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
import Unlock from '@/entrypoints/popup/pages/Unlock';
|
||||
import Login from '@/entrypoints/popup/pages/Login';
|
||||
import UnlockSuccess from '@/entrypoints/popup/pages/UnlockSuccess';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
|
||||
import Login from '@/entrypoints/popup/pages/Login';
|
||||
import Unlock from '@/entrypoints/popup/pages/Unlock';
|
||||
import UnlockSuccess from '@/entrypoints/popup/pages/UnlockSuccess';
|
||||
|
||||
/**
|
||||
* Home page that shows the correct page based on the user's authentication state.
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Buffer } from 'buffer';
|
||||
import { storage } from '#imports';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import Button from '@/entrypoints/popup/components/Button';
|
||||
import LoginServerInfo from '@/entrypoints/popup/components/LoginServerInfo';
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
import { AppInfo } from '@/utils/AppInfo';
|
||||
import Button from '@/entrypoints/popup/components/Button';
|
||||
import EncryptionUtility from '@/utils/EncryptionUtility';
|
||||
import SrpUtility from '@/entrypoints/popup/utils/SrpUtility';
|
||||
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
|
||||
import { VaultResponse } from '@/utils/types/webapi/VaultResponse';
|
||||
import { LoginResponse } from '@/utils/types/webapi/Login';
|
||||
import LoginServerInfo from '@/entrypoints/popup/components/LoginServerInfo';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
import SrpUtility from '@/entrypoints/popup/utils/SrpUtility';
|
||||
|
||||
import { AppInfo } from '@/utils/AppInfo';
|
||||
import EncryptionUtility from '@/utils/EncryptionUtility';
|
||||
import type { VaultResponse, LoginResponse } from '@/utils/shared/models';
|
||||
import { ApiAuthError } from '@/utils/types/errors/ApiAuthError';
|
||||
|
||||
import ConversionUtility from '../utils/ConversionUtility';
|
||||
|
||||
import { storage } from '#imports';
|
||||
|
||||
/**
|
||||
* Login page
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { storage } from "#imports";
|
||||
import { sendMessage } from 'webext-bridge/popup';
|
||||
import { DISABLED_SITES_KEY, GLOBAL_AUTOFILL_POPUP_ENABLED_KEY, GLOBAL_CONTEXT_MENU_ENABLED_KEY, TEMPORARY_DISABLED_SITES_KEY } from '@/utils/Constants';
|
||||
import { AppInfo } from '@/utils/AppInfo';
|
||||
|
||||
import { useTheme } from '@/entrypoints/popup/context/ThemeContext';
|
||||
|
||||
import { AppInfo } from '@/utils/AppInfo';
|
||||
import { DISABLED_SITES_KEY, GLOBAL_AUTOFILL_POPUP_ENABLED_KEY, GLOBAL_CONTEXT_MENU_ENABLED_KEY, TEMPORARY_DISABLED_SITES_KEY } from '@/utils/Constants';
|
||||
|
||||
import { storage } from "#imports";
|
||||
import { browser } from "#imports";
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import { Buffer } from 'buffer';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Buffer } from 'buffer';
|
||||
import { storage } from '#imports';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
|
||||
import Button from '@/entrypoints/popup/components/Button';
|
||||
import EncryptionUtility from '@/utils/EncryptionUtility';
|
||||
import SrpUtility from '@/entrypoints/popup/utils/SrpUtility';
|
||||
import { VaultResponse } from '@/utils/types/webapi/VaultResponse';
|
||||
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
|
||||
import { useWebApi } from '@/entrypoints/popup/context/WebApiContext';
|
||||
import SrpUtility from '@/entrypoints/popup/utils/SrpUtility';
|
||||
|
||||
import { VAULT_LOCKED_DISMISS_UNTIL_KEY } from '@/utils/Constants';
|
||||
import EncryptionUtility from '@/utils/EncryptionUtility';
|
||||
import type { VaultResponse } from '@/utils/shared/models';
|
||||
|
||||
import { storage } from '#imports';
|
||||
|
||||
/**
|
||||
* Unlock page
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import srp from 'secure-remote-password/client'
|
||||
import { WebApiService } from '@/utils/WebApiService';
|
||||
import { LoginRequest, LoginResponse } from '@/utils/types/webapi/Login';
|
||||
import { ValidateLoginRequest, ValidateLoginRequest2Fa, ValidateLoginResponse } from '@/utils/types/webapi/ValidateLogin';
|
||||
import BadRequestResponse from '@/utils/types/webapi/BadRequestResponse';
|
||||
|
||||
import type { LoginRequest, LoginResponse, ValidateLoginRequest, ValidateLoginRequest2Fa, ValidateLoginResponse, BadRequestResponse } from '@/utils/shared/models';
|
||||
import { ApiAuthError } from '@/utils/types/errors/ApiAuthError';
|
||||
import { WebApiService } from '@/utils/WebApiService';
|
||||
|
||||
/**
|
||||
* Utility class for SRP authentication operations.
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import argon2 from 'argon2-browser/dist/argon2-bundled.min.js';
|
||||
import { Email } from './types/webapi/Email';
|
||||
import { EncryptionKey } from './types/EncryptionKey';
|
||||
import { MailboxEmail } from './types/webapi/MailboxEmail';
|
||||
import { Buffer } from 'buffer';
|
||||
|
||||
import argon2 from 'argon2-browser/dist/argon2-bundled.min.js';
|
||||
|
||||
import type { Email, MailboxEmail } from '@/utils/shared/models';
|
||||
|
||||
import { EncryptionKey } from './types/EncryptionKey';
|
||||
|
||||
/**
|
||||
* Utility class for encryption operations including:
|
||||
* - Argon2Id key derivation
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import initSqlJs, { Database } from 'sql.js';
|
||||
|
||||
import { Credential } from './types/Credential';
|
||||
import { EncryptionKey } from './types/EncryptionKey';
|
||||
import { TotpCode } from './types/TotpCode';
|
||||
import { PasswordSettings } from './types/PasswordSettings';
|
||||
import { TotpCode } from './types/TotpCode';
|
||||
|
||||
/**
|
||||
* Placeholder base64 image for credentials without a logo.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { StatusResponse, VaultResponse } from '@/utils/shared/models';
|
||||
|
||||
import { AppInfo } from "./AppInfo";
|
||||
import { StatusResponse } from "./types/webapi/StatusResponse";
|
||||
import { VaultResponse } from "./types/webapi/VaultResponse";
|
||||
|
||||
import { storage } from '#imports';
|
||||
|
||||
type RequestInit = globalThis.RequestInit;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { AppInfo } from '../AppInfo';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
import { AppInfo } from '../AppInfo';
|
||||
|
||||
describe('AppInfo', () => {
|
||||
describe('isVersionSupported', () => {
|
||||
it('should support exact version match', () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FormFields } from "./types/FormFields";
|
||||
import { CombinedFieldPatterns, CombinedGenderOptionPatterns, CombinedStopWords } from "./FieldPatterns";
|
||||
import { FormFields } from "./types/FormFields";
|
||||
|
||||
/**
|
||||
* Form detector.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Credential } from "@/utils/types/Credential";
|
||||
import { FormFields } from "@/utils/formDetector/types/FormFields";
|
||||
import { CombinedDateOptionPatterns, CombinedGenderOptionPatterns } from "@/utils/formDetector/FieldPatterns";
|
||||
import { FormFields } from "@/utils/formDetector/types/FormFields";
|
||||
import { Gender, IdentityHelperUtils } from "@/utils/shared/identity-generator";
|
||||
import { Credential } from "@/utils/types/Credential";
|
||||
/**
|
||||
* Class to fill the fields of a form with the given credential.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { FormField, testField } from './TestUtils';
|
||||
|
||||
describe('FormDetector English tests', () => {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createTestDom } from './TestUtils';
|
||||
|
||||
import { FormDetector } from '../FormDetector';
|
||||
|
||||
import { createTestDom } from './TestUtils';
|
||||
|
||||
describe('FormDetector generic tests', () => {
|
||||
describe('Invalid form not detected as login form 1', () => {
|
||||
const htmlFile = 'invalid-form1.html';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
import { FormField, testField, testBirthdateFormat } from './TestUtils';
|
||||
|
||||
describe('FormDetector Dutch tests', () => {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createTestDocument } from './TestUtils';
|
||||
|
||||
import { FormDetector } from '../FormDetector';
|
||||
|
||||
import { createTestDocument } from './TestUtils';
|
||||
|
||||
describe('FormDetector.getSuggestedServiceName (English)', () => {
|
||||
it('should extract service name from title with divider and include domain', () => {
|
||||
const { document, location } = createTestDocument(
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createTestDocument } from './TestUtils';
|
||||
|
||||
import { FormDetector } from '../FormDetector';
|
||||
|
||||
import { createTestDocument } from './TestUtils';
|
||||
|
||||
describe('FormDetector.getSuggestedServiceName (Dutch)', () => {
|
||||
it('should extract service name from title with divider and include domain', () => {
|
||||
const { document, location } = createTestDocument(
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { FormFiller } from '../FormFiller';
|
||||
import { JSDOM } from 'jsdom';
|
||||
import { setupTestDOM, createMockFormFields, createMockCredential, wasTriggerCalledFor, createDateSelects } from './TestUtils';
|
||||
import { FormFields } from '../types/FormFields';
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
|
||||
import { Credential } from '../../types/Credential';
|
||||
import { FormFiller } from '../FormFiller';
|
||||
import { FormFields } from '../types/FormFields';
|
||||
|
||||
import { setupTestDOM, createMockFormFields, createMockCredential, wasTriggerCalledFor, createDateSelects } from './TestUtils';
|
||||
|
||||
const { window } = new JSDOM('<!DOCTYPE html>');
|
||||
global.HTMLSelectElement = window.HTMLSelectElement;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { FormFiller } from '../FormFiller';
|
||||
import { JSDOM } from 'jsdom';
|
||||
import { setupTestDOM, createMockFormFields, createMockCredential, wasTriggerCalledFor, createDateSelects } from './TestUtils';
|
||||
import { FormFields } from '../types/FormFields';
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
|
||||
import { Credential } from '../../types/Credential';
|
||||
import { FormFiller } from '../FormFiller';
|
||||
import { FormFields } from '../types/FormFields';
|
||||
|
||||
import { setupTestDOM, createMockFormFields, createMockCredential, wasTriggerCalledFor, createDateSelects } from './TestUtils';
|
||||
|
||||
const { window } = new JSDOM('<!DOCTYPE html>');
|
||||
global.HTMLSelectElement = window.HTMLSelectElement;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { FormFiller } from '../FormFiller';
|
||||
import { JSDOM } from 'jsdom';
|
||||
import { setupTestDOM, createMockFormFields, createMockCredential, wasTriggerCalledFor, createDateSelects } from './TestUtils';
|
||||
import { FormFields } from '../types/FormFields';
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
|
||||
import { Credential } from '../../types/Credential';
|
||||
import { FormFiller } from '../FormFiller';
|
||||
import { FormFields } from '../types/FormFields';
|
||||
|
||||
import { setupTestDOM, createMockFormFields, createMockCredential, wasTriggerCalledFor, createDateSelects } from './TestUtils';
|
||||
|
||||
const { window } = new JSDOM('<!DOCTYPE html>');
|
||||
global.HTMLSelectElement = window.HTMLSelectElement;
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { FormDetector } from '@/utils/formDetector/FormDetector';
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { it, expect, vi } from 'vitest';
|
||||
|
||||
import { JSDOM, DOMWindow } from 'jsdom';
|
||||
import { it, expect, vi } from 'vitest';
|
||||
|
||||
import { FormDetector } from '@/utils/formDetector/FormDetector';
|
||||
import { FormFields } from '@/utils/formDetector/types/FormFields';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
import { Gender } from '@/utils/shared/identity-generator';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
|
||||
export enum FormField {
|
||||
Username = 'username',
|
||||
|
||||
@@ -299,4 +299,12 @@ type VaultPasswordChangeRequest = Vault & {
|
||||
newPasswordVerifier: string;
|
||||
};
|
||||
|
||||
export type { Attachment, AuthLogModel, DeleteAccountInitiateRequest, DeleteAccountInitiateResponse, DeleteAccountRequest, Email, FaviconExtractModel, LoginRequest, LoginResponse, MailboxBulkRequest, MailboxBulkResponse, MailboxEmail, PasswordChangeInitiateResponse, RefreshToken, StatusResponse, ValidateLoginRequest, ValidateLoginRequest2Fa, ValidateLoginResponse, Vault, VaultPasswordChangeRequest, VaultPostResponse, VaultResponse };
|
||||
type BadRequestResponse = {
|
||||
type: string;
|
||||
title: string;
|
||||
status: number;
|
||||
errors: Record<string, string[]>;
|
||||
traceId: string;
|
||||
};
|
||||
|
||||
export type { Attachment, AuthLogModel, BadRequestResponse, DeleteAccountInitiateRequest, DeleteAccountInitiateResponse, DeleteAccountRequest, Email, FaviconExtractModel, LoginRequest, LoginResponse, MailboxBulkRequest, MailboxBulkResponse, MailboxEmail, PasswordChangeInitiateResponse, RefreshToken, StatusResponse, ValidateLoginRequest, ValidateLoginRequest2Fa, ValidateLoginResponse, Vault, VaultPasswordChangeRequest, VaultPostResponse, VaultResponse };
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Email attachment type.
|
||||
*/
|
||||
export type Attachment = {
|
||||
/** The ID of the attachment */
|
||||
id: number;
|
||||
|
||||
/** The ID of the email the attachment belongs to */
|
||||
emailId: number;
|
||||
|
||||
/** The filename of the attachment */
|
||||
filename: string;
|
||||
|
||||
/** The MIME type of the attachment */
|
||||
mimeType: string;
|
||||
|
||||
/** The size of the attachment in bytes */
|
||||
filesize: number;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
type BadRequestResponse = {
|
||||
type: string;
|
||||
title: string;
|
||||
status: number;
|
||||
errors: Record<string, string[]>;
|
||||
traceId: string;
|
||||
};
|
||||
|
||||
export default BadRequestResponse;
|
||||
@@ -1,51 +0,0 @@
|
||||
import { Attachment } from "./Attachment";
|
||||
|
||||
export type Email = {
|
||||
/** The body of the email message */
|
||||
messageHtml: string;
|
||||
|
||||
/** The plain text body of the email message */
|
||||
messagePlain: string;
|
||||
|
||||
/** The ID of the email */
|
||||
id: number;
|
||||
|
||||
/** The subject of the email */
|
||||
subject: string;
|
||||
|
||||
/** The display name of the sender */
|
||||
fromDisplay: string;
|
||||
|
||||
/** The domain of the sender's email address */
|
||||
fromDomain: string;
|
||||
|
||||
/** The local part of the sender's email address */
|
||||
fromLocal: string;
|
||||
|
||||
/** The domain of the recipient's email address */
|
||||
toDomain: string;
|
||||
|
||||
/** The local part of the recipient's email address */
|
||||
toLocal: string;
|
||||
|
||||
/** The date of the email */
|
||||
date: string;
|
||||
|
||||
/** The system date of the email */
|
||||
dateSystem: string;
|
||||
|
||||
/** The number of seconds ago the email was received */
|
||||
secondsAgo: number;
|
||||
|
||||
/**
|
||||
* The encrypted symmetric key which was used to encrypt the email message.
|
||||
* This key is encrypted with the public key of the user.
|
||||
*/
|
||||
encryptedSymmetricKey: string;
|
||||
|
||||
/** The public key of the user used to encrypt the symmetric key */
|
||||
encryptionKey: string;
|
||||
|
||||
/** The attachments of the email */
|
||||
attachments: Attachment[];
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Login request type.
|
||||
*/
|
||||
export type LoginRequest = {
|
||||
username: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login response type.
|
||||
*/
|
||||
export type LoginResponse = {
|
||||
salt: string;
|
||||
serverEphemeral: string;
|
||||
encryptionType: string;
|
||||
encryptionSettings: string;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { MailboxEmail } from "./MailboxEmail";
|
||||
|
||||
/**
|
||||
* Mailbox bulk request type.
|
||||
*/
|
||||
export type MailboxBulkRequest = {
|
||||
addresses: string[];
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mailbox bulk response type.
|
||||
*/
|
||||
export type MailboxBulkResponse = {
|
||||
addresses: string[];
|
||||
currentPage: number;
|
||||
pageSize: number;
|
||||
totalRecords: number;
|
||||
mails: MailboxEmail[];
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
export type MailboxEmail = {
|
||||
/** The preview of the email message */
|
||||
messagePreview: string;
|
||||
|
||||
/** Indicates whether the email has attachments */
|
||||
hasAttachments: boolean;
|
||||
|
||||
/** The ID of the email */
|
||||
id: number;
|
||||
|
||||
/** The subject of the email */
|
||||
subject: string;
|
||||
|
||||
/** The display name of the sender */
|
||||
fromDisplay: string;
|
||||
|
||||
/** The domain of the sender's email address */
|
||||
fromDomain: string;
|
||||
|
||||
/** The local part of the sender's email address */
|
||||
fromLocal: string;
|
||||
|
||||
/** The domain of the recipient's email address */
|
||||
toDomain: string;
|
||||
|
||||
/** The local part of the recipient's email address */
|
||||
toLocal: string;
|
||||
|
||||
/** The date of the email */
|
||||
date: string;
|
||||
|
||||
/** The system date of the email */
|
||||
dateSystem: string;
|
||||
|
||||
/** The number of seconds ago the email was received */
|
||||
secondsAgo: number;
|
||||
|
||||
/**
|
||||
* The encrypted symmetric key which was used to encrypt the email message.
|
||||
* This key is encrypted with the public key of the user.
|
||||
*/
|
||||
encryptedSymmetricKey: string;
|
||||
|
||||
/** The public key of the user used to encrypt the symmetric key */
|
||||
encryptionKey: string;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* Status response type.
|
||||
*/
|
||||
export type StatusResponse = {
|
||||
clientVersionSupported: boolean;
|
||||
serverVersion: string;
|
||||
vaultRevision: number;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Validate login request type.
|
||||
*/
|
||||
export type ValidateLoginRequest = {
|
||||
username: string;
|
||||
rememberMe: boolean;
|
||||
clientPublicEphemeral: string;
|
||||
clientSessionProof: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate login request type for 2FA.
|
||||
*/
|
||||
export type ValidateLoginRequest2Fa = {
|
||||
username: string;
|
||||
code2Fa: number;
|
||||
rememberMe: boolean;
|
||||
clientPublicEphemeral: string;
|
||||
clientSessionProof: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate login response type.
|
||||
*/
|
||||
export type ValidateLoginResponse = {
|
||||
requiresTwoFactor: boolean;
|
||||
token?: {
|
||||
token: string;
|
||||
refreshToken: string;
|
||||
};
|
||||
serverSessionProof: string;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* Vault type.
|
||||
*/
|
||||
export type Vault = {
|
||||
blob: string;
|
||||
createdAt: string;
|
||||
credentialsCount: number;
|
||||
currentRevisionNumber: number;
|
||||
emailAddressList: string[];
|
||||
privateEmailDomainList: string[];
|
||||
publicEmailDomainList: string[];
|
||||
encryptionPublicKey: string;
|
||||
updatedAt: string;
|
||||
username: string;
|
||||
version: string;
|
||||
client: string;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* Vault post response type returned after uploading a new vault to the server.
|
||||
*/
|
||||
export type VaultPostResponse = {
|
||||
status: number;
|
||||
newRevisionNumber: number;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Vault } from "./Vault";
|
||||
|
||||
/**
|
||||
* Vault response type.
|
||||
*/
|
||||
export type VaultResponse = {
|
||||
status: number;
|
||||
vault: Vault;
|
||||
}
|
||||
@@ -94,7 +94,44 @@ module.exports = {
|
||||
|
||||
// Import
|
||||
"import/no-unresolved": "error",
|
||||
"import/order": ["error", { "newlines-between": "always" }],
|
||||
"import/order": [
|
||||
"error",
|
||||
{
|
||||
"groups": [
|
||||
"builtin", // Node "fs", "path", etc.
|
||||
"external", // "react", "lodash", etc.
|
||||
"internal", // Aliased paths like "@/utils"
|
||||
"parent", // "../"
|
||||
"sibling", // "./"
|
||||
"index", // "./index"
|
||||
"object", // import 'foo'
|
||||
"type" // import type ...
|
||||
],
|
||||
"pathGroups": [
|
||||
{
|
||||
pattern: "@/entrypoints/**",
|
||||
group: "internal",
|
||||
position: "before"
|
||||
},
|
||||
{
|
||||
pattern: "@/utils/**",
|
||||
group: "internal",
|
||||
position: "before"
|
||||
},
|
||||
{
|
||||
pattern: "@/hooks/**",
|
||||
group: "internal",
|
||||
position: "before"
|
||||
}
|
||||
],
|
||||
"pathGroupsExcludedImportTypes": ["builtin"],
|
||||
"newlines-between": "always",
|
||||
"alphabetize": {
|
||||
order: "asc",
|
||||
caseInsensitive: true
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// JSDoc
|
||||
"jsdoc/require-jsdoc": [
|
||||
|
||||
@@ -16,3 +16,4 @@ export * from './webapi/DeleteAccountInitiate';
|
||||
export * from './webapi/DeleteAccountRequest';
|
||||
export * from './webapi/PasswordChangeInitiateResponse';
|
||||
export * from './webapi/VaultPasswordChangeRequest';
|
||||
export * from './webapi/BadRequestResponse';
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
type BadRequestResponse = {
|
||||
export type BadRequestResponse = {
|
||||
type: string;
|
||||
title: string;
|
||||
status: number;
|
||||
errors: Record<string, string[]>;
|
||||
traceId: string;
|
||||
};
|
||||
|
||||
export default BadRequestResponse;
|
||||
|
||||
Reference in New Issue
Block a user