mirror of
https://github.com/maxgoedjen/secretive.git
synced 2026-09-27 18:48:00 +02:00
Pending request view (#821)
* Splitting out auth context stuff in preparation for batch * Add uncommitted authhandler rename * Split out auth/nonauth paths * Messy auth batching infra WIP * Restrict connectionAcceptedNotifications to creating filehandle * WIP * WIP * WIP * WIP * WIP * Reenable multilineinfoview * WIP * WIP * Fixing up tests * WIP * Return empty bind response on parse throw * JSON project * JSON Project * WIP * WIP * Almost done * Tests * Cleanup test calls * Fixme * Cleanup * Localized strings
This commit is contained in:
@@ -11,7 +11,7 @@ import CertificateKit
|
||||
// MARK: Identity Listing
|
||||
|
||||
@Test func emptyStores() async throws {
|
||||
let agent = Agent(storeList: SecretStoreList(), certificateStore: CertificateStore())
|
||||
let agent = Agent(storeList: SecretStoreList(), certificateStore: CertificateStore(), authenticationHandler: AuthenticationHandler())
|
||||
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestIdentities)
|
||||
let response = await agent.handle(request: request, provenance: .test, hosts: nil)
|
||||
#expect(response == Constants.Responses.requestIdentitiesEmpty)
|
||||
@@ -19,7 +19,7 @@ import CertificateKit
|
||||
|
||||
@Test func identitiesList() async throws {
|
||||
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore())
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore(), authenticationHandler: AuthenticationHandler())
|
||||
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestIdentities)
|
||||
let response = await agent.handle(request: request, provenance: .test, hosts: nil)
|
||||
|
||||
@@ -33,7 +33,7 @@ import CertificateKit
|
||||
|
||||
@Test func noMatchingIdentities() async throws {
|
||||
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore())
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore(), authenticationHandler: AuthenticationHandler())
|
||||
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignatureWithNoneMatching)
|
||||
let response = await agent.handle(request: request, provenance: .test, hosts: nil)
|
||||
#expect(response == Constants.Responses.requestFailure)
|
||||
@@ -43,7 +43,7 @@ import CertificateKit
|
||||
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignature)
|
||||
guard case SSHAgent.Request.signRequest(let context) = request else { return }
|
||||
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore())
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore(), authenticationHandler: AuthenticationHandler())
|
||||
let response = await agent.handle(request: request, provenance: .test, hosts: nil)
|
||||
let responseReader = OpenSSHReader(data: response)
|
||||
let length = try responseReader.readNextBytes(as: UInt32.self)
|
||||
@@ -78,7 +78,7 @@ import CertificateKit
|
||||
let witness = StubWitness(speakNow: { _,_ in
|
||||
return true
|
||||
}, witness: { _, _ in })
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore(), witness: witness)
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore(), authenticationHandler: AuthenticationHandler(), witness: witness)
|
||||
let response = await agent.handle(request: .signRequest(.empty), provenance: .test, hosts: nil)
|
||||
#expect(response == Constants.Responses.requestFailure)
|
||||
}
|
||||
@@ -91,7 +91,7 @@ import CertificateKit
|
||||
}, witness: { _, trace in
|
||||
witnessed = true
|
||||
})
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore(), witness: witness)
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore(), authenticationHandler: AuthenticationHandler(), witness: witness)
|
||||
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignature)
|
||||
_ = await agent.handle(request: request, provenance: .test, hosts: nil)
|
||||
#expect(witnessed)
|
||||
@@ -107,7 +107,7 @@ import CertificateKit
|
||||
}, witness: { _, trace in
|
||||
witnessTrace = trace
|
||||
})
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore(), witness: witness)
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore(), authenticationHandler: AuthenticationHandler(), witness: witness)
|
||||
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignature)
|
||||
_ = await agent.handle(request: request, provenance: .test, hosts: nil)
|
||||
#expect(witnessTrace == speakNowTrace)
|
||||
@@ -120,7 +120,7 @@ import CertificateKit
|
||||
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
|
||||
let store = list.stores.first?.base as! Stub.Store
|
||||
store.shouldThrow = true
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore())
|
||||
let agent = Agent(storeList: list, certificateStore: CertificateStore(), authenticationHandler: AuthenticationHandler())
|
||||
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignature)
|
||||
let response = await agent.handle(request: request, provenance: .test, hosts: nil)
|
||||
#expect(response == Constants.Responses.requestFailure)
|
||||
@@ -129,48 +129,9 @@ import CertificateKit
|
||||
// MARK: Unsupported
|
||||
|
||||
@Test func unhandledAdd() async throws {
|
||||
let agent = Agent(storeList: SecretStoreList(), certificateStore: CertificateStore())
|
||||
let agent = Agent(storeList: SecretStoreList(), certificateStore: CertificateStore(), authenticationHandler: AuthenticationHandler())
|
||||
let response = await agent.handle(request: .addIdentity, provenance: .test, hosts: nil)
|
||||
#expect(response == Constants.Responses.requestFailure)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SigningRequestProvenance {
|
||||
|
||||
static let test = SigningRequestProvenance(root: .init(pid: 0, processName: "test", appName: nil, iconURL: nil, path: "/", validSignature: true, parentPID: 0))
|
||||
|
||||
}
|
||||
|
||||
extension AgentTests {
|
||||
|
||||
func storeList(with secrets: [Stub.Secret]) async -> SecretStoreList {
|
||||
let store = Stub.Store()
|
||||
store.secrets.append(contentsOf: secrets)
|
||||
let storeList = SecretStoreList()
|
||||
storeList.add(store: store)
|
||||
return storeList
|
||||
}
|
||||
|
||||
enum Constants {
|
||||
|
||||
enum Requests {
|
||||
static let requestIdentities = Data(base64Encoded: "AAAAAQs=")!
|
||||
static let requestSignatureWithNoneMatching = Data(base64Encoded: "AAABhA0AAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqCbkJbOHy5S1wVCaJoKPmpS0egM4frMqllgnlRRQ/Uvnn6EVS8oV03cPA2Bz0EdESyRKA/sbmn0aBtgjIwGELxu45UXEW1TEz6TxyS0u3vuIqR3Wo1CrQWRDnkrG/pBQAAAO8AAAAgbqmrqPUtJ8mmrtaSVexjMYyXWNqjHSnoto7zgv86xvcyAAAAA2dpdAAAAA5zc2gtY29ubmVjdGlvbgAAAAlwdWJsaWNrZXkBAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqCbkJbOHy5S1wVCaJoKPmpS0egM4frMqllgnlRRQ/Uvnn6EVS8oV03cPA2Bz0EdESyRKA/sbmn0aBtgjIwGELxu45UXEW1TEz6TxyS0u3vuIqR3Wo1CrQWRDnkrG/pBQAAAAA=")!
|
||||
static let requestSignature = Data(base64Encoded: "AAABRA0AAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy08AAADPAAAAIBIFsbCZ4/dhBmLNGHm0GKj7EJ4N8k/jXRxlyg+LFIYzMgAAAANnaXQAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAAA==")!
|
||||
}
|
||||
|
||||
enum Responses {
|
||||
static let requestIdentitiesEmpty = Data(base64Encoded: "AAAABQwAAAAA")!
|
||||
static let requestIdentitiesMultiple = Data(base64Encoded: "AAABLwwAAAACAAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAFWVjZHNhLTI1NkBleGFtcGxlLmNvbQAAAIgAAAATZWNkc2Etc2hhMi1uaXN0cDM4NAAAAAhuaXN0cDM4NAAAAGEEspLMDmreMJverQkqKC9zF9ZUasn5uSWkbRlz1jNTCtuyH1KKm+VImL6wdAj47SbzwM6lEEC24AdfrR64P9i/bnS2i83v/4wQVtcZn+Et13QGgWlZst8lxCPzTookaVwMAAAAFWVjZHNhLTM4NEBleGFtcGxlLmNvbQ==")!
|
||||
static let requestFailure = Data(base64Encoded: "AAAAAQU=")!
|
||||
}
|
||||
|
||||
enum Secrets {
|
||||
static let ecdsa256Secret = Stub.Secret(keySize: 256, publicKey: Data(base64Encoded: "BKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy08=")!, privateKey: Data(base64Encoded: "BKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy09nw780wy/TSfUmzj15iJkV234AaCLNl+H8qFL6qK8VIg==")!)
|
||||
static let ecdsa384Secret = Stub.Secret(keySize: 384, publicKey: Data(base64Encoded: "BLKSzA5q3jCb3q0JKigvcxfWVGrJ+bklpG0Zc9YzUwrbsh9SipvlSJi+sHQI+O0m88DOpRBAtuAHX60euD/Yv250tovN7/+MEFbXGZ/hLdd0BoFpWbLfJcQj806KJGlcDA==")!, privateKey: Data(base64Encoded: "BLKSzA5q3jCb3q0JKigvcxfWVGrJ+bklpG0Zc9YzUwrbsh9SipvlSJi+sHQI+O0m88DOpRBAtuAHX60euD/Yv250tovN7/+MEFbXGZ/hLdd0BoFpWbLfJcQj806KJGlcDHNapAOzrt9E+9QC4/KYoXS7Uw4pmdAz53uIj02tttiq3c0ZyIQ7XoscWWRqRrz8Kw==")!)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
import Testing
|
||||
import Foundation
|
||||
import LocalAuthentication
|
||||
import SecretKit
|
||||
import SecretAgentKit
|
||||
import SSHProtocolKit
|
||||
|
||||
public struct TestSecret: Secret {
|
||||
|
||||
public let id = UUID()
|
||||
public let name = "Test"
|
||||
public let publicKey = Data()
|
||||
public var attributes: Attributes
|
||||
|
||||
}
|
||||
|
||||
@MainActor final class TestContext: @preconcurrency AuthenticationContextProtocol, Sendable {
|
||||
|
||||
let id = UUID()
|
||||
private var testEvaluationResult: Bool
|
||||
|
||||
private(set) var canceled: Bool
|
||||
private(set) var evaluationResult: Bool? = nil
|
||||
|
||||
let approval: ApprovalMode
|
||||
let secret: AnySecret
|
||||
let laContext: LAContext? = nil
|
||||
|
||||
enum ApprovalMode {
|
||||
case manual
|
||||
case duration(Duration)
|
||||
}
|
||||
|
||||
init(authenticationRequirement: AuthenticationRequirement, testEvaluationResult: Bool, approval: ApprovalMode = .manual) {
|
||||
self.canceled = false
|
||||
self.testEvaluationResult = testEvaluationResult
|
||||
self.secret = AnySecret(TestSecret(attributes: .init(keyType: .ecdsa256, authentication: authenticationRequirement)))
|
||||
self.approval = approval
|
||||
}
|
||||
|
||||
nonisolated func valid(for request: SecretKit.SignatureRequest) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
func evaluate() async throws -> Bool {
|
||||
if case let .duration(duration) = approval {
|
||||
try await Task.sleep(for: duration)
|
||||
} else {
|
||||
while true {
|
||||
try await Task.sleep(for: .milliseconds(10))
|
||||
guard !canceled else { return false }
|
||||
}
|
||||
}
|
||||
guard !canceled else { return false }
|
||||
evaluationResult = testEvaluationResult
|
||||
return testEvaluationResult
|
||||
}
|
||||
|
||||
func cancel() async {
|
||||
assert(!canceled)
|
||||
assert(evaluationResult == nil)
|
||||
canceled = true
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@MainActor @Suite struct AuthenticationHandlerTests {
|
||||
|
||||
let handler = AuthenticationHandler()
|
||||
|
||||
@Test func singleImmediatelyRequests() async throws {
|
||||
var calledPresentPending = false
|
||||
handler.setPendingRequestHandler {
|
||||
calledPresentPending = true
|
||||
}
|
||||
let context = TestContext(authenticationRequirement: .presenceRequired, testEvaluationResult: true, approval: .duration(.zero))
|
||||
_ = try await handler.authenticatedContext(for: .init(secret: .init(context.secret), provenance: .test, target: nil), context: context)
|
||||
#expect(context.evaluationResult == true)
|
||||
#expect(!calledPresentPending)
|
||||
}
|
||||
|
||||
@Test func sequentialRequestsDoNotBlock() async throws {
|
||||
var calledPresentPending = false
|
||||
handler.setPendingRequestHandler {
|
||||
calledPresentPending = true
|
||||
}
|
||||
let context = TestContext(authenticationRequirement: .presenceRequired, testEvaluationResult: true, approval: .duration(.milliseconds(1)))
|
||||
_ = try await handler.authenticatedContext(for: .init(secret: .init(context.secret), provenance: .test, target: nil), context: context)
|
||||
#expect(context.evaluationResult == true)
|
||||
let second = TestContext(authenticationRequirement: .presenceRequired, testEvaluationResult: true, approval: .duration(.milliseconds(1)))
|
||||
_ = try await handler.authenticatedContext(for: .init(secret: .init(second.secret), provenance: .test, target: nil), context: second)
|
||||
#expect(context.evaluationResult == true)
|
||||
#expect(second.evaluationResult == true)
|
||||
#expect(!calledPresentPending)
|
||||
}
|
||||
|
||||
@Test func secondRetractsAndPresentsBatch() async throws {
|
||||
var calledPresentPending = false
|
||||
handler.setPendingRequestHandler {
|
||||
calledPresentPending = true
|
||||
}
|
||||
let contextA = TestContext(authenticationRequirement: .presenceRequired, testEvaluationResult: true)
|
||||
let contextB = TestContext(authenticationRequirement: .presenceRequired, testEvaluationResult: true)
|
||||
Task {
|
||||
_ = try? await handler.authenticatedContext(for: .init(secret: .init(contextA.secret), provenance: .test, target: nil), context: contextA)
|
||||
}
|
||||
Task {
|
||||
_ = try? await handler.authenticatedContext(for: .init(secret: .init(contextB.secret), provenance: .test, target: nil), context: contextB)
|
||||
}
|
||||
#expect(contextA.evaluationResult == nil)
|
||||
#expect(contextB.evaluationResult == nil)
|
||||
await Task.yield()
|
||||
#expect(contextA.canceled)
|
||||
#expect(calledPresentPending)
|
||||
}
|
||||
|
||||
@Test func authRequiredDoesNotBlockNoAuthRequired() async throws {
|
||||
var calledPresentPending = false
|
||||
handler.setPendingRequestHandler {
|
||||
calledPresentPending = true
|
||||
}
|
||||
let contextA = TestContext(authenticationRequirement: .presenceRequired, testEvaluationResult: true, approval: .manual)
|
||||
let contextB = TestContext(authenticationRequirement: .notRequired, testEvaluationResult: true)
|
||||
var unauthenticatedResult = false
|
||||
Task {
|
||||
Task {
|
||||
_ = try? await handler.authenticatedContext(for: .init(secret: .init(contextB.secret), provenance: .test, target: nil), context: contextB)
|
||||
unauthenticatedResult = true
|
||||
}
|
||||
_ = try? await handler.authenticatedContext(for: .init(secret: .init(contextA.secret), provenance: .test, target: nil), context: contextA)
|
||||
}
|
||||
try await Task.sleep(for: .milliseconds(10))
|
||||
#expect(contextA.evaluationResult == nil)
|
||||
#expect(unauthenticatedResult)
|
||||
#expect(!contextA.canceled)
|
||||
#expect(!contextB.canceled)
|
||||
#expect(!calledPresentPending)
|
||||
}
|
||||
|
||||
@Test func batchDoesNotBlockNoAuthRequired() async throws {
|
||||
var calledPresentPending = false
|
||||
handler.setPendingRequestHandler {
|
||||
calledPresentPending = true
|
||||
}
|
||||
let contextA = TestContext(authenticationRequirement: .presenceRequired, testEvaluationResult: true)
|
||||
let contextB = TestContext(authenticationRequirement: .presenceRequired, testEvaluationResult: true)
|
||||
let contextC = TestContext(authenticationRequirement: .notRequired, testEvaluationResult: true)
|
||||
Task {
|
||||
_ = try? await handler.authenticatedContext(for: .init(secret: .init(contextA.secret), provenance: .test, target: nil), context: contextA)
|
||||
}
|
||||
Task {
|
||||
_ = try? await handler.authenticatedContext(for: .init(secret: .init(contextB.secret), provenance: .test, target: nil), context: contextB)
|
||||
}
|
||||
#expect(contextA.evaluationResult == nil)
|
||||
#expect(contextB.evaluationResult == nil)
|
||||
await Task.yield()
|
||||
#expect(contextA.canceled)
|
||||
#expect(calledPresentPending)
|
||||
_ = try? await handler.authenticatedContext(for: .init(secret: .init(contextC.secret), provenance: .test, target: nil), context: contextA)
|
||||
#expect(contextA.evaluationResult == nil)
|
||||
#expect(contextB.evaluationResult == nil)
|
||||
}
|
||||
|
||||
@Test func batching() async throws {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import SecretKit
|
||||
import Foundation
|
||||
|
||||
extension SigningRequestProvenance {
|
||||
|
||||
static let test = SigningRequestProvenance(root: .init(pid: 0, processName: "test", appName: nil, iconURL: nil, path: "/", validSignature: true, parentPID: 0))
|
||||
|
||||
}
|
||||
|
||||
extension AgentTests {
|
||||
|
||||
func storeList(with secrets: [Stub.Secret]) async -> SecretStoreList {
|
||||
let store = Stub.Store()
|
||||
store.secrets.append(contentsOf: secrets)
|
||||
let storeList = SecretStoreList()
|
||||
storeList.add(store: store)
|
||||
return storeList
|
||||
}
|
||||
|
||||
enum Constants {
|
||||
|
||||
enum Requests {
|
||||
static let requestIdentities = Data(base64Encoded: "AAAAAQs=")!
|
||||
static let requestSignatureWithNoneMatching = Data(base64Encoded: "AAABhA0AAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqCbkJbOHy5S1wVCaJoKPmpS0egM4frMqllgnlRRQ/Uvnn6EVS8oV03cPA2Bz0EdESyRKA/sbmn0aBtgjIwGELxu45UXEW1TEz6TxyS0u3vuIqR3Wo1CrQWRDnkrG/pBQAAAO8AAAAgbqmrqPUtJ8mmrtaSVexjMYyXWNqjHSnoto7zgv86xvcyAAAAA2dpdAAAAA5zc2gtY29ubmVjdGlvbgAAAAlwdWJsaWNrZXkBAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBEqCbkJbOHy5S1wVCaJoKPmpS0egM4frMqllgnlRRQ/Uvnn6EVS8oV03cPA2Bz0EdESyRKA/sbmn0aBtgjIwGELxu45UXEW1TEz6TxyS0u3vuIqR3Wo1CrQWRDnkrG/pBQAAAAA=")!
|
||||
static let requestSignature = Data(base64Encoded: "AAABRA0AAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy08AAADPAAAAIBIFsbCZ4/dhBmLNGHm0GKj7EJ4N8k/jXRxlyg+LFIYzMgAAAANnaXQAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAAA==")!
|
||||
}
|
||||
|
||||
enum Responses {
|
||||
static let requestIdentitiesEmpty = Data(base64Encoded: "AAAABQwAAAAA")!
|
||||
static let requestIdentitiesMultiple = Data(base64Encoded: "AAABLwwAAAACAAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSszpFIlSRHAAjLQHfV+8WpW3NBWGcoW5r9nbFpeCD9hliIvkXLGh0DcPpwCEPAihGJi55dFSw6eRH/CjIYCMtPAAAAFWVjZHNhLTI1NkBleGFtcGxlLmNvbQAAAIgAAAATZWNkc2Etc2hhMi1uaXN0cDM4NAAAAAhuaXN0cDM4NAAAAGEEspLMDmreMJverQkqKC9zF9ZUasn5uSWkbRlz1jNTCtuyH1KKm+VImL6wdAj47SbzwM6lEEC24AdfrR64P9i/bnS2i83v/4wQVtcZn+Et13QGgWlZst8lxCPzTookaVwMAAAAFWVjZHNhLTM4NEBleGFtcGxlLmNvbQ==")!
|
||||
static let requestFailure = Data(base64Encoded: "AAAAAQU=")!
|
||||
}
|
||||
|
||||
enum Secrets {
|
||||
static let ecdsa256Secret = Stub.Secret(keySize: 256, publicKey: Data(base64Encoded: "BKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy08=")!, privateKey: Data(base64Encoded: "BKzOkUiVJEcACMtAd9X7xalbc0FYZyhbmv2dsWl4IP2GWIi+RcsaHQNw+nAIQ8CKEYmLnl0VLDp5Ef8KMhgIy09nw780wy/TSfUmzj15iJkV234AaCLNl+H8qFL6qK8VIg==")!)
|
||||
static let ecdsa384Secret = Stub.Secret(keySize: 384, publicKey: Data(base64Encoded: "BLKSzA5q3jCb3q0JKigvcxfWVGrJ+bklpG0Zc9YzUwrbsh9SipvlSJi+sHQI+O0m88DOpRBAtuAHX60euD/Yv250tovN7/+MEFbXGZ/hLdd0BoFpWbLfJcQj806KJGlcDA==")!, privateKey: Data(base64Encoded: "BLKSzA5q3jCb3q0JKigvcxfWVGrJ+bklpG0Zc9YzUwrbsh9SipvlSJi+sHQI+O0m88DOpRBAtuAHX60euD/Yv250tovN7/+MEFbXGZ/hLdd0BoFpWbLfJcQj806KJGlcDHNapAOzrt9E+9QC4/KYoXS7Uw4pmdAz53uIj02tttiq3c0ZyIQ7XoscWWRqRrz8Kw==")!)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import Foundation
|
||||
import SecretKit
|
||||
import CryptoKit
|
||||
import SSHProtocolKit
|
||||
import LocalAuthentication
|
||||
|
||||
struct Stub {}
|
||||
|
||||
@@ -49,7 +50,7 @@ extension Stub {
|
||||
print("Public Key OpenSSH: \(OpenSSHPublicKeyWriter().openSSHString(secret: secret))")
|
||||
}
|
||||
|
||||
public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance, target: SigningRequestTarget?) throws -> Data {
|
||||
public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance, target: SigningRequestTarget?, context: LAContext?) throws -> Data {
|
||||
guard !shouldThrow else {
|
||||
throw NSError(domain: "test", code: 0, userInfo: nil)
|
||||
}
|
||||
@@ -57,13 +58,6 @@ extension Stub {
|
||||
return try privateKey.signature(for: data).rawRepresentation
|
||||
}
|
||||
|
||||
public func existingPersistedAuthenticationContext(secret: Stub.Secret) -> PersistedAuthenticationContext? {
|
||||
nil
|
||||
}
|
||||
|
||||
public func persistAuthentication(secret: Stub.Secret, forDuration duration: TimeInterval) throws {
|
||||
}
|
||||
|
||||
public func reloadSecrets() {
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ extension StubWitness: SigningWitness {
|
||||
}
|
||||
}
|
||||
|
||||
func witness(accessTo secret: AnySecret, from store: AnySecretStore, by provenance: SigningRequestProvenance, target: SigningRequestTarget?) throws {
|
||||
func witness(accessTo secret: AnySecret, from store: AnySecretStore, by provenance: SigningRequestProvenance, target: SigningRequestTarget?, offerPersistence: Bool) async throws {
|
||||
witness(secret, provenance)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user