mirror of
https://github.com/bitwarden/browser
synced 2026-02-02 09:43:29 +00:00
Fix sign in
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { ipcRenderer } from "electron";
|
||||
|
||||
import { PublicKeyCredential } from "@bitwarden/common/auth/abstractions/webauthn/navigator-credentials.service";
|
||||
import { navigator_credentials } from "@bitwarden/desktop-napi";
|
||||
|
||||
export default {
|
||||
@@ -11,8 +12,7 @@ export default {
|
||||
}),
|
||||
navigatorCredentialsGet: (
|
||||
options: navigator_credentials.PublicKeyCredentialRequestOptions,
|
||||
): Promise<navigator_credentials.PublicKeyCredential | null> =>
|
||||
ipcRenderer.invoke("navigatorCredentials.get", options),
|
||||
): Promise<PublicKeyCredential | null> => ipcRenderer.invoke("navigatorCredentials.get", options),
|
||||
navigatorCredentialsAvailable: (): Promise<boolean> =>
|
||||
ipcRenderer.invoke("navigatorCredentials.available"),
|
||||
};
|
||||
|
||||
@@ -7,7 +7,20 @@ export class MainNavigatorCredentialsService {
|
||||
ipcMain.handle(
|
||||
"navigatorCredentials.get",
|
||||
async (_event: any, message: navigator_credentials.PublicKeyCredentialRequestOptions) => {
|
||||
return navigator_credentials.get(message);
|
||||
const result = navigator_credentials.get(message);
|
||||
return {
|
||||
authenticatorAttachment: result.authenticatorAttachment,
|
||||
id: result.id,
|
||||
rawId: result.rawId,
|
||||
response: {
|
||||
clientDataJSON: result.response.clientDataJson,
|
||||
authenticatorData: result.response.authenticatorData,
|
||||
signature: result.response.signature,
|
||||
userHandle: result.response.userHandle,
|
||||
},
|
||||
type: result.type,
|
||||
prf: result.prf,
|
||||
};
|
||||
},
|
||||
);
|
||||
ipcMain.handle("navigatorCredentials.available", async (_event: any, _message: any) => {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { navigator_credentials } from "apps/desktop/desktop_native/napi";
|
||||
|
||||
import { NavigatorCredentialsService } from "@bitwarden/common/auth/abstractions/webauthn/navigator-credentials.service";
|
||||
import {
|
||||
NavigatorCredentialsService,
|
||||
PublicKeyCredential,
|
||||
} from "@bitwarden/common/auth/abstractions/webauthn/navigator-credentials.service";
|
||||
|
||||
export class RendererNavigatorCredentialsService implements NavigatorCredentialsService {
|
||||
constructor() {}
|
||||
|
||||
async get(options: CredentialRequestOptions): Promise<Credential | null> {
|
||||
async get(options: CredentialRequestOptions): Promise<PublicKeyCredential | null> {
|
||||
return await ipc.auth.navigatorCredentialsGet({
|
||||
challenge: arrayBufferSourceToUint8Array(options.publicKey.challenge),
|
||||
timeout: options.publicKey.timeout,
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
export type AuthenticatorAssertionResponse = {
|
||||
clientDataJSON: Uint8Array;
|
||||
authenticatorData: Uint8Array;
|
||||
signature: Uint8Array;
|
||||
userHandle: Uint8Array | null;
|
||||
};
|
||||
|
||||
export type PublicKeyCredential = {
|
||||
authenticatorAttachment: string;
|
||||
id: string;
|
||||
rawId: Uint8Array;
|
||||
response: AuthenticatorAssertionResponse;
|
||||
type: string;
|
||||
prf?: Uint8Array;
|
||||
};
|
||||
|
||||
export abstract class NavigatorCredentialsService {
|
||||
abstract get(options: CredentialRequestOptions): Promise<Credential | null>;
|
||||
abstract get(options: CredentialRequestOptions): Promise<PublicKeyCredential | null>;
|
||||
abstract available(): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { ClientType } from "@bitwarden/client-type";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
import { NavigatorCredentialsService } from "../../abstractions/webauthn/navigator-credentials.service";
|
||||
import {
|
||||
NavigatorCredentialsService,
|
||||
PublicKeyCredential as CustomPublicKeyCredential,
|
||||
} from "../../abstractions/webauthn/navigator-credentials.service";
|
||||
|
||||
export class DefaultNavigatorCredentialsService implements NavigatorCredentialsService {
|
||||
private navigatorCredentials: CredentialsContainer;
|
||||
@@ -13,11 +16,36 @@ export class DefaultNavigatorCredentialsService implements NavigatorCredentialsS
|
||||
this.navigatorCredentials = this.window.navigator.credentials;
|
||||
}
|
||||
|
||||
async get(options: CredentialRequestOptions): Promise<Credential | null> {
|
||||
return await this.navigatorCredentials.get(options);
|
||||
async get(options: CredentialRequestOptions): Promise<CustomPublicKeyCredential | null> {
|
||||
const result: PublicKeyCredential = (await this.navigatorCredentials.get(
|
||||
options,
|
||||
)) as PublicKeyCredential;
|
||||
const response: AuthenticatorAssertionResponse =
|
||||
result.response as AuthenticatorAssertionResponse;
|
||||
return {
|
||||
authenticatorAttachment: result.authenticatorAttachment,
|
||||
id: result.id,
|
||||
rawId: new Uint8Array(result.rawId),
|
||||
response: {
|
||||
clientDataJSON: new Uint8Array(response.clientDataJSON),
|
||||
authenticatorData: new Uint8Array(response.authenticatorData),
|
||||
signature: new Uint8Array(response.signature),
|
||||
userHandle: response.userHandle ? new Uint8Array(response.userHandle) : null,
|
||||
},
|
||||
type: result.type,
|
||||
prf: bufferSourceToUint8Array(result.getClientExtensionResults().prf?.results?.first),
|
||||
};
|
||||
}
|
||||
|
||||
async available(): Promise<boolean> {
|
||||
return this.platformUtilsService.getClientType() === ClientType.Web;
|
||||
}
|
||||
}
|
||||
|
||||
function bufferSourceToUint8Array(source: BufferSource): Uint8Array {
|
||||
if (source instanceof ArrayBuffer) {
|
||||
return new Uint8Array(source);
|
||||
} else {
|
||||
return new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// @ts-strict-ignore
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
import { PublicKeyCredential } from "@bitwarden/common/auth/abstractions/webauthn/navigator-credentials.service";
|
||||
|
||||
import { Utils } from "../../../../platform/misc/utils";
|
||||
|
||||
import { WebAuthnLoginResponseRequest } from "./webauthn-login-response.request";
|
||||
@@ -20,15 +22,15 @@ export class WebAuthnLoginAssertionResponseRequest extends WebAuthnLoginResponse
|
||||
constructor(credential: PublicKeyCredential) {
|
||||
super(credential);
|
||||
|
||||
if (!(credential.response instanceof AuthenticatorAssertionResponse)) {
|
||||
throw new Error("Invalid authenticator response");
|
||||
}
|
||||
|
||||
this.response = {
|
||||
authenticatorData: Utils.fromBufferToUrlB64(credential.response.authenticatorData),
|
||||
signature: Utils.fromBufferToUrlB64(credential.response.signature),
|
||||
clientDataJSON: Utils.fromBufferToUrlB64(credential.response.clientDataJSON),
|
||||
userHandle: Utils.fromBufferToUrlB64(credential.response.userHandle),
|
||||
authenticatorData: Utils.fromBufferToUrlB64(
|
||||
credential.response.authenticatorData.buffer as ArrayBuffer,
|
||||
),
|
||||
signature: Utils.fromBufferToUrlB64(credential.response.signature.buffer as ArrayBuffer),
|
||||
clientDataJSON: Utils.fromBufferToUrlB64(
|
||||
credential.response.clientDataJSON.buffer as ArrayBuffer,
|
||||
),
|
||||
userHandle: Utils.fromBufferToUrlB64(credential.response.userHandle.buffer as ArrayBuffer),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { PublicKeyCredential } from "@bitwarden/common/auth/abstractions/webauthn/navigator-credentials.service";
|
||||
|
||||
import { Utils } from "../../../../platform/misc/utils";
|
||||
|
||||
export abstract class WebAuthnLoginResponseRequest {
|
||||
@@ -8,7 +10,7 @@ export abstract class WebAuthnLoginResponseRequest {
|
||||
|
||||
constructor(credential: PublicKeyCredential) {
|
||||
this.id = credential.id;
|
||||
this.rawId = Utils.fromBufferToUrlB64(credential.rawId);
|
||||
this.rawId = Utils.fromBufferToUrlB64(credential.rawId.buffer as ArrayBuffer);
|
||||
this.type = credential.type;
|
||||
|
||||
// WARNING: do not add PRF information here by mapping
|
||||
|
||||
@@ -43,15 +43,13 @@ export class WebAuthnLoginService implements WebAuthnLoginServiceAbstraction {
|
||||
|
||||
try {
|
||||
const response = await this.navigatorCredentialsService.get(nativeOptions);
|
||||
if (!(response instanceof PublicKeyCredential)) {
|
||||
return undefined;
|
||||
}
|
||||
// TODO: Remove `any` when typescript typings add support for PRF
|
||||
const prfResult = (response.getClientExtensionResults() as any).prf?.results?.first;
|
||||
const prfResult = response.prf;
|
||||
let symmetricPrfKey: PrfKey | undefined;
|
||||
if (prfResult != undefined) {
|
||||
symmetricPrfKey =
|
||||
await this.webAuthnLoginPrfKeyService.createSymmetricKeyFromPrf(prfResult);
|
||||
symmetricPrfKey = await this.webAuthnLoginPrfKeyService.createSymmetricKeyFromPrf(
|
||||
prfResult.buffer as ArrayBuffer,
|
||||
);
|
||||
}
|
||||
|
||||
const deviceResponse = new WebAuthnLoginAssertionResponseRequest(response);
|
||||
|
||||
Reference in New Issue
Block a user