use constants

This commit is contained in:
mertalev 2026-03-10 13:36:17 -05:00
parent c23c21c4aa
commit 5e095bd96e
No known key found for this signature in database
GPG Key ID: DF6ABC77AAD98C95
3 changed files with 59 additions and 29 deletions

View File

@ -39,6 +39,17 @@ private const val PREFS_CERT_ALIAS = "immich.client_cert"
private const val PREFS_HEADERS = "immich.request_headers"
private const val PREFS_SERVER_URLS = "immich.server_urls"
private const val PREFS_COOKIES = "immich.cookies"
private const val COOKIE_EXPIRY_DAYS = 400L
private enum class AuthCookie(val cookieName: String, val httpOnly: Boolean) {
ACCESS_TOKEN("immich_access_token", httpOnly = true),
IS_AUTHENTICATED("immich_is_authenticated", httpOnly = false),
AUTH_TYPE("immich_auth_type", httpOnly = true);
companion object {
val names = entries.map { it.cookieName }.toSet()
}
}
/**
* Manages a shared OkHttpClient with SSL configuration support.
@ -189,18 +200,19 @@ object HttpClientManager {
if (token != null) {
val url = serverUrls.firstNotNullOfOrNull { it.toHttpUrlOrNull() } ?: return
val expiry = System.currentTimeMillis() + 400L * 24 * 60 * 60 * 1000
fun cookie(name: String, value: String, httpOnly: Boolean) =
Cookie.Builder().name(name).value(value).domain(url.host).path("/").expiresAt(expiry)
val expiry = System.currentTimeMillis() + COOKIE_EXPIRY_DAYS * 24 * 60 * 60 * 1000
val values = mapOf(
AuthCookie.ACCESS_TOKEN to token,
AuthCookie.IS_AUTHENTICATED to "true",
AuthCookie.AUTH_TYPE to "password",
)
cookieJar.saveFromResponse(url, values.map { (cookie, value) ->
Cookie.Builder().name(cookie.cookieName).value(value).domain(url.host).path("/").expiresAt(expiry)
.apply {
if (url.isHttps) secure()
if (httpOnly) httpOnly()
if (cookie.httpOnly) httpOnly()
}.build()
cookieJar.saveFromResponse(url, listOf(
cookie("immich_access_token", token, httpOnly = true),
cookie("immich_is_authenticated", "true", httpOnly = false),
cookie("immich_auth_type", "password", httpOnly = true),
))
})
}
}
}
@ -300,9 +312,6 @@ object HttpClientManager {
private var serverUrls = listOf<HttpUrl>()
private var prefs: SharedPreferences? = null
companion object {
val AUTH_COOKIE_NAMES = setOf("immich_access_token", "immich_is_authenticated", "immich_auth_type")
}
fun init(prefs: SharedPreferences) {
this.prefs = prefs
@ -344,11 +353,11 @@ object HttpClientManager {
val serverHosts = serverUrls.map { it.host }.toSet()
val now = System.currentTimeMillis()
val sourceCookies = store
.filter { it.name in AUTH_COOKIE_NAMES && it.domain in serverHosts && it.expiresAt > now }
.filter { it.name in AuthCookie.names && it.domain in serverHosts && it.expiresAt > now }
.associateBy { it.name }
if (sourceCookies.isEmpty()) {
return store.removeAll { it.name in AUTH_COOKIE_NAMES && it.domain in serverHosts }
return store.removeAll { it.name in AuthCookie.names && it.domain in serverHosts }
}
var changed = false

View File

@ -62,27 +62,27 @@ class NetworkApiImpl: NetworkApi {
URLSessionManager.setServerUrls(serverUrls)
if let token = token {
let expiry = Date().addingTimeInterval(400 * 24 * 60 * 60)
let expiry = Date().addingTimeInterval(COOKIE_EXPIRY_DAYS * 24 * 60 * 60)
for serverUrl in serverUrls {
guard let url = URL(string: serverUrl), let domain = url.host else { continue }
let isSecure = serverUrl.hasPrefix("https")
let cookies: [(String, String, Bool)] = [
("immich_access_token", token, true),
("immich_is_authenticated", "true", false),
("immich_auth_type", "password", true),
let values: [AuthCookie: String] = [
.accessToken: token,
.isAuthenticated: "true",
.authType: "password",
]
for (name, value, httpOnly) in cookies {
for (cookie, value) in values {
var properties: [HTTPCookiePropertyKey: Any] = [
.name: name,
.name: cookie.name,
.value: value,
.domain: domain,
.path: "/",
.expires: expiry,
]
if isSecure { properties[.secure] = "TRUE" }
if httpOnly { properties[.init("HttpOnly")] = "TRUE" }
if let cookie = HTTPCookie(properties: properties) {
URLSessionManager.cookieStorage.setCookie(cookie)
if cookie.httpOnly { properties[.init("HttpOnly")] = "TRUE" }
if let httpCookie = HTTPCookie(properties: properties) {
URLSessionManager.cookieStorage.setCookie(httpCookie)
}
}
}

View File

@ -5,6 +5,28 @@ let CLIENT_CERT_LABEL = "app.alextran.immich.client_identity"
let HEADERS_KEY = "immich.request_headers"
let SERVER_URLS_KEY = "immich.server_urls"
let APP_GROUP = "group.app.immich.share"
let COOKIE_EXPIRY_DAYS: TimeInterval = 400
enum AuthCookie: CaseIterable {
case accessToken, isAuthenticated, authType
var name: String {
switch self {
case .accessToken: return "immich_access_token"
case .isAuthenticated: return "immich_is_authenticated"
case .authType: return "immich_auth_type"
}
}
var httpOnly: Bool {
switch self {
case .accessToken, .authType: return true
case .isAuthenticated: return false
}
}
static let names: Set<String> = Set(allCases.map(\.name))
}
extension UserDefaults {
static let group = UserDefaults(suiteName: APP_GROUP)!
@ -48,9 +70,9 @@ class URLSessionManager: NSObject {
Self.serverUrls = UserDefaults.group.stringArray(forKey: SERVER_URLS_KEY) ?? []
NotificationCenter.default.addObserver(
Self.self,
selector: #selector(cookiesDidChange),
selector: #selector(Self.cookiesDidChange),
name: NSHTTPCookieManagerCookiesChangedNotification,
object: cookieStorage
object: Self.cookieStorage
)
}
@ -71,13 +93,12 @@ class URLSessionManager: NSObject {
}
private static func syncAuthCookies() {
let authCookieNames: Set<String> = ["immich_access_token", "immich_is_authenticated", "immich_auth_type"]
let serverHosts = Set(serverUrls.compactMap { URL(string: $0)?.host })
let allCookies = cookieStorage.cookies ?? []
let now = Date()
let serverAuthCookies = allCookies.filter {
authCookieNames.contains($0.name) && serverHosts.contains($0.domain)
AuthCookie.names.contains($0.name) && serverHosts.contains($0.domain)
}
var sourceCookies: [String: HTTPCookie] = [:]
@ -111,7 +132,7 @@ class URLSessionManager: NSObject {
.value: source.value,
.domain: domain,
.path: "/",
.expires: source.expiresDate ?? Date().addingTimeInterval(400 * 24 * 60 * 60),
.expires: source.expiresDate ?? Date().addingTimeInterval(COOKIE_EXPIRY_DAYS * 24 * 60 * 60),
]
if isSecure { properties[.secure] = "TRUE" }
if source.isHTTPOnly { properties[.init("HttpOnly")] = "TRUE" }