Core of the Password-Manager used in Amethyst Browser [repo] and the Amethyst Authenticator App
AmethystAuthenticationCore handles all the logic of managing Passwords and TOTP Secrets and storing them safely in the keychain. When building a Password-Manager, you will only need to build the GUI around it.
This package is licensed under MIT, read more in the LICENSE File
- Swift 6 compatible
- macOS 15
- iOS 18
- activated Keychain sharing
AmethystAuthenticatorCore contains the SwiftData-Models, Migrations and Functions that handle all the data.
It provides a safe way of of storing and retrieving Passwords and Secrets. Its built for iCloud Sync of the Keychain and SwiftData Models.
Any app that uses this package will require the Keychain Sharing Entitlement
I have not tested it without the App Group entitlement, so keep in mind that it might not work without it.
Install the package via SwiftPackageManager.
Add
https://codeberg.org/miakoring/AmethystAuthenticatorCore.git
to the Package Dependencies of your App.
First import it:
import AmethystAuthenticatorCorethen, specify use of the model like this (example):
-
Not shared through AppGroup
let container = try! ModelContainer(for: Account.self, migrationPlan: AAuthenticatorMigrations.self)
Shared through AppGroup
let groupDBURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "YOURTEAMIDENTIFIER.com.yourcompany.yourappgroup")!.appendingPathComponent("shared.sqlite") let configuration = ModelConfiguration(url: groupDBURL) let container = try! ModelContainer(for: Account.self, migrationPlan: AAuthenticatorMigrations.self, configurations: configuration)
-
@main struct YourApp: App { var body: some Scene { WindowGroup { ContentView() .modelContainer(container) } } }
-
ONLY use the convenience init. The other one is not safe and only to get used by SwiftData. DO NOT use it outside of testing code. It requires an array of all stored accounts to check for collision.
let account = Account(service: "yourcompany.com", //the website to which the account belongs username: "[email protected]", comment: "", //automatically get saved to the Keychain password: "password", //automatically get saved to the Keychain allAccounts: allStoredAccounts) modelContext.insert(account)
-
Either use
let password = account.password account.password = "newPassword"
or
account.getPassword() account.setPassword(to: "newPassword")
-
let username = account.username try account.setUsername(to: "newUsername", allAccounts: allAccounts, context: modelContext) //Context and allAccounts are required for collision protection and concurrency safety
-
account.removeTOTPSecret() //deletes TOTP secret fromt the keychain account.setTOTPSecret(to: "New Base32 encoded secret") account.getCurrentTOTPCode() //returns totp code of the time of calling account.getTOTPSecret()
-
Either use
let comment = account.comment account.comment = "New Comment"
or
account.getComment() account.setComment(to: "New Comment")
-
Aliases are domains, that differ from the main one (account.service) on which the username and password also work. For example apple.com and alias idmsa.apple.com
account.aliases = ["alias.com"] account.aliases.append("new.alias.com") let aliases = account.aliases
The Library contains both unit and integration tests. Unfortunately, because the Library requires entitlements for use, integration-testing it only works in a real app.
Clone
https://codeberg.org/miakoring/AmethystAuthenticatorCoreIntegrationTests.git
and add your local version of this repository as Package Dependency. Then run it. Detailed errors will get printed to the console, in the app you can run single or all tests and see if they succeed or not.