mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-05-10 16:27:59 -04:00
Add excluded field definitions for settings related screens, update logic (#1935)
This commit is contained in:
committed by
Leendert de Borst
parent
e7251775eb
commit
59dde0230d
@@ -109,12 +109,15 @@ export const EnglishEmailVerificationPatterns: EmailVerificationPatterns = {
|
||||
|
||||
/**
|
||||
* English field exclusion patterns. These patterns identify fields that should NOT trigger autofill,
|
||||
* such as search boxes and filters. These are commonly found in admin panels,
|
||||
* data tables, and navigation areas where autofill would be inappropriate.
|
||||
* such as search boxes, filters, and configuration fields. These are commonly found in admin panels,
|
||||
* data tables, settings pages, and navigation areas where autofill would be inappropriate.
|
||||
*/
|
||||
export const EnglishFieldExclusionPatterns: FieldExclusionPatterns = [
|
||||
// Search and filter fields
|
||||
'search', 'find', 'lookup', 'searchbox', 'search-box', 'searchfield', 'search-field', 'searchinput', 'search-input', 'searchquery', 'search-query',
|
||||
'filter', 'filterable', 'filterinput', 'filter-input', 'filterfield', 'filter-field', 'filterbox', 'filter-box'
|
||||
'filter', 'filterable', 'filterinput', 'filter-input', 'filterfield', 'filter-field', 'filterbox', 'filter-box',
|
||||
// Settings and configuration fields
|
||||
'setting', 'settings', 'config', 'configuration', 'timeout', 'duration', 'interval', 'refresh', 'access'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -179,8 +182,11 @@ export const DutchFieldPatterns: FieldPatterns = {
|
||||
* Dutch field exclusion patterns. These patterns identify fields that should NOT trigger autofill.
|
||||
*/
|
||||
export const DutchFieldExclusionPatterns: FieldExclusionPatterns = [
|
||||
// Search and filter fields
|
||||
'zoeken', 'zoek', 'zoekveld', 'zoek-veld', 'zoekinput', 'zoek-input', 'zoekbox', 'zoek-box',
|
||||
'filter', 'filteren', 'filterveld', 'filter-veld', 'filterinput', 'filter-input'
|
||||
'filter', 'filteren', 'filterveld', 'filter-veld', 'filterinput', 'filter-input',
|
||||
// Settings and configuration fields
|
||||
'instelling', 'instellingen', 'configuratie', 'timeout', 'interval',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -211,7 +211,36 @@ export class FormDetector {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an input field matches exclusion patterns (search, filter, query fields).
|
||||
* Check if a pattern matches as a whole word or compound word in the given text.
|
||||
* Uses word boundaries to avoid false positives.
|
||||
*
|
||||
* Examples:
|
||||
* - "search" matches: "search", "user-search", "searchBox", "search_input"
|
||||
* - "search" doesn't match: "research", "searchable" (part of another word)
|
||||
*
|
||||
* @param text - The text to search in (lowercase).
|
||||
* @param pattern - The pattern to search for (lowercase).
|
||||
* @returns True if the pattern matches as a whole word/compound word.
|
||||
*/
|
||||
private matchesWordBoundary(text: string, pattern: string): boolean {
|
||||
/*
|
||||
* Word boundaries: start of string, space, hyphen, underscore, or transition from lowercase to uppercase
|
||||
* Pattern must be:
|
||||
* - At the start: "search", "searchbox", "search-box", "search_box"
|
||||
* - In the middle: "user-search", "data_search"
|
||||
* - At the end: "quick-search"
|
||||
* But NOT within another word: "research" (re-search), "birthdate" (date)
|
||||
*/
|
||||
const wordBoundaryPattern = new RegExp(
|
||||
`(^|[\\s\\-_]|(?<=[a-z])(?=[A-Z]))${pattern}($|[\\s\\-_]|(?<=[a-z])(?=[A-Z]))`,
|
||||
'i'
|
||||
);
|
||||
|
||||
return wordBoundaryPattern.test(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an input field matches exclusion patterns (search, filter fields).
|
||||
* These fields should not trigger autofill even if they match other patterns.
|
||||
* Uses whole-word matching to avoid false positives (e.g., "date" shouldn't match "birthdate").
|
||||
* @param input - The input element to check.
|
||||
@@ -246,22 +275,7 @@ export class FormDetector {
|
||||
*/
|
||||
for (const attr of attributesToCheck) {
|
||||
for (const pattern of allExclusionPatterns) {
|
||||
/*
|
||||
* Check for whole-word matches or compound word matches (search-box, searchInput, etc.)
|
||||
* Pattern must be:
|
||||
* - At the start: "search", "searchbox", "search-box", "search_box"
|
||||
* - In the middle: "user-search", "data_search"
|
||||
* - At the end: "quick-search"
|
||||
* But NOT within another word: "research" (re-search), "birthdate" (date)
|
||||
*
|
||||
* Word boundaries: start of string, space, hyphen, underscore, or transition from lowercase to uppercase
|
||||
*/
|
||||
const wordBoundaryPattern = new RegExp(
|
||||
`(^|[\\s\\-_]|(?<=[a-z])(?=[A-Z]))${pattern}($|[\\s\\-_]|(?<=[a-z])(?=[A-Z]))`,
|
||||
'i'
|
||||
);
|
||||
|
||||
if (wordBoundaryPattern.test(attr)) {
|
||||
if (this.matchesWordBoundary(attr, pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,34 @@ describe('FormDetector - Field Exclusion Patterns', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Real-world scenario: Settings page with token fields', () => {
|
||||
const htmlFile = 'exclusion-settings-tokens.html';
|
||||
|
||||
it('should not trigger TOTP autofill on refresh token lifetime field', () => {
|
||||
const dom = createTestDom(htmlFile);
|
||||
const document = dom.window.document;
|
||||
|
||||
const tokenInput = document.getElementById('refreshTokenShort');
|
||||
const formDetector = new FormDetector(document, tokenInput as HTMLElement);
|
||||
|
||||
// Should not detect as TOTP form (token fields in settings are not TOTP codes)
|
||||
expect(formDetector.containsLoginForm()).toBe(false);
|
||||
expect(formDetector.getDetectedFieldType()).toBeNull();
|
||||
});
|
||||
|
||||
it('should not trigger TOTP autofill on access token lifetime field', () => {
|
||||
const dom = createTestDom(htmlFile);
|
||||
const document = dom.window.document;
|
||||
|
||||
const tokenInput = document.getElementById('accessTokenLifetime');
|
||||
const formDetector = new FormDetector(document, tokenInput as HTMLElement);
|
||||
|
||||
// Should not detect as TOTP form
|
||||
expect(formDetector.containsLoginForm()).toBe(false);
|
||||
expect(formDetector.getDetectedFieldType()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Exclusion patterns should not affect legitimate login fields', () => {
|
||||
const htmlFile = 'exclusion-legitimate-login.html';
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Admin Settings - Token Configuration</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Settings page with token lifetime fields that should NOT trigger TOTP autofill -->
|
||||
<div class="settings-panel">
|
||||
<h1>Authentication Settings</h1>
|
||||
|
||||
<!-- Refresh Token Lifetime Field (should NOT trigger TOTP) -->
|
||||
<div>
|
||||
<label for="refreshTokenShort" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
||||
Short Refresh Token Lifetime (hours)
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id="refreshTokenShort"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
||||
autocomplete="off">
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
Determines how long the user stays logged in after inactivity. Used when "Remember me" is not checked during login.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Access Token Lifetime Field (should NOT trigger TOTP) -->
|
||||
<div>
|
||||
<label for="accessTokenLifetime" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
||||
Access Token Lifetime (minutes)
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id="accessTokenLifetime"
|
||||
name="accessToken"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg"
|
||||
autocomplete="off">
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
JWT token duration for API requests.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Session Timeout Field (should NOT trigger TOTP) -->
|
||||
<div>
|
||||
<label for="sessionTimeout" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
||||
Session Timeout (minutes)
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id="sessionTimeout"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg"
|
||||
autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user