mirror of
https://github.com/maxgoedjen/secretive.git
synced 2026-09-19 14:48:01 +02:00
Fixing up tests
This commit is contained in:
@@ -8,7 +8,7 @@ public final class AuthenticationContext: AuthenticationContextProtocol {
|
||||
/// The Secret to persist authentication for.
|
||||
public let secret: AnySecret
|
||||
/// The LAContext used to authorize the persistent context.
|
||||
public let laContext: LAContext
|
||||
public let laContext: LAContext?
|
||||
|
||||
enum Validity {
|
||||
/// - Note - Monotonic time instead of Date() to prevent people setting the clock back.
|
||||
@@ -55,12 +55,21 @@ public final class AuthenticationContext: AuthenticationContextProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
public func evaluate() async throws -> Bool {
|
||||
guard let laContext else { return false }
|
||||
return try await laContext.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: laContext.localizedReason)
|
||||
}
|
||||
|
||||
public func cancel() async {
|
||||
laContext?.invalidate()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@MainActor public protocol AuthenticationHandlerProtocol: Observable {
|
||||
var batchableRequests: [[SignatureRequest]] { get }
|
||||
func setBatchAuthHandler(_ handler: @escaping () async throws -> Void)
|
||||
func waitForAuthentication(for request: SignatureRequest) async throws -> any AuthenticationContextProtocol
|
||||
var batchableRequests: [[SignatureRequest]] { get }
|
||||
func persistAuthentication<SecretType: Secret>(secret: SecretType, forDuration duration: TimeInterval) async throws
|
||||
func requestAuthentication(for requests: Set<SignatureRequest>) async throws
|
||||
}
|
||||
@@ -70,7 +79,7 @@ public final class AuthenticationContext: AuthenticationContextProtocol {
|
||||
private var persistedContexts: [AnySecret: AuthenticationContext] = [:]
|
||||
private var holdingRequests: Set<SignatureRequest> = []
|
||||
private var activeTask: Task<Bool, any Error>?
|
||||
private var activeContext: LAContext?
|
||||
private var activeContext: (any AuthenticationContextProtocol)?
|
||||
|
||||
private var lastBatchAuthPresentation: Set<SignatureRequest>?
|
||||
private var presentBatchAuth: (() async throws -> Void)?
|
||||
@@ -102,7 +111,7 @@ public final class AuthenticationContext: AuthenticationContextProtocol {
|
||||
lastBatchAuthPresentation = holdingRequests
|
||||
logger.log("Requesting batch auth presentation")
|
||||
try await presentBatchAuth?()
|
||||
activeContext?.invalidate()
|
||||
await activeContext?.cancel()
|
||||
logger.log("Requested batch auth presentation")
|
||||
}
|
||||
if let preauthorized = existingAuthenticationContext(for: request) {
|
||||
@@ -117,11 +126,11 @@ public final class AuthenticationContext: AuthenticationContextProtocol {
|
||||
laContext.localizedReason = String(localized: .authContextRequestSignatureDescription(appName: request.provenance.origin.displayName, secretName: request.secret.name))
|
||||
laContext.localizedCancelTitle = String(localized: .authContextRequestDenyButton)
|
||||
let context = AuthenticationContext(secret: request.secret, context: laContext, requestID: request.id)
|
||||
activeContext = laContext
|
||||
activeContext = context
|
||||
|
||||
activeTask = Task {
|
||||
logger.log("Beginning individual auth prompt")
|
||||
let result = (try? await laContext.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: laContext.localizedReason)) ?? false
|
||||
let result = (try? await context.evaluate()) ?? false
|
||||
logger.log("Ended individual auth prompt")
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -3,14 +3,11 @@ import LocalAuthentication
|
||||
|
||||
/// Protocol describing an authentication context. This is an authorization that can be reused for multiple access to a secret that requires authentication for a specific period of time.
|
||||
public protocol AuthenticationContextProtocol: Sendable, Identifiable {
|
||||
/// Whether the context remains valid.
|
||||
|
||||
var secret: AnySecret { get }
|
||||
|
||||
var laContext: LAContext { get }
|
||||
|
||||
func valid(for request: SignatureRequest) -> Bool
|
||||
|
||||
var laContext: LAContext? { get }
|
||||
func evaluate() async throws -> Bool
|
||||
func cancel() async
|
||||
}
|
||||
|
||||
public struct SignatureRequest: Identifiable, Hashable, Sendable, Comparable {
|
||||
|
||||
@@ -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,7 +129,7 @@ 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)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import Testing
|
||||
import SecretAgentKit
|
||||
|
||||
@Suite @MainActor struct AuthenticationHandlerTests {
|
||||
|
||||
@Test func singleImmediatelyRequests() async throws {
|
||||
}
|
||||
|
||||
@Test func authRequiredDoesntBlockNoAuthRequired() async throws {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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