@pagopa/io-react-native-iso18013 0.3.0 → 0.4.0
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/android/src/main/java/com/ioreactnativeiso18013/IoReactNativeCborModule.kt +67 -164
- package/android/src/main/java/com/ioreactnativeiso18013/IoReactNativeIso18013Module.kt +95 -140
- package/ios/Base64Utils.swift +10 -3
- package/ios/IoReactNativeCbor.swift +55 -125
- package/ios/IoReactNativeIso18013.swift +87 -116
- package/lib/module/cbor/cbor/README.md +37 -5
- package/lib/module/cbor/cbor/error.js +15 -0
- package/lib/module/cbor/cbor/error.js.map +1 -0
- package/lib/module/cbor/cbor/index.js +1 -0
- package/lib/module/cbor/cbor/index.js.map +1 -1
- package/lib/module/cbor/cose/README.md +39 -9
- package/lib/module/cbor/cose/error.js +17 -0
- package/lib/module/cbor/cose/error.js.map +1 -0
- package/lib/module/cbor/cose/index.js +1 -0
- package/lib/module/cbor/cose/index.js.map +1 -1
- package/lib/module/iso18013/index.js +0 -1
- package/lib/module/iso18013/index.js.map +1 -1
- package/lib/module/iso18013/iso18013-5/README.md +52 -16
- package/lib/module/iso18013/iso18013-5/error.js +25 -0
- package/lib/module/iso18013/iso18013-5/error.js.map +1 -0
- package/lib/module/iso18013/iso18013-5/index.js +3 -2
- package/lib/module/iso18013/iso18013-5/index.js.map +1 -1
- package/lib/module/iso18013/iso18013-5/proximity.js +1 -9
- package/lib/module/iso18013/iso18013-5/proximity.js.map +1 -1
- package/lib/module/iso18013/iso18013-5/{schema.js → request.js} +1 -20
- package/lib/module/iso18013/iso18013-5/request.js.map +1 -0
- package/lib/module/iso18013/iso18013-7/README.md +38 -9
- package/lib/module/iso18013/iso18013-7/error.js +15 -0
- package/lib/module/iso18013/iso18013-7/error.js.map +1 -0
- package/lib/module/iso18013/iso18013-7/index.js +1 -0
- package/lib/module/iso18013/iso18013-7/index.js.map +1 -1
- package/lib/module/iso18013/iso18013-7/remote.js +0 -12
- package/lib/module/iso18013/iso18013-7/remote.js.map +1 -1
- package/lib/module/schema.js +46 -0
- package/lib/module/schema.js.map +1 -0
- package/lib/typescript/src/cbor/cbor/error.d.ts +68 -0
- package/lib/typescript/src/cbor/cbor/error.d.ts.map +1 -0
- package/lib/typescript/src/cbor/cbor/index.d.ts +1 -1
- package/lib/typescript/src/cbor/cbor/index.d.ts.map +1 -1
- package/lib/typescript/src/cbor/cose/error.d.ts +68 -0
- package/lib/typescript/src/cbor/cose/error.d.ts.map +1 -0
- package/lib/typescript/src/cbor/cose/index.d.ts +1 -1
- package/lib/typescript/src/cbor/cose/index.d.ts.map +1 -1
- package/lib/typescript/src/iso18013/index.d.ts +0 -1
- package/lib/typescript/src/iso18013/index.d.ts.map +1 -1
- package/lib/typescript/src/iso18013/iso18013-5/error.d.ts +73 -0
- package/lib/typescript/src/iso18013/iso18013-5/error.d.ts.map +1 -0
- package/lib/typescript/src/iso18013/iso18013-5/index.d.ts +3 -2
- package/lib/typescript/src/iso18013/iso18013-5/index.d.ts.map +1 -1
- package/lib/typescript/src/iso18013/iso18013-5/proximity.d.ts +2 -7
- package/lib/typescript/src/iso18013/iso18013-5/proximity.d.ts.map +1 -1
- package/lib/typescript/src/iso18013/iso18013-5/{schema.d.ts → request.d.ts} +1 -16
- package/lib/typescript/src/iso18013/iso18013-5/request.d.ts.map +1 -0
- package/lib/typescript/src/iso18013/iso18013-7/error.d.ts +68 -0
- package/lib/typescript/src/iso18013/iso18013-7/error.d.ts.map +1 -0
- package/lib/typescript/src/iso18013/iso18013-7/index.d.ts +2 -1
- package/lib/typescript/src/iso18013/iso18013-7/index.d.ts.map +1 -1
- package/lib/typescript/src/iso18013/iso18013-7/remote.d.ts +0 -14
- package/lib/typescript/src/iso18013/iso18013-7/remote.d.ts.map +1 -1
- package/lib/typescript/src/schema.d.ts +76 -0
- package/lib/typescript/src/schema.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/cbor/cbor/README.md +37 -5
- package/src/cbor/cbor/error.ts +23 -0
- package/src/cbor/cbor/index.ts +5 -1
- package/src/cbor/cose/README.md +39 -9
- package/src/cbor/cose/error.ts +23 -0
- package/src/cbor/cose/index.ts +5 -1
- package/src/iso18013/index.ts +0 -7
- package/src/iso18013/iso18013-5/README.md +52 -16
- package/src/iso18013/iso18013-5/error.ts +35 -0
- package/src/iso18013/iso18013-5/index.ts +9 -4
- package/src/iso18013/iso18013-5/proximity.ts +2 -10
- package/src/iso18013/iso18013-5/{schema.ts → request.ts} +0 -20
- package/src/iso18013/iso18013-7/README.md +38 -9
- package/src/iso18013/iso18013-7/error.ts +21 -0
- package/src/iso18013/iso18013-7/index.ts +5 -4
- package/src/iso18013/iso18013-7/remote.ts +0 -20
- package/src/schema.ts +55 -0
- package/lib/module/cbor/cbor/failure.js +0 -2
- package/lib/module/cbor/cbor/failure.js.map +0 -1
- package/lib/module/cbor/cose/failure.js +0 -2
- package/lib/module/cbor/cose/failure.js.map +0 -1
- package/lib/module/iso18013/iso18013-5/schema.js.map +0 -1
- package/lib/typescript/src/cbor/cbor/failure.d.ts +0 -15
- package/lib/typescript/src/cbor/cbor/failure.d.ts.map +0 -1
- package/lib/typescript/src/cbor/cose/failure.d.ts +0 -15
- package/lib/typescript/src/cbor/cose/failure.d.ts.map +0 -1
- package/lib/typescript/src/iso18013/iso18013-5/schema.d.ts.map +0 -1
- package/src/cbor/cbor/failure.ts +0 -18
- package/src/cbor/cose/failure.ts +0 -20
|
@@ -4,44 +4,42 @@ import CryptoKit
|
|
|
4
4
|
|
|
5
5
|
@objc(IoReactNativeCbor)
|
|
6
6
|
class IoReactNativeCbor: NSObject {
|
|
7
|
-
private typealias ME = ModuleException
|
|
8
|
-
private let keyConfig: KeyConfig = .ec
|
|
9
7
|
|
|
10
8
|
@objc func decode(
|
|
11
9
|
_ cbor: String,
|
|
12
10
|
resolver resolve: RCTPromiseResolveBlock,
|
|
13
11
|
rejecter reject: RCTPromiseRejectBlock
|
|
14
12
|
) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
do{
|
|
14
|
+
let data = try Base64Utils.decodeBase64OrBase64URL(base: cbor)
|
|
15
|
+
guard let json = CborCose.jsonFromCBOR(data: data) else {
|
|
16
|
+
// We don't have the exact error here as this method returns nil upon failure
|
|
17
|
+
reject(ModuleErrorCodes.decodeError.rawValue, "Unable to decode CBOR", nil)
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
resolve(json);
|
|
21
|
+
|
|
22
|
+
}catch{
|
|
23
|
+
reject(ModuleErrorCodes.decodeError.rawValue, error.localizedDescription, error)
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
-
resolve(json);
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
|
|
29
27
|
@objc func decodeDocuments(
|
|
30
28
|
_ mdoc: String,
|
|
31
29
|
resolver resolve: RCTPromiseResolveBlock,
|
|
32
30
|
rejecter reject: RCTPromiseRejectBlock
|
|
33
31
|
) {
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
do{
|
|
33
|
+
let data = try Base64Utils.decodeBase64OrBase64URL(base: mdoc)
|
|
34
|
+
guard let json = CborCose.decodeCBOR(data: data, true, true) else {
|
|
35
|
+
// We don't have the exact error here as this method returns nil upon failure
|
|
36
|
+
reject(ModuleErrorCodes.decodeDocumentsError.rawValue, "Unable to decode document CBOR", nil)
|
|
36
37
|
return
|
|
38
|
+
}
|
|
39
|
+
resolve(json);
|
|
40
|
+
}catch{
|
|
41
|
+
reject(ModuleErrorCodes.decodeDocumentsError.rawValue, error.localizedDescription, error)
|
|
37
42
|
}
|
|
38
|
-
|
|
39
|
-
guard let json = CborCose.decodeCBOR(data: data, true, true) else {
|
|
40
|
-
ME.unableToDecode.reject(reject: reject)
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
resolve(json);
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
@objc func decodeIssuerSigned(
|
|
@@ -49,17 +47,17 @@ class IoReactNativeCbor: NSObject {
|
|
|
49
47
|
resolver resolve: RCTPromiseResolveBlock,
|
|
50
48
|
rejecter reject: RCTPromiseRejectBlock
|
|
51
49
|
) {
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
do{
|
|
51
|
+
let data = try Base64Utils.decodeBase64OrBase64URL(base: issuerSigned)
|
|
52
|
+
guard let json = CborCose.issuerSignedCborToJson(data: data) else {
|
|
53
|
+
// We don't have the exact error here as this method returns nil upon failure
|
|
54
|
+
reject(ModuleErrorCodes.decodeIssuerSignedError.rawValue, "Unable to decode Issuer Signed CBOR", nil)
|
|
54
55
|
return
|
|
56
|
+
}
|
|
57
|
+
resolve(json);
|
|
58
|
+
}catch{
|
|
59
|
+
reject(ModuleErrorCodes.decodeIssuerSignedError.rawValue, error.localizedDescription, error)
|
|
55
60
|
}
|
|
56
|
-
|
|
57
|
-
guard let json = CborCose.issuerSignedCborToJson(data: data) else {
|
|
58
|
-
ME.unableToDecode.reject(reject: reject)
|
|
59
|
-
return
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
resolve(json);
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
@objc func sign(
|
|
@@ -68,24 +66,25 @@ class IoReactNativeCbor: NSObject {
|
|
|
68
66
|
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
69
67
|
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
70
68
|
) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
DispatchQueue.global().async { [weak self] in
|
|
70
|
+
guard self != nil else {
|
|
71
|
+
reject(ModuleErrorCodes.threadingError.rawValue, "Failed to perform background operation, self was deallocated", nil)
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
do{
|
|
76
|
+
let data = try Base64Utils.decodeBase64OrBase64URL(base: payloadData)
|
|
77
|
+
guard let coseKey = CoseKeyPrivate(crv: .p256, keyTag: keyTag) else {
|
|
78
|
+
// We don't have the exact error here as this method returns nil upon failure
|
|
79
|
+
reject(ModuleErrorCodes.signError.rawValue, "Unable to create a private key with the given keytag: \(keyTag)", nil)
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
let signedPayload = CborCose.sign(data: data, privateKey: coseKey)
|
|
83
|
+
resolve(signedPayload.base64EncodedString())
|
|
75
84
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
ME.invalidEncoding.reject(reject: reject)
|
|
79
|
-
return
|
|
85
|
+
catch{
|
|
86
|
+
reject(ModuleErrorCodes.signError.rawValue, error.localizedDescription, error)
|
|
80
87
|
}
|
|
81
|
-
|
|
82
|
-
guard let coseKey = CoseKeyPrivate(crv: .p256, keyTag: keyTag) else {
|
|
83
|
-
ME.publicKeyNotFound.reject(reject: reject)
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
let signedPayload = CborCose.sign(data: data, privateKey: coseKey)
|
|
88
|
-
resolve(signedPayload.base64EncodedString())
|
|
89
88
|
}
|
|
90
89
|
}
|
|
91
90
|
|
|
@@ -96,93 +95,24 @@ class IoReactNativeCbor: NSObject {
|
|
|
96
95
|
rejecter reject: RCTPromiseRejectBlock
|
|
97
96
|
) {
|
|
98
97
|
do {
|
|
99
|
-
|
|
100
|
-
ME.invalidEncoding.reject(reject: reject)
|
|
101
|
-
return
|
|
102
|
-
}
|
|
103
|
-
|
|
98
|
+
let data = try Base64Utils.decodeBase64OrBase64URL(base: sign1Data)
|
|
104
99
|
let publicKeyJson = try JSONSerialization.data(withJSONObject: jwk, options:[] )
|
|
105
100
|
let publicKeyString = String(data: publicKeyJson, encoding: .utf8)!
|
|
106
101
|
let publicKey = CoseKey(jwk: publicKeyString)!
|
|
107
|
-
|
|
108
102
|
let verified = CborCose.verify(data: data, publicKey: publicKey)
|
|
109
|
-
|
|
110
103
|
resolve(verified)
|
|
111
104
|
} catch {
|
|
112
|
-
|
|
105
|
+
reject(ModuleErrorCodes.verifyError.rawValue, error.localizedDescription, error)
|
|
113
106
|
}
|
|
114
107
|
}
|
|
115
|
-
|
|
116
|
-
private func keyExists(keyTag: String) -> (key: SecKey?, status: OSStatus) {
|
|
117
|
-
let getQuery = privateKeyKeychainQuery(keyTag: keyTag)
|
|
118
|
-
var item: CFTypeRef?
|
|
119
|
-
let status = SecItemCopyMatching(getQuery as CFDictionary, &item)
|
|
120
|
-
return (status == errSecSuccess ? (item as! SecKey) : nil, status)
|
|
121
|
-
}
|
|
122
108
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
kSecReturnRef as String: true
|
|
131
|
-
]
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private enum KeyConfig: Int, CaseIterable {
|
|
135
|
-
case ec
|
|
136
|
-
|
|
137
|
-
func keyType() -> CFString {
|
|
138
|
-
switch self {
|
|
139
|
-
case .ec:
|
|
140
|
-
return kSecAttrKeyTypeECSECPrimeRandom
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
func keySizeInBits() -> Int {
|
|
145
|
-
switch self {
|
|
146
|
-
case .ec:
|
|
147
|
-
return 256
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
func keySignAlgorithm() -> SecKeyAlgorithm {
|
|
152
|
-
switch self {
|
|
153
|
-
case .ec:
|
|
154
|
-
return .ecdsaSignatureMessageX962SHA256
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
private enum ModuleException: String, CaseIterable {
|
|
160
|
-
case unableToDecode = "UNABLE_TO_DECODE"
|
|
161
|
-
case publicKeyNotFound = "PUBLIC_KEY_NOT_FOUND"
|
|
162
|
-
case invalidEncoding = "INVALID_ENCODING"
|
|
109
|
+
// Errors which this module uses to reject a promise
|
|
110
|
+
private enum ModuleErrorCodes: String, CaseIterable {
|
|
111
|
+
case decodeError = "DECODE_ERROR"
|
|
112
|
+
case decodeDocumentsError = "DECODE_DOCUMENTS_ERROR"
|
|
113
|
+
case decodeIssuerSignedError = "DECODE_ISSUER_SIGNED_ERROR"
|
|
114
|
+
case signError = "SIGN_ERROR"
|
|
115
|
+
case verifyError = "VERIFY_ERROR"
|
|
163
116
|
case threadingError = "THREADING_ERROR"
|
|
164
|
-
case unknownException = "UNKNOWN_EXCEPTION"
|
|
165
|
-
|
|
166
|
-
func error(userInfo: [String : Any]? = nil) -> NSError {
|
|
167
|
-
switch self {
|
|
168
|
-
case .unableToDecode:
|
|
169
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
170
|
-
case .publicKeyNotFound:
|
|
171
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
172
|
-
case .invalidEncoding:
|
|
173
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
174
|
-
case .threadingError:
|
|
175
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
176
|
-
case .unknownException:
|
|
177
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
func reject(reject: RCTPromiseRejectBlock, _ moreUserInfo: (String, Any)...) {
|
|
182
|
-
var userInfo = [String : Any]()
|
|
183
|
-
moreUserInfo.forEach { userInfo[$0.0] = $0.1 }
|
|
184
|
-
let error = error(userInfo: userInfo)
|
|
185
|
-
reject("\(error.code)", error.domain, error)
|
|
186
|
-
}
|
|
187
117
|
}
|
|
188
118
|
}
|
|
@@ -5,8 +5,6 @@ import React
|
|
|
5
5
|
@objc(IoReactNativeIso18013)
|
|
6
6
|
class IoReactNativeIso18013: RCTEventEmitter {
|
|
7
7
|
|
|
8
|
-
private typealias ME = ModuleException
|
|
9
|
-
|
|
10
8
|
@objc
|
|
11
9
|
override static func requiresMainQueueSetup() -> Bool {
|
|
12
10
|
return true
|
|
@@ -53,11 +51,15 @@ class IoReactNativeIso18013: RCTEventEmitter {
|
|
|
53
51
|
reject: @escaping RCTPromiseRejectBlock
|
|
54
52
|
){
|
|
55
53
|
do {
|
|
56
|
-
let certsData = parseCertificates(certificates)
|
|
54
|
+
let certsData = try parseCertificates(certificates)
|
|
57
55
|
try Proximity.shared.start(certsData)
|
|
58
56
|
resolve(true)
|
|
59
|
-
} catch let
|
|
60
|
-
|
|
57
|
+
} catch let proximityError as ProximityError {
|
|
58
|
+
reject(ModuleErrorCodes.generateResponseError.rawValue, proximityError.description, proximityError)
|
|
59
|
+
} catch let parsingError as ParsingError{
|
|
60
|
+
reject(ModuleErrorCodes.generateResponseError.rawValue, parsingError.description, parsingError)
|
|
61
|
+
} catch {
|
|
62
|
+
reject(ModuleErrorCodes.generateResponseError.rawValue, error.localizedDescription, error)
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
|
|
@@ -69,15 +71,17 @@ class IoReactNativeIso18013: RCTEventEmitter {
|
|
|
69
71
|
|
|
70
72
|
- Returns: A two-dimensional array of Data containing DER encoded X.509 certificates.
|
|
71
73
|
*/
|
|
72
|
-
private func parseCertificates(_ certificates:
|
|
73
|
-
return certificates.compactMap { item in
|
|
74
|
+
private func parseCertificates(_ certificates: [Any]) throws -> [[Data]] {
|
|
75
|
+
return try certificates.enumerated().compactMap { (chainIndex, item) in
|
|
74
76
|
guard let certStrings = item as? [String] else {
|
|
75
|
-
|
|
77
|
+
throw ParsingError.certificatesNotValid("Certificate chain at index \(chainIndex) is not an array of strings.")
|
|
76
78
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
return try certStrings.enumerated().map { (certIndex, certString) in
|
|
80
|
+
guard let data = Data(base64Encoded: certString) else {
|
|
81
|
+
throw ParsingError.certificatesNotValid("Certificate at index \(certIndex) in the chain at index \(chainIndex) is not a valid base64 string.")
|
|
82
|
+
}
|
|
83
|
+
return data
|
|
79
84
|
}
|
|
80
|
-
return dataArray.isEmpty ? nil : dataArray
|
|
81
85
|
}
|
|
82
86
|
}
|
|
83
87
|
|
|
@@ -97,8 +101,8 @@ class IoReactNativeIso18013: RCTEventEmitter {
|
|
|
97
101
|
do{
|
|
98
102
|
let qrCodeString = try Proximity.shared.getQrCode()
|
|
99
103
|
resolve(qrCodeString)
|
|
100
|
-
} catch
|
|
101
|
-
|
|
104
|
+
} catch {
|
|
105
|
+
reject(ModuleErrorCodes.getQrCodeError.rawValue, error.localizedDescription, error)
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
108
|
|
|
@@ -113,26 +117,31 @@ class IoReactNativeIso18013: RCTEventEmitter {
|
|
|
113
117
|
- alias which is the alias of the key used to sign the credential;
|
|
114
118
|
- docType which is the document type.
|
|
115
119
|
|
|
116
|
-
- Throws: `
|
|
120
|
+
- Throws: `ParsingError`:
|
|
121
|
+
- If the provided documents array do not contain a dictionary;
|
|
122
|
+
- If the provided dictionary doesn't adhere to the structure we expect;
|
|
123
|
+
- If the issuerSignedContent is not a valid base64 or base64url encoded string;
|
|
124
|
+
- If the creation of a ProximityDdocument fails.
|
|
117
125
|
|
|
118
126
|
- Returns: An array of `ProximityDocument` containg the documents to be presented
|
|
119
127
|
*/
|
|
120
128
|
private func parseDocuments(documents: [Any]) throws -> [ProximityDocument] {
|
|
121
|
-
return try documents.
|
|
122
|
-
guard let dict : [String: Any] = element as? [String: Any] else { throw
|
|
129
|
+
return try documents.map{ (element) -> ProximityDocument in
|
|
130
|
+
guard let dict : [String: Any] = element as? [String: Any] else { throw ParsingError.documentsNotValid("The provided documents array element can't be parsed as a dictionary") }
|
|
123
131
|
guard
|
|
124
132
|
let issuerSignedContent = dict["issuerSignedContent"] as? String,
|
|
125
133
|
let alias = dict["alias"] as? String,
|
|
126
134
|
let docType = dict["docType"] as? String,
|
|
127
135
|
let decodedIssuerSignedContent = try? Base64Utils.decodeBase64OrBase64URL(base: issuerSignedContent)
|
|
128
|
-
else {
|
|
129
|
-
|
|
136
|
+
else {
|
|
137
|
+
throw ParsingError.documentsNotValid ("The provided issuerSignedContent is not a valid base64 or base64url or don't contain the required fields alas, doctype and issuerSignedContent")
|
|
138
|
+
}
|
|
130
139
|
guard let document = ProximityDocument(
|
|
131
140
|
docType: docType,
|
|
132
141
|
issuerSigned: [UInt8](decodedIssuerSignedContent),
|
|
133
142
|
deviceKeyTag: alias
|
|
134
143
|
) else {
|
|
135
|
-
throw
|
|
144
|
+
throw ParsingError.documentsNotValid("The parsing for the document with docType \(docType) failed")
|
|
136
145
|
}
|
|
137
146
|
return document
|
|
138
147
|
}
|
|
@@ -146,26 +155,26 @@ class IoReactNativeIso18013: RCTEventEmitter {
|
|
|
146
155
|
- Parameters:
|
|
147
156
|
- acceptedFields: A dictionary of any elements. In order to be added to the result dictionary each element must be shaped as ``AcceptedFieldsDict`` thus as [String: [String: [String: Bool]]]
|
|
148
157
|
|
|
149
|
-
- Throws: `
|
|
158
|
+
- Throws: `ParsingError` if a value doesn't has the ``AcceptedFieldsDict`` shape or the result dictionary is empty
|
|
150
159
|
|
|
151
160
|
- Returns: An ``AcceptedFieldsDict`` containg the accepted fields to be presented
|
|
152
161
|
|
|
153
162
|
*/
|
|
154
|
-
private func parseAcceptedFields(acceptedFields: [AnyHashable: Any]) throws -> AcceptedFieldsDict {
|
|
163
|
+
private func parseAcceptedFields(acceptedFields: [AnyHashable: Any]) throws(ParsingError) -> AcceptedFieldsDict {
|
|
155
164
|
var result: AcceptedFieldsDict = [:]
|
|
156
165
|
|
|
157
166
|
for (key, value) in acceptedFields {
|
|
158
167
|
guard let keyString = key as? String else {
|
|
159
|
-
throw
|
|
168
|
+
throw ParsingError.acceptedFieldsNotValid("The accepted fields keys must be a String")
|
|
160
169
|
}
|
|
161
170
|
guard let valueDict = value as? [String: [String: Bool]] else {
|
|
162
|
-
throw
|
|
171
|
+
throw ParsingError.acceptedFieldsNotValid("The accepted fields values must be of type [String: [String: Bool]]")
|
|
163
172
|
}
|
|
164
173
|
result[keyString] = valueDict
|
|
165
174
|
}
|
|
166
175
|
|
|
167
176
|
if(result.isEmpty){
|
|
168
|
-
throw
|
|
177
|
+
throw ParsingError.acceptedFieldsNotValid("Empty accepted fields cannot be empty")
|
|
169
178
|
}
|
|
170
179
|
|
|
171
180
|
return result
|
|
@@ -216,8 +225,14 @@ class IoReactNativeIso18013: RCTEventEmitter {
|
|
|
216
225
|
let deviceResponse = try Proximity.shared.generateDeviceResponse(items: items, documents: parsedDocuments, sessionTranscript: nil)
|
|
217
226
|
let strDeviceResponse = Data(deviceResponse).base64EncodedString()
|
|
218
227
|
resolve(strDeviceResponse)
|
|
219
|
-
}
|
|
220
|
-
|
|
228
|
+
}
|
|
229
|
+
catch let proximityError as ProximityError {
|
|
230
|
+
reject(ModuleErrorCodes.generateResponseError.rawValue, proximityError.description, proximityError)
|
|
231
|
+
}
|
|
232
|
+
catch let parsingError as ParsingError {
|
|
233
|
+
reject(ModuleErrorCodes.generateResponseError.rawValue, parsingError.description, parsingError)
|
|
234
|
+
} catch {
|
|
235
|
+
reject(ModuleErrorCodes.generateResponseError.rawValue, error.localizedDescription, error)
|
|
221
236
|
}
|
|
222
237
|
}
|
|
223
238
|
|
|
@@ -244,7 +259,7 @@ class IoReactNativeIso18013: RCTEventEmitter {
|
|
|
244
259
|
resolve(true)
|
|
245
260
|
}
|
|
246
261
|
}catch let error {
|
|
247
|
-
|
|
262
|
+
reject(ModuleErrorCodes.sendResponseError.rawValue, error.localizedDescription, error)
|
|
248
263
|
}
|
|
249
264
|
}
|
|
250
265
|
|
|
@@ -262,16 +277,16 @@ class IoReactNativeIso18013: RCTEventEmitter {
|
|
|
262
277
|
*/
|
|
263
278
|
@objc(sendErrorResponse:withResolver:withRejecter:)
|
|
264
279
|
func sendErrorResponse(status: UInt64, _ resolve: @escaping RCTPromiseResolveBlock,
|
|
265
|
-
|
|
280
|
+
reject: @escaping RCTPromiseRejectBlock){
|
|
266
281
|
do{
|
|
267
282
|
if let statusEnum = SessionDataStatus(rawValue: status) {
|
|
268
283
|
try Proximity.shared.errorPresentation(statusEnum)
|
|
269
284
|
} else {
|
|
270
|
-
|
|
285
|
+
reject(ModuleErrorCodes.sendErrorResponseError.rawValue, "Invalid status code provided: \(status)", nil)
|
|
271
286
|
}
|
|
272
287
|
resolve(true)
|
|
273
288
|
}catch let error{
|
|
274
|
-
|
|
289
|
+
reject(ModuleErrorCodes.sendErrorResponseError.rawValue, error.localizedDescription, error)
|
|
275
290
|
}
|
|
276
291
|
}
|
|
277
292
|
|
|
@@ -392,102 +407,58 @@ class IoReactNativeIso18013: RCTEventEmitter {
|
|
|
392
407
|
|
|
393
408
|
do {
|
|
394
409
|
let sessionTranscript = Proximity.shared.generateOID4VPSessionTranscriptCBOR(
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
410
|
+
clientId: clientId,
|
|
411
|
+
responseUri: responseUri,
|
|
412
|
+
authorizationRequestNonce: authorizationRequestNonce,
|
|
413
|
+
mdocGeneratedNonce: mdocGeneratedNonce
|
|
399
414
|
)
|
|
400
|
-
|
|
401
|
-
let documentsAsProximityDocument = try parseDocuments(documents: documents)
|
|
402
415
|
|
|
416
|
+
let documentsAsProximityDocument = try parseDocuments(documents: documents)
|
|
403
417
|
let items = try JSONDecoder().decode([String : [String : [String : Bool]]].self, from: Data(fieldRequestedAndAccepted.utf8))
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
return
|
|
411
|
-
}
|
|
412
|
-
} catch let error as NSError where error.domain == ME.invalidDocRequested.rawValue {
|
|
413
|
-
ME.invalidDocRequested.reject(reject: reject)
|
|
414
|
-
} catch _ as DecodingError {
|
|
415
|
-
ME.invalidItems.reject(reject: reject)
|
|
416
|
-
} catch {
|
|
417
|
-
ME.unexpected.reject(reject: reject)
|
|
418
|
+
let response = try Proximity.shared.generateDeviceResponse(items: items, documents: documentsAsProximityDocument, sessionTranscript: sessionTranscript)
|
|
419
|
+
resolve(Data(response).base64EncodedString())
|
|
420
|
+
} catch let parsingError as ParsingError{
|
|
421
|
+
reject(ModuleErrorCodes.generateOID4VPResponseError.rawValue, parsingError.description, parsingError)
|
|
422
|
+
} catch let proximityError as ProximityError{
|
|
423
|
+
reject(ModuleErrorCodes.generateOID4VPResponseError.rawValue, proximityError.description, proximityError)
|
|
418
424
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
private class DocRequested {
|
|
422
|
-
var issuerSignedContent : [UInt8]
|
|
423
|
-
var alias : String
|
|
424
|
-
var docType : String
|
|
425
|
-
|
|
426
|
-
public init(issuerSignedContent: [UInt8], alias: String, docType: String) {
|
|
427
|
-
self.issuerSignedContent = issuerSignedContent
|
|
428
|
-
self.alias = alias
|
|
429
|
-
self.docType = docType
|
|
425
|
+
catch {
|
|
426
|
+
reject(ModuleErrorCodes.generateOID4VPResponseError.rawValue, error.localizedDescription, error)
|
|
430
427
|
}
|
|
431
428
|
}
|
|
432
|
-
|
|
429
|
+
|
|
433
430
|
/**
|
|
434
|
-
|
|
435
|
-
|
|
431
|
+
Custom Error which is thrown when a parsing error occurs in our utility functions which converts data from the bridge to what
|
|
432
|
+
our underlying functions expect.
|
|
433
|
+
This is needed in order to provide a customized description which can include more debug information.
|
|
436
434
|
*/
|
|
437
|
-
|
|
435
|
+
enum ParsingError : Error, CustomStringConvertible {
|
|
436
|
+
case documentsNotValid(String)
|
|
437
|
+
case certificatesNotValid(String)
|
|
438
|
+
case acceptedFieldsNotValid(String)
|
|
439
|
+
|
|
440
|
+
public var description: String {
|
|
441
|
+
switch(self) {
|
|
442
|
+
case .documentsNotValid(let message):
|
|
443
|
+
return message
|
|
444
|
+
case .certificatesNotValid(let message):
|
|
445
|
+
return message
|
|
446
|
+
case .acceptedFieldsNotValid(let message):
|
|
447
|
+
return message
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Errors which this module uses to reject a promise
|
|
453
|
+
private enum ModuleErrorCodes: String, CaseIterable {
|
|
454
|
+
// ISO18013-5 related errors
|
|
438
455
|
case startError = "START_ERROR"
|
|
439
|
-
case
|
|
440
|
-
case generateDeviceResponseError = "GENERATE_DEVICE_RESPONSE_ERROR"
|
|
456
|
+
case getQrCodeError = "GET_QR_CODE_ERROR"
|
|
441
457
|
case sendResponseError = "SEND_RESPONSE_ERROR"
|
|
442
|
-
case
|
|
443
|
-
case
|
|
444
|
-
case unableToGenerateResponse = "UNABLE_TO_GENERATE_RESPONSE_ERROR"
|
|
445
|
-
case invalidItems = "REQUESTED_ITEMS_PARSING_ERROR"
|
|
446
|
-
case unexpected = "UNEXPECTED_ERROR"
|
|
447
|
-
case unableToDecode = "UNABLE_TO_DECODE"
|
|
448
|
-
|
|
449
|
-
func error(
|
|
450
|
-
userInfo: [String : Any]? = nil
|
|
451
|
-
) -> NSError {
|
|
452
|
-
switch self {
|
|
453
|
-
case .startError:
|
|
454
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
455
|
-
case .qrCodeError:
|
|
456
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
457
|
-
case .generateDeviceResponseError:
|
|
458
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
459
|
-
case .sendResponseError:
|
|
460
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
461
|
-
case .sendErrorResponse:
|
|
462
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
463
|
-
case .invalidDocRequested:
|
|
464
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
465
|
-
case .unableToGenerateResponse:
|
|
466
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
467
|
-
case .invalidItems:
|
|
468
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
469
|
-
case .unexpected:
|
|
470
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
471
|
-
case .unableToDecode:
|
|
472
|
-
return NSError(domain: self.rawValue, code: -1, userInfo: userInfo)
|
|
473
|
-
}
|
|
474
|
-
}
|
|
458
|
+
case sendErrorResponseError = "SEND_ERROR_RESPONSE_ERROR"
|
|
459
|
+
case generateResponseError = "GENERATE_RESPONSE_ERROR"
|
|
475
460
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
- Parameters:
|
|
480
|
-
- reject: the promise to be rejected.
|
|
481
|
-
- moreUserInfo: additional key-value pairs of data to be passed along with the error.
|
|
482
|
-
|
|
483
|
-
*/
|
|
484
|
-
func reject(
|
|
485
|
-
reject: RCTPromiseRejectBlock,
|
|
486
|
-
_ moreUserInfo: (String, Any)...
|
|
487
|
-
) {
|
|
488
|
-
let userInfo = [String: Any](uniqueKeysWithValues: moreUserInfo)
|
|
489
|
-
let error = error(userInfo: userInfo)
|
|
490
|
-
reject("\(error.code)", error.domain, error)
|
|
491
|
-
}
|
|
461
|
+
// ISO18013-7 related errors
|
|
462
|
+
case generateOID4VPResponseError = "GENERATE_OID4VP_RESPONSE_ERROR"
|
|
492
463
|
}
|
|
493
464
|
}
|
|
@@ -88,8 +88,40 @@ enum DocumentTypeEnum {
|
|
|
88
88
|
|
|
89
89
|
### Error Codes
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
-
|
|
|
95
|
-
|
|
|
91
|
+
This table contains the list of error codes that can be thrown by the `CBOR` module which are mapped via the `ModuleErrorCodes` type:
|
|
92
|
+
| Type | Platform | Description |
|
|
93
|
+
| -------------------------- | ----------- | ------------------------------------------------------------ |
|
|
94
|
+
| DECODE_ERROR | Android/iOS | An error occurred while decoding the CBOR |
|
|
95
|
+
| DECODE_DOCUMENTS_ERROR | Android/iOS | An error occurred while decoding a CBOR mDOC |
|
|
96
|
+
| DECODE_ISSUER_SIGNED_ERROR | Android/iOS | An error occurred while decoding a CBOR Issuer Signed object |
|
|
97
|
+
|
|
98
|
+
An error can be parsed using the `ModuleErrorSchema` with type `ModuleErrorCodes` exposed by the `ISO18013_5` module. The error can be parsed as follows:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { CBOR } from '@pagopa/io-react-native-iso18013';
|
|
102
|
+
try {
|
|
103
|
+
await CBOR.func();
|
|
104
|
+
} catch (error) {
|
|
105
|
+
const parsedError = CBOR.ModuleErrorSchema.parse(error); // Or ModuleErrorSchema.safeParse(error) for safe parsing
|
|
106
|
+
console.log(JSON.stringify(parsedError, null, 2));
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The parsed object will contain properties from both iOS and Android platforms:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
{
|
|
114
|
+
code: string; // Defined in ModuleErrorCodes
|
|
115
|
+
message: string;
|
|
116
|
+
name: string;
|
|
117
|
+
userInfo?: Record<string, any> | null;
|
|
118
|
+
nativeStackAndroid?: Array<{
|
|
119
|
+
lineNumber: number;
|
|
120
|
+
file: string;
|
|
121
|
+
methodName: string;
|
|
122
|
+
class: string;
|
|
123
|
+
}>;
|
|
124
|
+
domain?: string;
|
|
125
|
+
nativeStackIOS?: Array<string>;
|
|
126
|
+
};
|
|
127
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import z from 'zod';
|
|
4
|
+
import { GenericModuleErrorSchema } from "../../schema.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Error codes which the CBOR module uses to reject a promise.
|
|
8
|
+
*/
|
|
9
|
+
const ModuleErrorCodesSchema = z.enum(['DECODE_ERROR', 'DECODE_DOCUMENTS_ERROR', 'DECODE_ISSUER_SIGNED_ERROR', 'EUNSPECIFIED' // Android only default when no other error is specified
|
|
10
|
+
]);
|
|
11
|
+
/**
|
|
12
|
+
* Schema which can be used to parse a rejected promise error by the CBOR module.
|
|
13
|
+
*/
|
|
14
|
+
export const ModuleErrorSchema = GenericModuleErrorSchema(ModuleErrorCodesSchema);
|
|
15
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["z","GenericModuleErrorSchema","ModuleErrorCodesSchema","enum","ModuleErrorSchema"],"sourceRoot":"../../../../src","sources":["cbor/cbor/error.ts"],"mappings":";;AAAA,OAAOA,CAAC,MAAM,KAAK;AACnB,SAASC,wBAAwB,QAAQ,iBAAc;;AAEvD;AACA;AACA;AACA,MAAMC,sBAAsB,GAAGF,CAAC,CAACG,IAAI,CAAC,CACpC,cAAc,EACd,wBAAwB,EACxB,4BAA4B,EAC5B,cAAc,CAAE;AAAA,CACjB,CAAC;AAIF;AACA;AACA;AACA,OAAO,MAAMC,iBAAiB,GAAGH,wBAAwB,CACvDC,sBACF,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["decode","decodeDocuments","decodeIssuerSigned","DocumentValue","Documents","DocumentsFromString","IssuerSigned","MDOC"],"sourceRoot":"../../../../src","sources":["cbor/cbor/index.ts"],"mappings":";;AAAA,SAASA,MAAM,EAAEC,eAAe,EAAEC,kBAAkB,QAAQ,cAAW;AACvE,SACEC,aAAa,EACbC,SAAS,EACTC,mBAAmB,EACnBC,YAAY,EACZC,IAAI,QACC,aAAU","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["decode","decodeDocuments","decodeIssuerSigned","DocumentValue","Documents","DocumentsFromString","IssuerSigned","MDOC","ModuleErrorSchema"],"sourceRoot":"../../../../src","sources":["cbor/cbor/index.ts"],"mappings":";;AAAA,SAASA,MAAM,EAAEC,eAAe,EAAEC,kBAAkB,QAAQ,cAAW;AACvE,SACEC,aAAa,EACbC,SAAS,EACTC,mBAAmB,EACnBC,YAAY,EACZC,IAAI,QACC,aAAU;AACjB,SAGEC,iBAAiB,QACZ,YAAS","ignoreList":[]}
|