SHA256
Require iOS 18.4 for explicit upload denial in the isolated authentication window. Add origin-bound generated download policy, app-switcher privacy, typed metadata regressions and original community icon assets. Seven portable tests and Swift formatting checks pass; Apple SDK validation remains external.
41 lines
1.7 KiB
Swift
41 lines
1.7 KiB
Swift
import Foundation
|
|
|
|
final class NoRedirect: NSObject, URLSessionTaskDelegate {
|
|
func urlSession(
|
|
_ session: URLSession, task: URLSessionTask,
|
|
willPerformHTTPRedirection response: HTTPURLResponse,
|
|
newRequest request: URLRequest,
|
|
completionHandler: @escaping (URLRequest?) -> Void
|
|
) {
|
|
completionHandler(nil)
|
|
}
|
|
}
|
|
|
|
enum ServerProbe {
|
|
static func check(_ server: ServerAddress) async throws {
|
|
let configuration = URLSessionConfiguration.ephemeral
|
|
configuration.httpCookieStorage = nil
|
|
configuration.urlCache = nil
|
|
configuration.timeoutIntervalForRequest = 10
|
|
configuration.timeoutIntervalForResource = 20
|
|
let session = URLSession(configuration: configuration, delegate: NoRedirect(), delegateQueue: nil)
|
|
defer { session.invalidateAndCancel() }
|
|
let version = try await json(session, server.url.appendingPathComponent("api/v1/version"))
|
|
let auth = try await json(session, server.url.appendingPathComponent("api/v1/auth/oidc/config"))
|
|
try ServerMetadata.validate(bootstrap: version, authentication: auth)
|
|
}
|
|
|
|
private static func json(_ session: URLSession, _ url: URL) async throws -> Data {
|
|
var request = URLRequest(url: url)
|
|
request.setValue("application/json", forHTTPHeaderField: "Accept")
|
|
let (stream, response) = try await session.bytes(for: request)
|
|
guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw ConnectionError.unavailable }
|
|
var data = Data()
|
|
for try await byte in stream {
|
|
guard data.count < 65_536 else { throw ConnectionError.incompatible }
|
|
data.append(byte)
|
|
}
|
|
return data
|
|
}
|
|
}
|