@capgo/capacitor-updater 5.50.2 → 5.51.15
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.
- package/CapgoCapacitorUpdater.podspec +1 -1
- package/Package.swift +3 -2
- package/README.md +53 -48
- package/android/build.gradle +1 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/AppLifecycleObserver.java +29 -2
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleInfo.java +7 -3
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleStatus.java +1 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +452 -139
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +1354 -412
- package/android/src/main/java/ee/forgr/capacitor_updater/CryptoCipher.java +102 -31
- package/android/src/main/java/ee/forgr/capacitor_updater/DataManager.java +23 -7
- package/android/src/main/java/ee/forgr/capacitor_updater/DelayCondition.java +2 -2
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +540 -224
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadWorkerManager.java +103 -3
- package/android/src/main/java/ee/forgr/capacitor_updater/InternalUtils.java +1 -1
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeMenu.java +131 -145
- package/dist/docs.json +32 -8
- package/dist/esm/definitions.d.ts +41 -17
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/AES.swift +124 -0
- package/ios/Sources/CapacitorUpdaterPlugin/BundleInfo.swift +9 -1
- package/ios/Sources/CapacitorUpdaterPlugin/BundleStatus.swift +3 -0
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +787 -92
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +1014 -268
- package/ios/Sources/CapacitorUpdaterPlugin/CryptoCipher.swift +49 -31
- package/ios/Sources/CapacitorUpdaterPlugin/ShakeMenu.swift +44 -20
- package/ios/Sources/CapacitorUpdaterPlugin/WebViewStatsReporter.swift +28 -0
- package/package.json +12 -7
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import CommonCrypto
|
|
3
3
|
import CryptoKit
|
|
4
|
+
import Darwin
|
|
4
5
|
|
|
5
6
|
///
|
|
6
7
|
/// Constants
|
|
@@ -83,4 +84,127 @@ public struct AES128Key {
|
|
|
83
84
|
return nil
|
|
84
85
|
}
|
|
85
86
|
}
|
|
87
|
+
|
|
88
|
+
/// AES-CBC file-to-file. Never holds the whole ciphertext in RAM.
|
|
89
|
+
func decrypt(from source: URL, to destination: URL) throws {
|
|
90
|
+
var cryptor: CCCryptorRef?
|
|
91
|
+
let createStatus: CCCryptorStatus = aes128Key.withUnsafeBytes { keyBytes in
|
|
92
|
+
initVector.withUnsafeBytes { ivBytes in
|
|
93
|
+
guard let keyPtr = keyBytes.baseAddress, let ivPtr = ivBytes.baseAddress else {
|
|
94
|
+
return CCCryptorStatus(kCCParamError)
|
|
95
|
+
}
|
|
96
|
+
return CCCryptorCreate(
|
|
97
|
+
CCOperation(kCCDecrypt),
|
|
98
|
+
AESConstants.aesAlgorithm,
|
|
99
|
+
AESConstants.aesOptions,
|
|
100
|
+
keyPtr,
|
|
101
|
+
keyBytes.count,
|
|
102
|
+
ivPtr,
|
|
103
|
+
&cryptor
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
guard createStatus == kCCSuccess, let cryptor else {
|
|
108
|
+
logger.error("Failed to create AES cryptor")
|
|
109
|
+
throw NSError(domain: "AESDecryptError", code: Int(createStatus), userInfo: nil)
|
|
110
|
+
}
|
|
111
|
+
defer {
|
|
112
|
+
CCCryptorRelease(cryptor)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
guard let input = InputStream(url: source) else {
|
|
116
|
+
throw NSError(domain: "AESDecryptError", code: 1, userInfo: [NSLocalizedDescriptionKey: "Failed to open AES source"])
|
|
117
|
+
}
|
|
118
|
+
input.open()
|
|
119
|
+
defer {
|
|
120
|
+
input.close()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let tempURL = destination.deletingLastPathComponent().appendingPathComponent("capgo-aes-\(UUID().uuidString).tmp")
|
|
124
|
+
let fileManager = FileManager.default
|
|
125
|
+
fileManager.createFile(atPath: tempURL.path, contents: nil)
|
|
126
|
+
let output = try FileHandle(forWritingTo: tempURL)
|
|
127
|
+
defer {
|
|
128
|
+
try? output.close()
|
|
129
|
+
try? fileManager.removeItem(at: tempURL)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let bufferSize = CryptoCipher.ioBufferBytes()
|
|
133
|
+
let outBufSize = bufferSize + kCCBlockSizeAES128
|
|
134
|
+
var inBuf = [UInt8](repeating: 0, count: bufferSize)
|
|
135
|
+
var outBuf = [UInt8](repeating: 0, count: outBufSize)
|
|
136
|
+
let outFd = output.fileDescriptor
|
|
137
|
+
|
|
138
|
+
while true {
|
|
139
|
+
let n = inBuf.withUnsafeMutableBufferPointer { ptr in
|
|
140
|
+
input.read(ptr.baseAddress!, maxLength: ptr.count)
|
|
141
|
+
}
|
|
142
|
+
if n == 0 {
|
|
143
|
+
break
|
|
144
|
+
}
|
|
145
|
+
if n < 0 {
|
|
146
|
+
throw input.streamError ?? NSError(domain: "AESDecryptError", code: 2, userInfo: [NSLocalizedDescriptionKey: "AES stream read failed"])
|
|
147
|
+
}
|
|
148
|
+
var moved: size_t = 0
|
|
149
|
+
let status: CCCryptorStatus = inBuf.withUnsafeBufferPointer { inRaw in
|
|
150
|
+
outBuf.withUnsafeMutableBytes { outRaw in
|
|
151
|
+
CCCryptorUpdate(
|
|
152
|
+
cryptor,
|
|
153
|
+
inRaw.baseAddress,
|
|
154
|
+
n,
|
|
155
|
+
outRaw.baseAddress,
|
|
156
|
+
outBufSize,
|
|
157
|
+
&moved
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
guard status == kCCSuccess else {
|
|
162
|
+
logger.error("AES stream update failed")
|
|
163
|
+
throw NSError(domain: "AESDecryptError", code: Int(status), userInfo: nil)
|
|
164
|
+
}
|
|
165
|
+
if moved > 0 {
|
|
166
|
+
try Self.writeAll(fd: outFd, buffer: &outBuf, count: moved)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
var moved: size_t = 0
|
|
171
|
+
let finalStatus: CCCryptorStatus = outBuf.withUnsafeMutableBytes { outRaw in
|
|
172
|
+
CCCryptorFinal(cryptor, outRaw.baseAddress, outBufSize, &moved)
|
|
173
|
+
}
|
|
174
|
+
guard finalStatus == kCCSuccess else {
|
|
175
|
+
logger.error("AES stream finalize failed")
|
|
176
|
+
throw NSError(domain: "AESDecryptError", code: Int(finalStatus), userInfo: nil)
|
|
177
|
+
}
|
|
178
|
+
if moved > 0 {
|
|
179
|
+
try Self.writeAll(fd: outFd, buffer: &outBuf, count: moved)
|
|
180
|
+
}
|
|
181
|
+
try output.close()
|
|
182
|
+
|
|
183
|
+
let decryptedSize = (try fileManager.attributesOfItem(atPath: tempURL.path)[.size] as? NSNumber)?.uint64Value ?? 0
|
|
184
|
+
if decryptedSize == 0 {
|
|
185
|
+
throw NSError(domain: "Empty decrypted data", code: 7, userInfo: nil)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
do {
|
|
189
|
+
_ = try fileManager.replaceItemAt(destination, withItemAt: tempURL)
|
|
190
|
+
} catch {
|
|
191
|
+
if fileManager.fileExists(atPath: destination.path) {
|
|
192
|
+
throw error
|
|
193
|
+
}
|
|
194
|
+
try fileManager.moveItem(at: tempURL, to: destination)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private static func writeAll(fd: Int32, buffer: inout [UInt8], count: Int) throws {
|
|
199
|
+
var offset = 0
|
|
200
|
+
while offset < count {
|
|
201
|
+
let written = buffer.withUnsafeBufferPointer { ptr -> Int in
|
|
202
|
+
Darwin.write(fd, ptr.baseAddress!.advanced(by: offset), count - offset)
|
|
203
|
+
}
|
|
204
|
+
if written <= 0 {
|
|
205
|
+
throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: [NSLocalizedDescriptionKey: "AES stream write failed"])
|
|
206
|
+
}
|
|
207
|
+
offset += written
|
|
208
|
+
}
|
|
209
|
+
}
|
|
86
210
|
}
|
|
@@ -65,9 +65,17 @@ import Foundation
|
|
|
65
65
|
return BundleStatus.DELETED == self.status
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
public func isDeleting() -> Bool {
|
|
69
|
+
return BundleStatus.DELETING == self.status
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public func isDownloading() -> Bool {
|
|
73
|
+
return BundleStatus.DOWNLOADING == self.status
|
|
74
|
+
}
|
|
75
|
+
|
|
68
76
|
public func isDownloaded() -> Bool {
|
|
69
77
|
return !self.isBuiltin() && self.downloaded != "" &&
|
|
70
|
-
self.downloaded != BundleInfo.DOWNLOADED_BUILTIN && !self.isDeleted()
|
|
78
|
+
self.downloaded != BundleInfo.DOWNLOADED_BUILTIN && !self.isDeleted() && !self.isDeleting()
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
public func getDownloaded() -> String {
|
|
@@ -36,6 +36,7 @@ enum BundleStatus: LocalizedString, CaseIterable, Decodable, Encodable {
|
|
|
36
36
|
case ERROR = "error"
|
|
37
37
|
case PENDING = "pending"
|
|
38
38
|
case DELETED = "deleted"
|
|
39
|
+
case DELETING = "deleting"
|
|
39
40
|
case DOWNLOADING = "downloading"
|
|
40
41
|
|
|
41
42
|
var storedValue: String {
|
|
@@ -48,6 +49,8 @@ enum BundleStatus: LocalizedString, CaseIterable, Decodable, Encodable {
|
|
|
48
49
|
return "pending"
|
|
49
50
|
case .DELETED:
|
|
50
51
|
return "deleted"
|
|
52
|
+
case .DELETING:
|
|
53
|
+
return "deleting"
|
|
51
54
|
case .DOWNLOADING:
|
|
52
55
|
return "downloading"
|
|
53
56
|
}
|