@pagopa/io-react-native-iso18013 0.1.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.
Files changed (113) hide show
  1. package/IoReactNativeIso18013.podspec +29 -0
  2. package/LICENSE +20 -0
  3. package/README.md +30 -0
  4. package/android/build.gradle +83 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/src/main/AndroidManifest.xml +3 -0
  7. package/android/src/main/AndroidManifestNew.xml +2 -0
  8. package/android/src/main/java/com/ioreactnativeiso18013/Base64Utils.kt +56 -0
  9. package/android/src/main/java/com/ioreactnativeiso18013/IoReactNativeCborModule.kt +209 -0
  10. package/android/src/main/java/com/ioreactnativeiso18013/IoReactNativeIso18013Module.kt +439 -0
  11. package/android/src/main/java/com/ioreactnativeiso18013/IoReactNativeIso18013Package.kt +17 -0
  12. package/ios/Base64Utils.swift +47 -0
  13. package/ios/IoReactNativeCbor.mm +32 -0
  14. package/ios/IoReactNativeCbor.swift +188 -0
  15. package/ios/IoReactNativeIso18013-Bridging-Header.h +2 -0
  16. package/ios/IoReactNativeIso18013.mm +43 -0
  17. package/ios/IoReactNativeIso18013.swift +491 -0
  18. package/lib/module/cbor/cbor/README.md +95 -0
  19. package/lib/module/cbor/cbor/decoder.js +51 -0
  20. package/lib/module/cbor/cbor/decoder.js.map +1 -0
  21. package/lib/module/cbor/cbor/failure.js +2 -0
  22. package/lib/module/cbor/cbor/failure.js.map +1 -0
  23. package/lib/module/cbor/cbor/index.js +5 -0
  24. package/lib/module/cbor/cbor/index.js.map +1 -0
  25. package/lib/module/cbor/cbor/schema.js +117 -0
  26. package/lib/module/cbor/cbor/schema.js.map +1 -0
  27. package/lib/module/cbor/cbor/schema.utils.js +16 -0
  28. package/lib/module/cbor/cbor/schema.utils.js.map +1 -0
  29. package/lib/module/cbor/cose/README.md +53 -0
  30. package/lib/module/cbor/cose/failure.js +2 -0
  31. package/lib/module/cbor/cose/failure.js.map +1 -0
  32. package/lib/module/cbor/cose/index.js +4 -0
  33. package/lib/module/cbor/cose/index.js.map +1 -0
  34. package/lib/module/cbor/cose/sign.js +23 -0
  35. package/lib/module/cbor/cose/sign.js.map +1 -0
  36. package/lib/module/cbor/index.js +13 -0
  37. package/lib/module/cbor/index.js.map +1 -0
  38. package/lib/module/index.js +8 -0
  39. package/lib/module/index.js.map +1 -0
  40. package/lib/module/iso18013/index.js +14 -0
  41. package/lib/module/iso18013/index.js.map +1 -0
  42. package/lib/module/iso18013/iso18013-5/README.md +234 -0
  43. package/lib/module/iso18013/iso18013-5/index.js +5 -0
  44. package/lib/module/iso18013/iso18013-5/index.js.map +1 -0
  45. package/lib/module/iso18013/iso18013-5/proximity.js +112 -0
  46. package/lib/module/iso18013/iso18013-5/proximity.js.map +1 -0
  47. package/lib/module/iso18013/iso18013-5/schema.js +79 -0
  48. package/lib/module/iso18013/iso18013-5/schema.js.map +1 -0
  49. package/lib/module/iso18013/iso18013-7/README.md +59 -0
  50. package/lib/module/iso18013/iso18013-7/index.js +4 -0
  51. package/lib/module/iso18013/iso18013-7/index.js.map +1 -0
  52. package/lib/module/iso18013/iso18013-7/remote.js +31 -0
  53. package/lib/module/iso18013/iso18013-7/remote.js.map +1 -0
  54. package/lib/module/iso18013/types.js +2 -0
  55. package/lib/module/iso18013/types.js.map +1 -0
  56. package/lib/module/package.json +1 -0
  57. package/lib/typescript/package.json +1 -0
  58. package/lib/typescript/src/cbor/cbor/decoder.d.ts +35 -0
  59. package/lib/typescript/src/cbor/cbor/decoder.d.ts.map +1 -0
  60. package/lib/typescript/src/cbor/cbor/failure.d.ts +15 -0
  61. package/lib/typescript/src/cbor/cbor/failure.d.ts.map +1 -0
  62. package/lib/typescript/src/cbor/cbor/index.d.ts +4 -0
  63. package/lib/typescript/src/cbor/cbor/index.d.ts.map +1 -0
  64. package/lib/typescript/src/cbor/cbor/schema.d.ts +2420 -0
  65. package/lib/typescript/src/cbor/cbor/schema.d.ts.map +1 -0
  66. package/lib/typescript/src/cbor/cbor/schema.utils.d.ts +8 -0
  67. package/lib/typescript/src/cbor/cbor/schema.utils.d.ts.map +1 -0
  68. package/lib/typescript/src/cbor/cose/failure.d.ts +15 -0
  69. package/lib/typescript/src/cbor/cose/failure.d.ts.map +1 -0
  70. package/lib/typescript/src/cbor/cose/index.d.ts +3 -0
  71. package/lib/typescript/src/cbor/cose/index.d.ts.map +1 -0
  72. package/lib/typescript/src/cbor/cose/sign.d.ts +19 -0
  73. package/lib/typescript/src/cbor/cose/sign.d.ts.map +1 -0
  74. package/lib/typescript/src/cbor/index.d.ts +2 -0
  75. package/lib/typescript/src/cbor/index.d.ts.map +1 -0
  76. package/lib/typescript/src/index.d.ts +6 -0
  77. package/lib/typescript/src/index.d.ts.map +1 -0
  78. package/lib/typescript/src/iso18013/index.d.ts +3 -0
  79. package/lib/typescript/src/iso18013/index.d.ts.map +1 -0
  80. package/lib/typescript/src/iso18013/iso18013-5/index.d.ts +4 -0
  81. package/lib/typescript/src/iso18013/iso18013-5/index.d.ts.map +1 -0
  82. package/lib/typescript/src/iso18013/iso18013-5/proximity.d.ts +88 -0
  83. package/lib/typescript/src/iso18013/iso18013-5/proximity.d.ts.map +1 -0
  84. package/lib/typescript/src/iso18013/iso18013-5/schema.d.ts +85 -0
  85. package/lib/typescript/src/iso18013/iso18013-5/schema.d.ts.map +1 -0
  86. package/lib/typescript/src/iso18013/iso18013-7/index.d.ts +3 -0
  87. package/lib/typescript/src/iso18013/iso18013-7/index.d.ts.map +1 -0
  88. package/lib/typescript/src/iso18013/iso18013-7/remote.d.ts +29 -0
  89. package/lib/typescript/src/iso18013/iso18013-7/remote.d.ts.map +1 -0
  90. package/lib/typescript/src/iso18013/types.d.ts +16 -0
  91. package/lib/typescript/src/iso18013/types.d.ts.map +1 -0
  92. package/package.json +163 -0
  93. package/src/cbor/cbor/README.md +95 -0
  94. package/src/cbor/cbor/decoder.ts +56 -0
  95. package/src/cbor/cbor/failure.ts +18 -0
  96. package/src/cbor/cbor/index.ts +9 -0
  97. package/src/cbor/cbor/schema.ts +150 -0
  98. package/src/cbor/cbor/schema.utils.ts +13 -0
  99. package/src/cbor/cose/README.md +53 -0
  100. package/src/cbor/cose/failure.ts +20 -0
  101. package/src/cbor/cose/index.ts +2 -0
  102. package/src/cbor/cose/sign.ts +25 -0
  103. package/src/cbor/index.ts +18 -0
  104. package/src/index.tsx +5 -0
  105. package/src/iso18013/index.ts +25 -0
  106. package/src/iso18013/iso18013-5/README.md +234 -0
  107. package/src/iso18013/iso18013-5/index.ts +23 -0
  108. package/src/iso18013/iso18013-5/proximity.ts +134 -0
  109. package/src/iso18013/iso18013-5/schema.ts +87 -0
  110. package/src/iso18013/iso18013-7/README.md +59 -0
  111. package/src/iso18013/iso18013-7/index.ts +7 -0
  112. package/src/iso18013/iso18013-7/remote.ts +54 -0
  113. package/src/iso18013/types.ts +16 -0
@@ -0,0 +1,56 @@
1
+ import { IoReactNativeCbor } from '..';
2
+ import {
3
+ Documents,
4
+ DocumentsFromString,
5
+ IssuerSigned,
6
+ IssuerSignedFromString,
7
+ } from './schema';
8
+ import { coerceToJSON } from './schema.utils';
9
+
10
+ /**
11
+ * Decode base64 encoded CBOR data to JSON object.
12
+ *
13
+ * If it is not possibile to decode the provided data, the promise will be rejected with
14
+ * an instance of {@link CborFailure}.
15
+ *
16
+ * **NOTE**: this method does not handle nested CBOR data, which will need additional
17
+ * parsing.
18
+ *
19
+ * @param data - The base64 or base64url encoded CBOR data
20
+ * @returns The decoded data as JSON object
21
+ */
22
+ export const decode = async (data: string): Promise<any> => {
23
+ const jsonString = await IoReactNativeCbor.decode(data);
24
+ return await coerceToJSON.parseAsync(jsonString);
25
+ };
26
+
27
+ /**
28
+ * Decode base64 or base64url encoded CBOR data to mDOC object
29
+ *
30
+ * If it is not possibile to decode the provided data, the promise will be rejected with
31
+ * an instance of {@link CborFailure}.
32
+ *
33
+ * @param data - The base64 encoded MDOC data
34
+ * @returns The decoded data as mDOC object
35
+ */
36
+ export const decodeDocuments = async (data: string): Promise<Documents> => {
37
+ const documentsString = await IoReactNativeCbor.decodeDocuments(data);
38
+ return await DocumentsFromString.parseAsync(documentsString);
39
+ };
40
+
41
+ /**
42
+ * Extract and decode the {@link IssuerSigned} with the {@link IssuerAuth} decoded from base64 encoded CBOR
43
+ *
44
+ * If it is not possibile to decode the provided data, the promise will be rejected with
45
+ * an instance of {@link CborFailure}.
46
+ *
47
+ * @param issuerSigned - The base64 or base64url encoded MDOC data
48
+ * @returns The decoded {@link IssuerSigned} contained in the mDOC object
49
+ */
50
+ export const decodeIssuerSigned = async (
51
+ issuerSigned: string
52
+ ): Promise<IssuerSigned> => {
53
+ const decodedIssuerSignedString =
54
+ await IoReactNativeCbor.decodeIssuerSigned(issuerSigned);
55
+ return await IssuerSignedFromString.parseAsync(decodedIssuerSignedString);
56
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * All error codes that the module could return.
3
+ */
4
+ export type CborFailureCodes =
5
+ | 'UNABLE_TO_DECODE'
6
+ | 'INVALID_ENCODING'
7
+ | 'UNKNOWN_EXCEPTION';
8
+
9
+ /**
10
+ * Error type returned by a rejected promise.
11
+ *
12
+ * If additional error information are available,
13
+ * they are stored in the {@link CborFailure["userInfo"]} field.
14
+ */
15
+ export type CborFailure = {
16
+ message: CborFailureCodes;
17
+ userInfo: Record<string, string>;
18
+ };
@@ -0,0 +1,9 @@
1
+ export { decode, decodeDocuments, decodeIssuerSigned } from './decoder';
2
+ export {
3
+ DocumentValue,
4
+ Documents,
5
+ DocumentsFromString,
6
+ IssuerSigned,
7
+ MDOC,
8
+ } from './schema';
9
+ export { type CborFailure, type CborFailureCodes } from './failure';
@@ -0,0 +1,150 @@
1
+ import { z } from 'zod';
2
+ import { coerceToJSON } from './schema.utils';
3
+
4
+ export enum DocumentTypeEnum {
5
+ MDL = 'org.iso.18013.5.1.mDL',
6
+ EU_PID = 'eu.europa.ec.eudi.pid.1',
7
+ }
8
+
9
+ export const DocumentType = z.nativeEnum(DocumentTypeEnum);
10
+ export type DocumentType = z.infer<typeof DocumentType>;
11
+
12
+ /**
13
+ * Value contained in a document
14
+ */
15
+ export const DocumentValue = z.object({
16
+ digestID: z.coerce.number().optional(),
17
+ random: z.string().optional(),
18
+ elementIdentifier: z.string(),
19
+ elementValue: z.any(),
20
+ });
21
+
22
+ export type DocumentValue = z.infer<typeof DocumentValue>;
23
+
24
+ /**
25
+ * Issuer Auth Unprotected Header Entry
26
+ */
27
+ export const IssuerAuthUnprotectedHeader = z.object({
28
+ algorithm: z.coerce.string().optional(),
29
+ keyId: z.string().optional(),
30
+ x5chain: z.array(z.string()).optional(),
31
+ });
32
+
33
+ export type IssuerAuthUnprotectedHeader = z.infer<
34
+ typeof IssuerAuthUnprotectedHeader
35
+ >;
36
+
37
+ /**
38
+ * Issuer Auth Payload Validity Info
39
+ */
40
+ export const IssuerAuthPayloadValidityInfo = z.object({
41
+ signed: z.coerce.date(),
42
+ validUntil: z.coerce.date(),
43
+ validFrom: z.coerce.date(),
44
+ expectedUpdate: z.coerce.date().optional(),
45
+ });
46
+
47
+ export type IssuerAuthPayloadValidityInfo = z.infer<
48
+ typeof IssuerAuthPayloadValidityInfo
49
+ >;
50
+
51
+ /**
52
+ * EC KEY
53
+ */
54
+ const ECKey = z.object({
55
+ kty: z.enum(['EC']),
56
+ crv: z.enum(['P-256', 'P-384', 'P-521']),
57
+ x: z.string(),
58
+ y: z.string(),
59
+ });
60
+
61
+ /**
62
+ * RSA KEY
63
+ */
64
+ const RSAKEY = z.object({
65
+ kty: z.enum(['RSA']),
66
+ alg: z.string(),
67
+ e: z.string(),
68
+ n: z.string(),
69
+ });
70
+
71
+ const PublicKey = z.union([RSAKEY, ECKey]);
72
+
73
+ /**
74
+ * Issuer Auth Payload Device Key Info
75
+ */
76
+ export const IssuerAuthPayloadDeviceKeyInfo = z.object({
77
+ deviceKey: PublicKey,
78
+ });
79
+
80
+ export type IssuerAuthPayloadDeviceKeyInfo = z.infer<
81
+ typeof IssuerAuthPayloadDeviceKeyInfo
82
+ >;
83
+
84
+ /**
85
+ * Issuer Auth Payload Object
86
+ */
87
+ export const IssuerAuthPayload = z.object({
88
+ docType: z.string().optional(),
89
+ version: z.string().optional(),
90
+ validityInfo: IssuerAuthPayloadValidityInfo,
91
+ digestAlgorithm: z.string().optional(),
92
+ deviceKeyInfo: IssuerAuthPayloadDeviceKeyInfo,
93
+ valueDigests: z.record(z.any()),
94
+ });
95
+
96
+ export type IssuerAuthPayload = z.infer<typeof IssuerAuthPayload>;
97
+
98
+ /**
99
+ * Issuer Auth Object
100
+ */
101
+ export const IssuerAuth = z.object({
102
+ rawValue: z.string().optional(),
103
+ protectedHeader: z.string().optional(),
104
+ unprotectedHeader: IssuerAuthUnprotectedHeader,
105
+ payload: IssuerAuthPayload,
106
+ signature: z.string().optional(),
107
+ });
108
+
109
+ export type IssuerAuth = z.infer<typeof IssuerAuth>;
110
+
111
+ /**
112
+ * Issuer signed object
113
+ */
114
+ export const IssuerSigned = z.object({
115
+ nameSpaces: z.record(z.string(), coerceToJSON.pipe(z.array(DocumentValue))),
116
+ issuerAuth: IssuerAuth,
117
+ });
118
+
119
+ export type IssuerSigned = z.infer<typeof IssuerSigned>;
120
+
121
+ /**
122
+ * mDOC object
123
+ */
124
+ export const MDOC = z.object({
125
+ docType: DocumentType,
126
+ issuerSigned: IssuerSigned,
127
+ });
128
+
129
+ export type MDOC = z.infer<typeof MDOC>;
130
+
131
+ /**
132
+ * CBOR decoded data containing the status, version and the list of documents
133
+ */
134
+ export const Documents = z.object({
135
+ status: z.number().optional(),
136
+ version: z.string().optional(),
137
+ documents: coerceToJSON.pipe(z.array(MDOC)),
138
+ });
139
+
140
+ /**
141
+ * Documents object from string
142
+ */
143
+ export const DocumentsFromString = coerceToJSON.pipe(Documents);
144
+
145
+ /**
146
+ * IssuerSigned object from string
147
+ */
148
+ export const IssuerSignedFromString = coerceToJSON.pipe(IssuerSigned);
149
+
150
+ export type Documents = z.infer<typeof Documents>;
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * If the value is a string, parse it as JSON.
5
+ * Otherwise, return the value as is.
6
+ * Useful for unescaping stringified JSON content
7
+ */
8
+ export const coerceToJSON = z.any().transform((any) => {
9
+ if (typeof any === 'object') {
10
+ return any;
11
+ }
12
+ return JSON.parse(any);
13
+ });
@@ -0,0 +1,53 @@
1
+ ## COSE
2
+
3
+ This module provides methods to sign and verify data with COSE.
4
+
5
+ ```typescript
6
+ import { COSE } from '@pagopa/io-react-native-cbor';
7
+ ```
8
+
9
+ ### Methods
10
+
11
+ #### `sign`
12
+
13
+ Signs base64 encoded data using COSE (CBOR Object Signing and Encryption).
14
+ Returns a `Promise` which resolves to a `string` containing the COSE-Sign1 object in base64 encoding or rejects with an instance of `CoseFailure` in case of failures.
15
+
16
+ ```typescript
17
+ try {
18
+ const coseSign1 = await COSE.sign('base64EncodedData', 'keyTag');
19
+ } catch (e) {
20
+ const { message, userInfo } = e as CoseFailure;
21
+ }
22
+ ```
23
+
24
+ #### `verify`
25
+
26
+ Verifies a COSE-Sign1 object using the provided public key.
27
+ Returns a `Promise` which resolves to a `boolean` indicating if the signature is valid or rejects with an instance of `CoseFailure` in case of failures.
28
+
29
+ ```typescript
30
+ // public key in JWK format
31
+ const publicKey = {
32
+ kty: 'EC',
33
+ crv: 'P-256',
34
+ x: '...',
35
+ y: '...',
36
+ };
37
+
38
+ try {
39
+ const isValid = await COSE.verify('coseSign1Base64Data', publicKey);
40
+ } catch (e) {
41
+ const { message, userInfo } = e as CoseFailure;
42
+ }
43
+ ```
44
+
45
+ ### Error Codes
46
+
47
+ | Type | Platform | Description |
48
+ | -------------------- | ----------- | -------------------------------------------------- |
49
+ | PUBLIC_KEY_NOT_FOUND | Android/iOS | The public key is missing for the specified keyTag |
50
+ | INVALID_ENCODING | Android/iOS | Provided payload has incorrect encoding |
51
+ | UNABLE_TO_SIGN | Android/iOS | It was not possible to sign the given string |
52
+ | THREADING_ERROR | iOS | Unexpected failure |
53
+ | UNKNOWN_EXCEPTION | Android/iOS | Unexpected failure |
@@ -0,0 +1,20 @@
1
+ /**
2
+ * All error codes that the module could return.
3
+ */
4
+ export type CoseFailureCodes =
5
+ | 'PUBLIC_KEY_NOT_FOUND'
6
+ | 'UNABLE_TO_SIGN'
7
+ | 'INVALID_ENCODING'
8
+ | 'THREADING_ERROR'
9
+ | 'UNKNOWN_EXCEPTION';
10
+
11
+ /**
12
+ * Error type returned by a rejected promise.
13
+ *
14
+ * If additional error information are available,
15
+ * they are stored in the {@link CoseError["userInfo"]} field.
16
+ */
17
+ export type CoseFailure = {
18
+ message: CoseFailureCodes;
19
+ userInfo: Record<string, string>;
20
+ };
@@ -0,0 +1,2 @@
1
+ export { sign, verify } from './sign';
2
+ export { type CoseFailure, type CoseFailureCodes } from './failure';
@@ -0,0 +1,25 @@
1
+ import type { PublicKey } from '@pagopa/io-react-native-crypto';
2
+ import { IoReactNativeCbor } from '..';
3
+
4
+ /**
5
+ * Sign base64 encoded data with COSE and return the COSE-Sign1 object in base64 encoding
6
+ *
7
+ * @param payload - The base64 or base64url encoded payload to sign
8
+ * @param keyTag - The alias of the key to use for signing.
9
+ * @throws {CoseFailure} If the key does not exist
10
+ * @returns The COSE-Sign1 object in base64 encoding
11
+ */
12
+ export const sign = async (payload: string, keyTag: string): Promise<string> =>
13
+ await IoReactNativeCbor.sign(payload, keyTag);
14
+
15
+ /**
16
+ * Verifies a COSE-Sign1 object with the provided public key
17
+ *
18
+ * @param data - The COSE-Sign1 object in base64 or base64url encoding
19
+ * @param publicKey - The public key in JWK format
20
+ * @returns true if the signature is valid, false otherwise
21
+ */
22
+ export const verify = async (
23
+ data: string,
24
+ publicKey: PublicKey
25
+ ): Promise<boolean> => await IoReactNativeCbor.verify(data, publicKey);
@@ -0,0 +1,18 @@
1
+ import { NativeModules, Platform } from 'react-native';
2
+
3
+ const LINKING_ERROR =
4
+ `The package '@pagopa/io-react-native-cbor' doesn't seem to be linked. Make sure: \n\n` +
5
+ Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
6
+ '- You rebuilt the app after installing the package\n' +
7
+ '- You are not using Expo Go\n';
8
+
9
+ export const IoReactNativeCbor = NativeModules.IoReactNativeCbor
10
+ ? NativeModules.IoReactNativeCbor
11
+ : new Proxy(
12
+ {},
13
+ {
14
+ get() {
15
+ throw new Error(LINKING_ERROR);
16
+ },
17
+ }
18
+ );
package/src/index.tsx ADDED
@@ -0,0 +1,5 @@
1
+ import * as CBOR from './cbor/cbor';
2
+ import * as COSE from './cbor/cose';
3
+ import * as ISO18013_5 from './iso18013/iso18013-5';
4
+ import * as ISO18013_7 from './iso18013/iso18013-7';
5
+ export { CBOR, COSE, ISO18013_5, ISO18013_7 };
@@ -0,0 +1,25 @@
1
+ import { NativeModules, Platform } from 'react-native';
2
+ export {
3
+ type AcceptedFields,
4
+ type EventError,
5
+ type VerifierRequest,
6
+ parseEventError,
7
+ parseVerifierRequest,
8
+ } from './iso18013-5/schema';
9
+
10
+ const LINKING_ERROR =
11
+ `The package '@pagopa/io-react-native-proximity' doesn't seem to be linked. Make sure: \n\n` +
12
+ Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
13
+ '- You rebuilt the app after installing the package\n' +
14
+ '- You are not using Expo Go\n';
15
+
16
+ export const IoReactNativeProximity = NativeModules.IoReactNativeIso18013
17
+ ? NativeModules.IoReactNativeIso18013
18
+ : new Proxy(
19
+ {},
20
+ {
21
+ get() {
22
+ throw new Error(LINKING_ERROR);
23
+ },
24
+ }
25
+ );
@@ -0,0 +1,234 @@
1
+ # ISO18013-5
2
+
3
+ This library provides a React Native module based on [iso18013-android](https://github.com/pagopa/iso18013-android) and [iso18013-ios](https://github.com/pagopa/iso18013-ios) which allows mDL proximity presentation according to the
4
+ ISO 18013-5 standard and remote presentation according to the ISO 18013-7 standard.
5
+
6
+ ## Installation
7
+
8
+ ## Usage
9
+
10
+ ### `events`
11
+
12
+ This library emits the following events:
13
+ | Event | Payload | Description |
14
+ |---------------------------|--------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|
15
+ | onDeviceConnecting (iOS only) | `undefined` | Event dispatched when the verifier app is connecting |
16
+ | onDeviceConnected | `undefined` | Event dispatched when the verifier app is connected. |
17
+ | onDocumentRequestReceived | `{ data: string } \| undefined` | Event dispatched when the consumer app receives a new request, contained in the data payload. It can be parsed via the `parseVerifierRequest` provided [here](src/schema.ts). |
18
+ | onDeviceDisconnected | `undefined` | Event dispatched when the verifier app disconnects. |
19
+ | onError | `{ error: string } \| undefined` | Event dispatched when an error occurs which is contained in the error payload. It can be parsed via the `parseError` provided [here](src/schema.ts). |
20
+
21
+ Listeners can be added using the `addListener` method and removed using the `removeListener` method.
22
+
23
+ ```typescript
24
+ import { ISO18013_5 } from '@pagopa/io-react-native-iso18013';
25
+
26
+ ISO18013_5.addListener('event', () => console.log('event occurred'));
27
+
28
+ ISO18013_5.removeListener('event');
29
+ ```
30
+
31
+ #### `onDeviceConnecting`
32
+
33
+ ```typescript
34
+ import { ISO18013_5 } from '@pagopa/io-react-native-iso18013';
35
+
36
+ ISO18013_5.addListener('onDeviceConnecting', () => {
37
+ console.log('Device is connecting');
38
+ });
39
+ ```
40
+
41
+ #### `onDeviceConnected`
42
+
43
+ ```typescript
44
+ import { ISO18013_5 } from '@pagopa/io-react-native-iso18013';
45
+
46
+ ISO18013_5.addListener('onDeviceConnected', () => {
47
+ console.log('Device is connected');
48
+ });
49
+ ```
50
+
51
+ #### `onDocumentRequestReceived`
52
+
53
+ ```typescript
54
+ import { ISO18013_5 } from '@pagopa/io-react-native-iso18013';
55
+
56
+ ISO18013_5.addListener(
57
+ 'onDocumentRequestReceived',
58
+ (payload: ISO18013_5.EventsPayload['onDocumentRequestReceived']) => {
59
+ console.log('onDocumentRequestReceived', payload);
60
+ if (!payload || !payload.data) {
61
+ console.warn('Request does not contain a message.');
62
+ return;
63
+ }
64
+
65
+ // Parse and verify the received request with the exposed function
66
+ const parsedJson = JSON.parse(payload.data);
67
+ console.log('Parsed JSON:', parsedJson);
68
+ const parsedResponse = parseVerifierRequest(parsedJson);
69
+ console.log('Parsed response:', JSON.stringify(parsedResponse));
70
+ }
71
+ );
72
+ ```
73
+
74
+ #### `onDeviceDisconnected`
75
+
76
+ ```typescript
77
+ import { ISO18013_5 } from '@pagopa/io-react-native-iso18013';
78
+
79
+ ISO18013_5.addListener('onDeviceDisconnected', () => {
80
+ console.log('Device is disconnected');
81
+ });
82
+ ```
83
+
84
+ #### `onError`
85
+
86
+ ```typescript
87
+ import { ISO18013_5 } from '@pagopa/io-react-native-iso18013';
88
+
89
+ ISO18013_5.addListener(
90
+ 'onError',
91
+ async (data: ISO18013_5.EventsPayload['onError']) => {
92
+ try {
93
+ if (!data || !data.error) {
94
+ throw new Error('No error data received');
95
+ }
96
+ const parsedError = parseError(data.error);
97
+ console.error(`onError: ${parsedError}`);
98
+ } catch (e) {
99
+ console.error('Error parsing onError data:', e);
100
+ } finally {
101
+ // Close the flow on error
102
+ await closeFlow();
103
+ }
104
+ }
105
+ );
106
+ ```
107
+
108
+ ### `start`
109
+
110
+ Starts the proximity flow and starts the bluetooth service. This method also accepts optional parameters to configure the initialization on Android, along with the possibility
111
+ to specify a certificates of array to verify the reader app.
112
+
113
+ ```typescript
114
+ import { ISO18013_5 } from '@pagopa/io-react-native-iso18013';
115
+
116
+ await ISO18013_5.start();
117
+ ```
118
+
119
+ ### `getQrCodeString`
120
+
121
+ Returns the QR code string which contains a base64url encoded CBOR object which encodes the bluetooth engagement data.
122
+ It can be used to display the QR code in the UI which will be scanned by the verifier app.
123
+
124
+ ```typescript
125
+ import { ISO18013_5 } from '@pagopa/io-react-native-iso18013';
126
+
127
+ const qrCodeString = await ISO18013_5.getQrCodeString();
128
+ console.log(qrCodeString);
129
+ ```
130
+
131
+ ### `generateResponse`
132
+
133
+ Generates a response that will be sent to the verifier app containing the requested documents.
134
+
135
+ ```typescript
136
+ import { ISO18013_5 } from '@pagopa/io-react-native-iso18013';
137
+
138
+ const response = await ISO18013_5.generateResponse({
139
+ documents: [
140
+ {
141
+ type: 'mDL',
142
+ data: 'base64url-encoded-data',
143
+ },
144
+ ],
145
+ });
146
+ console.log(response);
147
+ ```
148
+
149
+ ### `sendResponse`
150
+
151
+ Sends the response generate by `generateResponse` to the verifier app.
152
+
153
+ ```typescript
154
+ import { ISO18013_5 } from '@pagopa/io-react-native-iso18013';
155
+
156
+ await ISO18013_5.sendResponse(response);
157
+ ```
158
+
159
+ ### `sendErrorResponse`
160
+
161
+ Sends an error response to the verifier app. The supported error codes are defined in the Table 20 of the ISO 18013-5 standard and are coded in the `ErrorCode` enum.
162
+
163
+ ```typescript
164
+ import { ISO18013_5, ErrorCode } from '@pagopa/io-react-native-iso18013';
165
+
166
+ await ISO18013_5.sendErrorResponse({
167
+ errorCode: ErrorCode.SESSION_ENCRYPTION,
168
+ errorMessage: 'An error occurred while encrypting the session',
169
+ });
170
+ ```
171
+
172
+ ### `close`
173
+
174
+ Closes the QR engagement by releasing the resources allocated during the `start` method.
175
+ Before starting a new flow, it is necessary to call this method to ensure that the previous flow is properly closed.
176
+ The listeners can be removed using the `removeListener` method.
177
+
178
+ ```typescript
179
+ import { ISO18013_5 } from '@pagopa/io-react-native-iso18013';
180
+
181
+ await ISO18013_5.close();
182
+ ```
183
+
184
+ ## Proximity Flow Schema
185
+
186
+ This section describes a high level overview of the interactions between an app implementing the `io-react-native-proximity` library and a verifier app.
187
+
188
+ ```mermaid
189
+ sequenceDiagram
190
+ participant app as Consumer App
191
+ participant proximity as io-react-native-iso18013
192
+ participant verifier as Verifier App
193
+
194
+ Note over proximity, verifier: If an error occurs during the flow, the onError callback is triggered
195
+ app->>+proximity: Calls start()
196
+ app->>+proximity: Calls getQrCode()
197
+ proximity-->>+app: QR code string
198
+ app->>+app: Renders the QR code string
199
+ verifier->>+app: Scans the QR code
200
+ proximity->>+app: Triggers the onDeviceConnecting callback
201
+ verifier->>+app: Connects to the verifier app
202
+ proximity->>+app: Triggers the onDeviceConnected callback
203
+ verifier->>+app: Requests the credential(s)
204
+ proximity->>+app: Triggers the onDocumentRequestReceived() callback
205
+ app->>+proximity: Parses the request by calling parseVerifierRequest()
206
+ proximity-->>+app: Returns a VerifierRequest
207
+ app->>+app: Shows the requested data and asks for user consent
208
+ alt The user accepts
209
+ app->>+proximity: Calls generateResponse()
210
+ proximity-->>+app: Returns the response
211
+ app->>+proximity: Calls sendResponse()
212
+ proximity->>+verifier: Sends the response
213
+ verifier->>+verifier: Shows the received credential(s) and the verification result
214
+ else The user rejects
215
+ app->>+proximity: Calls sendErrorResponse()
216
+ proximity->>+verifier: Sends the error response code
217
+ verifier->>+verifier: Shows the received error response code
218
+ end
219
+ verifier->>+app: Closes the connection
220
+ proximity->>+app: Calls the onDeviceDisconnected callback
221
+ ```
222
+
223
+ ## Error Codes
224
+
225
+ | Type | Platform | Description |
226
+ | ------------------------------- | ----------- | ---------------------------------------------------------------------------- |
227
+ | DRH_NOT_DEFINED | Android | The device retrieval helper hasn't been initialized, call the `start` method |
228
+ | QR_ENGAGEMENT_NOT_DEFINED_ERROR | Android | The QR engagement hasn't been initialized, call the `start` method |
229
+ | START_ERROR | Android/iOS | An error occurred while initializing the required resources |
230
+ | GET_QR_CODE_ERROR | Android/iOS | An error occurred while generating the engagement QR code |
231
+ | GENERATE_RESPONSE_ERROR | Android/iOS | An error occurred while generating the response for the verifier app |
232
+ | SEND_RESPONSE_ERROR | Android/iOS | An error occurred while sending the response to the verifier app |
233
+ | SEND_ERROR_RESPONSE_ERROR | Android/iOS | An error occurred while sending the error response to the verifier app |
234
+ | CLOSE_ERROR | Android | An error occured while closing the required resources |
@@ -0,0 +1,23 @@
1
+ export {
2
+ type AcceptedFields,
3
+ type EventError,
4
+ type VerifierRequest,
5
+ parseEventError,
6
+ parseVerifierRequest,
7
+ } from './schema';
8
+
9
+ export {
10
+ ErrorCode,
11
+ type Events,
12
+ type EventsPayload,
13
+ addListener,
14
+ close,
15
+ generateResponse,
16
+ getQrCodeString,
17
+ removeListener,
18
+ sendErrorResponse,
19
+ sendResponse,
20
+ start,
21
+ } from './proximity';
22
+
23
+ export { type RequestedDocument } from '../types';