diff --git a/apps/desktop/src/auth/login/login-approval.component.ts b/apps/desktop/src/auth/login/login-approval.component.ts index 39876f2945..4bffc338b3 100644 --- a/apps/desktop/src/auth/login/login-approval.component.ts +++ b/apps/desktop/src/auth/login/login-approval.component.ts @@ -79,9 +79,10 @@ export class LoginApprovalComponent implements OnInit, OnDestroy { this.email = await await firstValueFrom( this.accountService.activeAccount$.pipe(map((a) => a?.email)), ); - this.fingerprintPhrase = ( - await this.cryptoService.getFingerprint(this.email, publicKey) - ).join("-"); + this.fingerprintPhrase = await this.authRequestService.getFingerprintPhrase( + this.email, + publicKey, + ); this.updateTimeText(); this.interval = setInterval(() => { diff --git a/libs/angular/src/auth/components/login-via-auth-request.component.ts b/libs/angular/src/auth/components/login-via-auth-request.component.ts index a89952e024..ed9ed6ef70 100644 --- a/libs/angular/src/auth/components/login-via-auth-request.component.ts +++ b/libs/angular/src/auth/components/login-via-auth-request.component.ts @@ -210,9 +210,10 @@ export class LoginViaAuthRequestComponent const derivedPublicKeyArrayBuffer = await this.cryptoFunctionService.rsaExtractPublicKey( adminAuthReqStorable.privateKey, ); - this.fingerprintPhrase = ( - await this.cryptoService.getFingerprint(this.email, derivedPublicKeyArrayBuffer) - ).join("-"); + this.fingerprintPhrase = await this.authRequestService.getFingerprintPhrase( + this.email, + derivedPublicKeyArrayBuffer, + ); // Request denied if (adminAuthReqResponse.isAnswered && !adminAuthReqResponse.requestApproved) { @@ -259,9 +260,10 @@ export class LoginViaAuthRequestComponent length: 25, }); - this.fingerprintPhrase = ( - await this.cryptoService.getFingerprint(this.email, this.authRequestKeyPair.publicKey) - ).join("-"); + this.fingerprintPhrase = await this.authRequestService.getFingerprintPhrase( + this.email, + this.authRequestKeyPair.publicKey, + ); this.authRequest = new CreateAuthRequest( this.email, diff --git a/libs/auth/src/common/abstractions/auth-request.service.abstraction.ts b/libs/auth/src/common/abstractions/auth-request.service.abstraction.ts index aa5f52a8c9..371c32e42d 100644 --- a/libs/auth/src/common/abstractions/auth-request.service.abstraction.ts +++ b/libs/auth/src/common/abstractions/auth-request.service.abstraction.ts @@ -96,4 +96,12 @@ export abstract class AuthRequestServiceAbstraction { * @remark We should only be receiving approved push notifications to prevent enumeration. */ abstract sendAuthRequestPushNotification: (notification: AuthRequestPushNotification) => void; + + /** + * Creates a dash-delimited fingerprint for use in confirming the `AuthRequest` between the requesting and approving device. + * @param email The email address of the user. + * @param publicKey The public key for the user. + * @returns The dash-delimited fingerprint phrase. + */ + abstract getFingerprintPhrase(email: string, publicKey: Uint8Array): Promise; } diff --git a/libs/auth/src/common/services/auth-request/auth-request.service.spec.ts b/libs/auth/src/common/services/auth-request/auth-request.service.spec.ts index 885856517b..14f807a770 100644 --- a/libs/auth/src/common/services/auth-request/auth-request.service.spec.ts +++ b/libs/auth/src/common/services/auth-request/auth-request.service.spec.ts @@ -27,6 +27,7 @@ describe("AuthRequestService", () => { const apiService = mock(); let mockPrivateKey: Uint8Array; + let mockPublicKey: Uint8Array; const mockUserId = Utils.newGuid() as UserId; beforeEach(() => { @@ -44,6 +45,7 @@ describe("AuthRequestService", () => { ); mockPrivateKey = new Uint8Array(64); + mockPublicKey = new Uint8Array(64); }); describe("authRequestPushNotification$", () => { @@ -262,4 +264,14 @@ describe("AuthRequestService", () => { expect(result.masterKeyHash).toEqual(mockDecryptedMasterKeyHash); }); }); + + describe("getFingerprintPhrase", () => { + it("returns the same fingerprint regardless of email casing", () => { + const email = "test@email.com"; + const emailUpperCase = email.toUpperCase(); + const phrase = sut.getFingerprintPhrase(email, mockPublicKey); + const phraseUpperCase = sut.getFingerprintPhrase(emailUpperCase, mockPublicKey); + expect(phrase).toEqual(phraseUpperCase); + }); + }); }); diff --git a/libs/auth/src/common/services/auth-request/auth-request.service.ts b/libs/auth/src/common/services/auth-request/auth-request.service.ts index 68302cae92..eefee511f8 100644 --- a/libs/auth/src/common/services/auth-request/auth-request.service.ts +++ b/libs/auth/src/common/services/auth-request/auth-request.service.ts @@ -198,4 +198,8 @@ export class AuthRequestService implements AuthRequestServiceAbstraction { this.authRequestPushNotificationSubject.next(notification.id); } } + + async getFingerprintPhrase(email: string, publicKey: Uint8Array): Promise { + return (await this.cryptoService.getFingerprint(email.toLowerCase(), publicKey)).join("-"); + } }