@capgo/capacitor-updater 6.1.17 → 6.1.19
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/README.md +1 -5
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdater.java +130 -82
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +11 -30
- package/android/src/main/java/ee/forgr/capacitor_updater/CryptoCipherV2.java +4 -9
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +2 -15
- package/dist/docs.json +0 -32
- package/dist/esm/definitions.d.ts +0 -15
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Plugin/CapacitorUpdater.swift +222 -173
- package/ios/Plugin/CapacitorUpdaterPlugin.swift +23 -32
- package/ios/Plugin/CryptoCipher.swift +1 -36
- package/ios/Plugin/CryptoCipherV2.swift +4 -62
- package/package.json +1 -1
|
@@ -16,14 +16,13 @@ import SwiftyRSA
|
|
|
16
16
|
@objc(CapacitorUpdaterPlugin)
|
|
17
17
|
public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
18
18
|
public var implementation = CapacitorUpdater()
|
|
19
|
-
private let PLUGIN_VERSION: String = "6.1.
|
|
19
|
+
private let PLUGIN_VERSION: String = "6.1.19"
|
|
20
20
|
static let updateUrlDefault = "https://api.capgo.app/updates"
|
|
21
21
|
static let statsUrlDefault = "https://api.capgo.app/stats"
|
|
22
22
|
static let channelUrlDefault = "https://api.capgo.app/channel_self"
|
|
23
23
|
let DELAY_CONDITION_PREFERENCES = ""
|
|
24
24
|
private var updateUrl = ""
|
|
25
25
|
private var statsUrl = ""
|
|
26
|
-
private var defaultPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEA4pW9olT0FBXXivRCzd3xcImlWZrqkwcF2xTkX/FwXmj9eh9H\nkBLrsQmfsC+PJisRXIOGq6a0z3bsGq6jBpp3/Jr9jiaW5VuPGaKeMaZZBRvi/N5f\nIMG3hZXSOcy0IYg+E1Q7RkYO1xq5GLHseqG+PXvJsNe4R8R/Bmd/ngq0xh/cvcrH\nHpXwO0Aj9tfprlb+rHaVV79EkVRWYPidOLnK1n0EFHFJ1d/MyDIp10TEGm2xHpf/\nBrlb1an8wXEuzoC0DgYaczgTjovwR+ewSGhSHJliQdM0Qa3o1iN87DldWtydImMs\nPjJ3DUwpsjAMRe5X8Et4+udFW2ciYnQo9H0CkwIDAQABAoIBAQCtjlMV/4qBxAU4\nu0ZcWA9yywwraX0aJ3v1xrfzQYV322Wk4Ea5dbSxA5UcqCE29DA1M824t1Wxv/6z\npWbcTP9xLuresnJMtmgTE7umfiubvTONy2sENT20hgDkIwcq1CfwOEm61zjQzPhQ\nkSB5AmEsyR/BZEsUNc+ygR6AWOUFB7tj4yMc32LOTWSbE/znnF2BkmlmnQykomG1\n2oVqM3lUFP7+m8ux1O7scO6IMts+Z/eFXjWfxpbebUSvSIR83GXPQZ34S/c0ehOg\nyHdmCSOel1r3VvInMe+30j54Jr+Ml/7Ee6axiwyE2e/bd85MsK9sVdp0OtelXaqA\nOZZqWvN5AoGBAP2Hn3lSq+a8GsDH726mHJw60xM0LPbVJTYbXsmQkg1tl3NKJTMM\nQqz41+5uys+phEgLHI9gVJ0r+HaGHXnJ4zewlFjsudstb/0nfctUvTqnhEhfNo9I\ny4kufVKPRF3sMEeo7CDVJs4GNBLycEyIBy6Mbv0VcO7VaZqggRwu4no9AoGBAOTK\n6NWYs1BWlkua2wmxexGOzehNGedInp0wGr2l4FDayWjkZLqvB+nNXUQ63NdHlSs4\nWB2Z1kQXZxVaI2tPYexGUKXEo2uFob63uflbuE029ovDXIIPFTPtGNdNXwhHT5a+\nPhmy3sMc+s2BSNM5qaNmfxQxhdd6gRU6oikE+c0PAoGAMn3cKNFqIt27hkFLUgIL\nGKIuf1iYy9/PNWNmEUaVj88PpopRtkTu0nwMpROzmH/uNFriKTvKHjMvnItBO4wV\nkHW+VadvrFL0Rrqituf9d7z8/1zXBNo+juePVe3qc7oiM2NVA4Tv4YAixtM5wkQl\nCgQ15nlqsGYYTg9BJ1e/CxECgYEAjEYPzO2reuUrjr0p8F59ev1YJ0YmTJRMk0ks\nC/yIdGo/tGzbiU3JB0LfHPcN8Xu07GPGOpfYM7U5gXDbaG6qNgfCaHAQVdr/mQPi\nJQ1kCQtay8QCkscWk9iZM1//lP7LwDtxraXqSCwbZSYP9VlUNZeg8EuQqNU2EUL6\nqzWexmcCgYEA0prUGNBacraTYEknB1CsbP36UPWsqFWOvevlz+uEC5JPxPuW5ZHh\nSQN7xl6+PHyjPBM7ttwPKyhgLOVTb3K7ex/PXnudojMUK5fh7vYfChVTSlx2p6r0\nDi58PdD+node08cJH+ie0Yphp7m+D4+R9XD0v0nEvnu4BtAW6DrJasw=\n-----END RSA PRIVATE KEY-----\n"
|
|
27
26
|
private var backgroundTaskID: UIBackgroundTaskIdentifier = UIBackgroundTaskIdentifier.invalid
|
|
28
27
|
private var currentVersionNative: Version = "0.0.0"
|
|
29
28
|
private var autoUpdate = false
|
|
@@ -43,7 +42,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
43
42
|
print("\(self.implementation.TAG) ::::: SIMULATOR :::::")
|
|
44
43
|
print("\(self.implementation.TAG) Application directory: \(NSHomeDirectory())")
|
|
45
44
|
#endif
|
|
46
|
-
|
|
45
|
+
|
|
47
46
|
self.semaphoreUp()
|
|
48
47
|
self.implementation.deviceID = UserDefaults.standard.string(forKey: "appUUID") ?? UUID().uuidString
|
|
49
48
|
UserDefaults.standard.set( self.implementation.deviceID, forKey: "appUUID")
|
|
@@ -76,7 +75,11 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
76
75
|
periodCheckDelay = periodCheckDelayValue
|
|
77
76
|
}
|
|
78
77
|
|
|
79
|
-
implementation.privateKey = getConfig().getString("privateKey",
|
|
78
|
+
implementation.privateKey = getConfig().getString("privateKey", "")!
|
|
79
|
+
implementation.publicKey = getConfig().getString("publicKey", "")!
|
|
80
|
+
if !implementation.privateKey.isEmpty {
|
|
81
|
+
implementation.hasOldPrivateKeyPropertyInConfig = true
|
|
82
|
+
}
|
|
80
83
|
implementation.notifyDownloadRaw = notifyDownload
|
|
81
84
|
implementation.PLUGIN_VERSION = self.PLUGIN_VERSION
|
|
82
85
|
let config = (self.bridge?.viewController as? CAPBridgeViewController)?.instanceDescriptor().legacyConfig
|
|
@@ -90,15 +93,6 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
90
93
|
implementation.statsUrl = getConfig().getString("statsUrl", CapacitorUpdaterPlugin.statsUrlDefault)!
|
|
91
94
|
implementation.channelUrl = getConfig().getString("channelUrl", CapacitorUpdaterPlugin.channelUrlDefault)!
|
|
92
95
|
implementation.defaultChannel = getConfig().getString("defaultChannel", "")!
|
|
93
|
-
do {
|
|
94
|
-
let signKeyString = getConfig().getString("signKey", "")!
|
|
95
|
-
if (!signKeyString.isEmpty) {
|
|
96
|
-
implementation.signKey = try PublicKey(base64Encoded: signKeyString)
|
|
97
|
-
}
|
|
98
|
-
} catch {
|
|
99
|
-
print("\(self.implementation.TAG) Cannot get signKey, invalid key")
|
|
100
|
-
fatalError("Invalid signKey in capacitor config")
|
|
101
|
-
}
|
|
102
96
|
self.implementation.autoReset()
|
|
103
97
|
|
|
104
98
|
// Load the server
|
|
@@ -255,21 +249,18 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
255
249
|
call.reject("Download called without version")
|
|
256
250
|
return
|
|
257
251
|
}
|
|
258
|
-
|
|
259
|
-
if (self.implementation.signKey != nil && signature.isEmpty) {
|
|
260
|
-
print("\(self.implementation.TAG) Signature required but none provided for download call")
|
|
261
|
-
call.reject("Signature required but none provided")
|
|
262
|
-
return
|
|
263
|
-
}
|
|
264
|
-
|
|
252
|
+
|
|
265
253
|
let sessionKey = call.getString("sessionKey", "")
|
|
266
|
-
|
|
254
|
+
var checksum = call.getString("checksum", "")
|
|
267
255
|
let url = URL(string: urlString)
|
|
268
256
|
print("\(self.implementation.TAG) Downloading \(String(describing: url))")
|
|
269
257
|
DispatchQueue.global(qos: .background).async {
|
|
270
258
|
do {
|
|
271
|
-
let next = try self.implementation.download(url: url!, version: version, sessionKey: sessionKey
|
|
272
|
-
if
|
|
259
|
+
let next = try self.implementation.download(url: url!, version: version, sessionKey: sessionKey)
|
|
260
|
+
if !self.implementation.hasOldPrivateKeyPropertyInConfig {
|
|
261
|
+
checksum = try self.implementation.decryptChecksum(checksum: checksum, version: version)
|
|
262
|
+
}
|
|
263
|
+
if (checksum != "" || self.implementation.publicKey != "") && next.getChecksum() != checksum {
|
|
273
264
|
print("\(self.implementation.TAG) Error checksum", next.getChecksum(), checksum)
|
|
274
265
|
self.implementation.sendStats(action: "checksum_fail", versionName: next.getVersionName())
|
|
275
266
|
let id = next.getId()
|
|
@@ -278,6 +269,8 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
278
269
|
print("\(self.implementation.TAG) Delete failed, id \(id) doesn't exist")
|
|
279
270
|
}
|
|
280
271
|
throw ObjectSavableError.checksum
|
|
272
|
+
} else {
|
|
273
|
+
print("\(self.implementation.TAG) Good checksum", next.getChecksum(), checksum)
|
|
281
274
|
}
|
|
282
275
|
self.notifyListeners("updateAvailable", data: ["bundle": next.toJSON()])
|
|
283
276
|
call.resolve(next.toJSON())
|
|
@@ -547,15 +540,13 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
547
540
|
if !killed {
|
|
548
541
|
self._cancelDelay(source: "background check")
|
|
549
542
|
}
|
|
550
|
-
|
|
551
|
-
case "kill":
|
|
543
|
+
case "kill":
|
|
552
544
|
if killed {
|
|
553
545
|
self._cancelDelay(source: "kill check")
|
|
554
546
|
// instant install for kill action
|
|
555
547
|
self.installNext()
|
|
556
548
|
}
|
|
557
|
-
|
|
558
|
-
case "date":
|
|
549
|
+
case "date":
|
|
559
550
|
if value != nil && value != "" {
|
|
560
551
|
let dateFormatter = ISO8601DateFormatter()
|
|
561
552
|
dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
|
@@ -569,8 +560,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
569
560
|
} else {
|
|
570
561
|
self._cancelDelay(source: "delayVal absent")
|
|
571
562
|
}
|
|
572
|
-
|
|
573
|
-
case "nativeVersion":
|
|
563
|
+
case "nativeVersion":
|
|
574
564
|
if value != nil && value != "" {
|
|
575
565
|
do {
|
|
576
566
|
let versionLimit = try Version(value!)
|
|
@@ -583,7 +573,6 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
583
573
|
} else {
|
|
584
574
|
self._cancelDelay(source: "delayVal absent")
|
|
585
575
|
}
|
|
586
|
-
break
|
|
587
576
|
case .none:
|
|
588
577
|
print("\(self.implementation.TAG) _checkCancelDelay switch case none error")
|
|
589
578
|
case .some:
|
|
@@ -703,7 +692,6 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
703
692
|
return
|
|
704
693
|
}
|
|
705
694
|
let sessionKey = res.sessionKey ?? ""
|
|
706
|
-
let signature = res.signature ?? ""
|
|
707
695
|
guard let downloadUrl = URL(string: res.url) else {
|
|
708
696
|
print("\(self.implementation.TAG) Error no url or wrong format")
|
|
709
697
|
self.endBackGroundTaskWithNotif(msg: "Error no url or wrong format", latestVersionName: res.version, current: current)
|
|
@@ -724,7 +712,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
724
712
|
print("\(self.implementation.TAG) Failed to delete failed bundle: \(nextImpl!.toString())")
|
|
725
713
|
}
|
|
726
714
|
}
|
|
727
|
-
nextImpl = try self.implementation.download(url: downloadUrl, version: latestVersionName, sessionKey: sessionKey
|
|
715
|
+
nextImpl = try self.implementation.download(url: downloadUrl, version: latestVersionName, sessionKey: sessionKey)
|
|
728
716
|
}
|
|
729
717
|
guard let next = nextImpl else {
|
|
730
718
|
print("\(self.implementation.TAG) Error downloading file")
|
|
@@ -736,6 +724,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
736
724
|
self.endBackGroundTaskWithNotif(msg: "Latest version is in error state. Aborting update.", latestVersionName: latestVersionName, current: current)
|
|
737
725
|
return
|
|
738
726
|
}
|
|
727
|
+
if !self.implementation.hasOldPrivateKeyPropertyInConfig {
|
|
728
|
+
res.checksum = try self.implementation.decryptChecksum(checksum: res.checksum, version: latestVersionName)
|
|
729
|
+
}
|
|
739
730
|
if res.checksum != "" && next.getChecksum() != res.checksum {
|
|
740
731
|
print("\(self.implementation.TAG) Error checksum", next.getChecksum(), res.checksum)
|
|
741
732
|
self.implementation.sendStats(action: "checksum_fail", versionName: next.getVersionName())
|
|
@@ -83,10 +83,6 @@ public struct RSAKeyPair {
|
|
|
83
83
|
self.publicKey = publicKey
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
public func extractPublicKey() -> RSAPublicKey {
|
|
87
|
-
RSAPublicKey(publicKey: publicKey)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
86
|
///
|
|
91
87
|
/// Takes the data and uses the private key to decrypt it.
|
|
92
88
|
/// Returns the decrypted data.
|
|
@@ -103,21 +99,7 @@ public struct RSAKeyPair {
|
|
|
103
99
|
return nil
|
|
104
100
|
}
|
|
105
101
|
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
///
|
|
109
|
-
/// The RSA public key.
|
|
110
|
-
///
|
|
111
|
-
public struct RSAPublicKey {
|
|
112
|
-
private let publicKey: SecKey
|
|
113
102
|
|
|
114
|
-
#if DEBUG
|
|
115
|
-
public var __debug_publicKey: SecKey { self.publicKey }
|
|
116
|
-
#endif
|
|
117
|
-
|
|
118
|
-
fileprivate init(publicKey: SecKey) {
|
|
119
|
-
self.publicKey = publicKey
|
|
120
|
-
}
|
|
121
103
|
///
|
|
122
104
|
/// Takes the data and uses the public key to encrypt it.
|
|
123
105
|
/// Returns the encrypted data.
|
|
@@ -134,24 +116,7 @@ public struct RSAPublicKey {
|
|
|
134
116
|
return nil
|
|
135
117
|
}
|
|
136
118
|
}
|
|
137
|
-
///
|
|
138
|
-
/// Allows you to export the RSA public key to a format (so you can send over the net).
|
|
139
|
-
///
|
|
140
|
-
public func export() -> Data? {
|
|
141
|
-
return publicKey.exportToData()
|
|
142
|
-
}
|
|
143
|
-
//
|
|
144
119
|
|
|
145
|
-
///
|
|
146
|
-
/// Allows you to load an RSA public key (i.e. one downloaded from the net).
|
|
147
|
-
///
|
|
148
|
-
public static func load(rsaPublicKeyData: Data) -> RSAPublicKey? {
|
|
149
|
-
if let publicKey: SecKey = .loadPublicFromData(rsaPublicKeyData) {
|
|
150
|
-
return RSAPublicKey(publicKey: publicKey)
|
|
151
|
-
} else {
|
|
152
|
-
return nil
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
120
|
}
|
|
156
121
|
///
|
|
157
122
|
/// The RSA public key.
|
|
@@ -233,7 +198,7 @@ fileprivate extension SecKey {
|
|
|
233
198
|
kSecAttrKeyClass: kSecAttrKeyClassPublic,
|
|
234
199
|
kSecAttrKeySizeInBits: CryptoCipherConstants.rsaKeySizeInBits
|
|
235
200
|
]
|
|
236
|
-
return SecKeyCreateWithData(data as
|
|
201
|
+
return SecKeyCreateWithData(data as NSData, keyDict as CFDictionary, nil)
|
|
237
202
|
}
|
|
238
203
|
static func loadPrivateFromData(_ data: Data) -> SecKey? {
|
|
239
204
|
let keyDict: [NSObject: NSObject] = [
|
|
@@ -10,62 +10,12 @@ import CommonCrypto
|
|
|
10
10
|
///
|
|
11
11
|
/// Constants
|
|
12
12
|
///
|
|
13
|
-
private enum
|
|
13
|
+
private enum CryptoCipherConstants {
|
|
14
14
|
static let rsaKeySizeInBits: NSNumber = 2048
|
|
15
15
|
static let aesAlgorithm: CCAlgorithm = CCAlgorithm(kCCAlgorithmAES)
|
|
16
16
|
static let aesOptions: CCOptions = CCOptions(kCCOptionPKCS7Padding)
|
|
17
|
-
static let rsaAlgorithm: SecKeyAlgorithm = .
|
|
17
|
+
static let rsaAlgorithm: SecKeyAlgorithm = .rsaEncryptionOAEPSHA256
|
|
18
18
|
}
|
|
19
|
-
///
|
|
20
|
-
/// The AES key. Contains both the initialization vector and secret key.
|
|
21
|
-
///
|
|
22
|
-
public struct AES128KeyV2 {
|
|
23
|
-
/// Initialization vector
|
|
24
|
-
private let iv: Data
|
|
25
|
-
private let aes128Key: Data
|
|
26
|
-
#if DEBUG
|
|
27
|
-
public var __debug_iv: Data { iv }
|
|
28
|
-
public var __debug_aes128Key: Data { aes128Key }
|
|
29
|
-
#endif
|
|
30
|
-
init(iv: Data, aes128Key: Data) {
|
|
31
|
-
self.iv = iv
|
|
32
|
-
self.aes128Key = aes128Key
|
|
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), CryptoCipherConstants.aesAlgorithm, CryptoCipherConstants.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
|
-
return nil
|
|
62
|
-
}
|
|
63
|
-
} else {
|
|
64
|
-
return nil
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
19
|
///
|
|
70
20
|
/// The RSA keypair. Includes both private and public key.
|
|
71
21
|
///
|
|
@@ -108,7 +58,7 @@ public struct RSAKeyPairV2 {
|
|
|
108
58
|
///
|
|
109
59
|
/// The RSA public key.
|
|
110
60
|
///
|
|
111
|
-
public struct
|
|
61
|
+
public struct RSAPublicKey {
|
|
112
62
|
private let publicKey: SecKey
|
|
113
63
|
|
|
114
64
|
#if DEBUG
|
|
@@ -136,14 +86,6 @@ public struct RSAPublicKeyV2 {
|
|
|
136
86
|
}
|
|
137
87
|
}
|
|
138
88
|
|
|
139
|
-
///
|
|
140
|
-
/// Allows you to export the RSA public key to a format (so you can send over the net).
|
|
141
|
-
///
|
|
142
|
-
public func export() -> Data? {
|
|
143
|
-
return publicKey.exportToData()
|
|
144
|
-
}
|
|
145
|
-
//
|
|
146
|
-
|
|
147
89
|
///
|
|
148
90
|
/// Allows you to load an RSA public key (i.e. one downloaded from the net).
|
|
149
91
|
///
|
|
@@ -231,7 +173,7 @@ public struct RSAPublicKeyV2 {
|
|
|
231
173
|
}
|
|
232
174
|
}
|
|
233
175
|
|
|
234
|
-
fileprivate extension
|
|
176
|
+
fileprivate extension SecKey {
|
|
235
177
|
func exportToData() -> Data? {
|
|
236
178
|
var error: Unmanaged<CFError>?
|
|
237
179
|
if let cfData: CFData = SecKeyCopyExternalRepresentation(self, &error) {
|