@@ -208,12 +208,11 @@ static func parseHTML(html: String) -> [String: Any] {
208208 log ( " Alert div content length: \( divContent. count) characters " )
209209
210210 // Clean up the content but preserve line breaks
211- // First replace <br/> with newlines
212211 divContent = divContent. replacingOccurrences ( of: " <br/> " , with: " \n " , options: . caseInsensitive)
213212 divContent = divContent. replacingOccurrences ( of: " <br /> " , with: " \n " , options: . caseInsensitive)
214213 divContent = divContent. replacingOccurrences ( of: "   " , with: " " , options: . caseInsensitive)
215214
216- // Now remove HTML tags
215+ // Remove HTML tags
217216 let tagRegex = try ? NSRegularExpression ( pattern: " <[^>]+> " , options: [ ] )
218217 divContent = tagRegex? . stringByReplacingMatches ( in: divContent, range: NSRange ( 0 ..< divContent. utf16. count) , withTemplate: " " ) ?? divContent
219218
@@ -235,134 +234,160 @@ static func parseHTML(html: String) -> [String: Any] {
235234 log ( " Found \( lines. count) lines after cleaning " )
236235 log ( " Lines: \( lines) " )
237236
238- // Create a dictionary to store all parsed data
239- var parsedDict : [ String : String ] = [ : ]
237+ // Track which section we're in
238+ enum Section {
239+ case certificate
240+ case mobileprovision
241+ case bindingCertificates
242+ case permissions
243+ case unknown
244+ }
245+
246+ var currentSection : Section = . unknown
247+ var bindingCertIndex = 0
240248
241249 // Parse each line
242250 for line in lines {
243- // Handle different colon types
251+ // Detect section changes
252+ if line. contains ( " ----------------------------------- " ) {
253+ currentSection = . mobileprovision
254+ continue
255+ } else if line. contains ( " Binding Certificates: " ) {
256+ currentSection = . bindingCertificates
257+ continue
258+ } else if line. contains ( " Permission Status: " ) {
259+ currentSection = . permissions
260+ continue
261+ }
262+
263+ // Parse line based on current section
244264 let separators = [ " : " , " : " ]
265+ var parsedKey : String ?
266+ var parsedValue : String ?
267+
245268 for separator in separators {
246- if line. contains ( separator) {
247- let parts = line. components ( separatedBy: separator)
248- if parts. count >= 2 {
249- let key = parts [ 0 ] . trimmingCharacters ( in: . whitespaces)
250- let value = parts [ 1 ... ] . joined ( separator: separator) . trimmingCharacters ( in: . whitespaces)
251- parsedDict [ key] = value
252- break
253- }
269+ if let range = line. range ( of: separator) {
270+ parsedKey = String ( line [ ..< range. lowerBound] ) . trimmingCharacters ( in: . whitespaces)
271+ parsedValue = String ( line [ range. upperBound... ] ) . trimmingCharacters ( in: . whitespaces)
272+ break
254273 }
255274 }
256- }
257-
258- log ( " Parsed dictionary: \( parsedDict) " )
259-
260- // Extract certificate info
261- var cert = data [ " certificate " ] as! [ String : String ]
262- if let certName = parsedDict [ " CertName " ] {
263- cert [ " name " ] = certName
264- }
265- if let effDate = parsedDict [ " Effective Date " ] {
266- cert [ " effective " ] = effDate
267- }
268- if let expDate = parsedDict [ " Expiration Date " ] {
269- cert [ " expiration " ] = expDate
270- }
271- if let issuer = parsedDict [ " Issuer " ] {
272- cert [ " issuer " ] = issuer
273- }
274- if let country = parsedDict [ " Country " ] {
275- cert [ " country " ] = country
276- }
277- if let org = parsedDict [ " Organization " ] {
278- cert [ " organization " ] = org
279- }
280- if let numHex = parsedDict [ " Certificate Number (Hex) " ] {
281- cert [ " number_hex " ] = numHex
282- }
283- if let numDec = parsedDict [ " Certificate Number (Decimal) " ] {
284- cert [ " number_decimal " ] = numDec
285- }
286- if let certStatus = parsedDict [ " Certificate Status " ] {
287- cert [ " status " ] = certStatus
288- }
289- data [ " certificate " ] = cert
290-
291- // Extract mobileprovision info
292- var mp = data [ " mobileprovision " ] as! [ String : String ]
293- if let mpName = parsedDict [ " MP Name " ] {
294- mp [ " name " ] = mpName
295- }
296- if let appId = parsedDict [ " App ID " ] {
297- mp [ " app_id " ] = appId
298- }
299- if let identifier = parsedDict [ " Identifier " ] {
300- mp [ " identifier " ] = identifier
301- }
302- if let platform = parsedDict [ " Platform " ] {
303- mp [ " platform " ] = platform
304- }
305- // Look for mobileprovision dates (they might be duplicates from certificate section)
306- for (key, value) in parsedDict {
307- let lk = key. lowercased ( )
308- if lk. contains ( " effective date " ) && !lk. contains ( " cert " ) {
309- mp [ " effective " ] = value
310- }
311- if lk. contains ( " expiration date " ) && !lk. contains ( " cert " ) {
312- mp [ " expiration " ] = value
313- }
314- }
315- data [ " mobileprovision " ] = mp
316-
317- // Extract binding certificate info
318- // Look for "Certificate 1" and related info
319- var bc1 = data [ " binding_certificate_1 " ] as! [ String : String ]
320- for (key, value) in parsedDict {
321- if key. contains ( " Certificate 1 " ) || key. contains ( " Certificate Status " ) {
322- bc1 [ " status " ] = value
323- } else if key. contains ( " Certificate Number (Hex) " ) && ( bc1 [ " number_hex " ] == nil ) {
324- bc1 [ " number_hex " ] = value
325- } else if key. contains ( " Certificate Number (Decimal) " ) && ( bc1 [ " number_decimal " ] == nil ) {
326- bc1 [ " number_decimal " ] = value
275+
276+ guard let key = parsedKey, let value = parsedValue else { continue }
277+
278+ switch currentSection {
279+ case . certificate, . unknown:
280+ // Parse main certificate info (before separator)
281+ var cert = data [ " certificate " ] as! [ String : String ]
282+ let lk = key. lowercased ( )
283+
284+ if lk. contains ( " certname " ) {
285+ cert [ " name " ] = value
286+ } else if lk. contains ( " effective date " ) && !lk. contains ( " cert " ) {
287+ cert [ " effective " ] = value
288+ } else if lk. contains ( " expiration date " ) && !lk. contains ( " cert " ) {
289+ cert [ " expiration " ] = value
290+ } else if lk. contains ( " issuer " ) {
291+ cert [ " issuer " ] = value
292+ } else if lk. contains ( " country " ) {
293+ cert [ " country " ] = value
294+ } else if lk. contains ( " organization " ) {
295+ cert [ " organization " ] = value
296+ } else if lk. contains ( " certificate number (hex) " ) {
297+ cert [ " number_hex " ] = value
298+ } else if lk. contains ( " certificate number (decimal) " ) {
299+ cert [ " number_decimal " ] = value
300+ } else if lk. contains ( " certificate status " ) && !lk. contains ( " binding " ) {
301+ cert [ " status " ] = value
302+ }
303+ data [ " certificate " ] = cert
304+
305+ case . mobileprovision:
306+ // Parse mobileprovision info
307+ var mp = data [ " mobileprovision " ] as! [ String : String ]
308+ let lk = key. lowercased ( )
309+
310+ if lk. contains ( " mp name " ) {
311+ mp [ " name " ] = value
312+ } else if lk. contains ( " app id " ) {
313+ mp [ " app_id " ] = value
314+ } else if lk. contains ( " identifier " ) {
315+ mp [ " identifier " ] = value
316+ } else if lk. contains ( " platform " ) {
317+ mp [ " platform " ] = value
318+ } else if lk. contains ( " effective date " ) {
319+ mp [ " effective " ] = value
320+ } else if lk. contains ( " expiration date " ) {
321+ mp [ " expiration " ] = value
322+ }
323+ data [ " mobileprovision " ] = mp
324+
325+ case . bindingCertificates:
326+ // Parse binding certificates - only care about Certificate 1
327+ if key. contains ( " Certificate 1 " ) {
328+ bindingCertIndex = 1
329+ } else if key. contains ( " Certificate 2 " ) || key. contains ( " Certificate 3 " ) {
330+ bindingCertIndex = 0 // Stop parsing other certificates
331+ continue
332+ }
333+
334+ if bindingCertIndex == 1 {
335+ var bc1 = data [ " binding_certificate_1 " ] as! [ String : String ]
336+ let lk = key. lowercased ( )
337+
338+ if lk. contains ( " certificate status " ) {
339+ bc1 [ " status " ] = value
340+ } else if lk. contains ( " certificate number (hex) " ) {
341+ bc1 [ " number_hex " ] = value
342+ } else if lk. contains ( " certificate number (decimal) " ) {
343+ bc1 [ " number_decimal " ] = value
344+ }
345+ data [ " binding_certificate_1 " ] = bc1
346+ }
347+
348+ case . permissions:
349+ // Parse permissions
350+ var perms = data [ " permissions " ] as! [ String : String ]
351+ let permKeys = [
352+ " Apple Push Notification Service " ,
353+ " HealthKit " ,
354+ " VPN " ,
355+ " Communication Notifications " ,
356+ " Time-sensitive Notifications "
357+ ]
358+
359+ for permKey in permKeys {
360+ if key. contains ( permKey) {
361+ perms [ permKey] = value
362+ }
363+ }
364+ data [ " permissions " ] = perms
365+
366+ // Also check for Certificate Matching Status in this section
367+ if key. contains ( " Certificate Matching Status " ) {
368+ data [ " certificate_matching_status " ] = value
369+ }
327370 }
328371 }
329- data [ " binding_certificate_1 " ] = bc1
330372
331- // Extract certificate matching status
332- if let matchStatus = parsedDict [ " Certificate Matching Status " ] {
333- data [ " certificate_matching_status " ] = matchStatus
334- }
335-
336- // Extract permissions
337- var perms = data [ " permissions " ] as! [ String : String ]
338- let permKeys = [
339- " Apple Push Notification Service " ,
340- " HealthKit " ,
341- " VPN " ,
342- " Communication Notifications " ,
343- " Time-sensitive Notifications "
344- ]
373+ // Determine overall status based on main certificate status and matching status
374+ let cert = data [ " certificate " ] as! [ String : String ]
375+ let certStatus = cert [ " status " ] ?? " "
376+ let matchingStatus = data [ " certificate_matching_status " ] as? String ?? " "
345377
346- for key in permKeys {
347- if let value = parsedDict [ key] {
348- perms [ key] = value
349- }
350- }
351- data [ " permissions " ] = perms
352-
353- // Determine overall status
354378 let overallStatus : String
355- if let certStatus = cert [ " status " ] , certStatus. lowercased ( ) . contains ( " good " ) {
356- overallStatus = " Valid "
357- } else if let matchStatus = data [ " certificate_matching_status " ] as? String ,
358- matchStatus. lowercased ( ) . contains ( " match " ) {
379+ if certStatus. lowercased ( ) . contains ( " good " ) && matchingStatus. lowercased ( ) . contains ( " match " ) {
359380 overallStatus = " Valid "
381+ } else if certStatus. lowercased ( ) . contains ( " good " ) || matchingStatus. lowercased ( ) . contains ( " match " ) {
382+ overallStatus = " Partially Valid "
360383 } else {
361- overallStatus = " Unknown "
384+ overallStatus = " Invalid "
362385 }
363386
364387 data [ " overall_status " ] = overallStatus
365388 log ( " Overall Status: \( overallStatus) " )
389+ log ( " Certificate Status: \( certStatus) " )
390+ log ( " Certificate Matching Status: \( matchingStatus) " )
366391
367392 log ( " Final parsed data: \( data) " )
368393 log ( " === Finished parseHTML() Successfully === " )
@@ -387,14 +412,11 @@ static func parseHTML(html: String) -> [String: Any] {
387412 log ( " Fallback: Found 🔴 indicator " )
388413 }
389414
390- data [ " overall_status " ] = overallStatus
391- log ( " Fallback Overall Status: \( overallStatus) " )
415+ var data : [ String : Any ] = [ " overall_status " : overallStatus]
392416
393417 log ( " === parseHTML() Completed with Fallback === " )
394418
395- return [ " error " : " Could not fully parse certificate info " ,
396- " overall_status " : overallStatus,
397- " raw_html_preview " : String ( html. prefix ( 1000 ) ) ]
419+ return data
398420}
399421
400422 // MARK: - Main Check Function
0 commit comments