Skip to content
This repository was archived by the owner on Mar 7, 2026. It is now read-only.

Commit fa8e06b

Browse files
authored
Update to v0.8.12
1 parent 5f779de commit fa8e06b

File tree

2 files changed

+141
-119
lines changed

2 files changed

+141
-119
lines changed

Sources/prostore/certificates/certChecker.swift

Lines changed: 139 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -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: "&emsp;", 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

project.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ targets:
3030
properties:
3131
CFBundleDisplayName: "ProStore"
3232
CFBundleName: "prostore"
33-
CFBundleVersion: "28"
34-
CFBundleShortVersionString: "0.8.11"
33+
CFBundleVersion: "29"
34+
CFBundleShortVersionString: "0.8.12"
3535
UILaunchStoryboardName: "LaunchScreen"
3636
NSPrincipalClass: "UIApplication"
3737
NSAppTransportSecurity:

0 commit comments

Comments
 (0)