Package and updater
This commit is contained in:
parent
6f4226f97a
commit
56a662a9dd
|
@ -1,12 +1,14 @@
|
|||
// swift-tools-version:5.9
|
||||
// swift-tools-version: 6.0
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let secretiveDefaults: [PackageDescription.SwiftSetting]? = [.swiftLanguageMode(.v6), .unsafeFlags(["-warnings-as-errors"])]
|
||||
|
||||
let package = Package(
|
||||
name: "SecretivePackages",
|
||||
platforms: [
|
||||
.macOS(.v12)
|
||||
.macOS(.v13)
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
|
@ -34,27 +36,27 @@ let package = Package(
|
|||
.target(
|
||||
name: "SecretKit",
|
||||
dependencies: [],
|
||||
swiftSettings: [.enableExperimentalFeature("StrictConcurrency"), .unsafeFlags(["-warnings-as-errors"])]
|
||||
swiftSettings: secretiveDefaults
|
||||
),
|
||||
.testTarget(
|
||||
name: "SecretKitTests",
|
||||
dependencies: ["SecretKit", "SecureEnclaveSecretKit", "SmartCardSecretKit"],
|
||||
swiftSettings: [.enableExperimentalFeature("StrictConcurrency"), .unsafeFlags(["-warnings-as-errors"])]
|
||||
swiftSettings: secretiveDefaults
|
||||
),
|
||||
.target(
|
||||
name: "SecureEnclaveSecretKit",
|
||||
dependencies: ["SecretKit"],
|
||||
swiftSettings: [.enableExperimentalFeature("StrictConcurrency"), .unsafeFlags(["-warnings-as-errors"])]
|
||||
swiftSettings: secretiveDefaults
|
||||
),
|
||||
.target(
|
||||
name: "SmartCardSecretKit",
|
||||
dependencies: ["SecretKit"],
|
||||
swiftSettings: [.enableExperimentalFeature("StrictConcurrency"), .unsafeFlags(["-warnings-as-errors"])]
|
||||
swiftSettings: secretiveDefaults
|
||||
),
|
||||
.target(
|
||||
name: "SecretAgentKit",
|
||||
dependencies: ["SecretKit", "SecretAgentKitHeaders"],
|
||||
swiftSettings: [.enableExperimentalFeature("StrictConcurrency"), .unsafeFlags(["-warnings-as-errors"])]
|
||||
swiftSettings: secretiveDefaults
|
||||
),
|
||||
.systemLibrary(
|
||||
name: "SecretAgentKitHeaders"
|
||||
|
@ -73,3 +75,4 @@ let package = Package(
|
|||
),
|
||||
]
|
||||
)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Foundation
|
||||
|
||||
/// A release is a representation of a downloadable update.
|
||||
public struct Release: Codable {
|
||||
public struct Release: Codable, Sendable {
|
||||
|
||||
/// The user-facing name of the release. Typically "Secretive 1.2.3"
|
||||
public let name: String
|
||||
|
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import Combine
|
||||
|
||||
/// A concrete implementation of ``UpdaterProtocol`` which considers the current release and OS version.
|
||||
public final class Updater: ObservableObject, UpdaterProtocol {
|
||||
@MainActor public final class Updater: ObservableObject, UpdaterProtocol, Sendable {
|
||||
|
||||
@Published public var update: Release?
|
||||
public let testBuild: Bool
|
||||
|
@ -18,27 +18,27 @@ public final class Updater: ObservableObject, UpdaterProtocol {
|
|||
/// - checkFrequency: The interval at which the Updater should check for updates. Subject to a tolerance of 1 hour.
|
||||
/// - osVersion: The current OS version.
|
||||
/// - currentVersion: The current version of the app that is running.
|
||||
public init(checkOnLaunch: Bool, checkFrequency: TimeInterval = Measurement(value: 24, unit: UnitDuration.hours).converted(to: .seconds).value, osVersion: SemVer = SemVer(ProcessInfo.processInfo.operatingSystemVersion), currentVersion: SemVer = SemVer(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "0.0.0")) {
|
||||
public init(checkOnLaunch: Bool, checkFrequency: Duration = .seconds(24*60*60), osVersion: SemVer = SemVer(ProcessInfo.processInfo.operatingSystemVersion), currentVersion: SemVer = SemVer(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "0.0.0")) {
|
||||
self.osVersion = osVersion
|
||||
self.currentVersion = currentVersion
|
||||
testBuild = currentVersion == SemVer("0.0.0")
|
||||
if checkOnLaunch {
|
||||
// Don't do a launch check if the user hasn't seen the setup prompt explaining updater yet.
|
||||
checkForUpdates()
|
||||
Task {
|
||||
if checkOnLaunch {
|
||||
// Don't do a launch check if the user hasn't seen the setup prompt explaining updater yet.
|
||||
await checkForUpdates()
|
||||
}
|
||||
while true {
|
||||
try await Task.sleep(for: checkFrequency, tolerance: .seconds(60*60))
|
||||
await checkForUpdates()
|
||||
}
|
||||
}
|
||||
let timer = Timer.scheduledTimer(withTimeInterval: checkFrequency, repeats: true) { _ in
|
||||
self.checkForUpdates()
|
||||
}
|
||||
timer.tolerance = 60*60
|
||||
}
|
||||
|
||||
/// Manually trigger an update check.
|
||||
public func checkForUpdates() {
|
||||
URLSession.shared.dataTask(with: Constants.updateURL) { data, _, _ in
|
||||
guard let data = data else { return }
|
||||
guard let releases = try? JSONDecoder().decode([Release].self, from: data) else { return }
|
||||
self.evaluate(releases: releases)
|
||||
}.resume()
|
||||
public func checkForUpdates() async {
|
||||
guard let (data, _) = try? await URLSession.shared.data(from: Constants.updateURL) else { return }
|
||||
guard let releases = try? JSONDecoder().decode([Release].self, from: data) else { return }
|
||||
evaluate(releases: releases)
|
||||
}
|
||||
|
||||
/// Ignores a specified release. `update` will be nil if the user has ignored the latest available release.
|
||||
|
|
|
@ -5,7 +5,7 @@ import Combine
|
|||
public protocol UpdaterProtocol: ObservableObject {
|
||||
|
||||
/// The latest update
|
||||
var update: Release? { get }
|
||||
@MainActor var update: Release? { get }
|
||||
/// A boolean describing whether or not the current build of the app is a "test" build (ie, a debug build or otherwise special build)
|
||||
var testBuild: Bool { get }
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import SecretKit
|
|||
import AppKit
|
||||
|
||||
/// The `Agent` is an implementation of an SSH agent. It manages coordination and access between a socket, traces requests, notifies witnesses and passes requests to stores.
|
||||
public final class Agent {
|
||||
public actor Agent {
|
||||
|
||||
private let storeList: SecretStoreList
|
||||
private let witness: SigningWitness?
|
||||
|
@ -35,7 +35,7 @@ extension Agent {
|
|||
/// - writer: A ``FileHandleWriter`` to write the response to.
|
||||
/// - Return value:
|
||||
/// - 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")
|
||||
let data = Data(reader.availableData)
|
||||
guard data.count > 4 else { return false}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Foundation
|
||||
|
||||
/// Type eraser for Secret.
|
||||
public struct AnySecret: Secret {
|
||||
public struct AnySecret: Secret, @unchecked Sendable {
|
||||
|
||||
let base: Any
|
||||
private let hashable: AnyHashable
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Foundation
|
||||
|
||||
/// The base protocol for describing a Secret
|
||||
public protocol Secret: Identifiable, Hashable {
|
||||
public protocol Secret: Identifiable, Hashable, Sendable {
|
||||
|
||||
/// A user-facing string identifying the Secret.
|
||||
var name: String { get }
|
||||
|
@ -17,7 +17,7 @@ public protocol Secret: Identifiable, Hashable {
|
|||
}
|
||||
|
||||
/// The type of algorithm the Secret uses. Currently, only elliptic curve algorithms are supported.
|
||||
public enum Algorithm: Hashable {
|
||||
public enum Algorithm: Hashable, Sendable {
|
||||
|
||||
case ellipticCurve
|
||||
case rsa
|
||||
|
|
|
@ -8,7 +8,7 @@ import SecretKit
|
|||
extension SecureEnclave {
|
||||
|
||||
/// An implementation of Store backed by the Secure Enclave.
|
||||
public final class Store: SecretStoreModifiable {
|
||||
public final class Store: SecretStoreModifiable, Sendable {
|
||||
|
||||
public var isAvailable: Bool {
|
||||
// For some reason, as of build time, CryptoKit.SecureEnclave.isAvailable always returns false
|
||||
|
@ -18,14 +18,18 @@ extension SecureEnclave {
|
|||
}
|
||||
public let id = UUID()
|
||||
public let name = String(localized: "secure_enclave")
|
||||
@Published public private(set) var secrets: [Secret] = []
|
||||
@MainActor public private(set) var secrets: [Secret] = [] {
|
||||
willSet {
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
private var persistedAuthenticationContexts: [Secret: PersistentAuthenticationContext] = [:]
|
||||
@MainActor private var persistedAuthenticationContexts: [Secret: PersistentAuthenticationContext] = [:]
|
||||
|
||||
/// Initializes a Store.
|
||||
public init() {
|
||||
DistributedNotificationCenter.default().addObserver(forName: .secretStoreUpdated, object: nil, queue: .main) { [reload = reloadSecretsInternal(notifyAgent:)] _ in
|
||||
reload(false)
|
||||
DistributedNotificationCenter.default().addObserver(forName: .secretStoreUpdated, object: nil, queue: .main) { _ in
|
||||
self.reloadSecretsInternal(notifyAgent: false)
|
||||
}
|
||||
loadSecrets()
|
||||
}
|
||||
|
@ -211,7 +215,7 @@ extension SecureEnclave.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.
|
||||
@Sendable private func reloadSecretsInternal(notifyAgent: Bool = true) {
|
||||
private func reloadSecretsInternal(notifyAgent: Bool = true) {
|
||||
let before = secrets
|
||||
secrets.removeAll()
|
||||
loadSecrets()
|
||||
|
@ -304,8 +308,8 @@ extension SecureEnclave.Store {
|
|||
extension SecureEnclave {
|
||||
|
||||
enum Constants {
|
||||
static let keyTag = "com.maxgoedjen.secretive.secureenclave.key".data(using: .utf8)! as CFData
|
||||
static let keyType = kSecAttrKeyTypeECSECPrimeRandom
|
||||
static let keyTag = "com.maxgoedjen.secretive.secureenclave.key".data(using: .utf8)!
|
||||
static let keyType = kSecAttrKeyTypeECSECPrimeRandom as String
|
||||
static let unauthenticatedThreshold: TimeInterval = 0.05
|
||||
}
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@ extension SmartCard {
|
|||
/// Initializes a Store.
|
||||
public init() {
|
||||
tokenID = watcher.nonSecureEnclaveTokens.first
|
||||
watcher.setInsertionHandler { [reload = reloadSecretsInternal] string in
|
||||
watcher.setInsertionHandler { string in
|
||||
guard self.tokenID == nil else { return }
|
||||
guard !string.contains("setoken") else { return }
|
||||
|
||||
self.tokenID = string
|
||||
DispatchQueue.main.async {
|
||||
reload()
|
||||
// reload()
|
||||
}
|
||||
self.watcher.addRemovalHandler(self.smartcardRemoved, forTokenID: string)
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ extension SmartCard {
|
|||
|
||||
extension SmartCard.Store {
|
||||
|
||||
@Sendable private func reloadSecretsInternal() {
|
||||
private func reloadSecretsInternal() {
|
||||
self.isAvailable = self.tokenID != nil
|
||||
let before = self.secrets
|
||||
self.secrets.removeAll()
|
||||
|
|
|
@ -5,7 +5,7 @@ import SecretKit
|
|||
import SecretAgentKit
|
||||
import Brief
|
||||
|
||||
class Notifier {
|
||||
final class Notifier: Sendable {
|
||||
|
||||
private let notificationDelegate = NotificationDelegate()
|
||||
|
||||
|
@ -129,7 +129,8 @@ extension Notifier {
|
|||
|
||||
}
|
||||
|
||||
class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate {
|
||||
// FIXME: UNCHECKED SENDABLE
|
||||
@MainActor final class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate, @unchecked Sendable {
|
||||
|
||||
fileprivate var release: Release?
|
||||
fileprivate var ignore: ((Release) -> Void)?
|
||||
|
@ -138,7 +139,7 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate {
|
|||
fileprivate var pendingPersistableStores: [String: AnySecretStore] = [:]
|
||||
fileprivate var pendingPersistableSecrets: [String: AnySecret] = [:]
|
||||
|
||||
func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?) {
|
||||
nonisolated func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -619,6 +619,7 @@
|
|||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 6.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -678,6 +679,7 @@
|
|||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 6.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -700,13 +702,12 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -729,13 +730,12 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "Secretive - Host";
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -755,7 +755,6 @@
|
|||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretiveTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Secretive.app/Contents/MacOS/Secretive";
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -776,7 +775,6 @@
|
|||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretiveTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Secretive.app/Contents/MacOS/Secretive";
|
||||
};
|
||||
name = Release;
|
||||
|
@ -844,6 +842,7 @@
|
|||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 6.0;
|
||||
};
|
||||
name = Test;
|
||||
};
|
||||
|
@ -863,12 +862,11 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Test;
|
||||
};
|
||||
|
@ -889,7 +887,6 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.SecretiveTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Secretive.app/Contents/MacOS/Secretive";
|
||||
};
|
||||
name = Test;
|
||||
|
@ -908,12 +905,11 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Test;
|
||||
};
|
||||
|
@ -933,12 +929,11 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -959,13 +954,12 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "Secretive - Secret Agent";
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"agent_not_running_notice_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -48,6 +49,7 @@
|
|||
}
|
||||
},
|
||||
"agent_running_notice_detail_description" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -94,6 +96,7 @@
|
|||
}
|
||||
},
|
||||
"agent_running_notice_detail_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -140,6 +143,7 @@
|
|||
}
|
||||
},
|
||||
"agent_running_notice_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -186,6 +190,7 @@
|
|||
}
|
||||
},
|
||||
"agent_setup_notice_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -232,6 +237,7 @@
|
|||
}
|
||||
},
|
||||
"app_menu_help_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -278,6 +284,7 @@
|
|||
}
|
||||
},
|
||||
"app_menu_new_secret_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -324,6 +331,7 @@
|
|||
}
|
||||
},
|
||||
"app_menu_setup_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -370,6 +378,7 @@
|
|||
}
|
||||
},
|
||||
"app_not_in_applications_notice_detail_description" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -416,6 +425,7 @@
|
|||
}
|
||||
},
|
||||
"app_not_in_applications_notice_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -798,6 +808,7 @@
|
|||
}
|
||||
},
|
||||
"copyable_click_to_copy_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -844,6 +855,7 @@
|
|||
}
|
||||
},
|
||||
"copyable_copied" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -890,6 +902,7 @@
|
|||
}
|
||||
},
|
||||
"create_secret_cancel_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -936,6 +949,7 @@
|
|||
}
|
||||
},
|
||||
"create_secret_create_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -982,6 +996,7 @@
|
|||
}
|
||||
},
|
||||
"create_secret_name_label" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1028,6 +1043,7 @@
|
|||
}
|
||||
},
|
||||
"create_secret_name_placeholder" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1074,6 +1090,7 @@
|
|||
}
|
||||
},
|
||||
"create_secret_notify_description" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1120,6 +1137,7 @@
|
|||
}
|
||||
},
|
||||
"create_secret_notify_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1166,6 +1184,7 @@
|
|||
}
|
||||
},
|
||||
"create_secret_require_authentication_description" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1212,6 +1231,7 @@
|
|||
}
|
||||
},
|
||||
"create_secret_require_authentication_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1258,6 +1278,7 @@
|
|||
}
|
||||
},
|
||||
"create_secret_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1304,6 +1325,7 @@
|
|||
}
|
||||
},
|
||||
"delete_confirmation_cancel_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1350,6 +1372,7 @@
|
|||
}
|
||||
},
|
||||
"delete_confirmation_confirm_name_label" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1396,6 +1419,7 @@
|
|||
}
|
||||
},
|
||||
"delete_confirmation_delete_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1442,6 +1466,7 @@
|
|||
}
|
||||
},
|
||||
"delete_confirmation_description_%@_%@" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1488,6 +1513,7 @@
|
|||
}
|
||||
},
|
||||
"delete_confirmation_title_%@" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1534,6 +1560,7 @@
|
|||
}
|
||||
},
|
||||
"empty_store_modifiable_click_here_description" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1580,6 +1607,7 @@
|
|||
}
|
||||
},
|
||||
"empty_store_modifiable_click_here_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1626,6 +1654,7 @@
|
|||
}
|
||||
},
|
||||
"empty_store_modifiable_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1672,6 +1701,7 @@
|
|||
}
|
||||
},
|
||||
"empty_store_nonmodifiable_description" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1718,6 +1748,7 @@
|
|||
}
|
||||
},
|
||||
"empty_store_nonmodifiable_supported_key_types" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1764,6 +1795,7 @@
|
|||
}
|
||||
},
|
||||
"empty_store_nonmodifiable_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1810,6 +1842,7 @@
|
|||
}
|
||||
},
|
||||
"no_secure_storage_description" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1856,6 +1889,7 @@
|
|||
}
|
||||
},
|
||||
"no_secure_storage_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -1902,6 +1936,7 @@
|
|||
}
|
||||
},
|
||||
"no_secure_storage_yubico_link" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2044,6 +2079,7 @@
|
|||
}
|
||||
},
|
||||
"rename_cancel_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2084,6 +2120,7 @@
|
|||
}
|
||||
},
|
||||
"rename_rename_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2124,6 +2161,7 @@
|
|||
}
|
||||
},
|
||||
"rename_title_%@" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2164,6 +2202,7 @@
|
|||
}
|
||||
},
|
||||
"secret_detail_md5_fingerprint_label" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2204,6 +2243,7 @@
|
|||
}
|
||||
},
|
||||
"secret_detail_public_key_label" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2244,6 +2284,7 @@
|
|||
}
|
||||
},
|
||||
"secret_detail_public_key_path_label" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2284,6 +2325,7 @@
|
|||
}
|
||||
},
|
||||
"secret_detail_sha256_fingerprint_label" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2324,6 +2366,7 @@
|
|||
}
|
||||
},
|
||||
"secret_list_delete_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2364,6 +2407,7 @@
|
|||
}
|
||||
},
|
||||
"secret_list_rename_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2445,6 +2489,7 @@
|
|||
}
|
||||
},
|
||||
"setup_agent_activity_monitor_description" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2485,6 +2530,7 @@
|
|||
}
|
||||
},
|
||||
"setup_agent_description" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2525,6 +2571,7 @@
|
|||
}
|
||||
},
|
||||
"setup_agent_install_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2565,6 +2612,7 @@
|
|||
}
|
||||
},
|
||||
"setup_agent_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2605,6 +2653,7 @@
|
|||
}
|
||||
},
|
||||
"setup_ssh_add_for_me_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2645,6 +2694,7 @@
|
|||
}
|
||||
},
|
||||
"setup_ssh_add_to_config_button_%@" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2685,6 +2735,7 @@
|
|||
}
|
||||
},
|
||||
"setup_ssh_added_manually_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2725,6 +2776,7 @@
|
|||
}
|
||||
},
|
||||
"setup_ssh_description" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2765,6 +2817,7 @@
|
|||
}
|
||||
},
|
||||
"setup_ssh_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2805,6 +2858,7 @@
|
|||
}
|
||||
},
|
||||
"setup_step_complete_symbol" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2845,6 +2899,7 @@
|
|||
}
|
||||
},
|
||||
"setup_third_party_faq_link" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2885,6 +2940,7 @@
|
|||
}
|
||||
},
|
||||
"setup_updates_description" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2925,6 +2981,7 @@
|
|||
}
|
||||
},
|
||||
"setup_updates_ok" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -2965,6 +3022,7 @@
|
|||
}
|
||||
},
|
||||
"setup_updates_readmore" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -3005,6 +3063,7 @@
|
|||
}
|
||||
},
|
||||
"setup_updates_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -3211,6 +3270,7 @@
|
|||
}
|
||||
},
|
||||
"update_critical_notice_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -3251,6 +3311,7 @@
|
|||
}
|
||||
},
|
||||
"update_ignore_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -3291,6 +3352,7 @@
|
|||
}
|
||||
},
|
||||
"update_normal_notice_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -3541,6 +3603,7 @@
|
|||
}
|
||||
},
|
||||
"update_release_notes_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -3581,6 +3644,7 @@
|
|||
}
|
||||
},
|
||||
"update_test_notice_title" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -3621,6 +3685,7 @@
|
|||
}
|
||||
},
|
||||
"update_update_button" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
@ -3661,6 +3726,7 @@
|
|||
}
|
||||
},
|
||||
"update_version_name_%@" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
|
Loading…
Reference in New Issue