@doko/react-native-yubikit 0.0.2

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.
Files changed (144) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +126 -0
  3. package/RNYubikit.podspec +22 -0
  4. package/android/build.gradle +63 -0
  5. package/android/src/main/AndroidManifest.xml +9 -0
  6. package/android/src/main/java/com/yubikit/YubiKitManagerHolder.kt +330 -0
  7. package/android/src/main/java/com/yubikit/YubikitCoreModule.kt +142 -0
  8. package/android/src/main/java/com/yubikit/YubikitFidoModule.kt +418 -0
  9. package/android/src/main/java/com/yubikit/YubikitManagementModule.kt +132 -0
  10. package/android/src/main/java/com/yubikit/YubikitOathModule.kt +224 -0
  11. package/android/src/main/java/com/yubikit/YubikitOpenPgpModule.kt +317 -0
  12. package/android/src/main/java/com/yubikit/YubikitPackage.kt +44 -0
  13. package/android/src/main/java/com/yubikit/YubikitPivModule.kt +310 -0
  14. package/android/src/main/java/com/yubikit/YubikitSupportModule.kt +108 -0
  15. package/android/src/main/java/com/yubikit/YubikitYubiOtpModule.kt +248 -0
  16. package/android/src/main/java/com/yubikit/utils/YubikitUtils.kt +321 -0
  17. package/ios/YubikitCore.h +5 -0
  18. package/ios/YubikitCore.mm +101 -0
  19. package/ios/YubikitDeviceInfoHelper.h +13 -0
  20. package/ios/YubikitDeviceInfoHelper.mm +110 -0
  21. package/ios/YubikitFido.h +5 -0
  22. package/ios/YubikitFido.mm +373 -0
  23. package/ios/YubikitManagement.h +5 -0
  24. package/ios/YubikitManagement.mm +153 -0
  25. package/ios/YubikitManager.h +27 -0
  26. package/ios/YubikitManager.m +169 -0
  27. package/ios/YubikitOath.h +5 -0
  28. package/ios/YubikitOath.mm +583 -0
  29. package/ios/YubikitOpenPgp.h +5 -0
  30. package/ios/YubikitOpenPgp.mm +210 -0
  31. package/ios/YubikitPiv.h +5 -0
  32. package/ios/YubikitPiv.mm +813 -0
  33. package/ios/YubikitSupport.h +5 -0
  34. package/ios/YubikitSupport.mm +58 -0
  35. package/ios/YubikitYubiOtp.h +5 -0
  36. package/ios/YubikitYubiOtp.mm +120 -0
  37. package/lib/module/core.js +34 -0
  38. package/lib/module/core.js.map +1 -0
  39. package/lib/module/fido.js +40 -0
  40. package/lib/module/fido.js.map +1 -0
  41. package/lib/module/hooks/index.js +5 -0
  42. package/lib/module/hooks/index.js.map +1 -0
  43. package/lib/module/hooks/use-yubikey.js +12 -0
  44. package/lib/module/hooks/use-yubikey.js.map +1 -0
  45. package/lib/module/hooks/yubikey-provider.js +85 -0
  46. package/lib/module/hooks/yubikey-provider.js.map +1 -0
  47. package/lib/module/index.js +12 -0
  48. package/lib/module/index.js.map +1 -0
  49. package/lib/module/management.js +17 -0
  50. package/lib/module/management.js.map +1 -0
  51. package/lib/module/oath.js +53 -0
  52. package/lib/module/oath.js.map +1 -0
  53. package/lib/module/openpgp.js +89 -0
  54. package/lib/module/openpgp.js.map +1 -0
  55. package/lib/module/package.json +1 -0
  56. package/lib/module/piv.js +71 -0
  57. package/lib/module/piv.js.map +1 -0
  58. package/lib/module/specs/NativeYubikitCore.js +10 -0
  59. package/lib/module/specs/NativeYubikitCore.js.map +1 -0
  60. package/lib/module/specs/NativeYubikitFido.js +5 -0
  61. package/lib/module/specs/NativeYubikitFido.js.map +1 -0
  62. package/lib/module/specs/NativeYubikitManagement.js +5 -0
  63. package/lib/module/specs/NativeYubikitManagement.js.map +1 -0
  64. package/lib/module/specs/NativeYubikitOath.js +5 -0
  65. package/lib/module/specs/NativeYubikitOath.js.map +1 -0
  66. package/lib/module/specs/NativeYubikitOpenPgp.js +5 -0
  67. package/lib/module/specs/NativeYubikitOpenPgp.js.map +1 -0
  68. package/lib/module/specs/NativeYubikitPiv.js +5 -0
  69. package/lib/module/specs/NativeYubikitPiv.js.map +1 -0
  70. package/lib/module/specs/NativeYubikitSupport.js +5 -0
  71. package/lib/module/specs/NativeYubikitSupport.js.map +1 -0
  72. package/lib/module/specs/NativeYubikitYubiOtp.js +5 -0
  73. package/lib/module/specs/NativeYubikitYubiOtp.js.map +1 -0
  74. package/lib/module/support.js +11 -0
  75. package/lib/module/support.js.map +1 -0
  76. package/lib/module/types.js +2 -0
  77. package/lib/module/types.js.map +1 -0
  78. package/lib/module/yubiotp.js +32 -0
  79. package/lib/module/yubiotp.js.map +1 -0
  80. package/lib/typescript/package.json +1 -0
  81. package/lib/typescript/src/core.d.ts +14 -0
  82. package/lib/typescript/src/core.d.ts.map +1 -0
  83. package/lib/typescript/src/fido.d.ts +24 -0
  84. package/lib/typescript/src/fido.d.ts.map +1 -0
  85. package/lib/typescript/src/hooks/index.d.ts +3 -0
  86. package/lib/typescript/src/hooks/index.d.ts.map +1 -0
  87. package/lib/typescript/src/hooks/use-yubikey.d.ts +3 -0
  88. package/lib/typescript/src/hooks/use-yubikey.d.ts.map +1 -0
  89. package/lib/typescript/src/hooks/yubikey-provider.d.ts +23 -0
  90. package/lib/typescript/src/hooks/yubikey-provider.d.ts.map +1 -0
  91. package/lib/typescript/src/index.d.ts +10 -0
  92. package/lib/typescript/src/index.d.ts.map +1 -0
  93. package/lib/typescript/src/management.d.ts +8 -0
  94. package/lib/typescript/src/management.d.ts.map +1 -0
  95. package/lib/typescript/src/oath.d.ts +20 -0
  96. package/lib/typescript/src/oath.d.ts.map +1 -0
  97. package/lib/typescript/src/openpgp.d.ts +35 -0
  98. package/lib/typescript/src/openpgp.d.ts.map +1 -0
  99. package/lib/typescript/src/piv.d.ts +26 -0
  100. package/lib/typescript/src/piv.d.ts.map +1 -0
  101. package/lib/typescript/src/specs/NativeYubikitCore.d.ts +49 -0
  102. package/lib/typescript/src/specs/NativeYubikitCore.d.ts.map +1 -0
  103. package/lib/typescript/src/specs/NativeYubikitFido.d.ts +121 -0
  104. package/lib/typescript/src/specs/NativeYubikitFido.d.ts.map +1 -0
  105. package/lib/typescript/src/specs/NativeYubikitManagement.d.ts +53 -0
  106. package/lib/typescript/src/specs/NativeYubikitManagement.d.ts.map +1 -0
  107. package/lib/typescript/src/specs/NativeYubikitOath.d.ts +70 -0
  108. package/lib/typescript/src/specs/NativeYubikitOath.d.ts.map +1 -0
  109. package/lib/typescript/src/specs/NativeYubikitOpenPgp.d.ts +53 -0
  110. package/lib/typescript/src/specs/NativeYubikitOpenPgp.d.ts.map +1 -0
  111. package/lib/typescript/src/specs/NativeYubikitPiv.d.ts +47 -0
  112. package/lib/typescript/src/specs/NativeYubikitPiv.d.ts.map +1 -0
  113. package/lib/typescript/src/specs/NativeYubikitSupport.d.ts +49 -0
  114. package/lib/typescript/src/specs/NativeYubikitSupport.d.ts.map +1 -0
  115. package/lib/typescript/src/specs/NativeYubikitYubiOtp.d.ts +45 -0
  116. package/lib/typescript/src/specs/NativeYubikitYubiOtp.d.ts.map +1 -0
  117. package/lib/typescript/src/support.d.ts +6 -0
  118. package/lib/typescript/src/support.d.ts.map +1 -0
  119. package/lib/typescript/src/types.d.ts +293 -0
  120. package/lib/typescript/src/types.d.ts.map +1 -0
  121. package/lib/typescript/src/yubiotp.d.ts +13 -0
  122. package/lib/typescript/src/yubiotp.d.ts.map +1 -0
  123. package/package.json +181 -0
  124. package/src/core.ts +58 -0
  125. package/src/fido.ts +112 -0
  126. package/src/hooks/index.tsx +2 -0
  127. package/src/hooks/use-yubikey.tsx +10 -0
  128. package/src/hooks/yubikey-provider.tsx +146 -0
  129. package/src/index.tsx +10 -0
  130. package/src/management.ts +44 -0
  131. package/src/oath.ts +134 -0
  132. package/src/openpgp.ts +220 -0
  133. package/src/piv.ts +193 -0
  134. package/src/specs/NativeYubikitCore.ts +68 -0
  135. package/src/specs/NativeYubikitFido.ts +149 -0
  136. package/src/specs/NativeYubikitManagement.ts +78 -0
  137. package/src/specs/NativeYubikitOath.ts +110 -0
  138. package/src/specs/NativeYubikitOpenPgp.ts +148 -0
  139. package/src/specs/NativeYubikitPiv.ts +108 -0
  140. package/src/specs/NativeYubikitSupport.ts +61 -0
  141. package/src/specs/NativeYubikitYubiOtp.ts +82 -0
  142. package/src/support.ts +18 -0
  143. package/src/types.ts +404 -0
  144. package/src/yubiotp.ts +96 -0
@@ -0,0 +1,321 @@
1
+ package com.yubikit.utils
2
+
3
+ import android.os.Bundle
4
+ import android.util.Base64
5
+ import com.facebook.react.bridge.Arguments
6
+ import com.facebook.react.bridge.ReadableArray
7
+ import com.facebook.react.bridge.ReadableMap
8
+ import com.facebook.react.bridge.WritableArray
9
+ import com.facebook.react.bridge.WritableMap
10
+ import com.yubico.yubikit.core.Transport
11
+ import com.yubico.yubikit.core.Version
12
+ import com.yubico.yubikit.core.UsbInterface
13
+ import com.yubico.yubikit.management.Capability
14
+ import com.yubico.yubikit.management.DeviceConfig
15
+ import com.yubico.yubikit.management.DeviceInfo
16
+ import com.yubico.yubikit.management.FormFactor
17
+ import com.yubico.yubikit.oath.AccessKey
18
+ import com.yubico.yubikit.oath.Code
19
+ import com.yubico.yubikit.oath.Credential
20
+ import com.yubico.yubikit.oath.CredentialData
21
+ import com.yubico.yubikit.oath.HashAlgorithm
22
+ import com.yubico.yubikit.oath.OathType
23
+ import com.yubico.yubikit.piv.KeyType
24
+ import com.yubico.yubikit.piv.ManagementKeyType
25
+ import com.yubico.yubikit.piv.PinPolicy
26
+ import com.yubico.yubikit.piv.Slot
27
+ import com.yubico.yubikit.piv.TouchPolicy
28
+ import javax.crypto.Mac
29
+ import javax.crypto.spec.SecretKeySpec
30
+
31
+ object YubikitUtils {
32
+
33
+ @JvmStatic
34
+ fun base64Encode(bytes: ByteArray?): String? {
35
+ return bytes?.let { Base64.encodeToString(it, Base64.NO_WRAP) }
36
+ }
37
+
38
+ @JvmStatic
39
+ fun base64Decode(encoded: String?): ByteArray? {
40
+ return encoded?.let { Base64.decode(it, Base64.DEFAULT) }
41
+ }
42
+
43
+ @JvmStatic
44
+ fun versionToMap(version: Version): WritableMap {
45
+ return Arguments.createMap().apply {
46
+ putInt("major", version.major.toInt())
47
+ putInt("minor", version.minor.toInt())
48
+ putInt("micro", version.micro.toInt())
49
+ }
50
+ }
51
+
52
+ @JvmStatic
53
+ fun parseVersion(map: ReadableMap?): Version? {
54
+ if (map == null) return null
55
+ return Version(
56
+ map.getInt("major"),
57
+ map.getInt("minor"),
58
+ map.getInt("micro")
59
+ )
60
+ }
61
+
62
+ @JvmStatic
63
+ fun transportFromString(value: String?): Transport {
64
+ return when (value?.uppercase()) {
65
+ "USB" -> Transport.USB
66
+ "NFC" -> Transport.NFC
67
+ else -> throw IllegalArgumentException("Unknown transport: $value")
68
+ }
69
+ }
70
+
71
+ @JvmStatic
72
+ fun transportToString(transport: Transport): String {
73
+ return transport.name
74
+ }
75
+
76
+ @JvmStatic
77
+ fun capabilityToString(capability: Capability): String {
78
+ return capability.name
79
+ }
80
+
81
+ @JvmStatic
82
+ fun capabilityFromString(value: String): Capability {
83
+ return Capability.valueOf(value)
84
+ }
85
+
86
+ @JvmStatic
87
+ fun formFactorToString(formFactor: FormFactor): String {
88
+ return formFactor.name
89
+ }
90
+
91
+ @JvmStatic
92
+ fun formFactorFromString(value: String): FormFactor {
93
+ return FormFactor.valueOf(value)
94
+ }
95
+
96
+ @JvmStatic
97
+ fun oathTypeFromString(value: String): OathType {
98
+ return OathType.valueOf(value)
99
+ }
100
+
101
+ @JvmStatic
102
+ fun oathTypeToString(type: OathType): String {
103
+ return type.name
104
+ }
105
+
106
+ @JvmStatic
107
+ fun hashAlgorithmFromString(value: String): HashAlgorithm {
108
+ return HashAlgorithm.valueOf(value)
109
+ }
110
+
111
+ @JvmStatic
112
+ fun hashAlgorithmToString(algorithm: HashAlgorithm): String {
113
+ return algorithm.name
114
+ }
115
+
116
+ @JvmStatic
117
+ fun slotFromString(value: String): Slot {
118
+ return Slot.valueOf(value)
119
+ }
120
+
121
+ @JvmStatic
122
+ fun slotToString(slot: Slot): String {
123
+ return slot.name
124
+ }
125
+
126
+ @JvmStatic
127
+ fun keyTypeFromString(value: String): KeyType {
128
+ return KeyType.valueOf(value)
129
+ }
130
+
131
+ @JvmStatic
132
+ fun keyTypeToString(keyType: KeyType): String {
133
+ return keyType.name
134
+ }
135
+
136
+ @JvmStatic
137
+ fun pinPolicyFromString(value: String): PinPolicy {
138
+ return PinPolicy.valueOf(value)
139
+ }
140
+
141
+ @JvmStatic
142
+ fun pinPolicyToString(policy: PinPolicy): String {
143
+ return policy.name
144
+ }
145
+
146
+ @JvmStatic
147
+ fun touchPolicyFromString(value: String): TouchPolicy {
148
+ return TouchPolicy.valueOf(value)
149
+ }
150
+
151
+ @JvmStatic
152
+ fun touchPolicyToString(policy: TouchPolicy): String {
153
+ return policy.name
154
+ }
155
+
156
+ @JvmStatic
157
+ fun managementKeyTypeFromString(value: String): ManagementKeyType {
158
+ return ManagementKeyType.valueOf(value)
159
+ }
160
+
161
+ @JvmStatic
162
+ fun managementKeyTypeToString(type: ManagementKeyType): String {
163
+ return type.name
164
+ }
165
+
166
+ @JvmStatic
167
+ fun deviceInfoToMap(info: DeviceInfo): WritableMap {
168
+ return Arguments.createMap().apply {
169
+ putMap("version", versionToMap(info.version))
170
+ putString("versionName", info.versionName)
171
+ putString("formFactor", formFactorToString(info.formFactor))
172
+ info.serialNumber?.let { putInt("serialNumber", it) }
173
+ putBoolean("isLocked", info.isLocked)
174
+ putBoolean("isFips", info.isFips)
175
+ putBoolean("isSky", info.isSky)
176
+ info.partNumber?.let { putString("partNumber", it) }
177
+ putInt("fipsCapable", info.fipsCapable)
178
+ putInt("fipsApproved", info.fipsApproved)
179
+ putBoolean("pinComplexity", info.pinComplexity)
180
+ putInt("resetBlocked", info.resetBlocked)
181
+ putMap("supportedCapabilities", capabilitiesToMap(info))
182
+ putBoolean("hasTransportUsb", info.hasTransport(Transport.USB))
183
+ putBoolean("hasTransportNfc", info.hasTransport(Transport.NFC))
184
+ info.config?.let { putMap("config", deviceConfigToMap(it)) }
185
+ info.fpsVersion?.let { putMap("fpsVersion", versionToMap(it)) }
186
+ info.stmVersion?.let { putMap("stmVersion", versionToMap(it)) }
187
+ }
188
+ }
189
+
190
+ @JvmStatic
191
+ fun capabilitiesToMap(info: DeviceInfo): WritableMap {
192
+ return Arguments.createMap().apply {
193
+ listOf(Transport.USB, Transport.NFC).forEach { transport ->
194
+ info.getSupportedCapabilities(transport)?.let { value ->
195
+ putInt(transport.name.lowercase(), value)
196
+ }
197
+ }
198
+ }
199
+ }
200
+
201
+ @JvmStatic
202
+ fun deviceConfigToMap(config: DeviceConfig): WritableMap {
203
+ return Arguments.createMap().apply {
204
+ val capsMap = Arguments.createMap()
205
+ var hasCaps = false
206
+ listOf(Transport.USB, Transport.NFC).forEach { transport ->
207
+ config.getEnabledCapabilities(transport)?.let { value ->
208
+ capsMap.putInt(transport.name.lowercase(), value)
209
+ hasCaps = true
210
+ }
211
+ }
212
+ if (hasCaps) {
213
+ putMap("enabledCapabilities", capsMap)
214
+ }
215
+ config.autoEjectTimeout?.let { putInt("autoEjectTimeout", it.toInt()) }
216
+ config.challengeResponseTimeout?.let { putInt("challengeResponseTimeout", it.toInt()) }
217
+ config.nfcRestricted?.let { putBoolean("nfcRestricted", it) }
218
+ config.deviceFlags?.let { putInt("deviceFlags", it) }
219
+ }
220
+ }
221
+
222
+ @JvmStatic
223
+ fun parseDeviceConfig(map: ReadableMap?): DeviceConfig {
224
+ if (map == null) return DeviceConfig.Builder().build()
225
+ val builder = DeviceConfig.Builder()
226
+ map.getMap("enabledCapabilities")?.let { capsMap ->
227
+ listOf(Transport.USB, Transport.NFC).forEach { transport ->
228
+ val key = transport.name.lowercase()
229
+ if (capsMap.hasKey(key) && !capsMap.isNull(key)) {
230
+ builder.enabledCapabilities(transport, capsMap.getInt(key))
231
+ }
232
+ }
233
+ }
234
+ if (map.hasKey("autoEjectTimeout") && !map.isNull("autoEjectTimeout")) {
235
+ builder.autoEjectTimeout(map.getInt("autoEjectTimeout").toShort())
236
+ }
237
+ if (map.hasKey("challengeResponseTimeout") && !map.isNull("challengeResponseTimeout")) {
238
+ builder.challengeResponseTimeout(map.getInt("challengeResponseTimeout").toByte())
239
+ }
240
+ if (map.hasKey("nfcRestricted") && !map.isNull("nfcRestricted")) {
241
+ builder.nfcRestricted(map.getBoolean("nfcRestricted"))
242
+ }
243
+ if (map.hasKey("deviceFlags") && !map.isNull("deviceFlags")) {
244
+ builder.deviceFlags(map.getInt("deviceFlags"))
245
+ }
246
+ return builder.build()
247
+ }
248
+
249
+ @JvmStatic
250
+ fun credentialToMap(credential: Credential): WritableMap {
251
+ return Arguments.createMap().apply {
252
+ putString("id", base64Encode(credential.id))
253
+ putString("oathType", oathTypeToString(credential.oathType))
254
+ putString("accountName", credential.accountName)
255
+ credential.issuer?.let { putString("issuer", it) }
256
+ putInt("period", credential.period)
257
+ putBoolean("touchRequired", credential.isTouchRequired)
258
+ }
259
+ }
260
+
261
+ @JvmStatic
262
+ fun credentialDataFromMap(map: ReadableMap): CredentialData {
263
+ return CredentialData(
264
+ map.getString("accountName") ?: "",
265
+ oathTypeFromString(map.getString("oathType") ?: "TOTP"),
266
+ hashAlgorithmFromString(map.getString("hashAlgorithm") ?: "SHA1"),
267
+ base64Decode(map.getString("secret")) ?: byteArrayOf(),
268
+ map.getInt("digits"),
269
+ map.getInt("period"),
270
+ map.getInt("counter"),
271
+ map.getString("issuer")
272
+ )
273
+ }
274
+
275
+ @JvmStatic
276
+ fun codeToMap(code: Code): WritableMap {
277
+ return Arguments.createMap().apply {
278
+ putString("value", code.value)
279
+ putDouble("validFrom", code.validFrom.toDouble())
280
+ putDouble("validUntil", code.validUntil.toDouble())
281
+ }
282
+ }
283
+
284
+ @JvmStatic
285
+ fun parseUsbMode(mode: String): UsbInterface.Mode {
286
+ return UsbInterface.Mode.valueOf(mode)
287
+ }
288
+
289
+ @JvmStatic
290
+ fun readableArrayToBytes(array: ReadableArray?): ByteArray? {
291
+ if (array == null) return null
292
+ return ByteArray(array.size()) { array.getInt(it).toByte() }
293
+ }
294
+
295
+ @JvmStatic
296
+ fun bytesToWritableArray(bytes: ByteArray?): WritableArray? {
297
+ if (bytes == null) return null
298
+ return Arguments.createArray().apply {
299
+ bytes.forEach { pushInt(it.toInt()) }
300
+ }
301
+ }
302
+
303
+ @JvmStatic
304
+ fun Bundle.toWritableMap(): WritableMap {
305
+ return Arguments.fromBundle(this)
306
+ }
307
+
308
+ @JvmStatic
309
+ fun accessKeyFromBytes(key: ByteArray?): AccessKey? {
310
+ if (key == null) return null
311
+ return ByteArrayAccessKey(key)
312
+ }
313
+ }
314
+
315
+ private class ByteArrayAccessKey(private val key: ByteArray) : AccessKey {
316
+ override fun calculateResponse(challenge: ByteArray): ByteArray {
317
+ val mac = Mac.getInstance("HmacSHA1")
318
+ mac.init(SecretKeySpec(key, "HmacSHA1"))
319
+ return mac.doFinal(challenge)
320
+ }
321
+ }
@@ -0,0 +1,5 @@
1
+ #import <YubikitSpec/YubikitSpec.h>
2
+
3
+ @interface YubikitCore : NativeYubikitCoreSpecBase <NativeYubikitCoreSpec>
4
+
5
+ @end
@@ -0,0 +1,101 @@
1
+ #import "YubikitCore.h"
2
+ #import "YubikitManager.h"
3
+ #import <YubiKit/YubiKit.h>
4
+
5
+ @implementation YubikitCore
6
+
7
+ RCT_EXPORT_MODULE(YubikitCore)
8
+
9
+ - (instancetype)init {
10
+ self = [super init];
11
+ if (self) {
12
+ __weak YubikitCore *weakSelf = self;
13
+ [YubikitManager shared].eventHandler = ^(NSString *type, NSDictionary * _Nullable payload) {
14
+ YubikitCore *strongSelf = weakSelf;
15
+ if (strongSelf == nil) return;
16
+ NSMutableDictionary *body = [NSMutableDictionary dictionaryWithDictionary:payload ?: @{}];
17
+ body[@"type"] = type;
18
+ [strongSelf emitOnYubiKeyEvent:body];
19
+ };
20
+ }
21
+ return self;
22
+ }
23
+
24
+ - (void)startUsbDiscovery:(JS::NativeYubikitCore::UsbConfiguration &)config {
25
+ [[YubikitManager shared] startUsbDiscovery];
26
+ }
27
+
28
+ - (void)stopUsbDiscovery {
29
+ [[YubikitManager shared] stopUsbDiscovery];
30
+ }
31
+
32
+ - (void)startNfcDiscovery:(JS::NativeYubikitCore::NfcConfiguration &)config {
33
+ [[YubikitManager shared] startNfcDiscovery];
34
+ }
35
+
36
+ - (void)stopNfcDiscovery {
37
+ [[YubikitManager shared] stopNfcDiscovery];
38
+ }
39
+
40
+ - (void)requestConnection:(NSString *)deviceHandle
41
+ connectionType:(NSString *)connectionType
42
+ resolve:(RCTPromiseResolveBlock)resolve
43
+ reject:(RCTPromiseRejectBlock)reject {
44
+ id<YKFConnectionProtocol> connection = [[YubikitManager shared] connectionForHandle:deviceHandle];
45
+ if (connection == nil) {
46
+ reject(@"CONNECTION_ERROR", @"No device found for handle", nil);
47
+ return;
48
+ }
49
+ resolve(deviceHandle);
50
+ }
51
+
52
+ - (void)sendApdu:(NSString *)connectionHandle
53
+ apdu:(NSString *)apdu
54
+ resolve:(RCTPromiseResolveBlock)resolve
55
+ reject:(RCTPromiseRejectBlock)reject {
56
+ id<YKFConnectionProtocol> connection = [[YubikitManager shared] connectionForHandle:connectionHandle];
57
+ if (connection == nil) {
58
+ reject(@"CONNECTION_ERROR", @"No device found for handle", nil);
59
+ return;
60
+ }
61
+
62
+ NSData *apduData = [[NSData alloc] initWithBase64EncodedString:apdu options:0];
63
+ if (apduData == nil) {
64
+ reject(@"APDU_ERROR", @"Invalid base64 APDU", nil);
65
+ return;
66
+ }
67
+
68
+ YKFAPDU *command = [[YKFAPDU alloc] initWithData:apduData];
69
+ if (command == nil) {
70
+ reject(@"APDU_ERROR", @"Invalid APDU", nil);
71
+ return;
72
+ }
73
+
74
+ YKFSmartCardInterface *interface = connection.smartCardInterface;
75
+ if (interface == nil) {
76
+ reject(@"APDU_ERROR", @"Smart card interface not available", nil);
77
+ return;
78
+ }
79
+
80
+ [interface executeCommand:command completion:^(NSData * _Nullable response, NSError * _Nullable error) {
81
+ if (error) {
82
+ reject(@"APDU_ERROR", error.localizedDescription, error);
83
+ return;
84
+ }
85
+ resolve([response base64EncodedStringWithOptions:0]);
86
+ }];
87
+ }
88
+
89
+ - (void)closeConnection:(NSString *)connectionHandle {
90
+ [[YubikitManager shared] removeConnectionForHandle:connectionHandle];
91
+ }
92
+
93
+ - (NSArray<NSDictionary *> *)getDiscoveredDevices {
94
+ return [[YubikitManager shared] listDevices];
95
+ }
96
+
97
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
98
+ return std::make_shared<facebook::react::NativeYubikitCoreSpecJSI>(params);
99
+ }
100
+
101
+ @end
@@ -0,0 +1,13 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ @class YKFManagementDeviceInfo;
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ @interface YubikitDeviceInfoHelper : NSObject
8
+
9
+ + (NSDictionary *)dictionaryFromDeviceInfo:(YKFManagementDeviceInfo *)deviceInfo;
10
+
11
+ @end
12
+
13
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,110 @@
1
+ #import "YubikitDeviceInfoHelper.h"
2
+ #import <YubiKit/YubiKit.h>
3
+
4
+ @implementation YubikitDeviceInfoHelper
5
+
6
+ + (NSDictionary *)dictionaryFromDeviceInfo:(YKFManagementDeviceInfo *)deviceInfo {
7
+ YKFManagementInterfaceConfiguration *config = deviceInfo.configuration;
8
+ NSMutableDictionary *result = [NSMutableDictionary dictionary];
9
+
10
+ YKFVersion *version = deviceInfo.version;
11
+ NSString *versionName = [NSString stringWithFormat:@"%d.%d.%d", version.major, version.minor, version.micro];
12
+ result[@"version"] = @{
13
+ @"major": @(version.major),
14
+ @"minor": @(version.minor),
15
+ @"micro": @(version.micro)
16
+ };
17
+ result[@"versionName"] = versionName;
18
+
19
+ NSString *formFactor = @"UNKNOWN";
20
+ switch (deviceInfo.formFactor) {
21
+ case YKFFormFactorUSBAKeychain:
22
+ formFactor = @"USB_A_KEYCHAIN";
23
+ break;
24
+ case YKFFormFactorUSBANano:
25
+ formFactor = @"USB_A_NANO";
26
+ break;
27
+ case YKFFormFactorUSBCKeychain:
28
+ formFactor = @"USB_C_KEYCHAIN";
29
+ break;
30
+ case YKFFormFactorUSBCNano:
31
+ formFactor = @"USB_C_NANO";
32
+ break;
33
+ case YKFFormFactorUSBCLightning:
34
+ formFactor = @"USB_C_LIGHTNING";
35
+ break;
36
+ case YKFFormFactorUSBABio:
37
+ formFactor = @"USB_A_BIO";
38
+ break;
39
+ case YKFFormFactorUSBCBio:
40
+ formFactor = @"USB_C_BIO";
41
+ break;
42
+ default:
43
+ break;
44
+ }
45
+ result[@"formFactor"] = formFactor;
46
+
47
+ result[@"serialNumber"] = @(deviceInfo.serialNumber);
48
+ result[@"isLocked"] = @(deviceInfo.isConfigurationLocked);
49
+ if (deviceInfo.partNumber != nil) {
50
+ result[@"partNumber"] = deviceInfo.partNumber;
51
+ }
52
+ if (deviceInfo.fpsVersion != nil) {
53
+ result[@"fpsVersion"] = @{
54
+ @"major": @(deviceInfo.fpsVersion.major),
55
+ @"minor": @(deviceInfo.fpsVersion.minor),
56
+ @"micro": @(deviceInfo.fpsVersion.micro)
57
+ };
58
+ }
59
+ if (deviceInfo.stmVersion != nil) {
60
+ result[@"stmVersion"] = @{
61
+ @"major": @(deviceInfo.stmVersion.major),
62
+ @"minor": @(deviceInfo.stmVersion.minor),
63
+ @"micro": @(deviceInfo.stmVersion.micro)
64
+ };
65
+ }
66
+
67
+ if (config) {
68
+ // Read the raw bitmasks directly rather than re-deriving them by iterating a
69
+ // hardcoded list of YKFManagementApplicationType values - that list previously
70
+ // omitted YKFManagementApplicationTypeHSMAUTH, silently zeroing that bit for
71
+ // every device regardless of actual capability.
72
+ NSUInteger usbSupported = config.usbSupportedMask;
73
+ NSUInteger nfcSupported = config.nfcSupportedMask;
74
+ NSUInteger usbEnabled = config.usbEnabledMask;
75
+ NSUInteger nfcEnabled = config.nfcEnabledMask;
76
+
77
+ result[@"config"] = @{
78
+ @"enabledCapabilities": @{
79
+ @"usb": @(usbEnabled),
80
+ @"nfc": @(nfcEnabled)
81
+ },
82
+ @"autoEjectTimeout": @(config.autoEjectTimeout),
83
+ @"challengeResponseTimeout": @(config.challengeResponseTimeout),
84
+ @"nfcRestricted": @(config.isNFCRestricted)
85
+ // deviceFlags has no public accessor on YKFManagementInterfaceConfiguration in
86
+ // this SDK version, so it can't be populated here (matches Android parity gap).
87
+ };
88
+ result[@"supportedCapabilities"] = @{
89
+ @"usb": @(usbSupported),
90
+ @"nfc": @(nfcSupported)
91
+ };
92
+ result[@"hasTransportUsb"] = @(usbSupported != 0);
93
+ result[@"hasTransportNfc"] = @(nfcSupported != 0);
94
+ } else {
95
+ result[@"supportedCapabilities"] = @{};
96
+ result[@"hasTransportUsb"] = @NO;
97
+ result[@"hasTransportNfc"] = @NO;
98
+ }
99
+
100
+ result[@"isFips"] = @(deviceInfo.isFips);
101
+ result[@"isSky"] = @(deviceInfo.isSky);
102
+ result[@"fipsCapable"] = @(deviceInfo.isFIPSCapable);
103
+ result[@"fipsApproved"] = @(deviceInfo.isFIPSApproved);
104
+ result[@"pinComplexity"] = @(deviceInfo.pinComplexity);
105
+ result[@"resetBlocked"] = @(deviceInfo.isResetBlocked);
106
+
107
+ return result;
108
+ }
109
+
110
+ @end
@@ -0,0 +1,5 @@
1
+ #import <YubikitSpec/YubikitSpec.h>
2
+
3
+ @interface YubikitFido : NSObject <NativeYubikitFidoSpec>
4
+
5
+ @end