mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 00:03:56 +00:00
[BEEEP][PM-14388] Better dev experience on desktop-browser IPC (#11822)
This commit is contained in:
@@ -31,7 +31,7 @@ pub fn path(name: &str) -> std::path::PathBuf {
|
|||||||
format!(r"\\.\pipe\{hash_b64}.app.{name}").into()
|
format!(r"\\.\pipe\{hash_b64}.app.{name}").into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(all(target_os = "macos", not(debug_assertions)))]
|
||||||
{
|
{
|
||||||
let mut home = dirs::home_dir().unwrap();
|
let mut home = dirs::home_dir().unwrap();
|
||||||
|
|
||||||
@@ -53,6 +53,13 @@ pub fn path(name: &str) -> std::path::PathBuf {
|
|||||||
tmp.join(format!("app.{name}"))
|
tmp.join(format!("app.{name}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "macos", debug_assertions))]
|
||||||
|
{
|
||||||
|
// When running in debug mode, we use the tmp dir because the app is not sandboxed
|
||||||
|
let dir = std::env::temp_dir();
|
||||||
|
dir.join(format!("app.{name}"))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
// On Linux, we use the user's cache directory.
|
// On Linux, we use the user's cache directory.
|
||||||
|
|||||||
@@ -626,7 +626,8 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
|||||||
async saveBrowserIntegration() {
|
async saveBrowserIntegration() {
|
||||||
if (
|
if (
|
||||||
ipc.platform.deviceType === DeviceType.MacOsDesktop &&
|
ipc.platform.deviceType === DeviceType.MacOsDesktop &&
|
||||||
!this.platformUtilsService.isMacAppStore()
|
!this.platformUtilsService.isMacAppStore() &&
|
||||||
|
!ipc.platform.isDev
|
||||||
) {
|
) {
|
||||||
await this.dialogService.openSimpleDialog({
|
await this.dialogService.openSimpleDialog({
|
||||||
title: { key: "browserIntegrationUnsupportedTitle" },
|
title: { key: "browserIntegrationUnsupportedTitle" },
|
||||||
|
|||||||
@@ -132,18 +132,7 @@ export class NativeMessagingMain {
|
|||||||
};
|
};
|
||||||
const chromeJson = {
|
const chromeJson = {
|
||||||
...baseJson,
|
...baseJson,
|
||||||
...{
|
allowed_origins: await this.loadChromeIds(),
|
||||||
allowed_origins: [
|
|
||||||
// Chrome extension
|
|
||||||
"chrome-extension://nngceckbapebfimnlniiiahkandclblb/",
|
|
||||||
// Chrome beta extension
|
|
||||||
"chrome-extension://hccnnhgbibccigepcmlgppchkpfdophk/",
|
|
||||||
// Edge extension
|
|
||||||
"chrome-extension://jbkfoedolllekgbhcbcoahefnbanhhlh/",
|
|
||||||
// Opera extension
|
|
||||||
"chrome-extension://ccnckbpmaceehanjmeomladnmlffdjgn/",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
@@ -180,35 +169,26 @@ export class NativeMessagingMain {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "linux":
|
case "linux": {
|
||||||
if (existsSync(`${this.homedir()}/.mozilla/`)) {
|
for (const [key, value] of Object.entries(this.getLinuxNMHS())) {
|
||||||
await this.writeManifest(
|
if (existsSync(value)) {
|
||||||
`${this.homedir()}/.mozilla/native-messaging-hosts/com.8bit.bitwarden.json`,
|
if (key === "Firefox") {
|
||||||
firefoxJson,
|
await this.writeManifest(
|
||||||
);
|
path.join(value, "native-messaging-hosts", "com.8bit.bitwarden.json"),
|
||||||
}
|
firefoxJson,
|
||||||
|
);
|
||||||
if (existsSync(`${this.homedir()}/.config/google-chrome/`)) {
|
} else {
|
||||||
await this.writeManifest(
|
await this.writeManifest(
|
||||||
`${this.homedir()}/.config/google-chrome/NativeMessagingHosts/com.8bit.bitwarden.json`,
|
path.join(value, "NativeMessagingHosts", "com.8bit.bitwarden.json"),
|
||||||
chromeJson,
|
chromeJson,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if (existsSync(`${this.homedir()}/.config/microsoft-edge/`)) {
|
this.logService.warning(`${key} not found, skipping.`);
|
||||||
await this.writeManifest(
|
}
|
||||||
`${this.homedir()}/.config/microsoft-edge/NativeMessagingHosts/com.8bit.bitwarden.json`,
|
|
||||||
chromeJson,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existsSync(`${this.homedir()}/.config/chromium/`)) {
|
|
||||||
await this.writeManifest(
|
|
||||||
`${this.homedir()}/.config/chromium/NativeMessagingHosts/com.8bit.bitwarden.json`,
|
|
||||||
chromeJson,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -260,15 +240,18 @@ export class NativeMessagingMain {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "linux": {
|
case "linux": {
|
||||||
await this.removeIfExists(
|
for (const [key, value] of Object.entries(this.getLinuxNMHS())) {
|
||||||
`${this.homedir()}/.mozilla/native-messaging-hosts/com.8bit.bitwarden.json`,
|
if (key === "Firefox") {
|
||||||
);
|
await this.removeIfExists(
|
||||||
await this.removeIfExists(
|
path.join(value, "native-messaging-hosts", "com.8bit.bitwarden.json"),
|
||||||
`${this.homedir()}/.config/google-chrome/NativeMessagingHosts/com.8bit.bitwarden.json`,
|
);
|
||||||
);
|
} else {
|
||||||
await this.removeIfExists(
|
await this.removeIfExists(
|
||||||
`${this.homedir()}/.config/microsoft-edge/NativeMessagingHosts/com.8bit.bitwarden.json`,
|
path.join(value, "NativeMessagingHosts", "com.8bit.bitwarden.json"),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -317,6 +300,15 @@ export class NativeMessagingMain {
|
|||||||
/* eslint-enable no-useless-escape */
|
/* eslint-enable no-useless-escape */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getLinuxNMHS() {
|
||||||
|
return {
|
||||||
|
Firefox: `${this.homedir()}/.mozilla/`,
|
||||||
|
Chrome: `${this.homedir()}/.config/google-chrome/`,
|
||||||
|
Chromium: `${this.homedir()}/.config/chromium/`,
|
||||||
|
"Microsoft Edge": `${this.homedir()}/.config/microsoft-edge/`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private async writeManifest(destination: string, manifest: object) {
|
private async writeManifest(destination: string, manifest: object) {
|
||||||
this.logService.debug(`Writing manifest: ${destination}`);
|
this.logService.debug(`Writing manifest: ${destination}`);
|
||||||
|
|
||||||
@@ -327,6 +319,83 @@ export class NativeMessagingMain {
|
|||||||
await fs.writeFile(destination, JSON.stringify(manifest, null, 2));
|
await fs.writeFile(destination, JSON.stringify(manifest, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async loadChromeIds(): Promise<string[]> {
|
||||||
|
const ids: Set<string> = new Set([
|
||||||
|
// Chrome extension
|
||||||
|
"chrome-extension://nngceckbapebfimnlniiiahkandclblb/",
|
||||||
|
// Chrome beta extension
|
||||||
|
"chrome-extension://hccnnhgbibccigepcmlgppchkpfdophk/",
|
||||||
|
// Edge extension
|
||||||
|
"chrome-extension://jbkfoedolllekgbhcbcoahefnbanhhlh/",
|
||||||
|
// Opera extension
|
||||||
|
"chrome-extension://ccnckbpmaceehanjmeomladnmlffdjgn/",
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!isDev()) {
|
||||||
|
return Array.from(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The dev builds of the extension have a different random ID per user, so to make development easier
|
||||||
|
// we try to find the extension IDs from the user's Chrome profiles when we're running in dev mode.
|
||||||
|
let chromePaths: string[];
|
||||||
|
switch (process.platform) {
|
||||||
|
case "darwin": {
|
||||||
|
chromePaths = Object.entries(this.getDarwinNMHS())
|
||||||
|
.filter(([key]) => key !== "Firefox")
|
||||||
|
.map(([, value]) => value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "linux": {
|
||||||
|
chromePaths = Object.entries(this.getLinuxNMHS())
|
||||||
|
.filter(([key]) => key !== "Firefox")
|
||||||
|
.map(([, value]) => value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "win32": {
|
||||||
|
// TODO: Add more supported browsers for Windows?
|
||||||
|
chromePaths = [
|
||||||
|
path.join(process.env.LOCALAPPDATA, "Microsoft", "Edge", "User Data"),
|
||||||
|
path.join(process.env.LOCALAPPDATA, "Google", "Chrome", "User Data"),
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const chromePath of chromePaths) {
|
||||||
|
try {
|
||||||
|
// The chrome profile directories are named "Default", "Profile 1", "Profile 2", etc.
|
||||||
|
const profiles = (await fs.readdir(chromePath)).filter((f) => {
|
||||||
|
const lower = f.toLowerCase();
|
||||||
|
return lower == "default" || lower.startsWith("profile ");
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const profile of profiles) {
|
||||||
|
try {
|
||||||
|
// Read the profile Preferences file and find the extension commands section
|
||||||
|
const prefs = JSON.parse(
|
||||||
|
await fs.readFile(path.join(chromePath, profile, "Preferences"), "utf8"),
|
||||||
|
);
|
||||||
|
const commands: Map<string, any> = prefs.extensions.commands;
|
||||||
|
|
||||||
|
// If one of the commands is autofill_login or generate_password, we know it's probably the Bitwarden extension
|
||||||
|
for (const { command_name, extension } of Object.values(commands)) {
|
||||||
|
if (command_name === "autofill_login" || command_name === "generate_password") {
|
||||||
|
ids.add(`chrome-extension://${extension}/`);
|
||||||
|
this.logService.info(`Found extension from ${chromePath}: ${extension}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.logService.info(`Error reading preferences: ${e}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Browser is not installed, we can just skip it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(ids);
|
||||||
|
}
|
||||||
|
|
||||||
private binaryPath() {
|
private binaryPath() {
|
||||||
const ext = process.platform === "win32" ? ".exe" : "";
|
const ext = process.platform === "win32" ? ".exe" : "";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user