krz/domain-dig

an ios app for DNS & SSL analysis

clone: git clone https://gitbay.org/krz/domain-dig.git

v5.0.1: Shared/DomainDigDeepLink.swift · raw

 1import Foundation
 2
 3/// Shared builder/parser for the `domaindig://` URL scheme, used by the intents
 4/// and app (to open/route) and by the widget (to deep-link into a domain).
 5///
 6/// Lives in `Shared/` so it compiles into both the app and the widget target.
 7/// It relies only on Foundation and no actor isolation, so it is safe in the
 8/// widget extension (`APPLICATION_EXTENSION_API_ONLY`).
 9enum DomainDigDeepLink {
10    static let scheme = "domaindig"
11
12    enum Action: Equatable {
13        case inspect(String)
14        case watch(String)
15        case detail(String)
16        case sweep
17
18        var host: String {
19            switch self {
20            case .inspect: return "inspect"
21            case .watch: return "watch"
22            case .detail: return "domain"
23            case .sweep: return "sweep"
24            }
25        }
26
27        /// The domain the action targets, if any. `.sweep` has no domain.
28        var domain: String? {
29            switch self {
30            case let .inspect(domain), let .watch(domain), let .detail(domain):
31                return domain
32            case .sweep:
33                return nil
34            }
35        }
36    }
37
38    static func url(for action: Action) -> URL {
39        var components = URLComponents()
40        components.scheme = scheme
41        components.host = action.host
42        if let domain = action.domain {
43            components.queryItems = [URLQueryItem(name: "domain", value: domain)]
44        }
45        // The scheme and host are fixed and any domain is percent-encoded by
46        // URLComponents, so this is always a valid URL.
47        return components.url!
48    }
49
50    static func action(from url: URL) -> Action? {
51        guard url.scheme == scheme else { return nil }
52
53        if url.host() == "sweep" {
54            return .sweep
55        }
56
57        let domain = URLComponents(url: url, resolvingAgainstBaseURL: false)?
58            .queryItems?
59            .first { $0.name == "domain" }?
60            .value?
61            .trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
62        guard !domain.isEmpty else { return nil }
63
64        switch url.host() {
65        case "inspect": return .inspect(domain)
66        case "watch": return .watch(domain)
67        case "domain": return .detail(domain)
68        default: return nil
69        }
70    }
71}