mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
fix(mobile): mtls on native clients (#25802)
* handle mtls on ios * update android impl * ui improvements * dead code * no need to store data separately * improve concurrency * dead code * add migration * remove unused dependency * trust user-installed certs * removed print statement * fix ios * improve android styling * outdated comments * update lock file * handle translation * fix prompt cancellation * fix video playback * Apply suggestion from @shenlong-tanwen Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> * Apply suggestion from @shenlong-tanwen Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> * formatting --------- Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import Foundation
|
||||
|
||||
let CLIENT_CERT_LABEL = "app.alextran.immich.client_identity"
|
||||
|
||||
/// Manages a shared URLSession with SSL configuration support.
|
||||
class URLSessionManager: NSObject {
|
||||
static let shared = URLSessionManager()
|
||||
|
||||
let session: URLSession
|
||||
private let configuration = {
|
||||
let config = URLSessionConfiguration.default
|
||||
|
||||
let cacheDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
|
||||
.first!
|
||||
.appendingPathComponent("api", isDirectory: true)
|
||||
try! FileManager.default.createDirectory(at: cacheDir, withIntermediateDirectories: true)
|
||||
|
||||
config.urlCache = URLCache(
|
||||
memoryCapacity: 0,
|
||||
diskCapacity: 1024 * 1024 * 1024,
|
||||
directory: cacheDir
|
||||
)
|
||||
|
||||
config.httpMaximumConnectionsPerHost = 64
|
||||
config.timeoutIntervalForRequest = 60
|
||||
config.timeoutIntervalForResource = 300
|
||||
|
||||
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "unknown"
|
||||
config.httpAdditionalHeaders = ["User-Agent": "Immich_iOS_\(version)"]
|
||||
|
||||
return config
|
||||
}()
|
||||
|
||||
private override init() {
|
||||
session = URLSession(configuration: configuration, delegate: URLSessionManagerDelegate(), delegateQueue: nil)
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
class URLSessionManagerDelegate: NSObject, URLSessionTaskDelegate {
|
||||
func urlSession(
|
||||
_ session: URLSession,
|
||||
didReceive challenge: URLAuthenticationChallenge,
|
||||
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
|
||||
) {
|
||||
handleChallenge(challenge, completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
func urlSession(
|
||||
_ session: URLSession,
|
||||
task: URLSessionTask,
|
||||
didReceive challenge: URLAuthenticationChallenge,
|
||||
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
|
||||
) {
|
||||
handleChallenge(challenge, completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
func handleChallenge(
|
||||
_ challenge: URLAuthenticationChallenge,
|
||||
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
|
||||
) {
|
||||
switch challenge.protectionSpace.authenticationMethod {
|
||||
case NSURLAuthenticationMethodClientCertificate: handleClientCertificate(completion: completionHandler)
|
||||
default: completionHandler(.performDefaultHandling, nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func handleClientCertificate(
|
||||
completion: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
|
||||
) {
|
||||
let query: [String: Any] = [
|
||||
kSecClass as String: kSecClassIdentity,
|
||||
kSecAttrLabel as String: CLIENT_CERT_LABEL,
|
||||
kSecReturnRef as String: true,
|
||||
]
|
||||
|
||||
var item: CFTypeRef?
|
||||
let status = SecItemCopyMatching(query as CFDictionary, &item)
|
||||
if status == errSecSuccess, let identity = item {
|
||||
let credential = URLCredential(identity: identity as! SecIdentity,
|
||||
certificates: nil,
|
||||
persistence: .forSession)
|
||||
return completion(.useCredential, credential)
|
||||
}
|
||||
completion(.performDefaultHandling, nil)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user