Compare commits

..

22 Commits
v2.4.0 ... main

Author SHA1 Message Date
Max Goedjen
ad56019901
Update CI + Concurrency Warnings (#564)
* Update test.yml

* Update nightly.yml

* Update release.yml

* Tweak concurrency settings

* Remove bad annotations
2024-08-26 15:11:28 -07:00
Josep Mengual
5929137f20
Add Catalan localization (#558) 2024-08-26 21:21:45 +00:00
Max Goedjen
35a7c99cba
Turn down concurrency warnings until Swift 6 branch is merged. (#562) 2024-08-26 20:59:20 +00:00
Jason Garber
a543de0737
GitHub Actions updates (#554)
* Bump actions/add-to-project to v1.0.1

This _might_ address the failed workflow runs dating back to at least
the last six months:

https://github.com/maxgoedjen/secretive/actions/workflows/add-to-project.yml

* Bump actions/upload-artifact to v4

This should get rid of the deprecation notices displayed as annotations
beneath each Nightly job run. See:

https://github.com/maxgoedjen/secretive/actions/runs/9461831554

* Bump actions/upload-artifact to v4

Similar to cf25db6, this should silence some deprecation notices.
2024-06-25 21:08:38 +00:00
Yoshimasa Niwa
fc21018eb4
Add Japanese translations (#546) 2024-04-28 22:33:51 +00:00
mog422
52cc08424e
Add Korean localization (#537) 2024-03-01 22:58:08 +00:00
Max Goedjen
d13f4ee7ba
Revert "Use Apple Silicon runners (#519)" (#533)
This reverts commit 409efa5f9f45130249d257770162f1a7307b86a4.
2024-02-26 00:24:48 +00:00
Max Goedjen
6f4226f97a
Standardize newline handling (#522)
* Standardize newline handling

* Fix some unterminated bolds in other languages

* Set language back
2024-01-25 02:14:34 +00:00
Aarni Koskela
3315a4bfbc
Add Finnish localization (#521) 2024-01-23 00:58:36 +00:00
Riccardo Pesciarelli
85a7a64bc9
Updated Italian localization strings (#520)
* 🇮🇹 Initial proposal for Italian localization

* 🇮🇹 Updated Italian localization

---------

Co-authored-by: Max Goedjen <max.goedjen@gmail.com>
2024-01-18 17:35:36 +00:00
Max Goedjen
409efa5f9f
Use Apple Silicon runners (#519)
* Test running on XL (does this work for OSS projects?)

* Move over test/release
2024-01-17 19:28:29 +00:00
Max Goedjen
bb63ae8469
Set min width/height for setup. (#518) 2024-01-17 04:08:48 +00:00
Max Goedjen
30c1d36974
Mark newlines as verbatim (#517)
* Merge

* Add missing key
2024-01-17 03:49:14 +00:00
Max Goedjen
de8d18f9e9
Switch to Xcode 15.2 (#516) 2024-01-16 21:39:07 +00:00
Riccardo Pesciarelli
1ae0996e2c
🇮🇹 Initial proposal for Italian localization (#512)
Co-authored-by: Max Goedjen <max.goedjen@gmail.com>
2024-01-16 21:35:28 +00:00
Moritz Sternemann
3d50a99430
Add German Localization 🇩🇪 (#514)
* Add German localization

* Small adjustments

* Add German localization in project file

---------

Co-authored-by: Max Goedjen <max.goedjen@gmail.com>
2024-01-16 21:15:07 +00:00
Marcio Saeger
45fc356f0f
Add PT-BR to the i18n (#515) 2024-01-16 21:12:46 +00:00
Mahé
212678b94e
Fix missing French translations (#510) 2024-01-13 14:32:08 -08:00
RyuS
2e1f4881a9
Translate_Addlang_ZH_Han (#508)
Co-authored-by: Alex Q <ln41xgpy@addymail.com>
2024-01-13 06:25:20 +00:00
Max Goedjen
c2b80e3c7c
Localization fixes (#507)
* Consolidate localization files into one file that both targets reference

* Update readme

* Secret Agent/Agent consolidation

* NSLS -> String(localized:)

* Auth contexts
2024-01-12 12:50:52 -08:00
Mahé
15d2afd2cb
Add French localization (#506) 2024-01-12 12:14:02 -08:00
Ale Muñoz
2a4da36c4e
Fix escaped text on Agent is running popover (#505) 2024-01-11 23:09:04 +00:00
15 changed files with 4630 additions and 190 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

View File

@ -10,7 +10,7 @@ jobs:
name: Add issue to project name: Add issue to project
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/add-to-project@v0.0.3 - uses: actions/add-to-project@v1.0.1
with: with:
project-url: https://github.com/users/maxgoedjen/projects/1 project-url: https://github.com/users/maxgoedjen/projects/1
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}

View File

@ -6,7 +6,7 @@ on:
jobs: jobs:
build: build:
# runs-on: macOS-latest # runs-on: macOS-latest
runs-on: macos-13 runs-on: macos-14
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -20,7 +20,7 @@ jobs:
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
run: ./.github/scripts/signing.sh run: ./.github/scripts/signing.sh
- name: Set Environment - name: Set Environment
run: sudo xcrun xcode-select -s /Applications/Xcode_15.1.app run: sudo xcrun xcode-select -s /Applications/Xcode_15.4.app
- name: Update Build Number - name: Update Build Number
env: env:
RUN_ID: ${{ github.run_id }} RUN_ID: ${{ github.run_id }}
@ -48,7 +48,7 @@ jobs:
shasum -a 256 Secretive.zip shasum -a 256 Secretive.zip
shasum -a 256 Archive.zip shasum -a 256 Archive.zip
- name: Upload App to Artifacts - name: Upload App to Artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: Secretive.zip name: Secretive.zip
path: Secretive.zip path: Secretive.zip

View File

@ -7,7 +7,7 @@ on:
jobs: jobs:
test: test:
# runs-on: macOS-latest # runs-on: macOS-latest
runs-on: macos-13 runs-on: macos-14
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -21,7 +21,7 @@ jobs:
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
run: ./.github/scripts/signing.sh run: ./.github/scripts/signing.sh
- name: Set Environment - name: Set Environment
run: sudo xcrun xcode-select -s /Applications/Xcode_15.1.app run: sudo xcrun xcode-select -s /Applications/Xcode_15.4.app
- name: Test - name: Test
run: | run: |
pushd Sources/Packages pushd Sources/Packages
@ -29,7 +29,7 @@ jobs:
popd popd
build: build:
# runs-on: macOS-latest # runs-on: macOS-latest
runs-on: macos-13 runs-on: macos-14
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -43,7 +43,7 @@ jobs:
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
run: ./.github/scripts/signing.sh run: ./.github/scripts/signing.sh
- name: Set Environment - name: Set Environment
run: sudo xcrun xcode-select -s /Applications/Xcode_15.1.app run: sudo xcrun xcode-select -s /Applications/Xcode_15.4.app
- name: Update Build Number - name: Update Build Number
env: env:
TAG_NAME: ${{ github.ref }} TAG_NAME: ${{ github.ref }}
@ -107,12 +107,12 @@ jobs:
asset_name: Secretive.zip asset_name: Secretive.zip
asset_content_type: application/zip asset_content_type: application/zip
- name: Upload App to Artifacts - name: Upload App to Artifacts
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v4
with: with:
name: Secretive.zip name: Secretive.zip
path: Secretive.zip path: Secretive.zip
- name: Upload Archive to Artifacts - name: Upload Archive to Artifacts
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v4
with: with:
name: Xcode_Archive.zip name: Xcode_Archive.zip
path: Archive.zip path: Archive.zip

View File

@ -4,12 +4,12 @@ on: [push, pull_request]
jobs: jobs:
test: test:
# runs-on: macOS-latest # runs-on: macOS-latest
runs-on: macos-13 runs-on: macos-14
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set Environment - name: Set Environment
run: sudo xcrun xcode-select -s /Applications/Xcode_15.1.app run: sudo xcrun xcode-select -s /Applications/Xcode_15.4.app
- name: Test - name: Test
run: | run: |
pushd Sources/Packages pushd Sources/Packages

View File

@ -16,7 +16,7 @@ Clone Secretive using [these instructions from GitHub](https://docs.github.com/e
Open [Sources/Secretive.xcodeproj](Sources/Secretive.xcodeproj) in Xcode. Open [Sources/Secretive.xcodeproj](Sources/Secretive.xcodeproj) in Xcode.
### Localize the Main App ### Translate
Navigate to [Secretive/Localizable](Sources/Secretive/Localizable.xcstrings). Navigate to [Secretive/Localizable](Sources/Secretive/Localizable.xcstrings).
@ -28,14 +28,6 @@ If your language already has an in-progress localization, select it from the lis
Start translating! You'll see a list of english phrases, and a space to add a translation of your language. Start translating! You'll see a list of english phrases, and a space to add a translation of your language.
### Localize SecretAgent
Navigate to [Secretive/Localizable](Sources/SecretAgent/Localizable.xcstrings).
<img src="/.github/readme/localize_sidebar_agent.png" alt="Screenshot of Xcode navigating to the Localizable file" width="300">
Repeat the same steps from the process of localizing the main app.
### Create a Pull Request ### Create a Pull Request
Push your changes and open a pull request. Push your changes and open a pull request.

View File

@ -34,27 +34,27 @@ let package = Package(
.target( .target(
name: "SecretKit", name: "SecretKit",
dependencies: [], dependencies: [],
swiftSettings: [.enableExperimentalFeature("StrictConcurrency"), .unsafeFlags(["-warnings-as-errors"])] swiftSettings: [.unsafeFlags(["-warnings-as-errors"])]
), ),
.testTarget( .testTarget(
name: "SecretKitTests", name: "SecretKitTests",
dependencies: ["SecretKit", "SecureEnclaveSecretKit", "SmartCardSecretKit"], dependencies: ["SecretKit", "SecureEnclaveSecretKit", "SmartCardSecretKit"],
swiftSettings: [.enableExperimentalFeature("StrictConcurrency"), .unsafeFlags(["-warnings-as-errors"])] swiftSettings: [.unsafeFlags(["-warnings-as-errors"])]
), ),
.target( .target(
name: "SecureEnclaveSecretKit", name: "SecureEnclaveSecretKit",
dependencies: ["SecretKit"], dependencies: ["SecretKit"],
swiftSettings: [.enableExperimentalFeature("StrictConcurrency"), .unsafeFlags(["-warnings-as-errors"])] swiftSettings: [.unsafeFlags(["-warnings-as-errors"])]
), ),
.target( .target(
name: "SmartCardSecretKit", name: "SmartCardSecretKit",
dependencies: ["SecretKit"], dependencies: ["SecretKit"],
swiftSettings: [.enableExperimentalFeature("StrictConcurrency"), .unsafeFlags(["-warnings-as-errors"])] swiftSettings: [.unsafeFlags(["-warnings-as-errors"])]
), ),
.target( .target(
name: "SecretAgentKit", name: "SecretAgentKit",
dependencies: ["SecretKit", "SecretAgentKitHeaders"], dependencies: ["SecretKit", "SecretAgentKitHeaders"],
swiftSettings: [.enableExperimentalFeature("StrictConcurrency"), .unsafeFlags(["-warnings-as-errors"])] swiftSettings: [.unsafeFlags(["-warnings-as-errors"])]
), ),
.systemLibrary( .systemLibrary(
name: "SecretAgentKitHeaders" name: "SecretAgentKitHeaders"

View File

@ -35,7 +35,7 @@ extension Agent {
/// - writer: A ``FileHandleWriter`` to write the response to. /// - writer: A ``FileHandleWriter`` to write the response to.
/// - Return value: /// - Return value:
/// - Boolean if data could be read /// - Boolean if data could be read
@discardableResult @Sendable public func handle(reader: FileHandleReader, writer: FileHandleWriter) async -> Bool { @discardableResult public func handle(reader: FileHandleReader, writer: FileHandleWriter) async -> Bool {
logger.debug("Agent handling new data") logger.debug("Agent handling new data")
let data = Data(reader.availableData) let data = Data(reader.availableData)
guard data.count > 4 else { return false} guard data.count > 4 else { return false}

View File

@ -17,7 +17,7 @@ extension SecureEnclave {
TKTokenWatcher().tokenIDs.contains("com.apple.setoken") TKTokenWatcher().tokenIDs.contains("com.apple.setoken")
} }
public let id = UUID() public let id = UUID()
public let name = NSLocalizedString("Secure Enclave", comment: "Secure Enclave") public let name = String(localized: "secure_enclave")
@Published public private(set) var secrets: [Secret] = [] @Published public private(set) var secrets: [Secret] = []
private var persistedAuthenticationContexts: [Secret: PersistentAuthenticationContext] = [:] private var persistedAuthenticationContexts: [Secret: PersistentAuthenticationContext] = [:]
@ -107,10 +107,10 @@ extension SecureEnclave {
context = existing.context context = existing.context
} else { } else {
let newContext = LAContext() let newContext = LAContext()
newContext.localizedCancelTitle = "Deny" newContext.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
context = newContext context = newContext
} }
context.localizedReason = "sign a request from \"\(provenance.origin.displayName)\" using secret \"\(secret.name)\"" context.localizedReason = String(localized: "auth_context_request_signature_description_\(provenance.origin.displayName)_\(secret.name)")
let attributes = KeychainDictionary([ let attributes = KeychainDictionary([
kSecClass: kSecClassKey, kSecClass: kSecClassKey,
kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeyClass: kSecAttrKeyClassPrivate,
@ -140,8 +140,8 @@ extension SecureEnclave {
public func verify(signature: Data, for data: Data, with secret: Secret) throws -> Bool { public func verify(signature: Data, for data: Data, with secret: Secret) throws -> Bool {
let context = LAContext() let context = LAContext()
context.localizedReason = "verify a signature using secret \"\(secret.name)\"" context.localizedReason = String(localized: "auth_context_request_verify_description_\(secret.name)")
context.localizedCancelTitle = "Deny" context.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
let attributes = KeychainDictionary([ let attributes = KeychainDictionary([
kSecClass: kSecClassKey, kSecClass: kSecClassKey,
kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeyClass: kSecAttrKeyClassPrivate,
@ -181,16 +181,16 @@ extension SecureEnclave {
public func persistAuthentication(secret: Secret, forDuration duration: TimeInterval) throws { public func persistAuthentication(secret: Secret, forDuration duration: TimeInterval) throws {
let newContext = LAContext() let newContext = LAContext()
newContext.touchIDAuthenticationAllowableReuseDuration = duration newContext.touchIDAuthenticationAllowableReuseDuration = duration
newContext.localizedCancelTitle = "Deny" newContext.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
let formatter = DateComponentsFormatter() let formatter = DateComponentsFormatter()
formatter.unitsStyle = .spellOut formatter.unitsStyle = .spellOut
formatter.allowedUnits = [.hour, .minute, .day] formatter.allowedUnits = [.hour, .minute, .day]
if let durationString = formatter.string(from: duration) { if let durationString = formatter.string(from: duration) {
newContext.localizedReason = "unlock secret \"\(secret.name)\" for \(durationString)" newContext.localizedReason = String(localized: "auth_context_persist_for_duration_\(secret.name)_\(durationString)")
} else { } else {
newContext.localizedReason = "unlock secret \"\(secret.name)\"" newContext.localizedReason = String(localized: "auth_context_persist_for_duration_unknown_\(secret.name)")
} }
newContext.evaluatePolicy(LAPolicy.deviceOwnerAuthentication, localizedReason: newContext.localizedReason) { [weak self] success, _ in newContext.evaluatePolicy(LAPolicy.deviceOwnerAuthentication, localizedReason: newContext.localizedReason) { [weak self] success, _ in
guard success else { return } guard success else { return }
@ -211,7 +211,7 @@ extension SecureEnclave.Store {
/// Reloads all secrets from the store. /// Reloads all secrets from the store.
/// - Parameter notifyAgent: A boolean indicating whether a distributed notification should be posted, notifying other processes (ie, the SecretAgent) to reload their stores as well. /// - Parameter notifyAgent: A boolean indicating whether a distributed notification should be posted, notifying other processes (ie, the SecretAgent) to reload their stores as well.
@Sendable private func reloadSecretsInternal(notifyAgent: Bool = true) { private func reloadSecretsInternal(notifyAgent: Bool = true) {
let before = secrets let before = secrets
secrets.removeAll() secrets.removeAll()
loadSecrets() loadSecrets()
@ -260,7 +260,7 @@ extension SecureEnclave.Store {
nil)! nil)!
let wrapped: [SecureEnclave.Secret] = publicTyped.map { let wrapped: [SecureEnclave.Secret] = publicTyped.map {
let name = $0[kSecAttrLabel] as? String ?? "Unnamed" let name = $0[kSecAttrLabel] as? String ?? String(localized: "unnamed_secret")
let id = $0[kSecAttrApplicationLabel] as! Data let id = $0[kSecAttrApplicationLabel] as! Data
let publicKeyRef = $0[kSecValueRef] as! SecKey let publicKeyRef = $0[kSecValueRef] as! SecKey
let publicKeyAttributes = SecKeyCopyAttributes(publicKeyRef) as! [CFString: Any] let publicKeyAttributes = SecKeyCopyAttributes(publicKeyRef) as! [CFString: Any]

View File

@ -12,7 +12,7 @@ extension SmartCard {
@Published public var isAvailable: Bool = false @Published public var isAvailable: Bool = false
public let id = UUID() public let id = UUID()
public private(set) var name = NSLocalizedString("Smart Card", comment: "Smart Card") public private(set) var name = String(localized: "smart_card")
@Published public private(set) var secrets: [Secret] = [] @Published public private(set) var secrets: [Secret] = []
private let watcher = TKTokenWatcher() private let watcher = TKTokenWatcher()
private var tokenID: String? private var tokenID: String?
@ -50,8 +50,8 @@ extension SmartCard {
public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) throws -> Data { public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) throws -> Data {
guard let tokenID = tokenID else { fatalError() } guard let tokenID = tokenID else { fatalError() }
let context = LAContext() let context = LAContext()
context.localizedReason = "sign a request from \"\(provenance.origin.displayName)\" using secret \"\(secret.name)\"" context.localizedReason = String(localized: "auth_context_request_signature_description_\(provenance.origin.displayName)_\(secret.name)")
context.localizedCancelTitle = "Deny" context.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
let attributes = KeychainDictionary([ let attributes = KeychainDictionary([
kSecClass: kSecClassKey, kSecClass: kSecClassKey,
kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeyClass: kSecAttrKeyClassPrivate,
@ -117,7 +117,7 @@ extension SmartCard {
extension SmartCard.Store { extension SmartCard.Store {
@Sendable private func reloadSecretsInternal() { private func reloadSecretsInternal() {
self.isAvailable = self.tokenID != nil self.isAvailable = self.tokenID != nil
let before = self.secrets let before = self.secrets
self.secrets.removeAll() self.secrets.removeAll()
@ -138,7 +138,7 @@ extension SmartCard.Store {
private func loadSecrets() { private func loadSecrets() {
guard let tokenID = tokenID else { return } guard let tokenID = tokenID else { return }
let fallbackName = NSLocalizedString("Smart Card", comment: "Smart Card") let fallbackName = String(localized: "smart_card")
if let driverName = watcher.tokenInfo(forTokenID: tokenID)?.driverName { if let driverName = watcher.tokenInfo(forTokenID: tokenID)?.driverName {
name = driverName name = driverName
} else { } else {
@ -156,7 +156,7 @@ extension SmartCard.Store {
SecItemCopyMatching(attributes, &untyped) SecItemCopyMatching(attributes, &untyped)
guard let typed = untyped as? [[CFString: Any]] else { return } guard let typed = untyped as? [[CFString: Any]] else { return }
let wrapped = typed.map { let wrapped = typed.map {
let name = $0[kSecAttrLabel] as? String ?? "Unnamed" let name = $0[kSecAttrLabel] as? String ?? String(localized: "unnamed_secret")
let tokenID = $0[kSecAttrApplicationLabel] as! Data let tokenID = $0[kSecAttrApplicationLabel] as! Data
let algorithm = Algorithm(secAttr: $0[kSecAttrKeyType] as! NSNumber) let algorithm = Algorithm(secAttr: $0[kSecAttrKeyType] as! NSNumber)
let keySize = $0[kSecAttrKeySizeInBits] as! Int let keySize = $0[kSecAttrKeySizeInBits] as! Int
@ -183,8 +183,8 @@ extension SmartCard.Store {
/// - Warning: Encryption functions are deliberately only exposed on a library level, and are not exposed in Secretive itself to prevent users from data loss. Any pull requests which expose this functionality in the app will not be merged. /// - Warning: Encryption functions are deliberately only exposed on a library level, and are not exposed in Secretive itself to prevent users from data loss. Any pull requests which expose this functionality in the app will not be merged.
public func encrypt(data: Data, with secret: SecretType) throws -> Data { public func encrypt(data: Data, with secret: SecretType) throws -> Data {
let context = LAContext() let context = LAContext()
context.localizedReason = "encrypt data using secret \"\(secret.name)\"" context.localizedReason = String(localized: "auth_context_request_encrypt_description_\(secret.name)")
context.localizedCancelTitle = "Deny" context.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
let attributes = KeychainDictionary([ let attributes = KeychainDictionary([
kSecAttrKeyType: secret.algorithm.secAttrKeyType, kSecAttrKeyType: secret.algorithm.secAttrKeyType,
kSecAttrKeySizeInBits: secret.keySize, kSecAttrKeySizeInBits: secret.keySize,
@ -212,8 +212,8 @@ extension SmartCard.Store {
public func decrypt(data: Data, with secret: SecretType) throws -> Data { public func decrypt(data: Data, with secret: SecretType) throws -> Data {
guard let tokenID = tokenID else { fatalError() } guard let tokenID = tokenID else { fatalError() }
let context = LAContext() let context = LAContext()
context.localizedReason = "decrypt data using secret \"\(secret.name)\"" context.localizedReason = String(localized: "auth_context_request_decrypt_description_\(secret.name)")
context.localizedCancelTitle = "Deny" context.localizedCancelTitle = String(localized: "auth_context_request_deny_button")
let attributes = KeychainDictionary([ let attributes = KeychainDictionary([
kSecClass: kSecClassKey, kSecClass: kSecClassKey,
kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeyClass: kSecAttrKeyClassPrivate,

View File

@ -1,114 +0,0 @@
{
"sourceLanguage" : "en",
"strings" : {
"persist_authentication_accept_button" : {
"comment" : "When the user authorizes an action using a secret that requires unlock, they're shown a notification offering to leave the secret unlocked for a set period of time. This is the title for the notification.",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Leave Unlocked"
}
}
}
},
"persist_authentication_decline_button" : {
"comment" : "When the user authorizes an action using a secret that requires unlock, they're shown a notification offering to leave the secret unlocked for a set period of time. This is the decline button for the notification.",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Do Not Unlock"
}
}
}
},
"signed_notification_description_%@" : {
"comment" : "When the user performs an action using a secret, they're shown a notification describing what happened. This is the description, showing which secret was used. The placeholder is the name of the secret.",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Using secret %1$@"
}
}
}
},
"signed_notification_title_%@" : {
"comment" : "When the user performs an action using a secret, they're shown a notification describing what happened. This is the title, showing which app requested the action. The placeholder is the name of the app.",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Signed Request from %1$@"
}
}
}
},
"update_notification_ignore_button" : {
"comment" : "When an update is available, a notification is shown. This is the button to decline an update.",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Ignore"
}
}
}
},
"update_notification_update_button" : {
"comment" : "When an update is available, a notification is shown. This is the button to download an update.",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Update"
}
}
}
},
"update_notification_update_critical_title_%@" : {
"comment" : "When an update is available, a notification is shown. This is the title for a very high priority update with security fixes. The placeholder is for the application version, eg \"Critical Security Update - 2.0\"",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Critical Security Update - %1$@"
}
}
}
},
"update_notification_update_description" : {
"comment" : "When an update is available, a notification is shown. This is the description to download an update.",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Click to Update"
}
}
}
},
"update_notification_update_normal_title_%@" : {
"comment" : "When an update is available, a notification is shown. This is the title for a normal priority update. The placeholder is for the application version, eg \"Update Available - 2.0\"",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Update Available - %1$@"
}
}
}
}
},
"version" : "1.0"
}

View File

@ -19,7 +19,6 @@
5003EF632780081B00DF2006 /* SecureEnclaveSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF622780081B00DF2006 /* SecureEnclaveSecretKit */; }; 5003EF632780081B00DF2006 /* SecureEnclaveSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF622780081B00DF2006 /* SecureEnclaveSecretKit */; };
5003EF652780081B00DF2006 /* SmartCardSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF642780081B00DF2006 /* SmartCardSecretKit */; }; 5003EF652780081B00DF2006 /* SmartCardSecretKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5003EF642780081B00DF2006 /* SmartCardSecretKit */; };
500B93C32B478D8400E157DE /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 500B93C22B478D8400E157DE /* Localizable.xcstrings */; }; 500B93C32B478D8400E157DE /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 500B93C22B478D8400E157DE /* Localizable.xcstrings */; };
500B93C72B479E2E00E157DE /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 500B93C62B479E2E00E157DE /* Localizable.xcstrings */; };
501421622781262300BBAA70 /* Brief in Frameworks */ = {isa = PBXBuildFile; productRef = 501421612781262300BBAA70 /* Brief */; }; 501421622781262300BBAA70 /* Brief in Frameworks */ = {isa = PBXBuildFile; productRef = 501421612781262300BBAA70 /* Brief */; };
501421652781268000BBAA70 /* SecretAgent.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 50A3B78A24026B7500D209EA /* SecretAgent.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 501421652781268000BBAA70 /* SecretAgent.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 50A3B78A24026B7500D209EA /* SecretAgent.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
50153E20250AFCB200525160 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E1F250AFCB200525160 /* UpdateView.swift */; }; 50153E20250AFCB200525160 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E1F250AFCB200525160 /* UpdateView.swift */; };
@ -53,6 +52,7 @@
50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B8550C24138C4F009958AC /* DeleteSecretView.swift */; }; 50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B8550C24138C4F009958AC /* DeleteSecretView.swift */; };
50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */; }; 50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BB046A2418AAAE00D6E079 /* EmptyStoreView.swift */; };
50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C385A42407A76D00AF2719 /* SecretDetailView.swift */; }; 50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C385A42407A76D00AF2719 /* SecretDetailView.swift */; };
50E9CF422B51D596004AB36D /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 500B93C22B478D8400E157DE /* Localizable.xcstrings */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -111,7 +111,6 @@
50033AC227813F1700253856 /* BundleIDs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleIDs.swift; sourceTree = "<group>"; }; 50033AC227813F1700253856 /* BundleIDs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleIDs.swift; sourceTree = "<group>"; };
5003EF39278005C800DF2006 /* Packages */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Packages; sourceTree = "<group>"; }; 5003EF39278005C800DF2006 /* Packages */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Packages; sourceTree = "<group>"; };
500B93C22B478D8400E157DE /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; }; 500B93C22B478D8400E157DE /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
500B93C62B479E2E00E157DE /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
50153E1F250AFCB200525160 /* UpdateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateView.swift; sourceTree = "<group>"; }; 50153E1F250AFCB200525160 /* UpdateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateView.swift; sourceTree = "<group>"; };
50153E21250DECA300525160 /* SecretListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretListItemView.swift; sourceTree = "<group>"; }; 50153E21250DECA300525160 /* SecretListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretListItemView.swift; sourceTree = "<group>"; };
5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; }; 5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; };
@ -316,7 +315,6 @@
50A3B79824026B7600D209EA /* Info.plist */, 50A3B79824026B7600D209EA /* Info.plist */,
508BF29425B4F140009EFB7E /* InternetAccessPolicy.plist */, 508BF29425B4F140009EFB7E /* InternetAccessPolicy.plist */,
50A3B79924026B7600D209EA /* SecretAgent.entitlements */, 50A3B79924026B7600D209EA /* SecretAgent.entitlements */,
500B93C62B479E2E00E157DE /* Localizable.xcstrings */,
50A3B79224026B7600D209EA /* Preview Content */, 50A3B79224026B7600D209EA /* Preview Content */,
); );
path = SecretAgent; path = SecretAgent;
@ -431,6 +429,13 @@
knownRegions = ( knownRegions = (
en, en,
Base, Base,
it,
fr,
de,
"pt-BR",
fi,
ko,
ca,
); );
mainGroup = 50617D7623FCE48D0099B055; mainGroup = 50617D7623FCE48D0099B055;
productRefGroup = 50617D8023FCE48E0099B055 /* Products */; productRefGroup = 50617D8023FCE48E0099B055 /* Products */;
@ -469,7 +474,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
50A3B79724026B7600D209EA /* Main.storyboard in Resources */, 50A3B79724026B7600D209EA /* Main.storyboard in Resources */,
500B93C72B479E2E00E157DE /* Localizable.xcstrings in Resources */, 50E9CF422B51D596004AB36D /* Localizable.xcstrings in Resources */,
50A3B79424026B7600D209EA /* Preview Assets.xcassets in Resources */, 50A3B79424026B7600D209EA /* Preview Assets.xcassets in Resources */,
50A3B79124026B7600D209EA /* Assets.xcassets in Resources */, 50A3B79124026B7600D209EA /* Assets.xcassets in Resources */,
508BF2AA25B4F1CB009EFB7E /* InternetAccessPolicy.plist in Resources */, 508BF2AA25B4F1CB009EFB7E /* InternetAccessPolicy.plist in Resources */,
@ -609,7 +614,7 @@
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_SWIFT_FLAGS = "-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks"; OTHER_SWIFT_FLAGS = "";
SDKROOT = macosx; SDKROOT = macosx;
STRIP_INSTALLED_PRODUCT = NO; STRIP_INSTALLED_PRODUCT = NO;
STRIP_SWIFT_SYMBOLS = NO; STRIP_SWIFT_SYMBOLS = NO;
@ -668,7 +673,7 @@
MACOSX_DEPLOYMENT_TARGET = 11.0; MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks"; OTHER_SWIFT_FLAGS = "";
SDKROOT = macosx; SDKROOT = macosx;
STRIP_INSTALLED_PRODUCT = NO; STRIP_INSTALLED_PRODUCT = NO;
STRIP_SWIFT_SYMBOLS = NO; STRIP_SWIFT_SYMBOLS = NO;
@ -702,7 +707,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
}; };
name = Debug; name = Debug;
@ -731,7 +735,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "Secretive - Host"; PROVISIONING_PROFILE_SPECIFIER = "Secretive - Host";
SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
}; };
name = Release; name = Release;
@ -834,7 +837,7 @@
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_SWIFT_FLAGS = "-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks"; OTHER_SWIFT_FLAGS = "";
SDKROOT = macosx; SDKROOT = macosx;
STRIP_INSTALLED_PRODUCT = NO; STRIP_INSTALLED_PRODUCT = NO;
STRIP_SWIFT_SYMBOLS = NO; STRIP_SWIFT_SYMBOLS = NO;
@ -864,7 +867,6 @@
MARKETING_VERSION = 1; MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
}; };
name = Test; name = Test;
@ -909,7 +911,6 @@
MARKETING_VERSION = 1; MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
}; };
name = Test; name = Test;
@ -934,7 +935,6 @@
MARKETING_VERSION = 1; MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
}; };
name = Debug; name = Debug;
@ -961,7 +961,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent; PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "Secretive - Secret Agent"; PROVISIONING_PROFILE_SPECIFIER = "Secretive - Secret Agent";
SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
}; };
name = Release; name = Release;

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@ struct SetupView: View {
} }
} }
} }
.frame(idealWidth: 500, idealHeight: 500) .frame(minWidth: 500, idealWidth: 500, minHeight: 500, idealHeight: 500)
} }

View File

@ -42,16 +42,16 @@ struct UpdateDetailView<UpdaterType: Updater>: View {
if let prefix = split.first { if let prefix = split.first {
switch prefix { switch prefix {
case "#": case "#":
attributed = Text(unprefixed).font(.title) + Text("\n") attributed = Text(unprefixed).font(.title) + Text(verbatim: "\n")
case "##": case "##":
attributed = Text(unprefixed).font(.title2) + Text("\n") attributed = Text(unprefixed).font(.title2) + Text(verbatim: "\n")
case "###": case "###":
attributed = Text(unprefixed).font(.title3) + Text("\n") attributed = Text(unprefixed).font(.title3) + Text(verbatim: "\n")
default: default:
attributed = Text(line) + Text("\n\n") attributed = Text(line) + Text(verbatim: "\n\n")
} }
} else { } else {
attributed = Text(line) + Text("\n\n") attributed = Text(line) + Text(verbatim: "\n\n")
} }
text = text + attributed text = text + attributed
} }