@hot-updater/react-native 0.29.2 → 0.29.3

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.
@@ -1,5 +1,4 @@
1
1
  import Foundation
2
- import SWCompression
3
2
 
4
3
  /**
5
4
  * Strategy for handling ZIP compressed files
@@ -34,7 +33,8 @@ class ZipDecompressionStrategy: DecompressionStrategy {
34
33
  fileHandle.closeFile()
35
34
  }
36
35
 
37
- guard let header = try? fileHandle.read(upToCount: 4), header.count == 4 else {
36
+ guard let header = try? ArchiveExtractionUtilities.readUpToCount(from: fileHandle, count: 4),
37
+ header.count == 4 else {
38
38
  NSLog("[ZipStrategy] Invalid ZIP: cannot read header")
39
39
  return false
40
40
  }
@@ -45,121 +45,12 @@ class ZipDecompressionStrategy: DecompressionStrategy {
45
45
  return false
46
46
  }
47
47
 
48
- guard let zipData = try? Data(contentsOf: URL(fileURLWithPath: file)) else {
49
- NSLog("[ZipStrategy] Invalid ZIP: cannot read file data")
50
- return false
51
- }
52
-
53
- do {
54
- _ = try ZipContainer.open(container: zipData)
55
- return true
56
- } catch {
57
- NSLog("[ZipStrategy] Invalid ZIP: structure validation failed - \(error.localizedDescription)")
58
- return false
59
- }
48
+ return true
60
49
  }
61
50
 
62
51
  func decompress(file: String, to destination: String, progressHandler: @escaping (Double) -> Void) throws {
63
52
  NSLog("[ZipStrategy] Starting extraction of \(file) to \(destination)")
64
-
65
- guard let zipData = try? Data(contentsOf: URL(fileURLWithPath: file)) else {
66
- throw NSError(
67
- domain: "ZipDecompressionStrategy",
68
- code: 1,
69
- userInfo: [NSLocalizedDescriptionKey: "Failed to read ZIP file at: \(file)"]
70
- )
71
- }
72
-
73
- progressHandler(0.1)
74
-
75
- let zipEntries: [ZipEntry]
76
- do {
77
- zipEntries = try ZipContainer.open(container: zipData)
78
- NSLog("[ZipStrategy] ZIP extraction successful, found \(zipEntries.count) entries")
79
- } catch {
80
- throw NSError(
81
- domain: "ZipDecompressionStrategy",
82
- code: 2,
83
- userInfo: [NSLocalizedDescriptionKey: "ZIP extraction failed: \(error.localizedDescription)"]
84
- )
85
- }
86
-
87
- progressHandler(0.2)
88
-
89
- let destinationURL = URL(fileURLWithPath: destination)
90
- let canonicalDestination = destinationURL.standardized.path
91
-
92
- let fileManager = FileManager.default
93
- if !fileManager.fileExists(atPath: canonicalDestination) {
94
- try fileManager.createDirectory(
95
- atPath: canonicalDestination,
96
- withIntermediateDirectories: true,
97
- attributes: nil
98
- )
99
- }
100
-
101
- let totalEntries = Double(zipEntries.count)
102
- for (index, entry) in zipEntries.enumerated() {
103
- try extractZipEntry(entry, to: canonicalDestination)
104
- progressHandler(0.2 + (Double(index + 1) / totalEntries * 0.8))
105
- }
106
-
53
+ try ZipArchiveExtractor.extract(file: file, to: destination, progressHandler: progressHandler)
107
54
  NSLog("[ZipStrategy] Successfully extracted all entries")
108
55
  }
109
-
110
- private func extractZipEntry(_ entry: ZipEntry, to destination: String) throws {
111
- let fileManager = FileManager.default
112
- let entryPath = entry.info.name.trimmingCharacters(in: .init(charactersIn: "/"))
113
-
114
- guard !entryPath.isEmpty,
115
- !entryPath.contains(".."),
116
- !entryPath.hasPrefix("/") else {
117
- NSLog("[ZipStrategy] Skipping suspicious path: \(entry.info.name)")
118
- return
119
- }
120
-
121
- let fullPath = (destination as NSString).appendingPathComponent(entryPath)
122
- let fullURL = URL(fileURLWithPath: fullPath)
123
- let canonicalFullPath = fullURL.standardized.path
124
- let canonicalDestination = URL(fileURLWithPath: destination).standardized.path
125
-
126
- guard canonicalFullPath.hasPrefix(canonicalDestination + "/") ||
127
- canonicalFullPath == canonicalDestination else {
128
- throw NSError(
129
- domain: "ZipDecompressionStrategy",
130
- code: 3,
131
- userInfo: [NSLocalizedDescriptionKey: "Path traversal attempt detected: \(entry.info.name)"]
132
- )
133
- }
134
-
135
- if entry.info.type == .directory {
136
- if !fileManager.fileExists(atPath: canonicalFullPath) {
137
- try fileManager.createDirectory(
138
- atPath: canonicalFullPath,
139
- withIntermediateDirectories: true,
140
- attributes: nil
141
- )
142
- }
143
- return
144
- }
145
-
146
- if entry.info.type == .regular {
147
- let parentPath = (canonicalFullPath as NSString).deletingLastPathComponent
148
- if !fileManager.fileExists(atPath: parentPath) {
149
- try fileManager.createDirectory(
150
- atPath: parentPath,
151
- withIntermediateDirectories: true,
152
- attributes: nil
153
- )
154
- }
155
-
156
- guard let data = entry.data else {
157
- NSLog("[ZipStrategy] Skipping file with no data: \(entry.info.name)")
158
- return
159
- }
160
-
161
- try data.write(to: URL(fileURLWithPath: canonicalFullPath))
162
- NSLog("[ZipStrategy] Extracted: \(entryPath)")
163
- }
164
- }
165
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/react-native",
3
- "version": "0.29.2",
3
+ "version": "0.29.3",
4
4
  "description": "React Native OTA solution for self-hosted",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -120,14 +120,14 @@
120
120
  "react-native": "0.79.1",
121
121
  "react-native-builder-bob": "^0.40.10",
122
122
  "typescript": "^5.8.3",
123
- "hot-updater": "0.29.2"
123
+ "hot-updater": "0.29.3"
124
124
  },
125
125
  "dependencies": {
126
126
  "use-sync-external-store": "1.5.0",
127
- "@hot-updater/cli-tools": "0.29.2",
128
- "@hot-updater/core": "0.29.2",
129
- "@hot-updater/js": "0.29.2",
130
- "@hot-updater/plugin-core": "0.29.2"
127
+ "@hot-updater/cli-tools": "0.29.3",
128
+ "@hot-updater/core": "0.29.3",
129
+ "@hot-updater/js": "0.29.3",
130
+ "@hot-updater/plugin-core": "0.29.3"
131
131
  },
132
132
  "scripts": {
133
133
  "build": "bob build && tsc -p plugin/tsconfig.build.json",