@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
|
@@ -5,10 +5,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
|
5
5
|
import com.facebook.react.bridge.ReactMethod
|
|
6
6
|
import com.facebook.react.bridge.Promise
|
|
7
7
|
import com.facebook.react.bridge.ReadableMap
|
|
8
|
-
import com.facebook.react.bridge.WritableMap
|
|
9
|
-
import com.facebook.react.bridge.WritableNativeMap
|
|
10
8
|
import it.pagopa.io.wallet.cbor.cose.COSEManager
|
|
11
|
-
import it.pagopa.io.wallet.cbor.cose.FailureReason
|
|
12
9
|
import it.pagopa.io.wallet.cbor.cose.SignWithCOSEResult
|
|
13
10
|
import it.pagopa.io.wallet.cbor.parser.CBorParser
|
|
14
11
|
|
|
@@ -21,189 +18,95 @@ class IoReactNativeCborModule(reactContext: ReactApplicationContext) :
|
|
|
21
18
|
|
|
22
19
|
@ReactMethod
|
|
23
20
|
fun decode(data: String, promise: Promise) {
|
|
24
|
-
val buffer = try {
|
|
25
|
-
Base64Utils.decodeBase64AndBase64Url(data)
|
|
26
|
-
} catch (e: Exception) {
|
|
27
|
-
ModuleException.INVALID_ENCODING.reject(
|
|
28
|
-
promise,
|
|
29
|
-
Pair(ERROR_USER_INFO_KEY, e.message.orEmpty())
|
|
30
|
-
)
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
21
|
try {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
ModuleException.UNABLE_TO_DECODE.reject(promise)
|
|
39
|
-
}
|
|
22
|
+
val buffer = Base64Utils.decodeBase64AndBase64Url(data)
|
|
23
|
+
val result = CBorParser(buffer).toJson()
|
|
24
|
+
promise.resolve(result)
|
|
40
25
|
} catch (e: Exception) {
|
|
41
|
-
|
|
42
|
-
promise,
|
|
43
|
-
Pair(ERROR_USER_INFO_KEY, e.message.orEmpty())
|
|
44
|
-
)
|
|
26
|
+
promise.reject(ModuleErrorCodes.DECODE_ERROR, e.message, e)
|
|
45
27
|
}
|
|
46
28
|
}
|
|
47
29
|
|
|
48
|
-
@ReactMethod
|
|
49
|
-
fun decodeDocuments(data: String, promise: Promise) {
|
|
50
|
-
val buffer = try {
|
|
51
|
-
Base64Utils.decodeBase64AndBase64Url(data)
|
|
52
|
-
} catch (e: Exception) {
|
|
53
|
-
ModuleException.INVALID_ENCODING.reject(
|
|
54
|
-
promise,
|
|
55
|
-
Pair(ERROR_USER_INFO_KEY, e.message.orEmpty())
|
|
56
|
-
)
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
try {
|
|
60
|
-
CBorParser(buffer).documentsCborToJson(separateElementIdentifier = true, onComplete = {
|
|
61
|
-
promise.resolve(it)
|
|
62
|
-
}) { ex ->
|
|
63
|
-
ModuleException.UNABLE_TO_DECODE.reject(
|
|
64
|
-
promise,
|
|
65
|
-
Pair(ERROR_USER_INFO_KEY, ex.message.orEmpty())
|
|
66
|
-
)
|
|
67
|
-
}
|
|
68
|
-
} catch (e: Exception) {
|
|
69
|
-
ModuleException.UNKNOWN_EXCEPTION.reject(
|
|
70
|
-
promise,
|
|
71
|
-
Pair(ERROR_USER_INFO_KEY, e.message.orEmpty())
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
30
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
CBorParser(buffer).issuerSignedCborToJson(separateElementIdentifier = true).let {
|
|
89
|
-
if (it == null) {
|
|
90
|
-
ModuleException.UNABLE_TO_DECODE.reject(
|
|
91
|
-
promise,
|
|
92
|
-
Pair(ERROR_USER_INFO_KEY, "Unable to decode passed CBOR")
|
|
93
|
-
)
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
promise.resolve(it)
|
|
31
|
+
@ReactMethod
|
|
32
|
+
fun decodeDocuments(data: String, promise: Promise) {
|
|
33
|
+
try {
|
|
34
|
+
val buffer = Base64Utils.decodeBase64AndBase64Url(data)
|
|
35
|
+
CBorParser(buffer).documentsCborToJson(separateElementIdentifier = true, onComplete = {
|
|
36
|
+
promise.resolve(it)
|
|
37
|
+
}, onError = { e ->
|
|
38
|
+
promise.reject(ModuleErrorCodes.DECODE_DOCUMENTS_ERROR, e.message, e)
|
|
39
|
+
})
|
|
40
|
+
} catch (e: Exception) {
|
|
41
|
+
promise.reject(ModuleErrorCodes.DECODE_DOCUMENTS_ERROR, e.message, e)
|
|
97
42
|
}
|
|
98
|
-
} catch (e: Exception) {
|
|
99
|
-
ModuleException.UNKNOWN_EXCEPTION.reject(
|
|
100
|
-
promise,
|
|
101
|
-
Pair(ERROR_USER_INFO_KEY, e.message.orEmpty())
|
|
102
|
-
)
|
|
103
43
|
}
|
|
104
|
-
}
|
|
105
44
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
45
|
+
@ReactMethod
|
|
46
|
+
fun decodeIssuerSigned(issuerSigned: String, promise: Promise) {
|
|
47
|
+
try {
|
|
48
|
+
val buffer =
|
|
49
|
+
Base64Utils.decodeBase64AndBase64Url(issuerSigned)
|
|
50
|
+
val result =
|
|
51
|
+
CBorParser(buffer).issuerSignedCborToJson(separateElementIdentifier = true) ?: run {
|
|
52
|
+
// We don't have the exact error here for some reason
|
|
53
|
+
promise.reject(
|
|
54
|
+
ModuleErrorCodes.DECODE_ISSUER_SIGNED_ERROR,
|
|
55
|
+
"An error occurred while decoding the issuer signed content"
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
promise.resolve(result)
|
|
59
|
+
} catch (e: Exception) {
|
|
60
|
+
promise.reject(ModuleErrorCodes.DECODE_ISSUER_SIGNED_ERROR, e.message, e)
|
|
61
|
+
}
|
|
116
62
|
}
|
|
117
63
|
|
|
64
|
+
@ReactMethod
|
|
65
|
+
fun sign(payload: String, keyTag: String, promise: Promise){
|
|
118
66
|
try {
|
|
119
|
-
val
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
FailureReason.FAIL_TO_SIGN -> ModuleException.UNABLE_TO_SIGN.reject(
|
|
132
|
-
promise,
|
|
133
|
-
Pair(ERROR_USER_INFO_KEY, result.reason.msg)
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
else -> ModuleException.UNKNOWN_EXCEPTION.reject(
|
|
137
|
-
promise,
|
|
138
|
-
Pair(ERROR_USER_INFO_KEY, result.reason.msg)
|
|
139
|
-
)
|
|
67
|
+
val data = Base64Utils.decodeBase64AndBase64Url(payload)
|
|
68
|
+
val result = COSEManager().signWithCOSE(
|
|
69
|
+
data = data,
|
|
70
|
+
alias = keyTag
|
|
71
|
+
)
|
|
72
|
+
when (result) {
|
|
73
|
+
is SignWithCOSEResult.Failure -> {
|
|
74
|
+
// We don't have a throwable to pass here from the onError callback
|
|
75
|
+
promise.reject(ModuleErrorCodes.SIGN_ERROR, result.reason.msg)
|
|
76
|
+
}
|
|
77
|
+
is SignWithCOSEResult.Success -> {
|
|
78
|
+
promise.resolve(Base64Utils.encodeBase64(result.signature))
|
|
140
79
|
}
|
|
141
80
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
promise.resolve(Base64Utils.encodeBase64(result.signature))
|
|
145
|
-
}
|
|
81
|
+
} catch (e: Exception) {
|
|
82
|
+
promise.reject(ModuleErrorCodes.SIGN_ERROR, e.message, e)
|
|
146
83
|
}
|
|
147
|
-
} catch (e: Exception) {
|
|
148
|
-
ModuleException.UNKNOWN_EXCEPTION.reject(
|
|
149
|
-
promise,
|
|
150
|
-
Pair(ERROR_USER_INFO_KEY, e.message.orEmpty())
|
|
151
|
-
)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
@ReactMethod
|
|
156
|
-
fun verify(sign1Data: String, publicKey: ReadableMap, promise: Promise) {
|
|
157
|
-
val data = try {
|
|
158
|
-
Base64Utils.decodeBase64AndBase64Url(sign1Data)
|
|
159
|
-
} catch (e: Exception) {
|
|
160
|
-
ModuleException.INVALID_ENCODING.reject(
|
|
161
|
-
promise,
|
|
162
|
-
Pair(ERROR_USER_INFO_KEY, e.message.orEmpty())
|
|
163
|
-
)
|
|
164
|
-
return;
|
|
165
84
|
}
|
|
166
85
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
promise
|
|
176
|
-
|
|
177
|
-
|
|
86
|
+
@ReactMethod
|
|
87
|
+
fun verify(sign1Data: String, publicKey: ReadableMap, promise: Promise) {
|
|
88
|
+
try {
|
|
89
|
+
val data = Base64Utils.decodeBase64AndBase64Url(sign1Data)
|
|
90
|
+
val result = COSEManager().verifySign1FromJWK(
|
|
91
|
+
dataSigned = data,
|
|
92
|
+
jwk = publicKey.toString()
|
|
93
|
+
)
|
|
94
|
+
promise.resolve(result)
|
|
95
|
+
} catch (e: Exception) {
|
|
96
|
+
promise.reject(ModuleErrorCodes.VERIFY_ERROR, e.message, e)
|
|
97
|
+
}
|
|
178
98
|
}
|
|
179
|
-
}
|
|
180
99
|
|
|
181
100
|
companion object {
|
|
182
101
|
const val NAME = "IoReactNativeCbor"
|
|
183
|
-
const val ERROR_USER_INFO_KEY = "error"
|
|
184
|
-
|
|
185
|
-
private enum class ModuleException(
|
|
186
|
-
val ex: Exception
|
|
187
|
-
) {
|
|
188
|
-
UNABLE_TO_DECODE(Exception("UNABLE_TO_DECODE")),
|
|
189
|
-
PUBLIC_KEY_NOT_FOUND(Exception("PUBLIC_KEY_NOT_FOUND")),
|
|
190
|
-
UNABLE_TO_SIGN(Exception("UNABLE_TO_SIGN")),
|
|
191
|
-
INVALID_ENCODING(Exception("INVALID_ENCODING")),
|
|
192
|
-
UNKNOWN_EXCEPTION(Exception("UNKNOWN_EXCEPTION"));
|
|
193
|
-
|
|
194
|
-
fun reject(
|
|
195
|
-
promise: Promise, vararg args: Pair<String, String>
|
|
196
|
-
) {
|
|
197
|
-
exMap(*args).let {
|
|
198
|
-
promise.reject(it.first, ex.message, it.second)
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
102
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
103
|
+
// Errors which this module uses to reject a promise
|
|
104
|
+
private object ModuleErrorCodes {
|
|
105
|
+
const val DECODE_ERROR = "DECODE_ERROR"
|
|
106
|
+
const val DECODE_DOCUMENTS_ERROR = "DECODE_DOCUMENTS_ERROR"
|
|
107
|
+
const val DECODE_ISSUER_SIGNED_ERROR = "DECODE_ISSUER_SIGNED_ERROR"
|
|
108
|
+
const val SIGN_ERROR = "SIGN_ERROR"
|
|
109
|
+
const val VERIFY_ERROR = "VERIFY_ERROR"
|
|
207
110
|
}
|
|
208
111
|
}
|
|
209
112
|
}
|
|
@@ -9,8 +9,6 @@ import com.facebook.react.bridge.ReadableArray
|
|
|
9
9
|
import com.facebook.react.bridge.ReadableMap
|
|
10
10
|
import com.facebook.react.bridge.ReadableType
|
|
11
11
|
import com.facebook.react.bridge.WritableMap
|
|
12
|
-
import com.facebook.react.bridge.WritableNativeMap
|
|
13
|
-
import com.ioreactnativeiso18013.IoReactNativeCborModule.Companion.ERROR_USER_INFO_KEY
|
|
14
12
|
import it.pagopa.io.wallet.proximity.OpenID4VP
|
|
15
13
|
import it.pagopa.io.wallet.proximity.bluetooth.BleRetrievalMethod
|
|
16
14
|
import it.pagopa.io.wallet.proximity.qr_code.QrEngagement
|
|
@@ -64,11 +62,7 @@ class IoReactNativeIso18013Module(reactContext: ReactApplicationContext) :
|
|
|
64
62
|
setupProximityHandler()
|
|
65
63
|
promise.resolve(true)
|
|
66
64
|
} catch (e: Exception) {
|
|
67
|
-
|
|
68
|
-
ModuleException.START_ERROR.reject(
|
|
69
|
-
promise,
|
|
70
|
-
Pair(ERROR_KEY, getExceptionMessageOrEmpty(e))
|
|
71
|
-
)
|
|
65
|
+
promise.reject(ModuleErrorCodes.START_ERROR, e.message, e)
|
|
72
66
|
}
|
|
73
67
|
}
|
|
74
68
|
|
|
@@ -77,19 +71,38 @@ class IoReactNativeIso18013Module(reactContext: ReactApplicationContext) :
|
|
|
77
71
|
* of ByteArray representing DER encoded X.509 certificates.
|
|
78
72
|
* @param certificates - Two-dimensional array of base64 strings representing DER encoded X.509 certificate
|
|
79
73
|
* @returns An ArrayList of ByteArray representing DER encoded X.509 certificates.
|
|
80
|
-
* @throws
|
|
74
|
+
* @throws IllegalArgumentException if an element in the array is not base64 encoded
|
|
81
75
|
*/
|
|
82
76
|
private fun parseCertificates(certificates: ReadableArray): List<List<ByteArray>> =
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
77
|
+
/** Map the chain arrays and remove null entries. On each chain call the getArray method which
|
|
78
|
+
* can throw and if it does rethrow an exception with information on its position
|
|
79
|
+
*/
|
|
80
|
+
(0 until certificates.size()).mapNotNull { chainIndex ->
|
|
81
|
+
val chain = runCatching { certificates.getArray(chainIndex) }
|
|
82
|
+
.getOrElse { throw IllegalArgumentException("Certificate chain at $chainIndex is not an array", it) }
|
|
83
|
+
?: throw IllegalArgumentException("Certificate chain at index $chainIndex is null")
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Map each chain certificate and remove null entries. On each certificate call the getString
|
|
87
|
+
* method which can throw and if it does rethrow an exception with information on its position
|
|
88
|
+
*/
|
|
89
|
+
(0 until chain.size()).mapNotNull { certIndex ->
|
|
90
|
+
val base64 = runCatching { chain.getString(certIndex) }
|
|
91
|
+
.getOrElse { throw IllegalArgumentException("Failed to get certificate string at chain $chainIndex, cert $certIndex", it) }
|
|
92
|
+
?: throw java.lang.IllegalArgumentException("Certificate at index $certIndex is null")
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Decode the base64 string for each mapped certificate and if an error occurs rethrow
|
|
96
|
+
* an exception with information on its position
|
|
97
|
+
*/
|
|
98
|
+
runCatching {
|
|
99
|
+
Base64Utils.decodeBase64(base64)
|
|
100
|
+
}.getOrElse {
|
|
101
|
+
throw IllegalArgumentException("Certificate at index $certIndex in the chain at index $chainIndex is not a valid base64 string", it)
|
|
102
|
+
}
|
|
92
103
|
}
|
|
104
|
+
}
|
|
105
|
+
|
|
93
106
|
|
|
94
107
|
/**
|
|
95
108
|
* Creates a QR code to be scanned in order to initialize the presentation.
|
|
@@ -103,13 +116,10 @@ class IoReactNativeIso18013Module(reactContext: ReactApplicationContext) :
|
|
|
103
116
|
val qrCodeString = it.getQrCodeString()
|
|
104
117
|
promise.resolve(qrCodeString)
|
|
105
118
|
} ?: run {
|
|
106
|
-
|
|
119
|
+
promise.reject(ModuleErrorCodes.QR_ENGAGEMENT_NOT_DEFINED,NOT_INITIALIZED_ERROR_MESSAGE)
|
|
107
120
|
}
|
|
108
121
|
} catch (e: Exception) {
|
|
109
|
-
|
|
110
|
-
promise,
|
|
111
|
-
Pair(ERROR_KEY, getExceptionMessageOrEmpty(e))
|
|
112
|
-
)
|
|
122
|
+
promise.reject(ModuleErrorCodes.GET_QR_CODE_ERROR, e.message, e)
|
|
113
123
|
}
|
|
114
124
|
}
|
|
115
125
|
|
|
@@ -125,10 +135,7 @@ class IoReactNativeIso18013Module(reactContext: ReactApplicationContext) :
|
|
|
125
135
|
deviceRetrievalHelper?.disconnect()
|
|
126
136
|
promise.resolve(true)
|
|
127
137
|
} catch (e: Exception) {
|
|
128
|
-
|
|
129
|
-
promise,
|
|
130
|
-
Pair(ERROR_KEY, getExceptionMessageOrEmpty(e))
|
|
131
|
-
)
|
|
138
|
+
promise.reject(ModuleErrorCodes.CLOSE_ERROR, message=e.message, e)
|
|
132
139
|
}
|
|
133
140
|
}
|
|
134
141
|
|
|
@@ -150,19 +157,13 @@ class IoReactNativeIso18013Module(reactContext: ReactApplicationContext) :
|
|
|
150
157
|
it.sendErrorResponse(sessionDataStatus)
|
|
151
158
|
promise.resolve(true)
|
|
152
159
|
} else {
|
|
153
|
-
|
|
154
|
-
promise,
|
|
155
|
-
Pair(ERROR_KEY, "Invalid status code")
|
|
156
|
-
)
|
|
160
|
+
promise.reject(ModuleErrorCodes.SEND_ERROR_RESPONSE_ERROR, message="Invalid status code")
|
|
157
161
|
}
|
|
158
162
|
} ?: run {
|
|
159
|
-
|
|
163
|
+
promise.reject(ModuleErrorCodes.QR_ENGAGEMENT_NOT_DEFINED, message=NOT_INITIALIZED_ERROR_MESSAGE)
|
|
160
164
|
}
|
|
161
165
|
} catch (e: Exception) {
|
|
162
|
-
|
|
163
|
-
promise,
|
|
164
|
-
Pair(ERROR_KEY, getExceptionMessageOrEmpty(e))
|
|
165
|
-
)
|
|
166
|
+
promise.reject(ModuleErrorCodes.SEND_ERROR_RESPONSE_ERROR, message=e.message, e)
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
169
|
|
|
@@ -198,20 +199,14 @@ class IoReactNativeIso18013Module(reactContext: ReactApplicationContext) :
|
|
|
198
199
|
}
|
|
199
200
|
|
|
200
201
|
override fun onError(message: String) {
|
|
201
|
-
|
|
202
|
-
promise,
|
|
203
|
-
Pair(ERROR_KEY, message)
|
|
204
|
-
)
|
|
202
|
+
promise.reject(ModuleErrorCodes.GENERATE_RESPONSE_ERROR, message)
|
|
205
203
|
}
|
|
206
204
|
})
|
|
207
205
|
} ?: run {
|
|
208
|
-
|
|
206
|
+
promise.reject(ModuleErrorCodes.DRH_NOT_DEFINED, message=NOT_INITIALIZED_ERROR_MESSAGE)
|
|
209
207
|
}
|
|
210
208
|
} catch (e: Exception) {
|
|
211
|
-
|
|
212
|
-
promise,
|
|
213
|
-
Pair(ERROR_KEY, getExceptionMessageOrEmpty(e))
|
|
214
|
-
)
|
|
209
|
+
promise.reject(ModuleErrorCodes.GENERATE_RESPONSE_ERROR, message=e.message, e)
|
|
215
210
|
}
|
|
216
211
|
}
|
|
217
212
|
|
|
@@ -231,13 +226,10 @@ class IoReactNativeIso18013Module(reactContext: ReactApplicationContext) :
|
|
|
231
226
|
promise.resolve(true)
|
|
232
227
|
}
|
|
233
228
|
?: run {
|
|
234
|
-
|
|
229
|
+
promise.reject(ModuleErrorCodes.QR_ENGAGEMENT_NOT_DEFINED, message=NOT_INITIALIZED_ERROR_MESSAGE)
|
|
235
230
|
}
|
|
236
231
|
} catch (e: Exception) {
|
|
237
|
-
|
|
238
|
-
promise,
|
|
239
|
-
Pair(ERROR_KEY, getExceptionMessageOrEmpty(e))
|
|
240
|
-
)
|
|
232
|
+
promise.reject(ModuleErrorCodes.SEND_RESPONSE_ERROR, e.message, e)
|
|
241
233
|
}
|
|
242
234
|
}
|
|
243
235
|
|
|
@@ -247,32 +239,18 @@ class IoReactNativeIso18013Module(reactContext: ReactApplicationContext) :
|
|
|
247
239
|
mdocGeneratedNonce: String, documents: ReadableArray,
|
|
248
240
|
fieldRequestedAndAccepted: String, promise: Promise
|
|
249
241
|
) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
ModuleException.UNABLE_TO_GENERATE_TRANSCRIPT.reject(
|
|
259
|
-
promise,
|
|
260
|
-
Pair(ERROR_USER_INFO_KEY, e.message.orEmpty())
|
|
261
|
-
)
|
|
262
|
-
return
|
|
263
|
-
}
|
|
242
|
+
try {
|
|
243
|
+
val sessionTranscript =
|
|
244
|
+
OpenID4VP(
|
|
245
|
+
clientId,
|
|
246
|
+
responseUri,
|
|
247
|
+
authorizationRequestNonce,
|
|
248
|
+
mdocGeneratedNonce
|
|
249
|
+
).createSessionTranscript()
|
|
264
250
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
} catch (e: Exception) {
|
|
268
|
-
ModuleException.INVALID_DOC_REQUESTED.reject(
|
|
269
|
-
promise,
|
|
270
|
-
Pair(ERROR_USER_INFO_KEY, e.message.orEmpty())
|
|
271
|
-
)
|
|
272
|
-
return
|
|
273
|
-
}
|
|
251
|
+
val documentsParsed =
|
|
252
|
+
parseDocRequested(documents)
|
|
274
253
|
|
|
275
|
-
try {
|
|
276
254
|
val responseGenerator = ResponseGenerator(sessionTranscript)
|
|
277
255
|
responseGenerator.createResponse(
|
|
278
256
|
documentsParsed,
|
|
@@ -283,18 +261,12 @@ class IoReactNativeIso18013Module(reactContext: ReactApplicationContext) :
|
|
|
283
261
|
}
|
|
284
262
|
|
|
285
263
|
override fun onError(message: String) {
|
|
286
|
-
|
|
287
|
-
promise,
|
|
288
|
-
Pair(ERROR_USER_INFO_KEY, message)
|
|
289
|
-
)
|
|
264
|
+
promise.reject(ModuleErrorCodes.GENERATE_OID4VP_RESPONSE_ERROR, message)
|
|
290
265
|
}
|
|
291
266
|
}
|
|
292
267
|
)
|
|
293
268
|
} catch (e: Exception) {
|
|
294
|
-
|
|
295
|
-
promise,
|
|
296
|
-
Pair(ERROR_USER_INFO_KEY, e.message.orEmpty())
|
|
297
|
-
)
|
|
269
|
+
promise.reject(ModuleErrorCodes.GENERATE_OID4VP_RESPONSE_ERROR, e.message, e)
|
|
298
270
|
}
|
|
299
271
|
}
|
|
300
272
|
|
|
@@ -350,28 +322,31 @@ class IoReactNativeIso18013Module(reactContext: ReactApplicationContext) :
|
|
|
350
322
|
* @throws IllegalArgumentException if the provided document doesn't adhere to the expected format
|
|
351
323
|
*/
|
|
352
324
|
private fun parseDocRequested(documents: ReadableArray): Array<DocRequested> {
|
|
353
|
-
return
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
325
|
+
return try {
|
|
326
|
+
(0 until documents.size()).map { i ->
|
|
327
|
+
val entry = documents.getMap(i)
|
|
328
|
+
?: throw IllegalArgumentException("Entry at index $i in ReadableArray is null")
|
|
329
|
+
val alias = entry.getString("alias")
|
|
330
|
+
val issuerSignedContentStr = entry.getString("issuerSignedContent")
|
|
331
|
+
val docType = entry.getString("docType")
|
|
332
|
+
|
|
333
|
+
if (
|
|
334
|
+
alias == null || entry.getType("alias") != ReadableType.String ||
|
|
335
|
+
issuerSignedContentStr == null || entry.getType("issuerSignedContent") != ReadableType.String ||
|
|
336
|
+
docType == null || entry.getType("docType") != ReadableType.String
|
|
337
|
+
) throw IllegalArgumentException("Unable to decode the provided documents at index $i")
|
|
338
|
+
|
|
339
|
+
val issuerSignedContent = Base64Utils.decodeBase64AndBase64Url(issuerSignedContentStr)
|
|
340
|
+
|
|
341
|
+
DocRequested(
|
|
342
|
+
issuerSignedContent,
|
|
343
|
+
alias,
|
|
344
|
+
docType
|
|
345
|
+
)
|
|
346
|
+
}.toTypedArray()
|
|
347
|
+
} catch (e: Exception) {
|
|
348
|
+
throw IllegalArgumentException("Failed to parse documents: ${e.message}", e)
|
|
349
|
+
}
|
|
375
350
|
}
|
|
376
351
|
|
|
377
352
|
/**
|
|
@@ -398,44 +373,24 @@ class IoReactNativeIso18013Module(reactContext: ReactApplicationContext) :
|
|
|
398
373
|
*/
|
|
399
374
|
}
|
|
400
375
|
|
|
401
|
-
private enum class ModuleException(
|
|
402
|
-
val ex: Exception
|
|
403
|
-
) {
|
|
404
|
-
/** ISO18013-5 related errors **/
|
|
405
|
-
DRH_NOT_DEFINED(Exception("DRH_NOT_DEFINED")),
|
|
406
|
-
QR_ENGAGEMENT_NOT_DEFINED_ERROR(Exception("QR_ENGAGEMENT_NOT_DEFINED_ERROR")),
|
|
407
|
-
START_ERROR(Exception("START_ERROR")),
|
|
408
|
-
GET_QR_CODE_ERROR(Exception("GET_QR_CODE_ERROR")),
|
|
409
|
-
GENERATE_RESPONSE_ERROR(Exception("GENERATE_RESPONSE_ERROR")),
|
|
410
|
-
SEND_RESPONSE_ERROR(Exception("SEND_RESPONSE_ERROR")),
|
|
411
|
-
SEND_ERROR_RESPONSE_ERROR(Exception("SEND_ERROR_RESPONSE_ERROR")),
|
|
412
|
-
CLOSE_ERROR(Exception("CLOSE_ERROR")),
|
|
413
|
-
|
|
414
|
-
/** ISO18013-7 related errors **/
|
|
415
|
-
UNABLE_TO_GENERATE_RESPONSE(Exception("UNABLE_TO_GENERATE_RESPONSE")),
|
|
416
|
-
UNABLE_TO_GENERATE_TRANSCRIPT(Exception("UNABLE_TO_GENERATE_TRANSCRIPT")),
|
|
417
|
-
INVALID_DOC_REQUESTED(Exception("INVALID_DOC_REQUESTED")),
|
|
418
|
-
GENERATE_OID4VP_DEVICE_RESPONSE_FAILED(Exception("GENERATE_OID4VP_DEVICE_RESPONSE_FAILED"));
|
|
419
|
-
|
|
420
|
-
fun reject(
|
|
421
|
-
promise: Promise, vararg args: Pair<String, String>
|
|
422
|
-
) {
|
|
423
|
-
exMap(*args).let {
|
|
424
|
-
promise.reject(it.first, ex.message, it.second)
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
private fun exMap(vararg args: Pair<String, String>): Pair<String, WritableMap> {
|
|
429
|
-
val writableMap = WritableNativeMap()
|
|
430
|
-
args.forEach { writableMap.putString(it.first, it.second) }
|
|
431
|
-
return Pair(this.ex.message ?: "UNKNOWN", writableMap)
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
private fun getExceptionMessageOrEmpty(e: Exception): String = e.message ?: ""
|
|
436
|
-
|
|
437
376
|
companion object {
|
|
438
377
|
const val NAME = "IoReactNativeIso18013"
|
|
439
|
-
const val
|
|
378
|
+
const val NOT_INITIALIZED_ERROR_MESSAGE = "Resources not initialized properly, call the start method before this one."
|
|
379
|
+
|
|
380
|
+
// Errors which this module uses to reject a promise
|
|
381
|
+
private object ModuleErrorCodes {
|
|
382
|
+
// ISO18013-5 related errors
|
|
383
|
+
const val DRH_NOT_DEFINED = "DRH_NOT_DEFINED"
|
|
384
|
+
const val QR_ENGAGEMENT_NOT_DEFINED = "QR_ENGAGEMENT_NOT_DEFINED"
|
|
385
|
+
const val START_ERROR = "START_ERROR"
|
|
386
|
+
const val GET_QR_CODE_ERROR = "GET_QR_CODE_ERROR"
|
|
387
|
+
const val GENERATE_RESPONSE_ERROR = "GENERATE_RESPONSE_ERROR"
|
|
388
|
+
const val SEND_RESPONSE_ERROR = "SEND_RESPONSE_ERROR"
|
|
389
|
+
const val SEND_ERROR_RESPONSE_ERROR = "SEND_ERROR_RESPONSE_ERROR"
|
|
390
|
+
const val CLOSE_ERROR = "CLOSE_ERROR"
|
|
391
|
+
|
|
392
|
+
// ISO18013-7 related errors
|
|
393
|
+
const val GENERATE_OID4VP_RESPONSE_ERROR = "GENERATE_OID4VP_RESPONSE_ERROR"
|
|
394
|
+
}
|
|
440
395
|
}
|
|
441
396
|
}
|
package/ios/Base64Utils.swift
CHANGED
|
@@ -4,8 +4,15 @@ import Foundation
|
|
|
4
4
|
* This class contains a set of utilities for encoding and decoding base64 and base64url strings.
|
|
5
5
|
*/
|
|
6
6
|
class Base64Utils {
|
|
7
|
-
enum Base64DecodingError:
|
|
8
|
-
|
|
7
|
+
enum Base64DecodingError: LocalizedError {
|
|
8
|
+
case invalidBase64
|
|
9
|
+
|
|
10
|
+
var errorDescription: String? {
|
|
11
|
+
switch self {
|
|
12
|
+
case .invalidBase64:
|
|
13
|
+
return "Input is not a valid Base64 or Base64URL string"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
9
16
|
}
|
|
10
17
|
|
|
11
18
|
/**
|
|
@@ -24,7 +31,7 @@ class Base64Utils {
|
|
|
24
31
|
} else if let data = Data(base64Encoded: base) {
|
|
25
32
|
return data
|
|
26
33
|
} else {
|
|
27
|
-
throw Base64DecodingError.invalidBase64
|
|
34
|
+
throw Base64DecodingError.invalidBase64
|
|
28
35
|
}
|
|
29
36
|
}
|
|
30
37
|
|