initial commit
This commit is contained in:
commit
8de962eeb8
44 changed files with 4843 additions and 0 deletions
54
SessionStore.swift
Normal file
54
SessionStore.swift
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import Foundation
|
||||
|
||||
/// Holds session state for an authenticated MCMS connection.
|
||||
///
|
||||
/// Cookie handling: `URLSession` stores the `sessionid` and `csrftoken` cookies
|
||||
/// automatically and replays them. Our job is to (a) read the CSRF cookie value
|
||||
/// so we can echo it in the `X-CSRFToken` header on writes (Django-style), and
|
||||
/// (b) clear cookies on logout.
|
||||
@MainActor
|
||||
final class SessionStore {
|
||||
|
||||
private(set) var isAuthenticated = false
|
||||
|
||||
/// The cookie storage backing the session. Injected so a proxy deployment
|
||||
/// can use an isolated storage if needed.
|
||||
let cookieStorage: HTTPCookieStorage
|
||||
private let config: APIConfiguration
|
||||
|
||||
init(config: APIConfiguration, cookieStorage: HTTPCookieStorage = .shared) {
|
||||
self.config = config
|
||||
self.cookieStorage = cookieStorage
|
||||
}
|
||||
|
||||
func markAuthenticated() { isAuthenticated = true }
|
||||
|
||||
/// Current CSRF token (the value of the CSRF cookie), to be sent as the
|
||||
/// `X-CSRFToken` header on mutating requests. Returns nil before login.
|
||||
func csrfToken() -> String? {
|
||||
guard let cookies = cookieStorage.cookies(for: config.baseURL) else { return nil }
|
||||
return cookies.first { Self.matches($0.name, config.csrfCookieName) }?.value
|
||||
}
|
||||
|
||||
/// Whether a session cookie is currently present.
|
||||
var hasSessionCookie: Bool {
|
||||
guard let cookies = cookieStorage.cookies(for: config.baseURL) else { return false }
|
||||
return cookies.contains { Self.matches($0.name, config.sessionCookieName) }
|
||||
}
|
||||
|
||||
/// Modern MCMS 6.2 builds emit `__Host-csrftoken` / `__Host-sessionid`;
|
||||
/// older ones use the bare names. Accept either form (also `__Secure-`).
|
||||
static func matches(_ cookieName: String, _ base: String) -> Bool {
|
||||
cookieName == base
|
||||
|| cookieName == "__Host-" + base
|
||||
|| cookieName == "__Secure-" + base
|
||||
}
|
||||
|
||||
/// Drop all cookies for the configured host (call after logout / on reset).
|
||||
func clear() {
|
||||
if let cookies = cookieStorage.cookies(for: config.baseURL) {
|
||||
cookies.forEach { cookieStorage.deleteCookie($0) }
|
||||
}
|
||||
isAuthenticated = false
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue