@pagopa/io-react-native-jwt 0.4.1

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 (113) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +145 -0
  3. package/android/build.gradle +97 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +4 -0
  6. package/android/src/main/java/com/pagopa/ioreactnativejwt/IoReactNativeJwtModule.kt +114 -0
  7. package/android/src/main/java/com/pagopa/ioreactnativejwt/IoReactNativeJwtPackage.kt +17 -0
  8. package/android/src/main/java/com/pagopa/ioreactnativejwt/Utils.kt +95 -0
  9. package/ios/ASN1DERParsing.swift +226 -0
  10. package/ios/IoReactNativeJwt-Bridging-Header.h +2 -0
  11. package/ios/IoReactNativeJwt.mm +28 -0
  12. package/ios/IoReactNativeJwt.swift +156 -0
  13. package/ios/IoReactNativeJwt.xcodeproj/project.pbxproj +283 -0
  14. package/lib/commonjs/algorithms.js +39 -0
  15. package/lib/commonjs/algorithms.js.map +1 -0
  16. package/lib/commonjs/hash.js +17 -0
  17. package/lib/commonjs/hash.js.map +1 -0
  18. package/lib/commonjs/index.js +194 -0
  19. package/lib/commonjs/index.js.map +1 -0
  20. package/lib/commonjs/jwt_claims_set.js +112 -0
  21. package/lib/commonjs/jwt_claims_set.js.map +1 -0
  22. package/lib/commonjs/produce.js +140 -0
  23. package/lib/commonjs/produce.js.map +1 -0
  24. package/lib/commonjs/sign.js +159 -0
  25. package/lib/commonjs/sign.js.map +1 -0
  26. package/lib/commonjs/types.js +2 -0
  27. package/lib/commonjs/types.js.map +1 -0
  28. package/lib/commonjs/unsecured.js +118 -0
  29. package/lib/commonjs/unsecured.js.map +1 -0
  30. package/lib/commonjs/utils/asn1.js +37 -0
  31. package/lib/commonjs/utils/asn1.js.map +1 -0
  32. package/lib/commonjs/utils/base64.js +43 -0
  33. package/lib/commonjs/utils/base64.js.map +1 -0
  34. package/lib/commonjs/utils/errors.js +214 -0
  35. package/lib/commonjs/utils/errors.js.map +1 -0
  36. package/lib/commonjs/utils/is_object.js +23 -0
  37. package/lib/commonjs/utils/is_object.js.map +1 -0
  38. package/lib/commonjs/utils/proxy.js +17 -0
  39. package/lib/commonjs/utils/proxy.js.map +1 -0
  40. package/lib/commonjs/utils/secs.js +61 -0
  41. package/lib/commonjs/utils/secs.js.map +1 -0
  42. package/lib/module/algorithms.js +29 -0
  43. package/lib/module/algorithms.js.map +1 -0
  44. package/lib/module/hash.js +11 -0
  45. package/lib/module/hash.js.map +1 -0
  46. package/lib/module/index.js +115 -0
  47. package/lib/module/index.js.map +1 -0
  48. package/lib/module/jwt_claims_set.js +103 -0
  49. package/lib/module/jwt_claims_set.js.map +1 -0
  50. package/lib/module/produce.js +131 -0
  51. package/lib/module/produce.js.map +1 -0
  52. package/lib/module/sign.js +153 -0
  53. package/lib/module/sign.js.map +1 -0
  54. package/lib/module/types.js +2 -0
  55. package/lib/module/types.js.map +1 -0
  56. package/lib/module/unsecured.js +110 -0
  57. package/lib/module/unsecured.js.map +1 -0
  58. package/lib/module/utils/asn1.js +31 -0
  59. package/lib/module/utils/asn1.js.map +1 -0
  60. package/lib/module/utils/base64.js +36 -0
  61. package/lib/module/utils/base64.js.map +1 -0
  62. package/lib/module/utils/errors.js +200 -0
  63. package/lib/module/utils/errors.js.map +1 -0
  64. package/lib/module/utils/is_object.js +17 -0
  65. package/lib/module/utils/is_object.js.map +1 -0
  66. package/lib/module/utils/proxy.js +10 -0
  67. package/lib/module/utils/proxy.js.map +1 -0
  68. package/lib/module/utils/secs.js +53 -0
  69. package/lib/module/utils/secs.js.map +1 -0
  70. package/lib/typescript/algorithms.d.ts +5 -0
  71. package/lib/typescript/algorithms.d.ts.map +1 -0
  72. package/lib/typescript/hash.d.ts +5 -0
  73. package/lib/typescript/hash.d.ts.map +1 -0
  74. package/lib/typescript/index.d.ts +93 -0
  75. package/lib/typescript/index.d.ts.map +1 -0
  76. package/lib/typescript/jwt_claims_set.d.ts +4 -0
  77. package/lib/typescript/jwt_claims_set.d.ts.map +1 -0
  78. package/lib/typescript/produce.d.ts +55 -0
  79. package/lib/typescript/produce.d.ts.map +1 -0
  80. package/lib/typescript/sign.d.ts +61 -0
  81. package/lib/typescript/sign.d.ts.map +1 -0
  82. package/lib/typescript/types.d.ts +172 -0
  83. package/lib/typescript/types.d.ts.map +1 -0
  84. package/lib/typescript/unsecured.d.ts +64 -0
  85. package/lib/typescript/unsecured.d.ts.map +1 -0
  86. package/lib/typescript/utils/asn1.d.ts +2 -0
  87. package/lib/typescript/utils/asn1.d.ts.map +1 -0
  88. package/lib/typescript/utils/base64.d.ts +4 -0
  89. package/lib/typescript/utils/base64.d.ts.map +1 -0
  90. package/lib/typescript/utils/errors.d.ts +157 -0
  91. package/lib/typescript/utils/errors.d.ts.map +1 -0
  92. package/lib/typescript/utils/is_object.d.ts +2 -0
  93. package/lib/typescript/utils/is_object.d.ts.map +1 -0
  94. package/lib/typescript/utils/proxy.d.ts +2 -0
  95. package/lib/typescript/utils/proxy.d.ts.map +1 -0
  96. package/lib/typescript/utils/secs.d.ts +4 -0
  97. package/lib/typescript/utils/secs.d.ts.map +1 -0
  98. package/package.json +170 -0
  99. package/pagopa-io-react-native-jwt.podspec +44 -0
  100. package/src/algorithms.ts +46 -0
  101. package/src/hash.ts +10 -0
  102. package/src/index.tsx +120 -0
  103. package/src/jwt_claims_set.ts +194 -0
  104. package/src/produce.ts +109 -0
  105. package/src/sign.ts +180 -0
  106. package/src/types.ts +203 -0
  107. package/src/unsecured.ts +127 -0
  108. package/src/utils/asn1.ts +36 -0
  109. package/src/utils/base64.ts +37 -0
  110. package/src/utils/errors.ts +206 -0
  111. package/src/utils/is_object.ts +20 -0
  112. package/src/utils/proxy.ts +15 -0
  113. package/src/utils/secs.ts +58 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 PagoPa
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # ⚡️ @pagopa/io-react-native-jwt
2
+
3
+ A fast implementation of `jwt` module.
4
+ Provides much greater performance for decoding, signing and verifying JWTs!
5
+
6
+ 🚀 Use only native functions via the following libraries:
7
+ - 🤖 [nimbus-jose-jwt](https://github.com/felx/nimbus-jose-jwt/) on Android
8
+ - 📱 [JOSESwift](https://github.com/airsidemobile/JOSESwift/) on iOS
9
+
10
+
11
+
12
+
13
+ ## Installation
14
+
15
+ ```sh
16
+ npm install @pagopa/io-react-native-jwt
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ For detailed documentation go [here](/docs/modules/index.md)
22
+
23
+ ### Decode a JWT
24
+
25
+ ```js
26
+ import { decode } from '@pagopa/io-react-native-jwt';
27
+
28
+ // ...
29
+ const jwt = "eyJ0eXAiOiJlbnRpdHktc3.....";
30
+ const result = await decode(jwt);
31
+ console.log(result);
32
+ ```
33
+
34
+ ### Verify JWT
35
+
36
+ ```js
37
+ import { verify } from '@pagopa/io-react-native-jwt';
38
+
39
+ // ...
40
+ const pubJwk = {
41
+ crv: 'P-256',
42
+ kty: 'EC',
43
+ x: 'qrJrj.....',
44
+ y: '1H0cW.....',
45
+ };
46
+ const jwt = "eyJ0eXAiOiJlbnRpdHktc3.....";
47
+ const options = {
48
+ typ: 'jwt',
49
+ requiredClaims: ['iss', 'sub'],
50
+ }
51
+ const {protectedHeader, payload} = await verify(jwt, pubJwk, options);
52
+ console.log(protectedHeader, payload)
53
+ ```
54
+
55
+
56
+ ### Verify a JWT signature (JWS)
57
+
58
+ ```js
59
+ import { isSignatureValid } from '@pagopa/io-react-native-jwt';
60
+
61
+ // ...
62
+ const pubJwk = {
63
+ crv: 'P-256',
64
+ kty: 'EC',
65
+ x: 'qrJrj.....',
66
+ y: '1H0cW.....',
67
+ };
68
+ const jwt = "eyJ0eXAiOiJlbnRpdHktc3.....";
69
+
70
+ const isValid = await isSignatureValid(jwt, pubJwk);
71
+
72
+ if isValid {
73
+ console.log("Signature of JWT is valid!");
74
+ } else {
75
+ console.log("Signature of JWT is NOT valid!");
76
+ }
77
+ ```
78
+
79
+ ### Create and sign a JWT with a JWS
80
+
81
+ ```js
82
+ // Create unsecured jwt
83
+ let jwtToSign = new SignJWT({ metadata: 'demo' })
84
+ .setProtectedHeader({ alg: 'ES256', typ: 'JWT' })
85
+ .setAudience('demo')
86
+ .setExpirationTime('1h')
87
+ .setIssuedAt()
88
+ .toSign();
89
+
90
+ // Create signature
91
+ let signature = signWithMyCustomFunction(jwtToSign);
92
+
93
+ // Create signed JWT
94
+ let signedJwt = await SignJWT.appendSignature(jwtToSign, signature);
95
+
96
+ console.log(signedJwt)
97
+ ```
98
+
99
+ ### JWK thumbprint
100
+
101
+ ```js
102
+ import { thumbprint } from '@pagopa/io-react-native-jwt';
103
+
104
+ // ...
105
+ const pubJwk = {
106
+ crv: 'P-256',
107
+ kty: 'EC',
108
+ x: 'qrJrj.....',
109
+ y: '1H0cW.....',
110
+ };
111
+ const thumbprint = await thumbprint(pubJwk);
112
+ console.log(thumbprint)
113
+ ```
114
+
115
+ ##  Signature format
116
+
117
+ For an ECDSA signature it is required that this is in ASN.1/DER encoded format.
118
+ The same format supported by Secure Enclave (TEE).
119
+ Transcoding is done automatically via the following function:
120
+
121
+ ```js
122
+ derToJose = async (
123
+ asn1Signature: string,
124
+ alg: string
125
+ ): Promise<string>
126
+ ```
127
+
128
+ Refs: [RFC7515](https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.3.1)
129
+
130
+ ## Example
131
+
132
+ You can use the [sample app](example) to test and understand how to use the library.
133
+
134
+ ```sh
135
+ cd example
136
+
137
+ yarn install
138
+
139
+ # To use iOS
140
+ yarn ios
141
+
142
+ # To use Android
143
+ yarn android
144
+
145
+ ```
@@ -0,0 +1,97 @@
1
+ buildscript {
2
+ // Buildscript is evaluated before everything else so we can't use getExtOrDefault
3
+ def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["IoReactNativeJwt_kotlinVersion"]
4
+
5
+ repositories {
6
+ google()
7
+ mavenCentral()
8
+ }
9
+
10
+ dependencies {
11
+ classpath "com.android.tools.build:gradle:7.2.1"
12
+ // noinspection DifferentKotlinGradleVersion
13
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14
+ }
15
+ }
16
+
17
+ def isNewArchitectureEnabled() {
18
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
19
+ }
20
+
21
+ apply plugin: "com.android.library"
22
+ apply plugin: "kotlin-android"
23
+
24
+
25
+ def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
26
+
27
+ if (isNewArchitectureEnabled()) {
28
+ apply plugin: "com.facebook.react"
29
+ }
30
+
31
+ def getExtOrDefault(name) {
32
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["IoReactNativeJwt_" + name]
33
+ }
34
+
35
+ def getExtOrIntegerDefault(name) {
36
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["IoReactNativeJwt_" + name]).toInteger()
37
+ }
38
+
39
+ def isAGPVersionGreaterThan(version) {
40
+ def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger()
41
+ return agpVersion > version
42
+ }
43
+
44
+ android {
45
+ if (isAGPVersionGreaterThan(7)) {
46
+ namespace "com.pagopa.ioreactnativejwt"
47
+ }
48
+
49
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
50
+
51
+ defaultConfig {
52
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
53
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
54
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
55
+ }
56
+ buildTypes {
57
+ release {
58
+ minifyEnabled false
59
+ }
60
+ }
61
+
62
+ lintOptions {
63
+ disable "GradleCompatible"
64
+ }
65
+
66
+ compileOptions {
67
+ sourceCompatibility JavaVersion.VERSION_1_8
68
+ targetCompatibility JavaVersion.VERSION_1_8
69
+ }
70
+
71
+ }
72
+
73
+ repositories {
74
+ mavenCentral()
75
+ google()
76
+ }
77
+
78
+ def kotlin_version = getExtOrDefault("kotlinVersion")
79
+
80
+ dependencies {
81
+ // For < 0.71, this will be from the local maven repo
82
+ // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
83
+ //noinspection GradleDynamicVersion
84
+ implementation "com.facebook.react:react-native:+"
85
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
86
+ implementation 'com.nimbusds:nimbus-jose-jwt:8.0'
87
+ implementation 'org.bouncycastle:bcprov-jdk15on:[1.56,)'
88
+
89
+ }
90
+
91
+ if (isNewArchitectureEnabled()) {
92
+ react {
93
+ jsRootDir = file("../src/")
94
+ libraryName = "IoReactNativeJwt"
95
+ codegenJavaPackageName = "com.pagopa.ioreactnativejwt"
96
+ }
97
+ }
@@ -0,0 +1,5 @@
1
+ IoReactNativeJwt_kotlinVersion=1.7.0
2
+ IoReactNativeJwt_minSdkVersion=21
3
+ IoReactNativeJwt_targetSdkVersion=31
4
+ IoReactNativeJwt_compileSdkVersion=31
5
+ IoReactNativeJwt_ndkversion=21.4.7075529
@@ -0,0 +1,4 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.pagopa.ioreactnativejwt">
3
+
4
+ </manifest>
@@ -0,0 +1,114 @@
1
+ package com.pagopa.ioreactnativejwt
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
5
+ import com.facebook.react.bridge.ReactMethod
6
+ import com.facebook.react.bridge.Promise
7
+
8
+ import android.util.Base64
9
+ import android.util.Base64.DEFAULT
10
+ import com.nimbusds.jose.JWSHeader
11
+ import com.nimbusds.jose.crypto.RSASSASigner
12
+ import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton
13
+ import com.nimbusds.jose.jwk.RSAKey
14
+ import com.nimbusds.jose.jwk.ECKey
15
+ import com.nimbusds.jwt.JWTClaimsSet
16
+ import com.nimbusds.jwt.SignedJWT
17
+ import com.facebook.react.bridge.ReadableMap
18
+ import org.json.JSONObject
19
+ import com.nimbusds.jose.crypto.RSASSAVerifier
20
+ import com.nimbusds.jose.crypto.ECDSAVerifier
21
+ import com.facebook.react.bridge.WritableNativeMap
22
+ import com.nimbusds.jose.crypto.impl.RSA_OAEP
23
+ import com.pagopa.ioreactnativejwt.Utils.convertJsonToMap
24
+ import com.nimbusds.jose.crypto.impl.ECDSA.transcodeSignatureToConcat
25
+ import java.security.MessageDigest
26
+
27
+ class IoReactNativeJwtModule(reactContext: ReactApplicationContext) :
28
+ ReactContextBaseJavaModule(reactContext) {
29
+
30
+ override fun getName(): String {
31
+ return NAME
32
+ }
33
+
34
+ fun isECKey(jwk: JSONObject):Boolean {
35
+ return jwk.get("kty") == "EC";
36
+ }
37
+
38
+ @ReactMethod
39
+ fun verify(token: String, jwk: ReadableMap, promise: Promise) {
40
+ try {
41
+ val signedJWT = SignedJWT.parse(token)
42
+ val jwkJson = JSONObject(jwk.toHashMap())
43
+ var isValid = false
44
+
45
+ if (isECKey(jwkJson)) {
46
+ val internalJwk = ECKey.parse(jwkJson.toString())
47
+ val verifier = ECDSAVerifier(internalJwk)
48
+ verifier.jcaContext.provider = BouncyCastleProviderSingleton.getInstance()
49
+ isValid = signedJWT.verify(verifier)
50
+ } else {
51
+ val internalJwk = RSAKey.parse(jwkJson.toString())
52
+ val verifier = RSASSAVerifier(internalJwk)
53
+ verifier.jcaContext.provider = BouncyCastleProviderSingleton.getInstance()
54
+ isValid = signedJWT.verify(verifier)
55
+ }
56
+ promise.resolve(isValid)
57
+
58
+ } catch (ex: Exception) {
59
+ promise.reject(ex)
60
+ }
61
+ }
62
+
63
+ @ReactMethod
64
+ fun thumbprint(jwk: ReadableMap, promise: Promise) {
65
+ try {
66
+ val jwkJson = JSONObject(jwk.toHashMap())
67
+ var thumbprint = ""
68
+ if (isECKey(jwkJson)) {
69
+ val internalJwk = ECKey.parse(jwkJson.toString())
70
+ thumbprint = internalJwk.computeThumbprint().toString();
71
+ } else {
72
+ val internalJwk = RSAKey.parse(jwkJson.toString())
73
+ thumbprint = internalJwk.computeThumbprint().toString();
74
+ }
75
+ if (thumbprint != "") {
76
+ promise.resolve(thumbprint)
77
+ } else {
78
+ promise.reject(Exception("Unable to create thumbprint"))
79
+ }
80
+
81
+ } catch (ex: Exception) {
82
+ promise.reject(ex)
83
+ }
84
+ }
85
+
86
+ @ReactMethod
87
+ fun unpackBerEncodedASN1(asn1Signature: String, coordinateOctetLength: Int, promise: Promise) {
88
+ try {
89
+ val decodedBytes = Base64.decode(asn1Signature, DEFAULT)
90
+ val transcoded = transcodeSignatureToConcat(decodedBytes, coordinateOctetLength)
91
+ val signature = Base64.encodeToString(transcoded, DEFAULT)
92
+ promise.resolve(signature)
93
+ } catch (ex: Exception) {
94
+ promise.reject(ex)
95
+ }
96
+ }
97
+
98
+ @ReactMethod
99
+ fun sha256(toHash: String, promise: Promise) {
100
+ try {
101
+ val digest = MessageDigest.getInstance("SHA-256")
102
+ val hashBytes = digest.digest(toHash.toByteArray(Charsets.UTF_8))
103
+ val base64String = Base64.encodeToString(hashBytes, Base64.NO_WRAP)
104
+ promise.resolve(base64String)
105
+ } catch (ex: Exception) {
106
+ promise.reject(ex)
107
+ }
108
+ }
109
+
110
+
111
+ companion object {
112
+ const val NAME = "IoReactNativeJwt"
113
+ }
114
+ }
@@ -0,0 +1,17 @@
1
+ package com.pagopa.ioreactnativejwt
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+
9
+ class IoReactNativeJwtPackage : ReactPackage {
10
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
11
+ return listOf(IoReactNativeJwtModule(reactContext))
12
+ }
13
+
14
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15
+ return emptyList()
16
+ }
17
+ }
@@ -0,0 +1,95 @@
1
+ package com.pagopa.ioreactnativejwt
2
+
3
+ import com.facebook.react.bridge.*
4
+ import org.json.JSONException
5
+ import org.json.JSONObject
6
+ import org.json.JSONArray
7
+
8
+ object Utils {
9
+ @Throws(JSONException::class)
10
+ fun convertJsonToMap(jsonObject: JSONObject): WritableMap {
11
+ val map = WritableNativeMap()
12
+
13
+ val iterator = jsonObject.keys()
14
+ while (iterator.hasNext()) {
15
+ val key = iterator.next()
16
+ val value = jsonObject.get(key)
17
+ if (value is JSONObject) {
18
+ map.putMap(key, convertJsonToMap(value))
19
+ } else if (value is JSONArray) {
20
+ map.putArray(key, convertJsonToArray(value))
21
+ } else if (value is Boolean) {
22
+ map.putBoolean(key, value)
23
+ } else if (value is Int) {
24
+ map.putInt(key, value)
25
+ } else if (value is Double) {
26
+ map.putDouble(key, value)
27
+ } else if (value is String) {
28
+ map.putString(key, value)
29
+ } else {
30
+ map.putString(key, value.toString())
31
+ }
32
+ }
33
+ return map
34
+ }
35
+
36
+ @Throws(JSONException::class)
37
+ fun convertJsonToArray(jsonArray: JSONArray): WritableArray {
38
+ val array = WritableNativeArray()
39
+
40
+ for (i in 0 until jsonArray.length()) {
41
+ val value = jsonArray.get(i)
42
+ if (value is JSONObject) {
43
+ array.pushMap(convertJsonToMap(value))
44
+ } else if (value is JSONArray) {
45
+ array.pushArray(convertJsonToArray(value))
46
+ } else if (value is Boolean) {
47
+ array.pushBoolean(value)
48
+ } else if (value is Int) {
49
+ array.pushInt(value)
50
+ } else if (value is Double) {
51
+ array.pushDouble(value)
52
+ } else if (value is String) {
53
+ array.pushString(value)
54
+ } else {
55
+ array.pushString(value.toString())
56
+ }
57
+ }
58
+ return array
59
+ }
60
+
61
+ @Throws(JSONException::class)
62
+ fun convertMapToJson(readableMap: ReadableMap): JSONObject {
63
+ val `object` = JSONObject()
64
+ val iterator = readableMap.keySetIterator()
65
+ while (iterator.hasNextKey()) {
66
+ val key = iterator.nextKey()
67
+ when (readableMap.getType(key)) {
68
+ ReadableType.Null -> `object`.put(key, JSONObject.NULL)
69
+ ReadableType.Boolean -> `object`.put(key, readableMap.getBoolean(key))
70
+ ReadableType.Number -> `object`.put(key, readableMap.getDouble(key))
71
+ ReadableType.String -> `object`.put(key, readableMap.getString(key))
72
+ ReadableType.Map -> `object`.put(key, convertMapToJson(readableMap.getMap(key)!!))
73
+ ReadableType.Array -> `object`.put(key, convertArrayToJson(readableMap.getArray(key)!!))
74
+ }
75
+ }
76
+ return `object`
77
+ }
78
+
79
+ @Throws(JSONException::class)
80
+ fun convertArrayToJson(readableArray: ReadableArray): JSONArray {
81
+ val array = JSONArray()
82
+ for (i in 0 until readableArray.size()) {
83
+ when (readableArray.getType(i)) {
84
+ ReadableType.Null -> {
85
+ }
86
+ ReadableType.Boolean -> array.put(readableArray.getBoolean(i))
87
+ ReadableType.Number -> array.put(readableArray.getDouble(i))
88
+ ReadableType.String -> array.put(readableArray.getString(i))
89
+ ReadableType.Map -> array.put(convertMapToJson(readableArray.getMap(i)!!))
90
+ ReadableType.Array -> array.put(convertArrayToJson(readableArray.getArray(i)!!))
91
+ }
92
+ }
93
+ return array
94
+ }
95
+ }