Update password autofill to improve compatibility (#718)

This commit is contained in:
Leendert de Borst
2025-03-24 21:13:14 +01:00
committed by Leendert de Borst
parent 4f7212668e
commit ef36a08ef4
3 changed files with 60 additions and 48 deletions

View File

@@ -161,51 +161,53 @@ export function injectIcon(input: HTMLInputElement, container: HTMLElement): voi
* Trigger input events for an element to trigger form validation
* which some websites require before the "continue" button is enabled.
*/
function triggerInputEvents(element: HTMLInputElement | HTMLSelectElement) : void {
// Create an overlay div that will show the highlight effect
const overlay = document.createElement('div');
function triggerInputEvents(element: HTMLInputElement | HTMLSelectElement, animate: boolean = true) : void {
// Add keyframe animation if animation is requested
if (animate) {
// Create an overlay div that will show the highlight effect
const overlay = document.createElement('div');
/**
* Update position of the overlay.
*/
const updatePosition = () : void => {
const rect = element.getBoundingClientRect();
overlay.style.cssText = `
position: fixed;
z-index: 999999991;
pointer-events: none;
top: ${rect.top}px;
left: ${rect.left}px;
width: ${rect.width}px;
height: ${rect.height}px;
background-color: rgba(244, 149, 65, 0.3);
border-radius: ${getComputedStyle(element).borderRadius};
animation: fadeOut 1.4s ease-out forwards;
/**
* Update position of the overlay.
*/
const updatePosition = () : void => {
const rect = element.getBoundingClientRect();
overlay.style.cssText = `
position: fixed;
z-index: 999999991;
pointer-events: none;
top: ${rect.top}px;
left: ${rect.left}px;
width: ${rect.width}px;
height: ${rect.height}px;
background-color: rgba(244, 149, 65, 0.3);
border-radius: ${getComputedStyle(element).borderRadius};
animation: fadeOut 1.4s ease-out forwards;
`;
};
updatePosition();
// Add scroll event listener
window.addEventListener('scroll', updatePosition);
const style = document.createElement('style');
style.textContent = `
@keyframes fadeOut {
0% { opacity: 1; transform: scale(1.02); }
100% { opacity: 0; transform: scale(1); }
}
`;
};
document.head.appendChild(style);
document.body.appendChild(overlay);
updatePosition();
// Add scroll event listener
window.addEventListener('scroll', updatePosition);
// Add keyframe animation
const style = document.createElement('style');
style.textContent = `
@keyframes fadeOut {
0% { opacity: 1; transform: scale(1.02); }
100% { opacity: 0; transform: scale(1); }
}
`;
document.head.appendChild(style);
document.body.appendChild(overlay);
// Remove overlay and cleanup after animation
setTimeout(() => {
window.removeEventListener('scroll', updatePosition);
overlay.remove();
style.remove();
}, 1400);
// Remove overlay and cleanup after animation
setTimeout(() => {
window.removeEventListener('scroll', updatePosition);
overlay.remove();
style.remove();
}, 1400);
}
// Trigger events
element.dispatchEvent(new Event('input', { bubbles: true }));

View File

@@ -11,8 +11,13 @@ export class FormFiller {
*/
public constructor(
private readonly form: FormFields,
private readonly triggerInputEvents: (element: HTMLInputElement | HTMLSelectElement) => void
) {}
private readonly triggerInputEvents: (element: HTMLInputElement | HTMLSelectElement, animate?: boolean) => void
) {
/**
* Trigger input events.
*/
this.triggerInputEvents = (element: HTMLInputElement | HTMLSelectElement, animate = true) : void => triggerInputEvents(element, animate);
}
/**
* Fill the fields of the form with the given credential.
@@ -72,7 +77,7 @@ export class FormFiller {
/**
* Fill the password field with the given password. This uses a small delay between each character to simulate human typing.
* In the past there have been issues where Microsoft 365 login forms would clear the password field when just setting the value directly.
* Simulates actual keystroke behavior by appending characters one by one.
*
* @param field The password field to fill.
* @param password The password to fill the field with.
@@ -80,14 +85,17 @@ export class FormFiller {
private async fillPasswordField(field: HTMLInputElement, password: string): Promise<void> {
// Clear the field first
field.value = '';
this.triggerInputEvents(field);
this.triggerInputEvents(field, false);
// Type each character with a small delay
for (let i = 0; i < password.length; i++) {
field.value = password.substring(0, i + 1);
for (const char of password) {
// Append the character to the current value instead of using substring
field.value += char;
// Small random delay between 5-15ms to simulate human typing
await new Promise(resolve => setTimeout(resolve, Math.random() * 10 + 5));
}
this.triggerInputEvents(field, false);
}
/**

View File

@@ -109,3 +109,5 @@ The following websites have been known to cause issues in the past (but should b
| https://bloshing.com/inschrijven-nieuwsbrief | Popup CSS style conflicts |
| https://gamefaqs.gamespot.com/user | Popup buttons not working |
| https://news.ycombinator.com/login?goto=news | Popup and client favicon not showing due to SVG format |
| https://vault.bitwarden.com/#/login | Autofill password not detected (input not long enough), manually typing in works |
| https://login.microsoftonline.com/ | Password gets reset after autofill |