ServerUrlPolicy.swift
63 lignes · 2905 octets
import Foundation /// Server URL policy: HTTPS required by default. /// Cleartext HTTP is only accepted when the user checked /// « Autoriser HTTP (clair) » (dev / internal network / demo). enum ServerUrlPolicy { static let ERROR_HTTPS_REQUIRED = "L'URL doit commencer par https:// (cochez « Autoriser HTTP (clair) » pour le développement)." static let ERROR_INVALID_URL = "URL invalide : utilisez https://… (ou http://… si HTTP clair autorisé)." static let ERROR_LAN_HTTPS_NO_PORT = "URL HTTPS sans port sur une IP locale : Projectiaon écoute en HTTP sur le port 3000. " + "Utilisez http://192.168.x.x:3000 et cochez « Autoriser HTTP (clair) »." static let ERROR_LAN_HTTP_NO_PORT = "URL sans port : Projectiaon écoute sur le port 3000 (ex. http://192.168.x.x:3000)." static func isHttps(_ url: String) -> Bool { url.trimmingCharacters(in: .whitespacesAndNewlines).lowercased().hasPrefix("https://") } static func isHttp(_ url: String) -> Bool { url.trimmingCharacters(in: .whitespacesAndNewlines).lowercased().hasPrefix("http://") } /// API root: no trailing slash nor browser-test path (`/version`). static func normalizeBaseUrl(_ url: String) -> String { var trimmed = url.trimmingCharacters(in: .whitespacesAndNewlines) while trimmed.hasSuffix("/") { trimmed.removeLast() } if trimmed.hasSuffix("/version") { trimmed.removeLast("/version".count) } return trimmed } /// `nil` when the URL is acceptable, otherwise the error message to display. static func validate(_ url: String, allowCleartext: Bool) -> String? { let trimmed = normalizeBaseUrl(url) if trimmed.isEmpty { return ERROR_INVALID_URL } if isHttps(trimmed) { return lanHostWithoutPortError(trimmed) } if isHttp(trimmed) { if !allowCleartext { return ERROR_HTTPS_REQUIRED } return lanHostWithoutPortError(trimmed) } return ERROR_INVALID_URL } private static func lanHostWithoutPortError(_ url: String) -> String? { guard let components = URLComponents(string: url) else { return nil } if components.port != nil { return nil } guard let host = components.host else { return nil } if !isPrivateLanHost(host) { return nil } if isHttps(url) { return ERROR_LAN_HTTPS_NO_PORT } if isHttp(url) { return ERROR_LAN_HTTP_NO_PORT } return nil } private static func isPrivateLanHost(_ host: String) -> Bool { if host.caseInsensitiveCompare("localhost") == .orderedSame || host == "127.0.0.1" { return true } if host.hasPrefix("192.168.") { return true } if host.hasPrefix("10.") { return true } return host.range(of: #"^172\.(1[6-9]|2\d|3[01])\..+$"#, options: .regularExpression) != nil } }
GitRust