1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
import Foundation
struct LookupSnapshot {
let historyEntryID: UUID?
let domain: String
let timestamp: Date
let trackedDomainID: UUID?
let note: String?
let appVersion: String
let resolverDisplayName: String
let resolverURLString: String
let dataSources: [String]
let provenanceBySection: [LookupSectionKind: SectionProvenance]
let availabilityConfidence: ConfidenceLevel?
let ownershipConfidence: ConfidenceLevel?
let subdomainConfidence: ConfidenceLevel?
let emailSecurityConfidence: ConfidenceLevel?
let geolocationConfidence: ConfidenceLevel?
let errorDetails: [LookupSectionKind: InspectionFailure]
let isPartialSnapshot: Bool
let validationIssues: [String]
let totalLookupDurationMs: Int?
let snapshotIndex: Int?
let previousSnapshotID: UUID?
let changeCount: Int
let severitySummary: ChangeSeverity?
let dnsSections: [DNSSection]
let dnsError: String?
let availabilityResult: DomainAvailabilityResult?
let suggestions: [DomainSuggestionResult]
let sslInfo: SSLCertificateInfo?
let sslError: String?
let hstsPreloaded: Bool?
let httpHeaders: [HTTPHeader]
let httpSecurityGrade: String?
let httpStatusCode: Int?
let httpResponseTimeMs: Int?
let httpProtocol: String?
let http3Advertised: Bool
let httpHeadersError: String?
let reachabilityResults: [PortReachability]
let reachabilityError: String?
let ipGeolocation: IPGeolocation?
let ipGeolocationError: String?
let emailSecurity: EmailSecurityResult?
let emailSecurityError: String?
let ownership: DomainOwnership?
let ownershipError: String?
let ownershipHistory: [DomainOwnershipHistoryEvent]
let ownershipHistoryError: String?
let inferredProvider: InferredProviderFingerprint?
let priorProviders: [String]
let domainClassification: DomainClassificationSummary?
let ownershipTransitions: [OwnershipTransitionEvent]
let hostingTransitions: [HostingTransitionEvent]
let subdomainHistory: [SubdomainHistoryEntry]
let riskSignals: [IntelligenceRiskSignal]
let intelligenceTimeline: [IntelligenceTimelineEvent]
let ptrRecord: String?
let ptrError: String?
let redirectChain: [RedirectHop]
let redirectChainError: String?
let subdomains: [DiscoveredSubdomain]
let subdomainsError: String?
let extendedSubdomains: [DiscoveredSubdomain]
let extendedSubdomainsError: String?
let dnsHistory: [DNSHistoryEvent]
let dnsHistoryError: String?
let domainPricing: DomainPricingInsight?
let domainPricingError: String?
let reputation: DomainReputationResult?
let reputationError: String?
let portScanResults: [PortScanResult]
let portScanError: String?
let changeSummary: DomainChangeSummary?
let resultSource: LookupResultSource
let cachedSections: [LookupSectionKind]
let statusMessage: String?
var isLive: Bool {
resultSource == .live
}
}
extension HistoryEntry {
var snapshot: LookupSnapshot {
LookupSnapshot(
historyEntryID: id,
domain: domain,
timestamp: timestamp,
trackedDomainID: trackedDomainID,
note: note,
appVersion: appVersion,
resolverDisplayName: resolverDisplayName,
resolverURLString: resolverURLString,
dataSources: dataSources,
provenanceBySection: provenanceBySection,
availabilityConfidence: availabilityConfidence,
ownershipConfidence: ownershipConfidence,
subdomainConfidence: subdomainConfidence,
emailSecurityConfidence: emailSecurityConfidence,
geolocationConfidence: geolocationConfidence,
errorDetails: errorDetails,
isPartialSnapshot: isPartialSnapshot,
validationIssues: validationIssues,
totalLookupDurationMs: totalLookupDurationMs,
snapshotIndex: snapshotIndex,
previousSnapshotID: previousSnapshotID,
changeCount: changeCount,
severitySummary: severitySummary,
dnsSections: dnsSections,
dnsError: nil,
availabilityResult: availabilityResult,
suggestions: suggestions,
sslInfo: sslInfo,
sslError: sslError,
hstsPreloaded: hstsPreloaded,
httpHeaders: httpHeaders,
httpSecurityGrade: HTTPSecurityGrade.grade(for: httpHeaders).rawValue,
httpStatusCode: nil,
httpResponseTimeMs: nil,
httpProtocol: nil,
http3Advertised: false,
httpHeadersError: httpHeadersError,
reachabilityResults: reachabilityResults,
reachabilityError: reachabilityError,
ipGeolocation: ipGeolocation,
ipGeolocationError: ipGeolocationError,
emailSecurity: emailSecurity,
emailSecurityError: emailSecurityError,
ownership: ownership,
ownershipError: ownershipError,
ownershipHistory: ownershipHistory,
ownershipHistoryError: ownershipHistoryError,
inferredProvider: inferredProvider,
priorProviders: priorProviders,
domainClassification: domainClassification,
ownershipTransitions: ownershipTransitions,
hostingTransitions: hostingTransitions,
subdomainHistory: subdomainHistory,
riskSignals: riskSignals,
intelligenceTimeline: intelligenceTimeline,
ptrRecord: ptrRecord,
ptrError: ptrError,
redirectChain: redirectChain,
redirectChainError: redirectChainError,
subdomains: subdomains,
subdomainsError: subdomainsError,
extendedSubdomains: extendedSubdomains,
extendedSubdomainsError: extendedSubdomainsError,
dnsHistory: dnsHistory,
dnsHistoryError: dnsHistoryError,
domainPricing: domainPricing,
domainPricingError: domainPricingError,
reputation: reputation,
reputationError: reputationError,
portScanResults: portScanResults,
portScanError: portScanError,
changeSummary: changeSummary,
resultSource: resultSource,
cachedSections: [],
statusMessage: nil
)
}
}
|