@capgo/capacitor-updater 7.39.0 → 7.40.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,11 +5,7 @@
5
5
  */
6
6
 
7
7
  import Foundation
8
- #if canImport(ZipArchive)
9
- import ZipArchive
10
- #else
11
- import SSZipArchive
12
- #endif
8
+ import ZIPFoundation
13
9
  import Alamofire
14
10
  import Compression
15
11
  import UIKit
@@ -159,7 +155,8 @@ import UIKit
159
155
  case .success:
160
156
  self.logger.info("Rate limit statistic sent")
161
157
  case let .failure(error):
162
- self.logger.error("Error sending rate limit statistic: \(error.localizedDescription)")
158
+ self.logger.error("Error sending rate limit statistic")
159
+ self.logger.debug("Error: \(error.localizedDescription)")
163
160
  }
164
161
  semaphore.signal()
165
162
  }
@@ -205,7 +202,8 @@ import UIKit
205
202
  do {
206
203
  try FileManager.default.createDirectory(atPath: source.path, withIntermediateDirectories: true, attributes: nil)
207
204
  } catch {
208
- logger.error("Cannot createDirectory \(source.path)")
205
+ logger.error("Cannot create directory")
206
+ logger.debug("Directory path: \(source.path)")
209
207
  throw CustomError.cannotCreateDirectory
210
208
  }
211
209
  }
@@ -215,7 +213,8 @@ import UIKit
215
213
  do {
216
214
  try FileManager.default.removeItem(atPath: source.path)
217
215
  } catch {
218
- logger.error("File not removed. \(source.path)")
216
+ logger.error("File not removed")
217
+ logger.debug("Path: \(source.path)")
219
218
  throw CustomError.cannotDeleteDirectory
220
219
  }
221
220
  }
@@ -232,43 +231,29 @@ import UIKit
232
231
  return false
233
232
  }
234
233
  } catch {
235
- logger.error("File not moved. source: \(source.path) dest: \(dest.path)")
234
+ logger.error("File not moved")
235
+ logger.debug("Source: \(source.path), Dest: \(dest.path)")
236
236
  throw CustomError.cannotUnflat
237
237
  }
238
238
  }
239
239
 
240
- private func unzipProgressHandler(entry: String, zipInfo: unz_file_info, entryNumber: Int, total: Int, destUnZip: URL, id: String, unzipError: inout NSError?) {
241
- if entry.contains("\\") {
242
- logger.error("unzip: Windows path is not supported, please use unix path as required by zip RFC: \(entry)")
240
+ private func validateZipEntry(path: String, destUnZip: URL) throws {
241
+ // Check for Windows paths
242
+ if path.contains("\\") {
243
+ logger.error("Unzip failed: Windows path not supported")
244
+ logger.debug("Invalid path: \(path)")
243
245
  self.sendStats(action: "windows_path_fail")
246
+ throw CustomError.cannotUnzip
244
247
  }
245
248
 
246
- let fileURL = destUnZip.appendingPathComponent(entry)
247
- let canonicalPath = fileURL.path
248
- let canonicalDir = destUnZip.path
249
+ // Check for path traversal
250
+ let fileURL = destUnZip.appendingPathComponent(path)
251
+ let canonicalPath = fileURL.standardizedFileURL.path
252
+ let canonicalDir = destUnZip.standardizedFileURL.path
249
253
 
250
254
  if !canonicalPath.hasPrefix(canonicalDir) {
251
255
  self.sendStats(action: "canonical_path_fail")
252
- unzipError = NSError(domain: "CanonicalPathError", code: 0, userInfo: nil)
253
- }
254
-
255
- let isDirectory = entry.hasSuffix("/")
256
- if !isDirectory {
257
- let folderURL = fileURL.deletingLastPathComponent()
258
- if !FileManager.default.fileExists(atPath: folderURL.path) {
259
- do {
260
- try FileManager.default.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
261
- } catch {
262
- self.sendStats(action: "directory_path_fail")
263
- unzipError = error as NSError
264
- }
265
- }
266
- }
267
-
268
- let newPercent = self.calcTotalPercent(percent: Int(Double(entryNumber) / Double(total) * 100), min: 75, max: 81)
269
- if newPercent != self.unzipPercent {
270
- self.unzipPercent = newPercent
271
- self.notifyDownload(id: id, percent: newPercent)
256
+ throw CustomError.cannotUnzip
272
257
  }
273
258
  }
274
259
 
@@ -280,36 +265,52 @@ import UIKit
280
265
  self.unzipPercent = 0
281
266
  self.notifyDownload(id: id, percent: 75)
282
267
 
283
- let semaphore = DispatchSemaphore(value: 0)
284
- var unzipError: NSError?
285
-
286
- let success = SSZipArchive.unzipFile(atPath: sourceZip.path,
287
- toDestination: destUnZip.path,
288
- preserveAttributes: true,
289
- overwrite: true,
290
- nestedZipLevel: 1,
291
- password: nil,
292
- error: &unzipError,
293
- delegate: nil,
294
- progressHandler: { [weak self] (entry, zipInfo, entryNumber, total) in
295
- DispatchQueue.global(qos: .background).async {
296
- guard let self = self else { return }
297
- if !notify {
298
- return
299
- }
300
- self.unzipProgressHandler(entry: entry, zipInfo: zipInfo, entryNumber: entryNumber, total: total, destUnZip: destUnZip, id: id, unzipError: &unzipError)
301
- }
302
- },
303
- completionHandler: { _, _, _ in
304
- semaphore.signal()
305
- })
268
+ // Open the archive
269
+ let archive: Archive
270
+ do {
271
+ archive = try Archive(url: sourceZip, accessMode: .read)
272
+ } catch {
273
+ self.sendStats(action: "unzip_fail")
274
+ throw CustomError.cannotUnzip
275
+ }
306
276
 
307
- semaphore.wait()
277
+ // Create destination directory
278
+ try FileManager.default.createDirectory(at: destUnZip, withIntermediateDirectories: true, attributes: nil)
279
+
280
+ // Count total entries for progress
281
+ let totalEntries = archive.reduce(0) { count, _ in count + 1 }
282
+ var processedEntries = 0
283
+
284
+ do {
285
+ for entry in archive {
286
+ // Validate entry path for security
287
+ try validateZipEntry(path: entry.path, destUnZip: destUnZip)
288
+
289
+ let destPath = destUnZip.appendingPathComponent(entry.path)
290
+
291
+ // Create parent directories if needed
292
+ let parentDir = destPath.deletingLastPathComponent()
293
+ if !FileManager.default.fileExists(atPath: parentDir.path) {
294
+ try FileManager.default.createDirectory(at: parentDir, withIntermediateDirectories: true, attributes: nil)
295
+ }
308
296
 
309
- if !success || unzipError != nil {
297
+ // Extract the entry
298
+ _ = try archive.extract(entry, to: destPath, skipCRC32: true)
299
+
300
+ // Update progress
301
+ processedEntries += 1
302
+ if notify && totalEntries > 0 {
303
+ let newPercent = self.calcTotalPercent(percent: Int(Double(processedEntries) / Double(totalEntries) * 100), min: 75, max: 81)
304
+ if newPercent != self.unzipPercent {
305
+ self.unzipPercent = newPercent
306
+ self.notifyDownload(id: id, percent: newPercent)
307
+ }
308
+ }
309
+ }
310
+ } catch {
310
311
  self.sendStats(action: "unzip_fail")
311
312
  try? FileManager.default.removeItem(at: destUnZip)
312
- throw unzipError ?? CustomError.cannotUnzip
313
+ throw error
313
314
  }
314
315
 
315
316
  if try unflatFolder(source: destUnZip, dest: destPersist) {
@@ -322,7 +323,8 @@ import UIKit
322
323
  try FileManager.default.removeItem(at: sourceZip)
323
324
  }
324
325
  } catch {
325
- logger.error("Could not delete source zip at \(sourceZip.path): \(error)")
326
+ logger.error("Could not delete source zip")
327
+ logger.debug("Path: \(sourceZip.path), Error: \(error)")
326
328
  }
327
329
  }
328
330
 
@@ -397,8 +399,9 @@ import UIKit
397
399
  latest.comment = comment
398
400
  }
399
401
  case let .failure(error):
400
- self.logger.error("Error getting Latest \(response.value.debugDescription) \(error)")
401
- latest.message = "Error getting Latest \(String(describing: response.value))"
402
+ self.logger.error("Error getting latest version")
403
+ self.logger.debug("Response: \(response.value.debugDescription), Error: \(error)")
404
+ latest.message = "Error getting Latest"
402
405
  latest.error = "response_error"
403
406
  latest.statusCode = response.response?.statusCode ?? 0
404
407
  }
@@ -465,7 +468,8 @@ import UIKit
465
468
  fileHash = try CryptoCipher.decryptChecksum(checksum: fileHash, publicKey: self.publicKey)
466
469
  } catch {
467
470
  downloadError = error
468
- logger.error("CryptoCipher.decryptChecksum error \(id) \(fileName) error: \(error)")
471
+ logger.error("Checksum decryption failed")
472
+ logger.debug("Bundle: \(id), File: \(fileName), Error: \(error)")
469
473
  }
470
474
  }
471
475
 
@@ -494,7 +498,8 @@ import UIKit
494
498
  self.notifyDownload(id: id, percent: self.calcTotalPercent(percent: Int((Double(completedFiles) / Double(totalFiles)) * 100), min: 10, max: 70))
495
499
  } catch {
496
500
  downloadError = error
497
- logger.error("Failed to copy builtin file \(fileName): \(error.localizedDescription)")
501
+ logger.error("Failed to copy builtin file")
502
+ logger.debug("File: \(fileName), Error: \(error.localizedDescription)")
498
503
  }
499
504
  dispatchGroup.leave()
500
505
  } else if self.tryCopyFromCache(from: cacheFilePath, to: destFilePath, expectedHash: fileHash) {
@@ -566,15 +571,18 @@ import UIKit
566
571
 
567
572
  completedFiles += 1
568
573
  self.notifyDownload(id: id, percent: self.calcTotalPercent(percent: Int((Double(completedFiles) / Double(totalFiles)) * 100), min: 10, max: 70))
569
- self.logger.info("downloadManifest \(id) \(fileName) downloaded\(isBrotli ? ", decompressed" : "")\(!self.publicKey.isEmpty && !sessionKey.isEmpty ? ", decrypted" : ""), and cached")
574
+ self.logger.info("Manifest file downloaded and cached")
575
+ self.logger.debug("Bundle: \(id), File: \(fileName), Brotli: \(isBrotli), Encrypted: \(!self.publicKey.isEmpty && !sessionKey.isEmpty)")
570
576
  } catch {
571
577
  downloadError = error
572
- self.logger.error("downloadManifest \(id) \(fileName) error: \(error.localizedDescription)")
578
+ self.logger.error("Manifest file download failed")
579
+ self.logger.debug("Bundle: \(id), File: \(fileName), Error: \(error.localizedDescription)")
573
580
  }
574
581
  case .failure(let error):
575
582
  downloadError = error
576
583
  self.sendStats(action: "download_manifest_file_fail", versionName: "\(version):\(fileName)")
577
- self.logger.error("downloadManifest \(id) \(fileName) download error: \(error.localizedDescription). Debug response: \(response.debugDescription).")
584
+ self.logger.error("Manifest file download network error")
585
+ self.logger.debug("Bundle: \(id), File: \(fileName), Error: \(error.localizedDescription), Response: \(response.debugDescription)")
578
586
  }
579
587
  }
580
588
  }
@@ -662,7 +670,8 @@ import UIKit
662
670
  var status = compression_stream_init(streamPointer, COMPRESSION_STREAM_DECODE, COMPRESSION_BROTLI)
663
671
 
664
672
  guard status != COMPRESSION_STATUS_ERROR else {
665
- logger.error("Error: Failed to initialize Brotli stream for \(fileName). Status: \(status)")
673
+ logger.error("Failed to initialize Brotli stream")
674
+ logger.debug("File: \(fileName), Status: \(status)")
666
675
  return nil
667
676
  }
668
677
 
@@ -684,7 +693,8 @@ import UIKit
684
693
  if let baseAddress = rawBufferPointer.baseAddress {
685
694
  streamPointer.pointee.src_ptr = baseAddress.assumingMemoryBound(to: UInt8.self)
686
695
  } else {
687
- logger.error("Error: Failed to get base address for \(fileName)")
696
+ logger.error("Failed to get base address for Brotli decompression")
697
+ logger.debug("File: \(fileName)")
688
698
  status = COMPRESSION_STATUS_ERROR
689
699
  return
690
700
  }
@@ -694,7 +704,8 @@ import UIKit
694
704
  if status == COMPRESSION_STATUS_ERROR {
695
705
  let maxBytes = min(32, data.count)
696
706
  let hexDump = data.prefix(maxBytes).map { String(format: "%02x", $0) }.joined(separator: " ")
697
- logger.error("Error: Brotli decompression failed for \(fileName). First \(maxBytes) bytes: \(hexDump)")
707
+ logger.error("Brotli decompression failed")
708
+ logger.debug("File: \(fileName), First \(maxBytes) bytes: \(hexDump)")
698
709
  break
699
710
  }
700
711
 
@@ -708,18 +719,19 @@ import UIKit
708
719
  if status == COMPRESSION_STATUS_END {
709
720
  break
710
721
  } else if status == COMPRESSION_STATUS_ERROR {
711
- logger.error("Error: Brotli process failed for \(fileName). Status: \(status)")
722
+ logger.error("Brotli process failed")
723
+ logger.debug("File: \(fileName), Status: \(status)")
712
724
  if let text = String(data: data, encoding: .utf8) {
713
725
  let asciiCount = text.unicodeScalars.filter { $0.isASCII }.count
714
726
  let totalCount = text.unicodeScalars.count
715
727
  if totalCount > 0 && Double(asciiCount) / Double(totalCount) >= 0.8 {
716
- logger.error("Error: Input appears to be plain text: \(text)")
728
+ logger.debug("Input appears to be plain text: \(text)")
717
729
  }
718
730
  }
719
731
 
720
732
  let maxBytes = min(32, data.count)
721
733
  let hexDump = data.prefix(maxBytes).map { String(format: "%02x", $0) }.joined(separator: " ")
722
- logger.error("Error: Raw data (\(fileName)): \(hexDump)")
734
+ logger.debug("Raw data: \(hexDump)")
723
735
 
724
736
  return nil
725
737
  }
@@ -730,7 +742,8 @@ import UIKit
730
742
  }
731
743
 
732
744
  if input.count == 0 {
733
- logger.error("Error: Zero input size for \(fileName)")
745
+ logger.error("Zero input size for Brotli decompression")
746
+ logger.debug("File: \(fileName)")
734
747
  break
735
748
  }
736
749
  }
@@ -822,7 +835,8 @@ import UIKit
822
835
  reachabilityManager?.stopListening()
823
836
 
824
837
  if mainError != nil {
825
- logger.error("Failed to download: \(String(describing: mainError))")
838
+ logger.error("Failed to download bundle")
839
+ logger.debug("Error: \(String(describing: mainError))")
826
840
  self.saveBundleInfo(id: id, bundle: BundleInfo(id: id, version: version, status: BundleStatus.ERROR, downloaded: Date(), checksum: checksum, link: link, comment: comment))
827
841
  throw mainError!
828
842
  }
@@ -832,7 +846,8 @@ import UIKit
832
846
  try CryptoCipher.decryptFile(filePath: tempDataPath, publicKey: self.publicKey, sessionKey: sessionKey, version: version)
833
847
  try FileManager.default.moveItem(at: tempDataPath, to: finalPath)
834
848
  } catch {
835
- logger.error("Failed decrypt file : \(error)")
849
+ logger.error("Failed to decrypt file")
850
+ logger.debug("Error: \(error)")
836
851
  self.saveBundleInfo(id: id, bundle: BundleInfo(id: id, version: version, status: BundleStatus.ERROR, downloaded: Date(), checksum: checksum, link: link, comment: comment))
837
852
  cleanDownloadData()
838
853
  throw error
@@ -845,7 +860,8 @@ import UIKit
845
860
  try self.saveDownloaded(sourceZip: finalPath, id: id, base: self.libraryDir.appendingPathComponent(self.bundleDirectory), notify: true)
846
861
 
847
862
  } catch {
848
- logger.error("Failed to unzip file: \(error)")
863
+ logger.error("Failed to unzip file")
864
+ logger.debug("Error: \(error)")
849
865
  self.saveBundleInfo(id: id, bundle: BundleInfo(id: id, version: version, status: BundleStatus.ERROR, downloaded: Date(), checksum: checksum, link: link, comment: comment))
850
866
  // Best-effort cleanup of the decrypted zip file when unzip fails
851
867
  do {
@@ -853,7 +869,8 @@ import UIKit
853
869
  try FileManager.default.removeItem(at: finalPath)
854
870
  }
855
871
  } catch {
856
- logger.error("Could not delete failed zip at \(finalPath.path): \(error)")
872
+ logger.error("Could not delete failed zip")
873
+ logger.debug("Path: \(finalPath.path), Error: \(error)")
857
874
  }
858
875
  cleanDownloadData()
859
876
  throw error
@@ -876,13 +893,15 @@ import UIKit
876
893
  let fileManager = FileManager.default
877
894
  if !fileManager.fileExists(atPath: tempDataPath.path) {
878
895
  if !fileManager.createFile(atPath: tempDataPath.path, contents: Data()) {
879
- logger.error("Cannot ensure that a file at \(tempDataPath.path) exists")
896
+ logger.error("Cannot ensure temp data file exists")
897
+ logger.debug("Path: \(tempDataPath.path)")
880
898
  }
881
899
  }
882
900
 
883
901
  if !fileManager.fileExists(atPath: updateInfo.path) {
884
902
  if !fileManager.createFile(atPath: updateInfo.path, contents: Data()) {
885
- logger.error("Cannot ensure that a file at \(updateInfo.path) exists")
903
+ logger.error("Cannot ensure update info file exists")
904
+ logger.debug("Path: \(updateInfo.path)")
886
905
  }
887
906
  }
888
907
  }
@@ -894,7 +913,8 @@ import UIKit
894
913
  do {
895
914
  try fileManager.removeItem(at: tempDataPath)
896
915
  } catch {
897
- logger.error("Could not delete file at \(tempDataPath): \(error)")
916
+ logger.error("Could not delete temp data file")
917
+ logger.debug("Path: \(tempDataPath), Error: \(error)")
898
918
  }
899
919
  }
900
920
  // Deleting update.dat
@@ -902,7 +922,8 @@ import UIKit
902
922
  do {
903
923
  try fileManager.removeItem(at: updateInfo)
904
924
  } catch {
905
- logger.error("Could not delete file at \(updateInfo): \(error)")
925
+ logger.error("Could not delete update info file")
926
+ logger.debug("Path: \(updateInfo), Error: \(error)")
906
927
  }
907
928
  }
908
929
  }
@@ -921,7 +942,8 @@ import UIKit
921
942
  fileHandle.closeFile()
922
943
  }
923
944
  } catch {
924
- logger.error("Failed to write data starting at byte \(byteOffset): \(error)")
945
+ logger.error("Failed to write partial data")
946
+ logger.debug("Byte offset: \(byteOffset), Error: \(error)")
925
947
  }
926
948
  self.tempData.removeAll() // Clearing tempData to avoid writing the same data multiple times
927
949
  }
@@ -930,7 +952,8 @@ import UIKit
930
952
  do {
931
953
  try "\(version)".write(to: updateInfo, atomically: true, encoding: .utf8)
932
954
  } catch {
933
- logger.error("Failed to save progress: \(error)")
955
+ logger.error("Failed to save download progress")
956
+ logger.debug("Error: \(error)")
934
957
  }
935
958
  }
936
959
  private func getLocalUpdateVersion() -> String { // Return the version that was tried to be downloaded on last download attempt
@@ -952,7 +975,8 @@ import UIKit
952
975
  return fileSize.int64Value
953
976
  }
954
977
  } catch {
955
- logger.error("Could not retrieve already downloaded data size : \(error)")
978
+ logger.error("Could not retrieve download progress size")
979
+ logger.debug("Error: \(error)")
956
980
  }
957
981
  return 0
958
982
  }
@@ -996,7 +1020,8 @@ import UIKit
996
1020
  public func delete(id: String, removeInfo: Bool) -> Bool {
997
1021
  let deleted: BundleInfo = self.getBundleInfo(id: id)
998
1022
  if deleted.isBuiltin() || self.getCurrentBundleId() == id {
999
- logger.info("Cannot delete \(id)")
1023
+ logger.info("Cannot delete current or builtin bundle")
1024
+ logger.debug("Bundle ID: \(id)")
1000
1025
  return false
1001
1026
  }
1002
1027
 
@@ -1005,7 +1030,8 @@ import UIKit
1005
1030
  !next.isDeleted() &&
1006
1031
  !next.isErrorStatus() &&
1007
1032
  next.getId() == id {
1008
- logger.info("Cannot delete the next bundle \(id)")
1033
+ logger.info("Cannot delete the next bundle")
1034
+ logger.debug("Bundle ID: \(id)")
1009
1035
  return false
1010
1036
  }
1011
1037
 
@@ -1013,7 +1039,8 @@ import UIKit
1013
1039
  do {
1014
1040
  try FileManager.default.removeItem(atPath: destPersist.path)
1015
1041
  } catch {
1016
- logger.error("Folder \(destPersist.path), not removed.")
1042
+ logger.error("Bundle folder not removed")
1043
+ logger.debug("Path: \(destPersist.path)")
1017
1044
  // even if, we don;t care. Android doesn't care
1018
1045
  if removeInfo {
1019
1046
  self.removeBundleInfo(id: id)
@@ -1026,7 +1053,8 @@ import UIKit
1026
1053
  } else {
1027
1054
  self.saveBundleInfo(id: id, bundle: deleted.setStatus(status: BundleStatus.DELETED.localizedString))
1028
1055
  }
1029
- logger.info("bundle delete \(deleted.getVersionName())")
1056
+ logger.info("Bundle deleted successfully")
1057
+ logger.debug("Version: \(deleted.getVersionName())")
1030
1058
  self.sendStats(action: "delete", versionName: deleted.getVersionName())
1031
1059
  return true
1032
1060
  }
@@ -1054,7 +1082,8 @@ import UIKit
1054
1082
  try fileManager.removeItem(at: cacheFolder)
1055
1083
  logger.info("Cleaned up delta cache folder")
1056
1084
  } catch {
1057
- logger.error("Failed to cleanup delta cache: \(error.localizedDescription)")
1085
+ logger.error("Failed to cleanup delta cache")
1086
+ logger.debug("Error: \(error.localizedDescription)")
1058
1087
  }
1059
1088
  }
1060
1089
 
@@ -1094,13 +1123,16 @@ import UIKit
1094
1123
  do {
1095
1124
  try fileManager.removeItem(at: url)
1096
1125
  self.removeBundleInfo(id: id)
1097
- logger.info("Deleted orphan bundle directory: \(id)")
1126
+ logger.info("Deleted orphan bundle directory")
1127
+ logger.debug("Bundle ID: \(id)")
1098
1128
  } catch {
1099
- logger.error("Failed to delete orphan bundle directory: \(id) \(error.localizedDescription)")
1129
+ logger.error("Failed to delete orphan bundle directory")
1130
+ logger.debug("Bundle ID: \(id), Error: \(error.localizedDescription)")
1100
1131
  }
1101
1132
  }
1102
1133
  } catch {
1103
- logger.error("Failed to enumerate bundle directory for cleanup: \(error.localizedDescription)")
1134
+ logger.error("Failed to enumerate bundle directory for cleanup")
1135
+ logger.debug("Error: \(error.localizedDescription)")
1104
1136
  }
1105
1137
  }
1106
1138
 
@@ -1131,13 +1163,16 @@ import UIKit
1131
1163
 
1132
1164
  do {
1133
1165
  try fileManager.removeItem(at: url)
1134
- logger.info("Deleted orphaned temp unzip folder: \(folderName)")
1166
+ logger.info("Deleted orphaned temp unzip folder")
1167
+ logger.debug("Folder: \(folderName)")
1135
1168
  } catch {
1136
- logger.error("Failed to delete orphaned temp folder: \(folderName) \(error.localizedDescription)")
1169
+ logger.error("Failed to delete orphaned temp folder")
1170
+ logger.debug("Folder: \(folderName), Error: \(error.localizedDescription)")
1137
1171
  }
1138
1172
  }
1139
1173
  } catch {
1140
- logger.error("Failed to enumerate library directory for temp folder cleanup: \(error.localizedDescription)")
1174
+ logger.error("Failed to enumerate library directory for temp folder cleanup")
1175
+ logger.debug("Error: \(error.localizedDescription)")
1141
1176
  }
1142
1177
  }
1143
1178
 
@@ -1213,9 +1248,11 @@ import UIKit
1213
1248
  if autoDeletePrevious && !fallback.isBuiltin() && fallback.getId() != bundle.getId() {
1214
1249
  let res = self.delete(id: fallback.getId())
1215
1250
  if res {
1216
- logger.info("Deleted previous bundle: \(fallback.toString())")
1251
+ logger.info("Deleted previous bundle")
1252
+ logger.debug("Bundle: \(fallback.toString())")
1217
1253
  } else {
1218
- logger.error("Failed to delete previous bundle: \(fallback.toString())")
1254
+ logger.error("Failed to delete previous bundle")
1255
+ logger.debug("Bundle: \(fallback.toString())")
1219
1256
  }
1220
1257
  }
1221
1258
  self.setFallbackBundle(fallback: bundle)
@@ -1296,7 +1333,8 @@ import UIKit
1296
1333
  }
1297
1334
  }
1298
1335
  case let .failure(error):
1299
- self.logger.error("Error set Channel \(error)")
1336
+ self.logger.error("Error setting channel")
1337
+ self.logger.debug("Error: \(error)")
1300
1338
  setChannel.error = "Request failed: \(error.localizedDescription)"
1301
1339
  }
1302
1340
  semaphore.signal()
@@ -1359,7 +1397,8 @@ import UIKit
1359
1397
  }
1360
1398
  }
1361
1399
 
1362
- self.logger.error("Error get Channel \(error)")
1400
+ self.logger.error("Error getting channel")
1401
+ self.logger.debug("Error: \(error)")
1363
1402
  getChannel.error = "Request failed: \(error.localizedDescription)"
1364
1403
  }
1365
1404
  }
@@ -1449,7 +1488,8 @@ import UIKit
1449
1488
  }
1450
1489
  }
1451
1490
  case let .failure(error):
1452
- self.logger.error("Error list channels \(error)")
1491
+ self.logger.error("Error listing channels")
1492
+ self.logger.debug("Error: \(error)")
1453
1493
  listChannels.error = "Request failed: \(error.localizedDescription)"
1454
1494
  }
1455
1495
  }
@@ -1495,9 +1535,11 @@ import UIKit
1495
1535
 
1496
1536
  switch response.result {
1497
1537
  case .success:
1498
- self.logger.info("Stats sent for \(action), version \(versionName)")
1538
+ self.logger.info("Stats sent successfully")
1539
+ self.logger.debug("Action: \(action), Version: \(versionName)")
1499
1540
  case let .failure(error):
1500
- self.logger.error("Error sending stats: \(response.value?.debugDescription ?? "") \(error.localizedDescription)")
1541
+ self.logger.error("Error sending stats")
1542
+ self.logger.debug("Response: \(response.value?.debugDescription ?? "nil"), Error: \(error.localizedDescription)")
1501
1543
  }
1502
1544
  semaphore.signal()
1503
1545
  }
@@ -1521,7 +1563,8 @@ import UIKit
1521
1563
  do {
1522
1564
  result = try UserDefaults.standard.getObj(forKey: "\(trueId)\(self.INFO_SUFFIX)", castTo: BundleInfo.self)
1523
1565
  } catch {
1524
- logger.error("Failed to parse info for bundle [\(trueId)] \(error.localizedDescription)")
1566
+ logger.error("Failed to parse bundle info")
1567
+ logger.debug("Bundle ID: \(trueId), Error: \(error.localizedDescription)")
1525
1568
  result = BundleInfo(id: trueId, version: "", status: BundleStatus.PENDING, checksum: "")
1526
1569
  }
1527
1570
  }
@@ -1556,7 +1599,8 @@ import UIKit
1556
1599
  do {
1557
1600
  try UserDefaults.standard.setObj(update, forKey: "\(id)\(self.INFO_SUFFIX)")
1558
1601
  } catch {
1559
- logger.error("Failed to save info for bundle [\(id)] \(error.localizedDescription)")
1602
+ logger.error("Failed to save bundle info")
1603
+ logger.debug("Bundle ID: \(id), Error: \(error.localizedDescription)")
1560
1604
  }
1561
1605
  }
1562
1606
  UserDefaults.standard.synchronize()