main
swift 69 lines 2.43 KB
Raw
1 import Foundation
2
3 /// Abstraction over session persistence.
4 ///
5 /// `AuthCore` is platform-agnostic, so it does not assume a Keychain (or any
6 /// particular storage backend). Provide a conforming type to persist sessions
7 /// however is appropriate for your platform:
8 ///
9 /// - On Apple platforms, `SmbCloudCredentialsManager` (from the `SmbCloudAuth`
10 /// product) stores sessions in the Keychain.
11 /// - For tests, scripts, or servers, use ``SmbCloudInMemoryCredentialsStore``.
12 /// - On Linux / Windows / Android, implement this protocol on top of your
13 /// platform's secure storage (e.g. libsecret, DPAPI, Android Keystore).
14 public protocol SmbCloudCredentialsStore: Sendable {
15 /// Persists (or replaces) the stored session.
16 func store(_ session: SmbCloudSession) throws
17 /// Returns the stored session, if any.
18 func current() throws -> SmbCloudSession?
19 /// Removes any stored session.
20 func clear() throws
21 }
22
23 extension SmbCloudCredentialsStore {
24 /// Returns the stored session only if it is still valid within `leeway` seconds.
25 public func currentValidSession(leeway: TimeInterval = 60) throws -> SmbCloudSession? {
26 guard let session = try current() else {
27 return nil
28 }
29
30 return session.isValid(leeway: leeway) ? session : nil
31 }
32
33 /// Whether a valid (non-expired) session is currently stored.
34 public func hasValidSession(leeway: TimeInterval = 60) throws -> Bool {
35 try currentValidSession(leeway: leeway) != nil
36 }
37 }
38
39 /// A thread-safe, in-memory ``SmbCloudCredentialsStore``.
40 ///
41 /// Sessions live only for the lifetime of the process. This is handy for unit
42 /// tests, command-line tools, and server-side flows, and it works identically
43 /// on every platform AuthCore supports.
44 public final class SmbCloudInMemoryCredentialsStore: SmbCloudCredentialsStore, @unchecked Sendable {
45 private let lock = NSLock()
46 private var session: SmbCloudSession?
47
48 public init(session: SmbCloudSession? = nil) {
49 self.session = session?.storedRepresentation()
50 }
51
52 public func store(_ session: SmbCloudSession) throws {
53 lock.lock()
54 defer { lock.unlock() }
55 self.session = session.storedRepresentation()
56 }
57
58 public func current() throws -> SmbCloudSession? {
59 lock.lock()
60 defer { lock.unlock() }
61 return session
62 }
63
64 public func clear() throws {
65 lock.lock()
66 defer { lock.unlock() }
67 session = nil
68 }
69 }