@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.
- package/LICENSE +20 -0
- package/README.md +145 -0
- package/android/build.gradle +97 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/com/pagopa/ioreactnativejwt/IoReactNativeJwtModule.kt +114 -0
- package/android/src/main/java/com/pagopa/ioreactnativejwt/IoReactNativeJwtPackage.kt +17 -0
- package/android/src/main/java/com/pagopa/ioreactnativejwt/Utils.kt +95 -0
- package/ios/ASN1DERParsing.swift +226 -0
- package/ios/IoReactNativeJwt-Bridging-Header.h +2 -0
- package/ios/IoReactNativeJwt.mm +28 -0
- package/ios/IoReactNativeJwt.swift +156 -0
- package/ios/IoReactNativeJwt.xcodeproj/project.pbxproj +283 -0
- package/lib/commonjs/algorithms.js +39 -0
- package/lib/commonjs/algorithms.js.map +1 -0
- package/lib/commonjs/hash.js +17 -0
- package/lib/commonjs/hash.js.map +1 -0
- package/lib/commonjs/index.js +194 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/jwt_claims_set.js +112 -0
- package/lib/commonjs/jwt_claims_set.js.map +1 -0
- package/lib/commonjs/produce.js +140 -0
- package/lib/commonjs/produce.js.map +1 -0
- package/lib/commonjs/sign.js +159 -0
- package/lib/commonjs/sign.js.map +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/unsecured.js +118 -0
- package/lib/commonjs/unsecured.js.map +1 -0
- package/lib/commonjs/utils/asn1.js +37 -0
- package/lib/commonjs/utils/asn1.js.map +1 -0
- package/lib/commonjs/utils/base64.js +43 -0
- package/lib/commonjs/utils/base64.js.map +1 -0
- package/lib/commonjs/utils/errors.js +214 -0
- package/lib/commonjs/utils/errors.js.map +1 -0
- package/lib/commonjs/utils/is_object.js +23 -0
- package/lib/commonjs/utils/is_object.js.map +1 -0
- package/lib/commonjs/utils/proxy.js +17 -0
- package/lib/commonjs/utils/proxy.js.map +1 -0
- package/lib/commonjs/utils/secs.js +61 -0
- package/lib/commonjs/utils/secs.js.map +1 -0
- package/lib/module/algorithms.js +29 -0
- package/lib/module/algorithms.js.map +1 -0
- package/lib/module/hash.js +11 -0
- package/lib/module/hash.js.map +1 -0
- package/lib/module/index.js +115 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/jwt_claims_set.js +103 -0
- package/lib/module/jwt_claims_set.js.map +1 -0
- package/lib/module/produce.js +131 -0
- package/lib/module/produce.js.map +1 -0
- package/lib/module/sign.js +153 -0
- package/lib/module/sign.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/unsecured.js +110 -0
- package/lib/module/unsecured.js.map +1 -0
- package/lib/module/utils/asn1.js +31 -0
- package/lib/module/utils/asn1.js.map +1 -0
- package/lib/module/utils/base64.js +36 -0
- package/lib/module/utils/base64.js.map +1 -0
- package/lib/module/utils/errors.js +200 -0
- package/lib/module/utils/errors.js.map +1 -0
- package/lib/module/utils/is_object.js +17 -0
- package/lib/module/utils/is_object.js.map +1 -0
- package/lib/module/utils/proxy.js +10 -0
- package/lib/module/utils/proxy.js.map +1 -0
- package/lib/module/utils/secs.js +53 -0
- package/lib/module/utils/secs.js.map +1 -0
- package/lib/typescript/algorithms.d.ts +5 -0
- package/lib/typescript/algorithms.d.ts.map +1 -0
- package/lib/typescript/hash.d.ts +5 -0
- package/lib/typescript/hash.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +93 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/jwt_claims_set.d.ts +4 -0
- package/lib/typescript/jwt_claims_set.d.ts.map +1 -0
- package/lib/typescript/produce.d.ts +55 -0
- package/lib/typescript/produce.d.ts.map +1 -0
- package/lib/typescript/sign.d.ts +61 -0
- package/lib/typescript/sign.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +172 -0
- package/lib/typescript/types.d.ts.map +1 -0
- package/lib/typescript/unsecured.d.ts +64 -0
- package/lib/typescript/unsecured.d.ts.map +1 -0
- package/lib/typescript/utils/asn1.d.ts +2 -0
- package/lib/typescript/utils/asn1.d.ts.map +1 -0
- package/lib/typescript/utils/base64.d.ts +4 -0
- package/lib/typescript/utils/base64.d.ts.map +1 -0
- package/lib/typescript/utils/errors.d.ts +157 -0
- package/lib/typescript/utils/errors.d.ts.map +1 -0
- package/lib/typescript/utils/is_object.d.ts +2 -0
- package/lib/typescript/utils/is_object.d.ts.map +1 -0
- package/lib/typescript/utils/proxy.d.ts +2 -0
- package/lib/typescript/utils/proxy.d.ts.map +1 -0
- package/lib/typescript/utils/secs.d.ts +4 -0
- package/lib/typescript/utils/secs.d.ts.map +1 -0
- package/package.json +170 -0
- package/pagopa-io-react-native-jwt.podspec +44 -0
- package/src/algorithms.ts +46 -0
- package/src/hash.ts +10 -0
- package/src/index.tsx +120 -0
- package/src/jwt_claims_set.ts +194 -0
- package/src/produce.ts +109 -0
- package/src/sign.ts +180 -0
- package/src/types.ts +203 -0
- package/src/unsecured.ts +127 -0
- package/src/utils/asn1.ts +36 -0
- package/src/utils/base64.ts +37 -0
- package/src/utils/errors.ts +206 -0
- package/src/utils/is_object.ts +20 -0
- package/src/utils/proxy.ts +15 -0
- 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,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
|
+
}
|