@capgo/capacitor-updater 7.13.5 → 7.13.11
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 +2 -2
- package/Package.swift +3 -3
- package/android/build.gradle +2 -2
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +2 -2
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +4 -4
- package/android/src/main/java/ee/forgr/capacitor_updater/{CryptoCipherV2.java → CryptoCipher.java} +7 -7
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +3 -3
- package/package.json +3 -4
- package/ios/Plugin/AES.swift +0 -69
- package/ios/Plugin/BigInt.swift +0 -55
- package/ios/Plugin/BundleInfo.swift +0 -113
- package/ios/Plugin/BundleStatus.swift +0 -48
- package/ios/Plugin/CapacitorUpdaterPlugin.swift +0 -1182
- package/ios/Plugin/CapgoUpdater.swift +0 -1301
- package/ios/Plugin/CryptoCipherV2.swift +0 -187
- package/ios/Plugin/DelayCondition.swift +0 -74
- package/ios/Plugin/DelayUntilNext.swift +0 -30
- package/ios/Plugin/DelayUpdateUtils.swift +0 -222
- package/ios/Plugin/Info.plist +0 -28
- package/ios/Plugin/InternalUtils.swift +0 -303
- package/ios/Plugin/Logger.swift +0 -310
- package/ios/Plugin/RSA.swift +0 -274
- package/ios/Plugin/ShakeMenu.swift +0 -112
- package/ios/Plugin/UserDefaultsExtension.swift +0 -46
|
@@ -10,12 +10,12 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.homepage = package['repository']['url']
|
|
11
11
|
s.author = package['author']
|
|
12
12
|
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
|
13
|
-
s.source_files = 'ios/
|
|
13
|
+
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
14
|
s.ios.deployment_target = '14.0'
|
|
15
15
|
s.dependency 'Capacitor'
|
|
16
16
|
s.dependency 'SSZipArchive', '2.4.3'
|
|
17
17
|
s.dependency 'Alamofire', '5.10.2'
|
|
18
18
|
s.dependency 'Version', '0.8.0'
|
|
19
|
-
s.dependency 'BigInt', '5.
|
|
19
|
+
s.dependency 'BigInt', '5.6.0'
|
|
20
20
|
s.swift_version = '5.1'
|
|
21
21
|
end
|
package/Package.swift
CHANGED
|
@@ -14,7 +14,7 @@ let package = Package(
|
|
|
14
14
|
.package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.10.2")),
|
|
15
15
|
.package(url: "https://github.com/ZipArchive/ZipArchive.git", exact: "2.4.3"),
|
|
16
16
|
.package(url: "https://github.com/mrackwitz/Version.git", exact: "0.8.0"),
|
|
17
|
-
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.
|
|
17
|
+
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.6.0")
|
|
18
18
|
],
|
|
19
19
|
targets: [
|
|
20
20
|
.target(
|
|
@@ -27,11 +27,11 @@ let package = Package(
|
|
|
27
27
|
.product(name: "Version", package: "Version"),
|
|
28
28
|
.product(name: "BigInt", package: "BigInt")
|
|
29
29
|
],
|
|
30
|
-
path: "ios/
|
|
30
|
+
path: "ios/Sources/CapacitorUpdaterPlugin"),
|
|
31
31
|
.testTarget(
|
|
32
32
|
name: "CapacitorUpdaterPluginTests",
|
|
33
33
|
dependencies: ["CapacitorUpdaterPlugin"],
|
|
34
|
-
path: "ios/
|
|
34
|
+
path: "ios/Tests/CapacitorUpdaterPluginTests")
|
|
35
35
|
],
|
|
36
36
|
swiftLanguageVersions: [.v5]
|
|
37
37
|
)
|
package/android/build.gradle
CHANGED
|
@@ -49,7 +49,7 @@ repositories {
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
dependencies {
|
|
52
|
-
def work_version = "2.10.
|
|
52
|
+
def work_version = "2.10.2"
|
|
53
53
|
implementation "androidx.work:work-runtime:$work_version"
|
|
54
54
|
implementation "com.google.android.gms:play-services-tasks:18.2.1"
|
|
55
55
|
implementation "com.google.guava:guava:33.4.8-android"
|
|
@@ -57,7 +57,7 @@ dependencies {
|
|
|
57
57
|
implementation project(':capacitor-android')
|
|
58
58
|
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
59
59
|
implementation 'io.github.g00fy2:versioncompare:1.5.0'
|
|
60
|
-
implementation 'com.google.code.gson:gson:2.13.
|
|
60
|
+
implementation 'com.google.code.gson:gson:2.13.2'
|
|
61
61
|
testImplementation "junit:junit:$junitVersion"
|
|
62
62
|
testImplementation 'org.mockito:mockito-core:5.14.2'
|
|
63
63
|
testImplementation 'org.robolectric:robolectric:4.13'
|
|
@@ -58,7 +58,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
58
58
|
private static final String statsUrlDefault = "https://plugin.capgo.app/stats";
|
|
59
59
|
private static final String channelUrlDefault = "https://plugin.capgo.app/channel_self";
|
|
60
60
|
|
|
61
|
-
private final String PLUGIN_VERSION = "7.13.
|
|
61
|
+
private final String PLUGIN_VERSION = "7.13.11";
|
|
62
62
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
63
63
|
|
|
64
64
|
private SharedPreferences.Editor editor;
|
|
@@ -196,7 +196,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
// Set logger for shared classes
|
|
199
|
-
|
|
199
|
+
CryptoCipher.setLogger(logger);
|
|
200
200
|
DownloadService.setLogger(logger);
|
|
201
201
|
DownloadWorkerManager.setLogger(logger);
|
|
202
202
|
|
|
@@ -371,11 +371,11 @@ public class CapgoUpdater {
|
|
|
371
371
|
}
|
|
372
372
|
|
|
373
373
|
if (!sessionKey.isEmpty()) {
|
|
374
|
-
|
|
375
|
-
checksumDecrypted =
|
|
376
|
-
checksum =
|
|
374
|
+
CryptoCipher.decryptFile(downloaded, publicKey, sessionKey);
|
|
375
|
+
checksumDecrypted = CryptoCipher.decryptChecksum(checksumRes, publicKey);
|
|
376
|
+
checksum = CryptoCipher.calcChecksum(downloaded);
|
|
377
377
|
} else {
|
|
378
|
-
checksum =
|
|
378
|
+
checksum = CryptoCipher.calcChecksum(downloaded);
|
|
379
379
|
}
|
|
380
380
|
if ((!checksumDecrypted.isEmpty() || !this.publicKey.isEmpty()) && !checksumDecrypted.equals(checksum)) {
|
|
381
381
|
logger.error("Error checksum '" + checksumDecrypted + "' '" + checksum + "' '");
|
package/android/src/main/java/ee/forgr/capacitor_updater/{CryptoCipherV2.java → CryptoCipher.java}
RENAMED
|
@@ -35,7 +35,7 @@ import javax.crypto.SecretKey;
|
|
|
35
35
|
import javax.crypto.spec.IvParameterSpec;
|
|
36
36
|
import javax.crypto.spec.SecretKeySpec;
|
|
37
37
|
|
|
38
|
-
public class
|
|
38
|
+
public class CryptoCipher {
|
|
39
39
|
|
|
40
40
|
private static Logger logger;
|
|
41
41
|
|
|
@@ -153,10 +153,10 @@ public class CryptoCipherV2 {
|
|
|
153
153
|
String sessionKeyB64 = ivSessionKey.split(":")[1];
|
|
154
154
|
byte[] iv = Base64.decode(ivB64.getBytes(), Base64.DEFAULT);
|
|
155
155
|
byte[] sessionKey = Base64.decode(sessionKeyB64.getBytes(), Base64.DEFAULT);
|
|
156
|
-
PublicKey pKey =
|
|
157
|
-
byte[] decryptedSessionKey =
|
|
156
|
+
PublicKey pKey = CryptoCipher.stringToPublicKey(publicKey);
|
|
157
|
+
byte[] decryptedSessionKey = CryptoCipher.decryptRSA(sessionKey, pKey);
|
|
158
158
|
|
|
159
|
-
SecretKey sKey =
|
|
159
|
+
SecretKey sKey = CryptoCipher.byteToSessionKey(decryptedSessionKey);
|
|
160
160
|
byte[] content = new byte[(int) file.length()];
|
|
161
161
|
|
|
162
162
|
try (
|
|
@@ -166,7 +166,7 @@ public class CryptoCipherV2 {
|
|
|
166
166
|
) {
|
|
167
167
|
dis.readFully(content);
|
|
168
168
|
dis.close();
|
|
169
|
-
byte[] decrypted =
|
|
169
|
+
byte[] decrypted = CryptoCipher.decryptAES(content, sKey, iv);
|
|
170
170
|
// write the decrypted string to the file
|
|
171
171
|
try (final FileOutputStream fos = new FileOutputStream(file.getAbsolutePath())) {
|
|
172
172
|
fos.write(decrypted);
|
|
@@ -186,8 +186,8 @@ public class CryptoCipherV2 {
|
|
|
186
186
|
}
|
|
187
187
|
try {
|
|
188
188
|
byte[] checksumBytes = Base64.decode(checksum, Base64.DEFAULT);
|
|
189
|
-
PublicKey pKey =
|
|
190
|
-
byte[] decryptedChecksum =
|
|
189
|
+
PublicKey pKey = CryptoCipher.stringToPublicKey(publicKey);
|
|
190
|
+
byte[] decryptedChecksum = CryptoCipher.decryptRSA(checksumBytes, pKey);
|
|
191
191
|
// return Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
|
|
192
192
|
String result = Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
|
|
193
193
|
return result.replaceAll("\\s", ""); // Remove all whitespace, including newlines
|
|
@@ -210,7 +210,7 @@ public class DownloadService extends Worker {
|
|
|
210
210
|
|
|
211
211
|
if (!publicKey.isEmpty() && sessionKey != null && !sessionKey.isEmpty()) {
|
|
212
212
|
try {
|
|
213
|
-
fileHash =
|
|
213
|
+
fileHash = CryptoCipher.decryptChecksum(fileHash, publicKey);
|
|
214
214
|
} catch (Exception e) {
|
|
215
215
|
logger.error("Error decrypting checksum for " + fileName + "fileHash: " + fileHash);
|
|
216
216
|
hasError.set(true);
|
|
@@ -512,7 +512,7 @@ public class DownloadService extends Worker {
|
|
|
512
512
|
|
|
513
513
|
if (!publicKey.isEmpty() && sessionKey != null && !sessionKey.isEmpty()) {
|
|
514
514
|
logger.debug("Decrypting file " + targetFile.getName());
|
|
515
|
-
|
|
515
|
+
CryptoCipher.decryptFile(compressedFile, publicKey, sessionKey);
|
|
516
516
|
}
|
|
517
517
|
|
|
518
518
|
// Only decompress if file has .br extension
|
|
@@ -537,7 +537,7 @@ public class DownloadService extends Worker {
|
|
|
537
537
|
|
|
538
538
|
// Delete the compressed file
|
|
539
539
|
compressedFile.delete();
|
|
540
|
-
String calculatedHash =
|
|
540
|
+
String calculatedHash = CryptoCipher.calcChecksum(finalTargetFile);
|
|
541
541
|
|
|
542
542
|
// Verify checksum
|
|
543
543
|
if (calculatedHash.equals(expectedHash)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/capacitor-updater",
|
|
3
|
-
"version": "7.13.
|
|
3
|
+
"version": "7.13.11",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "Live update for capacitor apps",
|
|
6
6
|
"main": "dist/plugin.cjs.js",
|
|
@@ -41,12 +41,11 @@
|
|
|
41
41
|
],
|
|
42
42
|
"scripts": {
|
|
43
43
|
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
44
|
-
"verify:ios": "
|
|
45
|
-
"verify:iosSPM": "xcodebuild -workspace ios/Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS",
|
|
44
|
+
"verify:ios": "xcodebuild -scheme CapgoCapacitorUpdater -destination generic/platform=iOS",
|
|
46
45
|
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
47
46
|
"verify:web": "npm run build",
|
|
48
47
|
"test": "npm run test:ios && npm run test:android",
|
|
49
|
-
"test:ios": "
|
|
48
|
+
"test:ios": "./scripts/test-ios.sh",
|
|
50
49
|
"test:android": "cd android && ./gradlew test && cd ..",
|
|
51
50
|
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
52
51
|
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --autocorrect --format",
|
package/ios/Plugin/AES.swift
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import BigInt
|
|
2
|
-
import Foundation
|
|
3
|
-
import CommonCrypto
|
|
4
|
-
import CryptoKit
|
|
5
|
-
|
|
6
|
-
///
|
|
7
|
-
/// Constants
|
|
8
|
-
///
|
|
9
|
-
private enum AESConstants {
|
|
10
|
-
static let aesAlgorithm: CCAlgorithm = CCAlgorithm(kCCAlgorithmAES)
|
|
11
|
-
static let aesOptions: CCOptions = CCOptions(kCCOptionPKCS7Padding)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// We do all this stuff because ios is shit and open source libraries allow to do decryption with public key
|
|
15
|
-
// So we have to do it manually, while in nodejs or Java it's ok and done at language level.
|
|
16
|
-
|
|
17
|
-
///
|
|
18
|
-
/// The AES key. Contains both the initialization vector and secret key.
|
|
19
|
-
///
|
|
20
|
-
public struct AES128Key {
|
|
21
|
-
/// Initialization vector
|
|
22
|
-
private let iv: Data
|
|
23
|
-
private let logger: Logger
|
|
24
|
-
private let aes128Key: Data
|
|
25
|
-
#if DEBUG
|
|
26
|
-
public var __debug_iv: Data { iv }
|
|
27
|
-
public var __debug_aes128Key: Data { aes128Key }
|
|
28
|
-
#endif
|
|
29
|
-
init(iv: Data, aes128Key: Data, logger: Logger) {
|
|
30
|
-
self.iv = iv
|
|
31
|
-
self.aes128Key = aes128Key
|
|
32
|
-
self.logger = logger
|
|
33
|
-
}
|
|
34
|
-
///
|
|
35
|
-
/// Takes the data and uses the private key to decrypt it. Will call `CCCrypt` in CommonCrypto
|
|
36
|
-
/// and provide it `ivData` for the initialization vector. Will use cipher block chaining (CBC) as
|
|
37
|
-
/// the mode of operation.
|
|
38
|
-
///
|
|
39
|
-
/// Returns the decrypted data.
|
|
40
|
-
///
|
|
41
|
-
public func decrypt(data: Data) -> Data? {
|
|
42
|
-
let encryptedData: UnsafePointer<UInt8> = (data as NSData).bytes.bindMemory(to: UInt8.self, capacity: data.count)
|
|
43
|
-
let encryptedDataLength: Int = data.count
|
|
44
|
-
|
|
45
|
-
if let result: NSMutableData = NSMutableData(length: encryptedDataLength) {
|
|
46
|
-
let keyData: UnsafePointer<UInt8> = (self.aes128Key as NSData).bytes.bindMemory(to: UInt8.self, capacity: self.aes128Key.count)
|
|
47
|
-
let keyLength: size_t = size_t(self.aes128Key.count)
|
|
48
|
-
let ivData: UnsafePointer<UInt8> = (iv as NSData).bytes.bindMemory(to: UInt8.self, capacity: self.iv.count)
|
|
49
|
-
|
|
50
|
-
let decryptedData: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>(result.mutableBytes.assumingMemoryBound(to: UInt8.self))
|
|
51
|
-
let decryptedDataLength: size_t = size_t(result.length)
|
|
52
|
-
|
|
53
|
-
var decryptedLength: size_t = 0
|
|
54
|
-
|
|
55
|
-
let status: CCCryptorStatus = CCCrypt(CCOperation(kCCDecrypt), AESConstants.aesAlgorithm, AESConstants.aesOptions, keyData, keyLength, ivData, encryptedData, encryptedDataLength, decryptedData, decryptedDataLength, &decryptedLength)
|
|
56
|
-
|
|
57
|
-
if Int32(status) == Int32(kCCSuccess) {
|
|
58
|
-
result.length = Int(decryptedLength)
|
|
59
|
-
return result as Data
|
|
60
|
-
} else {
|
|
61
|
-
logger.error("AES decryption failed with status: \(status)")
|
|
62
|
-
return nil
|
|
63
|
-
}
|
|
64
|
-
} else {
|
|
65
|
-
logger.error("Failed to allocate memory for AES decryption")
|
|
66
|
-
return nil
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
package/ios/Plugin/BigInt.swift
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import BigInt
|
|
2
|
-
|
|
3
|
-
// Extension to serialize BigInt to bytes array
|
|
4
|
-
extension BigInt {
|
|
5
|
-
func serializeToBytes() -> [UInt8] {
|
|
6
|
-
let byteCount = (self.bitWidth + 7) / 8
|
|
7
|
-
var bytes = [UInt8](repeating: 0, count: byteCount)
|
|
8
|
-
|
|
9
|
-
var value = self
|
|
10
|
-
for i in 0..<byteCount {
|
|
11
|
-
bytes[byteCount - i - 1] = UInt8(truncatingIfNeeded: value & 0xFF)
|
|
12
|
-
value >>= 8
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return bytes
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Add this custom power function to ensure safer handling of power operations
|
|
20
|
-
|
|
21
|
-
// Manual exponentiation using the square-and-multiply algorithm
|
|
22
|
-
// which is more efficient and avoids using the built-in functions that might handle BigInt differently
|
|
23
|
-
extension BigInt {
|
|
24
|
-
func manualPower(_ exponent: BigInt, modulus: BigInt) -> BigInt {
|
|
25
|
-
// Quick checks
|
|
26
|
-
if modulus == 0 {
|
|
27
|
-
return 0
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if exponent == 0 {
|
|
31
|
-
return 1
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
guard let base = self.magnitude as? BigUInt,
|
|
35
|
-
let exp = exponent.magnitude as? BigUInt,
|
|
36
|
-
let mod = modulus.magnitude as? BigUInt else {
|
|
37
|
-
return 0
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Square and multiply algorithm for modular exponentiation
|
|
41
|
-
var result = BigUInt(1)
|
|
42
|
-
var x = base % mod
|
|
43
|
-
var e = exp
|
|
44
|
-
|
|
45
|
-
while e > 0 {
|
|
46
|
-
if e & 1 == 1 {
|
|
47
|
-
result = (result * x) % mod
|
|
48
|
-
}
|
|
49
|
-
x = (x * x) % mod
|
|
50
|
-
e >>= 1
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return BigInt(result)
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
-
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
-
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import Foundation
|
|
8
|
-
|
|
9
|
-
@objc public class BundleInfo: NSObject, Decodable, Encodable {
|
|
10
|
-
public static let ID_BUILTIN: String = "builtin"
|
|
11
|
-
public static let VERSION_UNKNOWN: String = "unknown"
|
|
12
|
-
public static let DOWNLOADED_BUILTIN: String = "1970-01-01T00:00:00.000Z"
|
|
13
|
-
|
|
14
|
-
private let downloaded: String
|
|
15
|
-
private let id: String
|
|
16
|
-
private let version: String
|
|
17
|
-
private let checksum: String
|
|
18
|
-
private let status: BundleStatus
|
|
19
|
-
|
|
20
|
-
convenience init(id: String, version: String, status: BundleStatus, downloaded: Date, checksum: String) {
|
|
21
|
-
self.init(id: id, version: version, status: status, downloaded: downloaded.iso8601withFractionalSeconds, checksum: checksum)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
init(id: String, version: String, status: BundleStatus, downloaded: String = BundleInfo.DOWNLOADED_BUILTIN, checksum: String) {
|
|
25
|
-
self.downloaded = downloaded.trim()
|
|
26
|
-
self.id = id
|
|
27
|
-
self.version = version
|
|
28
|
-
self.checksum = checksum
|
|
29
|
-
self.status = status
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
enum CodingKeys: String, CodingKey {
|
|
33
|
-
case downloaded, id, version, status, checksum
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public func isBuiltin() -> Bool {
|
|
37
|
-
return BundleInfo.ID_BUILTIN == self.id
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
public func isUnknown() -> Bool {
|
|
41
|
-
return BundleInfo.VERSION_UNKNOWN == self.id
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
public func isErrorStatus() -> Bool {
|
|
45
|
-
return BundleStatus.ERROR == self.status
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
public func isDeleted() -> Bool {
|
|
49
|
-
return BundleStatus.DELETED == self.status
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
public func isDownloaded() -> Bool {
|
|
53
|
-
return !self.isBuiltin() && self.downloaded != "" && self.downloaded != BundleInfo.DOWNLOADED_BUILTIN && !self.isDeleted()
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public func getDownloaded() -> String {
|
|
57
|
-
return self.isBuiltin() ? BundleInfo.DOWNLOADED_BUILTIN : self.downloaded
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
public func getChecksum() -> String {
|
|
61
|
-
return self.isBuiltin() ? "" : self.checksum
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
public func setChecksum(checksum: String) -> BundleInfo {
|
|
65
|
-
return BundleInfo(id: self.id, version: self.version, status: self.status, downloaded: self.downloaded, checksum: checksum)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
public func setDownloaded(downloaded: Date) -> BundleInfo {
|
|
69
|
-
return BundleInfo(id: self.id, version: self.version, status: self.status, downloaded: downloaded, checksum: self.checksum)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
public func getId() -> String {
|
|
73
|
-
return self.isBuiltin() ? BundleInfo.ID_BUILTIN : self.id
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
public func setId(id: String) -> BundleInfo {
|
|
77
|
-
return BundleInfo(id: id, version: self.version, status: self.status, downloaded: self.downloaded, checksum: self.checksum)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
public func getVersionName() -> String {
|
|
81
|
-
return self.version.isEmpty ? BundleInfo.ID_BUILTIN : self.version
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
public func setVersionName(version: String) -> BundleInfo {
|
|
85
|
-
return BundleInfo(id: self.id, version: version, status: self.status, downloaded: self.downloaded, checksum: self.checksum)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public func getStatus() -> String {
|
|
89
|
-
return self.isBuiltin() ? BundleStatus.SUCCESS.localizedString : self.status.localizedString
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
public func setStatus(status: String) -> BundleInfo {
|
|
93
|
-
return BundleInfo(id: self.id, version: self.version, status: BundleStatus(localizedString: status)!, downloaded: self.downloaded, checksum: self.checksum)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
public func toJSON() -> [String: String] {
|
|
97
|
-
return [
|
|
98
|
-
"id": self.getId(),
|
|
99
|
-
"version": self.getVersionName(),
|
|
100
|
-
"downloaded": self.getDownloaded(),
|
|
101
|
-
"checksum": self.getChecksum(),
|
|
102
|
-
"status": self.getStatus()
|
|
103
|
-
]
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
public static func == (lhs: BundleInfo, rhs: BundleInfo) -> Bool {
|
|
107
|
-
return lhs.getVersionName() == rhs.getVersionName()
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
public func toString() -> String {
|
|
111
|
-
return "{ \"id\": \"\(self.getId())\", \"version\": \"\(self.getVersionName())\", \"downloaded\": \"\(self.getDownloaded())\", \"checksum\": \"\(self.getChecksum())\", \"status\": \"\(self.getStatus())\"}"
|
|
112
|
-
}
|
|
113
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
-
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
-
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import Foundation
|
|
8
|
-
|
|
9
|
-
struct LocalizedString: ExpressibleByStringLiteral, Equatable {
|
|
10
|
-
|
|
11
|
-
let v: String
|
|
12
|
-
|
|
13
|
-
init(key: String) {
|
|
14
|
-
self.v = NSLocalizedString(key, comment: "")
|
|
15
|
-
}
|
|
16
|
-
init(localized: String) {
|
|
17
|
-
self.v = localized
|
|
18
|
-
}
|
|
19
|
-
init(stringLiteral value: String) {
|
|
20
|
-
self.init(key: value)
|
|
21
|
-
}
|
|
22
|
-
init(extendedGraphemeClusterLiteral value: String) {
|
|
23
|
-
self.init(key: value)
|
|
24
|
-
}
|
|
25
|
-
init(unicodeScalarLiteral value: String) {
|
|
26
|
-
self.init(key: value)
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
func ==(lhs: LocalizedString, rhs: LocalizedString) -> Bool {
|
|
31
|
-
return lhs.v == rhs.v
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
enum BundleStatus: LocalizedString, Decodable, Encodable {
|
|
35
|
-
case SUCCESS = "success"
|
|
36
|
-
case ERROR = "error"
|
|
37
|
-
case PENDING = "pending"
|
|
38
|
-
case DELETED = "deleted"
|
|
39
|
-
case DOWNLOADING = "downloading"
|
|
40
|
-
|
|
41
|
-
var localizedString: String {
|
|
42
|
-
return self.rawValue.v
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
init?(localizedString: String) {
|
|
46
|
-
self.init(rawValue: LocalizedString(localized: localizedString))
|
|
47
|
-
}
|
|
48
|
-
}
|