mirror of
https://github.com/bitwarden/browser
synced 2025-12-22 03:03:43 +00:00
* Update unix biometrics for desktop biometrics rework * Implement polkit policy setup * Enable browser integration on Linux * Remove polkit policy file * Undo change to messages.json * Fix biometrics setup, implement missing functions * Implement osSupportsBiometrics * Fix polkit settings message * Remove unwraps in biometrics unix rust module * Force password reprompt on start on linux with biometrics * Merge branch 'main' into feature/unix-biometrics * Allow browser extension to be unlocked on Linux via Polkit * Implement availability check * Cleanup * Add auto-setup, manual setup, setup detection and change localized prompts * Implement missing methods * Add i18n to polkit message * Implement missing method * Small cleanup * Update polkit consent message * Fix unlock and print errors on failed biometrics * Add dependencies to core crate * Fix reference and update polkit policy * Remove async-trait * Add tsdoc * Add comment about auto setup * Delete unused init * Update help link * Remove additional settings for polkit * Add availability-check to passwords implementation on linux * Add availability test * Add availability check to libsecret * Expose availability check in napi crate * Update d.ts * Update osSupportsBiometric check to detect libsecret presence * Improve secret service detection * Add client half to Linux biometrics * Fix windows build * Remove unencrypted key handling for biometric key * Move rng to rust, align linux bio implementation with windows * Consolidate elevated commands into one * Disable snap support in linux biometrics --------- Co-authored-by: DigitallyRefined <129616584+DigitallyRefined@users.noreply.github.com>
194 lines
6.6 KiB
TypeScript
194 lines
6.6 KiB
TypeScript
import { ipcRenderer } from "electron";
|
|
|
|
import { DeviceType } from "@bitwarden/common/enums";
|
|
import { ThemeType, KeySuffixOptions, LogLevelType } from "@bitwarden/common/platform/enums";
|
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
|
|
|
import {
|
|
EncryptedMessageResponse,
|
|
LegacyMessageWrapper,
|
|
Message,
|
|
UnencryptedMessageResponse,
|
|
} from "../models/native-messaging";
|
|
import { BiometricMessage, BiometricAction } from "../types/biometric-message";
|
|
import { isDev, isFlatpak, isMacAppStore, isSnapStore, isWindowsStore } from "../utils";
|
|
|
|
import { ClipboardWriteMessage } from "./types/clipboard";
|
|
|
|
const storage = {
|
|
get: <T>(key: string): Promise<T> => ipcRenderer.invoke("storageService", { action: "get", key }),
|
|
has: (key: string): Promise<boolean> =>
|
|
ipcRenderer.invoke("storageService", { action: "has", key }),
|
|
save: (key: string, obj: any): Promise<void> =>
|
|
ipcRenderer.invoke("storageService", { action: "save", key, obj }),
|
|
remove: (key: string): Promise<void> =>
|
|
ipcRenderer.invoke("storageService", { action: "remove", key }),
|
|
};
|
|
|
|
const passwords = {
|
|
get: (key: string, keySuffix: string): Promise<string> =>
|
|
ipcRenderer.invoke("keytar", { action: "getPassword", key, keySuffix }),
|
|
has: (key: string, keySuffix: string): Promise<boolean> =>
|
|
ipcRenderer.invoke("keytar", { action: "hasPassword", key, keySuffix }),
|
|
set: (key: string, keySuffix: string, value: string): Promise<void> =>
|
|
ipcRenderer.invoke("keytar", { action: "setPassword", key, keySuffix, value }),
|
|
delete: (key: string, keySuffix: string): Promise<void> =>
|
|
ipcRenderer.invoke("keytar", { action: "deletePassword", key, keySuffix }),
|
|
};
|
|
|
|
const biometric = {
|
|
enabled: (userId: string): Promise<boolean> =>
|
|
ipcRenderer.invoke("biometric", {
|
|
action: BiometricAction.EnabledForUser,
|
|
key: `${userId}_user_biometric`,
|
|
keySuffix: KeySuffixOptions.Biometric,
|
|
userId: userId,
|
|
} satisfies BiometricMessage),
|
|
osSupported: (): Promise<boolean> =>
|
|
ipcRenderer.invoke("biometric", {
|
|
action: BiometricAction.OsSupported,
|
|
} satisfies BiometricMessage),
|
|
biometricsNeedsSetup: (): Promise<boolean> =>
|
|
ipcRenderer.invoke("biometric", {
|
|
action: BiometricAction.NeedsSetup,
|
|
} satisfies BiometricMessage),
|
|
biometricsSetup: (): Promise<void> =>
|
|
ipcRenderer.invoke("biometric", {
|
|
action: BiometricAction.Setup,
|
|
} satisfies BiometricMessage),
|
|
biometricsCanAutoSetup: (): Promise<boolean> =>
|
|
ipcRenderer.invoke("biometric", {
|
|
action: BiometricAction.CanAutoSetup,
|
|
} satisfies BiometricMessage),
|
|
authenticate: (): Promise<boolean> =>
|
|
ipcRenderer.invoke("biometric", {
|
|
action: BiometricAction.Authenticate,
|
|
} satisfies BiometricMessage),
|
|
};
|
|
|
|
const clipboard = {
|
|
read: (): Promise<string> => ipcRenderer.invoke("clipboard.read"),
|
|
write: (message: ClipboardWriteMessage) => ipcRenderer.invoke("clipboard.write", message),
|
|
};
|
|
|
|
const powermonitor = {
|
|
isLockMonitorAvailable: (): Promise<boolean> =>
|
|
ipcRenderer.invoke("powermonitor.isLockMonitorAvailable"),
|
|
};
|
|
|
|
const nativeMessaging = {
|
|
sendReply: (message: EncryptedMessageResponse | UnencryptedMessageResponse) => {
|
|
ipcRenderer.send("nativeMessagingReply", message);
|
|
},
|
|
sendMessage: (message: {
|
|
appId: string;
|
|
command?: string;
|
|
sharedSecret?: string;
|
|
message?: EncString;
|
|
}) => {
|
|
ipcRenderer.send("nativeMessagingReply", message);
|
|
},
|
|
onMessage: (callback: (message: LegacyMessageWrapper | Message) => void) => {
|
|
ipcRenderer.on("nativeMessaging", (_event, message) => callback(message));
|
|
},
|
|
|
|
manifests: {
|
|
generate: (create: boolean): Promise<Error | null> =>
|
|
ipcRenderer.invoke("nativeMessaging.manifests", { create }),
|
|
generateDuckDuckGo: (create: boolean): Promise<Error | null> =>
|
|
ipcRenderer.invoke("nativeMessaging.ddgManifests", { create }),
|
|
},
|
|
};
|
|
|
|
const crypto = {
|
|
argon2: (
|
|
password: string | Uint8Array,
|
|
salt: string | Uint8Array,
|
|
iterations: number,
|
|
memory: number,
|
|
parallelism: number,
|
|
): Promise<Uint8Array> =>
|
|
ipcRenderer.invoke("crypto.argon2", { password, salt, iterations, memory, parallelism }),
|
|
};
|
|
|
|
const ephemeralStore = {
|
|
setEphemeralValue: (key: string, value: string): Promise<void> =>
|
|
ipcRenderer.invoke("setEphemeralValue", { key, value }),
|
|
getEphemeralValue: (key: string): Promise<string> => ipcRenderer.invoke("getEphemeralValue", key),
|
|
removeEphemeralValue: (key: string): Promise<void> =>
|
|
ipcRenderer.invoke("deleteEphemeralValue", key),
|
|
};
|
|
|
|
export default {
|
|
versions: {
|
|
app: (): Promise<string> => ipcRenderer.invoke("appVersion"),
|
|
},
|
|
deviceType: deviceType(),
|
|
isDev: isDev(),
|
|
isMacAppStore: isMacAppStore(),
|
|
isWindowsStore: isWindowsStore(),
|
|
isFlatpak: isFlatpak(),
|
|
isSnapStore: isSnapStore(),
|
|
reloadProcess: () => ipcRenderer.send("reload-process"),
|
|
log: (level: LogLevelType, message?: any, ...optionalParams: any[]) =>
|
|
ipcRenderer.invoke("ipc.log", { level, message, optionalParams }),
|
|
|
|
openContextMenu: (
|
|
menu: {
|
|
label?: string;
|
|
type?: "normal" | "separator" | "submenu" | "checkbox" | "radio";
|
|
}[],
|
|
): Promise<number> => ipcRenderer.invoke("openContextMenu", { menu }),
|
|
|
|
getSystemTheme: (): Promise<ThemeType> => ipcRenderer.invoke("systemTheme"),
|
|
onSystemThemeUpdated: (callback: (theme: ThemeType) => void) => {
|
|
ipcRenderer.on("systemThemeUpdated", (_event, theme: ThemeType) => callback(theme));
|
|
},
|
|
|
|
isWindowVisible: (): Promise<boolean> => ipcRenderer.invoke("windowVisible"),
|
|
|
|
getLanguageFile: (formattedLocale: string): Promise<object> =>
|
|
ipcRenderer.invoke("getLanguageFile", formattedLocale),
|
|
|
|
sendMessage: (message: { command: string } & any) =>
|
|
ipcRenderer.send("messagingService", message),
|
|
onMessage: {
|
|
addListener: (callback: (message: { command: string } & any) => void) => {
|
|
ipcRenderer.addListener("messagingService", (_event, message: any) => {
|
|
if (message.command) {
|
|
callback(message);
|
|
}
|
|
});
|
|
},
|
|
removeListener: (callback: (message: { command: string } & any) => void) => {
|
|
ipcRenderer.removeListener("messagingService", (_event, message: any) => {
|
|
if (message.command) {
|
|
callback(message);
|
|
}
|
|
});
|
|
},
|
|
},
|
|
|
|
launchUri: (uri: string) => ipcRenderer.invoke("launchUri", uri),
|
|
|
|
storage,
|
|
passwords,
|
|
biometric,
|
|
clipboard,
|
|
powermonitor,
|
|
nativeMessaging,
|
|
crypto,
|
|
ephemeralStore,
|
|
};
|
|
|
|
function deviceType(): DeviceType {
|
|
switch (process.platform) {
|
|
case "win32":
|
|
return DeviceType.WindowsDesktop;
|
|
case "darwin":
|
|
return DeviceType.MacOsDesktop;
|
|
default:
|
|
return DeviceType.LinuxDesktop;
|
|
}
|
|
}
|