@@ -12,6 +12,8 @@ struct Cert: Identifiable, Hashable {
1212 let downloadURL : URL
1313 let type : CertType
1414 let lastModified : Date ?
15+ var status : String = " "
16+ var isProcessing : Bool = false
1517}
1618
1719@MainActor
@@ -106,24 +108,30 @@ class OfficialCertificateManager: ObservableObject {
106108 }
107109
108110 func checkCert( _ cert: Cert ) async {
111+ // Find the cert in our list so we can update its individual state
112+ guard let index = certs. firstIndex ( where: { $0. id == cert. id } ) else { return }
113+
114+ // Mark this cert as processing (individual + global)
115+ certs [ index] . isProcessing = true
116+ certs [ index] . status = " Checking... "
109117 isProcessing = true
110- currentStatus = " Checking... "
111-
118+ currentStatus = certs [ index ] . status
119+
112120 let tempDir = FileManager . default. temporaryDirectory. appendingPathComponent ( UUID ( ) . uuidString)
113121 defer {
114122 try ? FileManager . default. removeItem ( at: tempDir)
115123 }
116-
124+
117125 do {
118126 try FileManager . default. createDirectory ( at: tempDir, withIntermediateDirectories: true , attributes: nil )
119-
127+
120128 let ( zipData, _) = try await URLSession . shared. data ( from: cert. downloadURL)
121129 let tempZipURL = tempDir. appendingPathComponent ( " cert.zip " )
122130 try zipData. write ( to: tempZipURL)
123-
131+
124132 // Unzip using ZIPFoundation
125133 try FileManager . default. unzipItem ( at: tempZipURL, to: tempDir)
126-
134+
127135 // Find the extraction directory (root or single subdir)
128136 let contents = try FileManager . default. contentsOfDirectory ( at: tempDir, includingPropertiesForKeys: nil , options: . skipsHiddenFiles)
129137 var searchDir = tempDir
@@ -134,47 +142,52 @@ class OfficialCertificateManager: ObservableObject {
134142 searchDir = firstItem
135143 }
136144 }
137-
145+
138146 let fileContents = try FileManager . default. contentsOfDirectory ( at: searchDir, includingPropertiesForKeys: nil , options: . skipsHiddenFiles)
139147 var p12URL : URL ?
140148 var provURL : URL ?
141149 var txtURL : URL ?
142-
150+
143151 for url in fileContents {
144152 let ext = url. pathExtension. lowercased ( )
145153 if ext == " p12 " { p12URL = url }
146154 else if ext == " mobileprovision " { provURL = url }
147155 else if ext == " txt " { txtURL = url }
148156 }
149-
157+
150158 guard let p12U = p12URL, let provU = provURL, let txtU = txtURL else {
159+ certs [ index] . status = " Error: Missing p12, mobileprovision or txt "
160+ currentStatus = certs [ index] . status
151161 throw NSError ( domain: " MissingFiles " , code: 1 , userInfo: [ NSLocalizedDescriptionKey: " Zip missing p12, provision, or txt " ] )
152162 }
153-
163+
154164 let txtData = try Data ( contentsOf: txtU)
155165 let password = String ( data: txtData, encoding: . utf8) ? . trimmingCharacters ( in: . whitespacesAndNewlines) ?? " "
156-
166+
157167 let p12Data = try Data ( contentsOf: p12U)
158168 let provData = try Data ( contentsOf: provU)
159-
169+
160170 let result = CertificatesManager . check ( p12Data: p12Data, password: password, mobileProvisionData: provData)
161-
171+
162172 switch result {
163173 case . success( . success) :
164- currentStatus = " Success! "
174+ certs [ index ] . status = " Success! "
165175 case . success( . incorrectPassword) :
166- currentStatus = " Incorrect Password "
176+ certs [ index ] . status = " Incorrect Password "
167177 case . success( . noMatch) :
168- currentStatus = " P12 and MobileProvision do not match "
178+ certs [ index ] . status = " P12 and MobileProvision do not match "
169179 case . failure( let err) :
170180 print ( " Official check error: \( err) " )
171- currentStatus = " P12 and MobileProvision do not match "
181+ certs [ index ] . status = " P12 and MobileProvision do not match "
172182 }
173183 } catch {
174184 print ( " Official cert process error: \( error) " )
175- currentStatus = " Error: Couldn't process zip "
185+ certs [ index ] . status = " Error: Couldn't process zip "
176186 }
177-
178- isProcessing = false
187+
188+ // Turn off this cert's processing flag and refresh global processing state + currentStatus
189+ certs [ index] . isProcessing = false
190+ isProcessing = certs. contains ( where: { $0. isProcessing } )
191+ currentStatus = certs [ index] . status
179192 }
180193}
0 commit comments