-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[PM-9022] scaffold the extension and build pipeline #9948
Merged
coroiu
merged 29 commits into
main
from
PM-9022-scaffold-the-extension-and-build-pipeline
Nov 13, 2024
+740
โ26
Merged
Changes from 25 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
ae88536
feat: add macos xcode project
coroiu f4949ed
feat: add extension to mas build
coroiu 6d01fbe
feat: use `after-sign` to avoid issues
coroiu 83371cd
feat: always clean build and add better error handling
coroiu 86b6d8f
chore: add some logging to after-sign
coroiu c21fc22
feat: automatically cleanup xcode build to avoid duplicate extensions
coroiu 44a010c
docs: add information about managing extensions
coroiu 02acb72
feat: add missing safari extension logging
coroiu 80ee12a
lint: allow macos filenames
coroiu 63df9ce
chore: add macos to platform ownership
coroiu b26b358
lint: add some additional allowed files
coroiu 2aa57c1
Merge branch 'main' into PM-9022-scaffold-the-extension-and-build-pipโฆ
coroiu ffc0f0b
feat: don't build autofill extension for MAS
coroiu 2498088
chore: ignore capital letters linting for all macos files
coroiu 68669d1
chore: replace gulpfile with regular node script
coroiu 58bb09d
chore: add lint rules to script
coroiu 2859cc1
lint: fix remaining lint issues in script
coroiu bbd7638
chore: tweak lint rule
coroiu c5fcfd3
feat: remove desktop target
coroiu 142ad9d
fix: use new provisioning profile for dev extension
coroiu abb7f08
Update to unblock CI builds
vgrassia 9a73e97
Merge branch 'main' into PM-9022-scaffold-the-extension-and-build-pipโฆ
michalchecinski 16db304
chore: remove extension from masdev pack
coroiu b9d23da
chore: add autofill as codeowner
coroiu 996a321
Merge branch 'main' into PM-9022-scaffold-the-extension-and-build-pipโฆ
coroiu e3f3207
Merge branch 'main' into PM-9022-scaffold-the-extension-and-build-pipโฆ
withinfocus 4618c94
chore: remove xcuserdata
coroiu 15aa3d9
chore: ignore xcuserdata
coroiu 22e790e
Merge branch 'main' into PM-9022-scaffold-the-extension-and-build-pipโฆ
coroiu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# MacOS Extensions for Desktop Apps | ||
|
||
This folder contains an Xcode project that builds macOS extensions for our desktop app. The extensions are used to provide additional functionality to the desktop app, such as autofill (password and passkeys). | ||
|
||
## Manage loaded extensions | ||
|
||
macOS automatically loads extensions from apps, even if they have never been used (especially if built with Xcode). This can be confusing when you have multiple copies of the same application. To see where an extension is loaded from, use the following command: | ||
|
||
```bash | ||
# To list all extensions | ||
pluginkit -m -v | ||
|
||
# To list a specific extension | ||
pluginkit -m -v -i com.bitwarden.desktop.autofill-extension | ||
``` | ||
|
||
To unregister an extension, you can either remove it from your filesystem, or use the following command: | ||
|
||
```bash | ||
pluginkit -r <path to .appex> | ||
``` | ||
|
||
where the path to the .appex file can be found in the output of the first command. |
69 changes: 69 additions & 0 deletions
69
apps/desktop/macos/autofill-extension/Base.lproj/CredentialProviderViewController.xib
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17021" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> | ||
<dependencies> | ||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17021"/> | ||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | ||
</dependencies> | ||
<objects> | ||
<customObject id="-2" userLabel="File's Owner" customClass="CredentialProviderViewController" customModuleProvider="target"> | ||
<connections> | ||
<outlet property="view" destination="1" id="2"/> | ||
</connections> | ||
</customObject> | ||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> | ||
<customObject id="-3" userLabel="Application" customClass="NSObject"/> | ||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="1"> | ||
<rect key="frame" x="0.0" y="0.0" width="378" height="94"/> | ||
<subviews> | ||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1uM-r7-H1c"> | ||
<rect key="frame" x="177" y="3" width="197" height="32"/> | ||
<buttonCell key="cell" type="push" title="Return Example Password" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="2l4-PO-we5"> | ||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> | ||
<font key="font" metaFont="system"/> | ||
<string key="keyEquivalent">D</string> | ||
<modifierMask key="keyEquivalentModifierMask" command="YES"/> | ||
</buttonCell> | ||
<connections> | ||
<action selector="passwordSelected:" target="-2" id="yic-EC-GGk"/> | ||
</connections> | ||
</button> | ||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="NVE-vN-dkz"> | ||
<rect key="frame" x="99" y="3" width="82" height="32"/> | ||
<constraints> | ||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="60" id="cP1-hK-9ZX"/> | ||
</constraints> | ||
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="6Up-t3-mwm"> | ||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> | ||
<font key="font" metaFont="system"/> | ||
<string key="keyEquivalent" base64-UTF8="YES"> | ||
Gw | ||
</string> | ||
</buttonCell> | ||
<connections> | ||
<action selector="cancel:" target="-2" id="Qav-AK-DGt"/> | ||
</connections> | ||
</button> | ||
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aNc-0i-CWK"> | ||
<rect key="frame" x="135" y="63" width="108" height="16"/> | ||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="autofill-extension" id="0xp-rC-2gr"> | ||
<font key="font" metaFont="systemBold"/> | ||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> | ||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> | ||
</textFieldCell> | ||
</textField> | ||
</subviews> | ||
<constraints> | ||
<constraint firstItem="1uM-r7-H1c" firstAttribute="leading" secondItem="NVE-vN-dkz" secondAttribute="trailing" constant="8" id="1UO-J1-LbJ"/> | ||
<constraint firstItem="NVE-vN-dkz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="1" secondAttribute="leading" constant="20" symbolic="YES" id="3N9-qo-UfS"/> | ||
<constraint firstAttribute="bottom" secondItem="1uM-r7-H1c" secondAttribute="bottom" constant="10" id="4wH-De-nMF"/> | ||
<constraint firstItem="NVE-vN-dkz" firstAttribute="firstBaseline" secondItem="aNc-0i-CWK" secondAttribute="baseline" constant="50" id="Dpq-cK-cPE"/> | ||
<constraint firstAttribute="bottom" secondItem="NVE-vN-dkz" secondAttribute="bottom" constant="10" id="USG-Gg-of3"/> | ||
<constraint firstItem="1uM-r7-H1c" firstAttribute="leading" secondItem="NVE-vN-dkz" secondAttribute="trailing" constant="8" id="a8N-vS-Ew9"/> | ||
<constraint firstAttribute="trailing" secondItem="1uM-r7-H1c" secondAttribute="trailing" constant="10" id="qfT-cw-QQ2"/> | ||
<constraint firstAttribute="centerX" secondItem="aNc-0i-CWK" secondAttribute="centerX" id="uV3-Wn-RA3"/> | ||
<constraint firstItem="aNc-0i-CWK" firstAttribute="top" secondItem="1" secondAttribute="top" constant="15" id="vpR-tf-ebx"/> | ||
</constraints> | ||
<point key="canvasLocation" x="162" y="146"/> | ||
</customView> | ||
</objects> | ||
</document> |
93 changes: 93 additions & 0 deletions
93
apps/desktop/macos/autofill-extension/CredentialProviderViewController.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// | ||
// CredentialProviderViewController.swift | ||
// autofill-extension | ||
// | ||
// Created by Andreas Coroiu on 2023-12-21. | ||
// | ||
|
||
import AuthenticationServices | ||
import os | ||
|
||
class CredentialProviderViewController: ASCredentialProviderViewController { | ||
let logger = Logger() | ||
|
||
/* | ||
Implement this method if your extension supports showing credentials in the QuickType bar. | ||
When the user selects a credential from your app, this method will be called with the | ||
ASPasswordCredentialIdentity your app has previously saved to the ASCredentialIdentityStore. | ||
Provide the password by completing the extension request with the associated ASPasswordCredential. | ||
If using the credential would require showing custom UI for authenticating the user, cancel | ||
the request with error code ASExtensionError.userInteractionRequired. | ||
|
||
override func provideCredentialWithoutUserInteraction(for credentialIdentity: ASPasswordCredentialIdentity) { | ||
let databaseIsUnlocked = true | ||
if (databaseIsUnlocked) { | ||
let passwordCredential = ASPasswordCredential(user: "j_appleseed", password: "apple1234") | ||
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential, completionHandler: nil) | ||
} else { | ||
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code:ASExtensionError.userInteractionRequired.rawValue)) | ||
} | ||
} | ||
*/ | ||
|
||
/* | ||
Implement this method if provideCredentialWithoutUserInteraction(for:) can fail with | ||
ASExtensionError.userInteractionRequired. In this case, the system may present your extension's | ||
UI and call this method. Show appropriate UI for authenticating the user then provide the password | ||
by completing the extension request with the associated ASPasswordCredential. | ||
|
||
override func prepareInterfaceToProvideCredential(for credentialIdentity: ASPasswordCredentialIdentity) { | ||
} | ||
*/ | ||
|
||
@IBAction func cancel(_ sender: AnyObject?) { | ||
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue)) | ||
} | ||
|
||
@IBAction func passwordSelected(_ sender: AnyObject?) { | ||
let passwordCredential = ASPasswordCredential(user: "j_appleseed", password: "apple1234") | ||
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential, completionHandler: nil) | ||
} | ||
|
||
override func prepareInterfaceForExtensionConfiguration() { | ||
logger.log("[autofill-extension] prepareInterfaceForExtensionConfiguration called") | ||
} | ||
|
||
override func prepareInterface(forPasskeyRegistration registrationRequest: ASCredentialRequest) { | ||
logger.log("[autofill-extension] prepare interface for registration request \(registrationRequest.description)") | ||
|
||
// self.extensionContext.cancelRequest(withError: ExampleError.nope) | ||
} | ||
|
||
override func prepareInterfaceToProvideCredential(for credentialRequest: ASCredentialRequest) { | ||
logger.log("[autofill-extension] prepare interface for credential request \(credentialRequest.description)") | ||
} | ||
|
||
/* | ||
Prepare your UI to list available credentials for the user to choose from. The items in | ||
'serviceIdentifiers' describe the service the user is logging in to, so your extension can | ||
prioritize the most relevant credentials in the list. | ||
*/ | ||
override func prepareCredentialList(for serviceIdentifiers: [ASCredentialServiceIdentifier]) { | ||
logger.log("[autofill-extension] prepareCredentialList for serviceIdentifiers: \(serviceIdentifiers.count)") | ||
|
||
for serviceIdentifier in serviceIdentifiers { | ||
logger.log(" service: \(serviceIdentifier.identifier)") | ||
} | ||
} | ||
|
||
override func prepareInterfaceToProvideCredential(for credentialIdentity: ASPasswordCredentialIdentity) { | ||
logger.log("[autofill-extension] prepareInterfaceToProvideCredential for credentialIdentity: \(credentialIdentity.user)") | ||
} | ||
|
||
override func prepareCredentialList(for serviceIdentifiers: [ASCredentialServiceIdentifier], requestParameters: ASPasskeyCredentialRequestParameters) { | ||
logger.log("[autofill-extension] prepareCredentialList(passkey) for serviceIdentifiers: \(serviceIdentifiers.count)") | ||
|
||
for serviceIdentifier in serviceIdentifiers { | ||
logger.log(" service: \(serviceIdentifier.identifier)") | ||
} | ||
|
||
logger.log("request parameters: \(requestParameters.relyingPartyIdentifier)") | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>NSExtension</key> | ||
<dict> | ||
<key>NSExtensionAttributes</key> | ||
<dict> | ||
<key>ASCredentialProviderExtensionCapabilities</key> | ||
<dict> | ||
<key>ProvidesPasskeys</key> | ||
<true/> | ||
</dict> | ||
<key>ASCredentialProviderExtensionShowsConfigurationUI</key> | ||
<false/> | ||
</dict> | ||
<key>NSExtensionPointIdentifier</key> | ||
<string>com.apple.authentication-services-credential-provider-ui</string> | ||
<key>NSExtensionPrincipalClass</key> | ||
<string>$(PRODUCT_MODULE_NAME).CredentialProviderViewController</string> | ||
</dict> | ||
</dict> | ||
</plist> |
10 changes: 10 additions & 0 deletions
10
apps/desktop/macos/autofill-extension/autofill_extension.entitlements
Hinton marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>com.apple.developer.authentication-services.autofill-credential-provider</key> | ||
<true/> | ||
<key>com.apple.security.app-sandbox</key> | ||
<true/> | ||
</dict> | ||
</plist> |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: we might want to assign some this folder to team-autofill-dev
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added autofill as owner of the autofill-extension