diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json index 83bd2921551..481d12f02b4 100644 --- a/apps/desktop/electron-builder.json +++ b/apps/desktop/electron-builder.json @@ -85,7 +85,8 @@ "signIgnore": [ "MacOS/desktop_proxy", "MacOS/desktop_proxy.inherit", - "Contents/Plugins/autofill-extension.appex" + "Contents/Plugins/autofill-extension.appex", + "Frameworks/Electron Framework.framework/(Electron Framework|Libraries|Resources|Versions/Current)/.*" ], "target": ["dmg", "zip"] }, diff --git a/apps/desktop/macos/autofill-extension/autofill_extension_enabled.entitlements b/apps/desktop/macos/autofill-extension/autofill_extension_enabled.entitlements new file mode 100644 index 00000000000..49fda8f8af8 --- /dev/null +++ b/apps/desktop/macos/autofill-extension/autofill_extension_enabled.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.application-groups + + LTZ2PFU5D6.com.bitwarden.desktop + + com.apple.developer.authentication-services.autofill-credential-provider + + + diff --git a/apps/desktop/macos/desktop.xcodeproj/project.pbxproj b/apps/desktop/macos/desktop.xcodeproj/project.pbxproj index ed19fc9ef5d..c3cb34b6bea 100644 --- a/apps/desktop/macos/desktop.xcodeproj/project.pbxproj +++ b/apps/desktop/macos/desktop.xcodeproj/project.pbxproj @@ -256,7 +256,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = D83832AD2D67B9D0003FB9F8 /* ReleaseDeveloper.xcconfig */; buildSettings = { - CODE_SIGN_ENTITLEMENTS = "autofill-extension/autofill_extension.entitlements"; + CODE_SIGN_ENTITLEMENTS = "autofill-extension/autofill_extension_enabled.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; CODE_SIGN_STYLE = Manual; @@ -409,7 +409,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = D83832AB2D67B9AE003FB9F8 /* Debug.xcconfig */; buildSettings = { - CODE_SIGN_ENTITLEMENTS = "autofill-extension/autofill_extension.entitlements"; + CODE_SIGN_ENTITLEMENTS = "autofill-extension/autofill_extension_enabled.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; CODE_SIGN_STYLE = Manual; diff --git a/apps/desktop/macos/desktop.xcodeproj/xcshareddata/xcschemes/autofill-extension.xcscheme b/apps/desktop/macos/desktop.xcodeproj/xcshareddata/xcschemes/autofill-extension.xcscheme new file mode 100644 index 00000000000..18357be4570 --- /dev/null +++ b/apps/desktop/macos/desktop.xcodeproj/xcshareddata/xcschemes/autofill-extension.xcscheme @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/desktop/package.json b/apps/desktop/package.json index ad20e7c0e69..174f3a22a23 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -46,7 +46,7 @@ "pack:mac:with-extension": "npm run clean:dist && npm run build:macos-extension:mac && electron-builder --mac --universal -p never", "pack:mac:arm64": "npm run clean:dist && electron-builder --mac --arm64 -p never", "pack:mac:mas": "npm run clean:dist && npm run build:macos-extension:mas && electron-builder --mac mas --universal -p never", - "pack:mac:masdev": "npm run clean:dist && npm run build:macos-extension:masdev && electron-builder --mac mas-dev --universal -p never", + "pack:mac:masdev": "npm run clean:dist && electron-builder --mac mas-dev --universal -p never -c.mac.identity=null -c.mas.identity=$CSC_NAME -c.mas.provisioningProfile=bitwarden_desktop_developer_id.provisionprofile -c.mas.entitlements=resources/entitlements.mas.autofill-enabled.plist", "pack:local:mac": "npm run clean:dist && npm run build:macos-extension:masdev && electron-builder --mac mas-dev --universal -p never -c.mac.provisioningProfile=\"\" -c.mas.provisioningProfile=\"\"", "pack:win": "npm run clean:dist && electron-builder --win --x64 --arm64 --ia32 -p never", "pack:win:beta": "npm run clean:dist && electron-builder --config electron-builder.beta.json --win --x64 --arm64 --ia32 -p never", diff --git a/apps/desktop/resources/entitlements.mas.autofill-enabled.plist b/apps/desktop/resources/entitlements.mas.autofill-enabled.plist new file mode 100644 index 00000000000..f25780e5c12 --- /dev/null +++ b/apps/desktop/resources/entitlements.mas.autofill-enabled.plist @@ -0,0 +1,42 @@ + + + + + com.apple.application-identifier + LTZ2PFU5D6.com.bitwarden.desktop + com.apple.developer.team-identifier + LTZ2PFU5D6 + com.apple.security.app-sandbox + + com.apple.security.application-groups + + LTZ2PFU5D6.com.bitwarden.desktop + + com.apple.security.cs.allow-jit + + com.apple.security.device.usb + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + com.apple.security.temporary-exception.files.home-relative-path.read-write + + /Library/Application Support/Mozilla/NativeMessagingHosts/ + /Library/Application Support/Google/Chrome/NativeMessagingHosts/ + /Library/Application Support/Google/Chrome Beta/NativeMessagingHosts/ + /Library/Application Support/Google/Chrome Dev/NativeMessagingHosts/ + /Library/Application Support/Google/Chrome Canary/NativeMessagingHosts/ + /Library/Application Support/Chromium/NativeMessagingHosts/ + /Library/Application Support/Microsoft Edge/NativeMessagingHosts/ + /Library/Application Support/Microsoft Edge Beta/NativeMessagingHosts/ + /Library/Application Support/Microsoft Edge Dev/NativeMessagingHosts/ + /Library/Application Support/Microsoft Edge Canary/NativeMessagingHosts/ + /Library/Application Support/Vivaldi/NativeMessagingHosts/ + /Library/Application Support/Zen/NativeMessagingHosts/ + /Library/Application Support/net.imput.helium + + com.apple.developer.authentication-services.autofill-credential-provider + + + diff --git a/apps/desktop/scripts/after-sign.js b/apps/desktop/scripts/after-sign.js index 4275ec7d051..0e0e22fc24a 100644 --- a/apps/desktop/scripts/after-sign.js +++ b/apps/desktop/scripts/after-sign.js @@ -16,7 +16,9 @@ async function run(context) { const appPath = `${context.appOutDir}/${appName}.app`; const macBuild = context.electronPlatformName === "darwin"; const copySafariExtension = ["darwin", "mas"].includes(context.electronPlatformName); - const copyAutofillExtension = ["darwin"].includes(context.electronPlatformName); // Disabled for mas builds + const isMasDevBuild = + context.electronPlatformName === "mas" && context.targets.at(0)?.name === "mas-dev"; + const copyAutofillExtension = ["darwin"].includes(context.electronPlatformName) || isMasDevBuild; let shouldResign = false; @@ -31,7 +33,6 @@ async function run(context) { fse.mkdirSync(path.join(appPath, "Contents/PlugIns")); } fse.copySync(extensionPath, path.join(appPath, "Contents/PlugIns/autofill-extension.appex")); - shouldResign = true; } } diff --git a/apps/desktop/src/autofill/services/desktop-autofill.service.ts b/apps/desktop/src/autofill/services/desktop-autofill.service.ts index c50964e31e3..e5cd85aa7a3 100644 --- a/apps/desktop/src/autofill/services/desktop-autofill.service.ts +++ b/apps/desktop/src/autofill/services/desktop-autofill.service.ts @@ -10,6 +10,7 @@ import { mergeMap, switchMap, takeUntil, + tap, } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; @@ -52,6 +53,8 @@ import type { NativeWindowObject } from "./desktop-fido2-user-interface.service" export class DesktopAutofillService implements OnDestroy { private destroy$ = new Subject(); private registrationRequest: autofill.PasskeyRegistrationRequest; + private featureFlag?: FeatureFlag; + private isEnabled: boolean = false; constructor( private logService: LogService, @@ -60,19 +63,26 @@ export class DesktopAutofillService implements OnDestroy { private fido2AuthenticatorService: Fido2AuthenticatorServiceAbstraction, private accountService: AccountService, private authService: AuthService, - private platformUtilsService: PlatformUtilsService, - ) {} + platformUtilsService: PlatformUtilsService, + ) { + const deviceType = platformUtilsService.getDevice(); + if (deviceType === DeviceType.MacOsDesktop) { + this.featureFlag = FeatureFlag.MacOsNativeCredentialSync; + } + } async init() { - // Currently only supported for MacOS - if (this.platformUtilsService.getDevice() !== DeviceType.MacOsDesktop) { + this.isEnabled = + this.featureFlag && (await this.configService.getFeatureFlag(this.featureFlag)); + if (!this.isEnabled) { return; } this.configService - .getFeatureFlag$(FeatureFlag.MacOsNativeCredentialSync) + .getFeatureFlag$(this.featureFlag) .pipe( distinctUntilChanged(), + tap((enabled) => (this.isEnabled = enabled)), filter((enabled) => enabled === true), // Only proceed if feature is enabled switchMap(() => { return combineLatest([ @@ -199,11 +209,11 @@ export class DesktopAutofillService implements OnDestroy { listenIpc() { ipc.autofill.listenPasskeyRegistration(async (clientId, sequenceNumber, request, callback) => { - if (!(await this.configService.getFeatureFlag(FeatureFlag.MacOsNativeCredentialSync))) { + if (!this.isEnabled) { this.logService.debug( - "listenPasskeyRegistration: MacOsNativeCredentialSync feature flag is disabled", + `listenPasskeyRegistration: Native credential sync feature flag (${this.featureFlag}) is disabled`, ); - callback(new Error("MacOsNativeCredentialSync feature flag is disabled"), null); + callback(new Error("Native credential sync feature flag is disabled"), null); return; } @@ -230,11 +240,11 @@ export class DesktopAutofillService implements OnDestroy { ipc.autofill.listenPasskeyAssertionWithoutUserInterface( async (clientId, sequenceNumber, request, callback) => { - if (!(await this.configService.getFeatureFlag(FeatureFlag.MacOsNativeCredentialSync))) { + if (!this.isEnabled) { this.logService.debug( - "listenPasskeyAssertionWithoutUserInterface: MacOsNativeCredentialSync feature flag is disabled", + `listenPasskeyAssertionWithoutUserInterface: Native credential sync feature flag (${this.featureFlag}) is disabled`, ); - callback(new Error("MacOsNativeCredentialSync feature flag is disabled"), null); + callback(new Error("Native credential sync feature flag is disabled"), null); return; } @@ -297,11 +307,11 @@ export class DesktopAutofillService implements OnDestroy { ); ipc.autofill.listenPasskeyAssertion(async (clientId, sequenceNumber, request, callback) => { - if (!(await this.configService.getFeatureFlag(FeatureFlag.MacOsNativeCredentialSync))) { + if (!this.isEnabled) { this.logService.debug( - "listenPasskeyAssertion: MacOsNativeCredentialSync feature flag is disabled", + `listenPasskeyAssertion: Native credential sync feature flag (${this.featureFlag}) is disabled`, ); - callback(new Error("MacOsNativeCredentialSync feature flag is disabled"), null); + callback(new Error("Native credential sync feature flag is disabled"), null); return; } @@ -324,9 +334,9 @@ export class DesktopAutofillService implements OnDestroy { // Listen for native status messages ipc.autofill.listenNativeStatus(async (clientId, sequenceNumber, status) => { - if (!(await this.configService.getFeatureFlag(FeatureFlag.MacOsNativeCredentialSync))) { + if (!this.isEnabled) { this.logService.debug( - "listenNativeStatus: MacOsNativeCredentialSync feature flag is disabled", + `listenNativeStatus: Native credential sync feature flag (${this.featureFlag}) is disabled`, ); return; }