diff --git a/apps/desktop/desktop_native/objc/src/native/autofill/commands/sync.m b/apps/desktop/desktop_native/objc/src/native/autofill/commands/sync.m index 2580c2c8a6f..30c8c1d8d59 100644 --- a/apps/desktop/desktop_native/objc/src/native/autofill/commands/sync.m +++ b/apps/desktop/desktop_native/objc/src/native/autofill/commands/sync.m @@ -38,6 +38,9 @@ void runSync(void* context, NSDictionary *params) { [mappedCredentials addObject:passwordIdentity]; } else if (@available(macos 14, *)) { + // Fido2CredentialView uses `userName` (camelCase) while Login uses `username`. + // This is intentional. Fido2 fields are flattened from the FIDO2 spec's nested structure + // (user.name -> userName, rp.id -> rpId) to maintain a clear distinction between these fields. if ([type isEqualToString:@"fido2"]) { NSString *cipherId = credential[@"cipherId"]; NSString *rpId = credential[@"rpId"]; @@ -78,4 +81,4 @@ void runSync(void* context, NSDictionary *params) { _return(context, _success(@{@"added": @([mappedCredentials count])})); }]; -} \ No newline at end of file +} diff --git a/apps/desktop/src/autofill/modal/credentials/fido2-create.component.ts b/apps/desktop/src/autofill/modal/credentials/fido2-create.component.ts index e3e0fba73fa..f25fcc40f35 100644 --- a/apps/desktop/src/autofill/modal/credentials/fido2-create.component.ts +++ b/apps/desktop/src/autofill/modal/credentials/fido2-create.component.ts @@ -1,7 +1,7 @@ import { CommonModule } from "@angular/common"; import { Component, OnInit, OnDestroy } from "@angular/core"; import { RouterModule, Router } from "@angular/router"; -import { combineLatest, map, Observable, switchMap } from "rxjs"; +import { combineLatest, map, Observable, Subject, switchMap } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { BitwardenShield, NoResults } from "@bitwarden/assets/svg"; @@ -54,6 +54,7 @@ import { export class Fido2CreateComponent implements OnInit, OnDestroy { session?: DesktopFido2UserInterfaceSession = null; ciphers$: Observable; + private destroy$ = new Subject(); readonly Icons = { BitwardenShield, NoResults }; private get DIALOG_MESSAGES() { @@ -96,17 +97,18 @@ export class Fido2CreateComponent implements OnInit, OnDestroy { async ngOnInit(): Promise { this.session = this.fido2UserInterfaceService.getCurrentSession(); - const rpid = await this.session?.getRpId(); - if (!this.session) { + if (this.session) { + const rpid = await this.session.getRpId(); + this.initializeCiphersObservable(rpid); + } else { await this.showErrorDialog(this.DIALOG_MESSAGES.unableToSavePasskey); - return; } - - this.initializeCiphersObservable(rpid); } async ngOnDestroy(): Promise { + this.destroy$.next(); + this.destroy$.complete(); await this.closeModal(); } diff --git a/apps/desktop/src/autofill/services/desktop-autofill.service.ts b/apps/desktop/src/autofill/services/desktop-autofill.service.ts index c2f81252145..29ecb83f3a1 100644 --- a/apps/desktop/src/autofill/services/desktop-autofill.service.ts +++ b/apps/desktop/src/autofill/services/desktop-autofill.service.ts @@ -43,6 +43,7 @@ import { NativeAutofillPasswordCredential, NativeAutofillSyncCommand, } from "../../platform/main/autofill/sync.command"; +import { isMac } from "../../utils"; import type { NativeWindowObject } from "./desktop-fido2-user-interface.service"; @@ -444,8 +445,10 @@ export class DesktopAutofillService implements OnDestroy { function normalizePosition(position: { x: number; y: number }): { x: number; y: number } { // If macOS, the position we're sending is too far left. // Add 100 pixels to the x-coordinate to offset the native OS dialog positioning. + const xPostionOffset = isMac() ? 100 : 0; // Offset for native dialog positioning + return { - x: Math.round(position.x + 100), // Offset for native dialog positioning + x: Math.round(position.x + xPostionOffset), y: Math.round(position.y), }; }