partner_react_native_sdk 0.1.4 → 0.1.6
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/lib/module/helpers/analytics/analytics_logger.js +4 -3
- package/lib/module/helpers/analytics/analytics_logger.js.map +1 -1
- package/lib/module/helpers/network/APICall.js +96 -4
- package/lib/module/helpers/network/APICall.js.map +1 -1
- package/lib/module/helpers/network/Encryption.js +241 -0
- package/lib/module/helpers/network/Encryption.js.map +1 -0
- package/lib/module/helpers/partner_library_react_native.js +52 -54
- package/lib/module/helpers/partner_library_react_native.js.map +1 -1
- package/lib/module/helpers/webview.js +30 -10
- package/lib/module/helpers/webview.js.map +1 -1
- package/lib/typescript/src/helpers/analytics/analytics_logger.d.ts.map +1 -1
- package/lib/typescript/src/helpers/network/APICall.d.ts.map +1 -1
- package/lib/typescript/src/helpers/network/Encryption.d.ts +1 -0
- package/lib/typescript/src/helpers/network/Encryption.d.ts.map +1 -0
- package/lib/typescript/src/helpers/partner_library_react_native.d.ts.map +1 -1
- package/lib/typescript/src/helpers/webview.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/helpers/analytics/analytics_logger.tsx +73 -72
- package/src/helpers/network/APICall.tsx +139 -54
- package/src/helpers/network/Encryption.tsx +239 -0
- package/src/helpers/partner_library_react_native.tsx +279 -273
- package/src/helpers/webview.tsx +39 -12
|
@@ -24,7 +24,8 @@ export class AnalyticsLogger {
|
|
|
24
24
|
async logEvent(info) {
|
|
25
25
|
const device = await DeviceInfoManager.getDeviceInfo();
|
|
26
26
|
const now = new Date().toLocaleString('sv-SE').replace('T', ' ').slice(0, 19);
|
|
27
|
-
console.log('Logging event:', info);
|
|
27
|
+
// console.log('Logging event:', info);
|
|
28
|
+
|
|
28
29
|
const event = new AnalyticsEvent({
|
|
29
30
|
time: now,
|
|
30
31
|
info,
|
|
@@ -54,8 +55,8 @@ export class AnalyticsLogger {
|
|
|
54
55
|
this.events = [];
|
|
55
56
|
this._lastPost = Date.now();
|
|
56
57
|
try {
|
|
57
|
-
console.log("ANALYTICS_URL ", this.analyticsUrl);
|
|
58
|
-
console.log('Posting events:', eventsToSend);
|
|
58
|
+
// console.log("ANALYTICS_URL ", this.analyticsUrl);
|
|
59
|
+
// console.log('Posting events:', eventsToSend);
|
|
59
60
|
const payload = {
|
|
60
61
|
body: {
|
|
61
62
|
data: eventsToSend.map(event => event.toJson())
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["APICall","ServiceNames","DeviceInfoManager","AnalyticsEvent","EventStorage","AnalyticsLogger","apiCall","events","debouncerTimer","_lastPost","maxBatchSize","maxInterval","analyticsUrl","ANALYTICS_URL","eventStorage","constructor","getInstance","instance","logEvent","info","device","getDeviceInfo","now","Date","toLocaleString","replace","slice","
|
|
1
|
+
{"version":3,"names":["APICall","ServiceNames","DeviceInfoManager","AnalyticsEvent","EventStorage","AnalyticsLogger","apiCall","events","debouncerTimer","_lastPost","maxBatchSize","maxInterval","analyticsUrl","ANALYTICS_URL","eventStorage","constructor","getInstance","instance","logEvent","info","device","getDeviceInfo","now","Date","toLocaleString","replace","slice","event","time","loadEvents","push","saveEvents","nowMillis","length","post","debouncePost","clearTimeout","setTimeout","eventsToSend","payload","body","data","map","toJson","response","callAPI","clearEvents","error","console"],"sourceRoot":"../../../../src","sources":["helpers/analytics/analytics_logger.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
// APICall.ts (updated)
|
|
3
4
|
import NetworkManager from "./network_manager.js";
|
|
4
5
|
import { HeaderManager } from "../utils/headerManager.js";
|
|
6
|
+
|
|
7
|
+
// import {
|
|
8
|
+
// generateAESKey,
|
|
9
|
+
// exportAESKeyBase64,
|
|
10
|
+
// encryptAESKeyWithRSA,
|
|
11
|
+
// encryptAES,
|
|
12
|
+
// decryptAES,
|
|
13
|
+
// getWebsiteKey,
|
|
14
|
+
// } from './Encryption';
|
|
15
|
+
|
|
5
16
|
export class APICall {
|
|
6
17
|
networkManager = new NetworkManager();
|
|
7
18
|
headerManager = new HeaderManager();
|
|
@@ -15,7 +26,7 @@ export class APICall {
|
|
|
15
26
|
const response = encrypted ? await this._callAPIEncrypt(method, apiUrl, body, headers) : await this._callAPIRaw(method, apiUrl, body, headers);
|
|
16
27
|
return response;
|
|
17
28
|
} catch (error) {
|
|
18
|
-
console.log(
|
|
29
|
+
console.log('Error in callAPI:', error);
|
|
19
30
|
throw error;
|
|
20
31
|
}
|
|
21
32
|
}
|
|
@@ -32,10 +43,91 @@ export class APICall {
|
|
|
32
43
|
});
|
|
33
44
|
}
|
|
34
45
|
|
|
35
|
-
//
|
|
46
|
+
// ----------------- ENCRYPTED CALL -----------------
|
|
36
47
|
async _callAPIEncrypt(method, apiUrl, body, headers) {
|
|
37
|
-
//
|
|
38
|
-
|
|
48
|
+
// 1) Generate ephemeral AES-256 key
|
|
49
|
+
// const aesKey = await generateAESKey();
|
|
50
|
+
// // 2) Export AES key bytes -> Base64 (for RSA input)
|
|
51
|
+
// const aesKeyBase64 = await exportAESKeyBase64(aesKey);
|
|
52
|
+
// // 3) Fetch server public key (cached) and RSA-wrap the AES key
|
|
53
|
+
// const websiteKey = await getWebsiteKey(); // { kid, public, expiry }
|
|
54
|
+
// const rsaEncryptedKey = await encryptAESKeyWithRSA(
|
|
55
|
+
// aesKeyBase64,
|
|
56
|
+
// websiteKey.public
|
|
57
|
+
// );
|
|
58
|
+
// // 4) Encrypt payload with AES-GCM -> Base64(IV||CT||TAG)
|
|
59
|
+
// const encryptedPayload = await encryptAES(
|
|
60
|
+
// JSON.stringify(body ?? {}),
|
|
61
|
+
// aesKey
|
|
62
|
+
// );
|
|
63
|
+
// // 5) Merge headers (stringify all values)
|
|
64
|
+
// const baseHeaders = await this.headerManager.generateHeaders();
|
|
65
|
+
// const mergedHeaders: Record<string, string> = {
|
|
66
|
+
// ...Object.fromEntries(
|
|
67
|
+
// Object.entries(baseHeaders).map(([k, v]) => [k, String(v)])
|
|
68
|
+
// ),
|
|
69
|
+
// ...(headers
|
|
70
|
+
// ? Object.fromEntries(
|
|
71
|
+
// Object.entries(headers).map(([k, v]) => [k, String(v)])
|
|
72
|
+
// )
|
|
73
|
+
// : {}),
|
|
74
|
+
// };
|
|
75
|
+
// // 6) Add encryption headers
|
|
76
|
+
// const encryptedHeaders: Record<string, string> = {
|
|
77
|
+
// 'Content-Type': 'application/json;charset=utf-8',
|
|
78
|
+
// 'Accept': 'application/json',
|
|
79
|
+
// ...mergedHeaders,
|
|
80
|
+
// 'kid': websiteKey.kid ?? '',
|
|
81
|
+
// 'key': rsaEncryptedKey ?? '',
|
|
82
|
+
// };
|
|
83
|
+
// // 7) Make the encrypted request with { encrypted: "<blob>" }
|
|
84
|
+
// const response = await this.networkManager.request({
|
|
85
|
+
// url: apiUrl,
|
|
86
|
+
// method,
|
|
87
|
+
// body: { encrypted: encryptedPayload },
|
|
88
|
+
// headers: encryptedHeaders,
|
|
89
|
+
// });
|
|
90
|
+
// // 8) Decrypt response if it has { encrypted }
|
|
91
|
+
// const decrypted = await APICall.handleDecryptedResponse(response, aesKey);
|
|
92
|
+
// if (decrypted != null) {
|
|
93
|
+
// if (response) {
|
|
94
|
+
// response.data = decrypted;
|
|
95
|
+
// }
|
|
96
|
+
// }
|
|
97
|
+
// return response;
|
|
98
|
+
// }
|
|
99
|
+
// // ----------------- RESPONSE DECRYPT -----------------
|
|
100
|
+
// static async handleDecryptedResponse(
|
|
101
|
+
// response: any,
|
|
102
|
+
// aesKey: CryptoKey
|
|
103
|
+
// ): Promise<Record<string, any> | null> {
|
|
104
|
+
// try {
|
|
105
|
+
// if (!response) return null;
|
|
106
|
+
// const raw = response.data;
|
|
107
|
+
// // Accept string or object
|
|
108
|
+
// const data: Record<string, any> =
|
|
109
|
+
// typeof raw === 'string' ? JSON.parse(raw) : (raw as any);
|
|
110
|
+
// if (!data || typeof data !== 'object' || !('encrypted' in data)) {
|
|
111
|
+
// // no encrypted field, return null to signal "not decrypted"
|
|
112
|
+
// return null;
|
|
113
|
+
// }
|
|
114
|
+
// const encryptedPayload = String(data.encrypted ?? '');
|
|
115
|
+
// if (!encryptedPayload) return null;
|
|
116
|
+
// const decryptedJson = await decryptAES(encryptedPayload, aesKey);
|
|
117
|
+
// try {
|
|
118
|
+
// const obj = JSON.parse(decryptedJson);
|
|
119
|
+
// if (obj && typeof obj === 'object') {
|
|
120
|
+
// return obj as Record<string, any>;
|
|
121
|
+
// }
|
|
122
|
+
// return null;
|
|
123
|
+
// } catch {
|
|
124
|
+
// // decrypted payload wasn't valid JSON
|
|
125
|
+
// return null;
|
|
126
|
+
// }
|
|
127
|
+
// } catch {
|
|
128
|
+
// return null;
|
|
129
|
+
// }
|
|
130
|
+
// }
|
|
39
131
|
}
|
|
40
132
|
}
|
|
41
133
|
//# sourceMappingURL=APICall.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NetworkManager","HeaderManager","APICall","networkManager","headerManager","callAPI","method","apiUrl","options","body","headers","encrypted","response","_callAPIEncrypt","_callAPIRaw","error","console","log","mergedHeaders","generateHeaders","request","url"],"sourceRoot":"../../../../src","sources":["helpers/network/APICall.tsx"],"mappings":";;AAAA,OAAOA,cAAc,MAAM,sBAAmB;AAC9C,SAASC,aAAa,QAAQ,2BAAwB;
|
|
1
|
+
{"version":3,"names":["NetworkManager","HeaderManager","APICall","networkManager","headerManager","callAPI","method","apiUrl","options","body","headers","encrypted","response","_callAPIEncrypt","_callAPIRaw","error","console","log","mergedHeaders","generateHeaders","request","url"],"sourceRoot":"../../../../src","sources":["helpers/network/APICall.tsx"],"mappings":";;AAAA;AACA,OAAOA,cAAc,MAAM,sBAAmB;AAC9C,SAASC,aAAa,QAAQ,2BAAwB;;AAEtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAO,MAAMC,OAAO,CAAC;EACXC,cAAc,GAAmB,IAAIH,cAAc,CAAC,CAAC;EACrDI,aAAa,GAAkB,IAAIH,aAAa,CAAC,CAAC;EAE1D,MAAMI,OAAOA,CACXC,MAAc,EACdC,MAAc,EACdC,OAIC,EACa;IACd,MAAM;MAAEC,IAAI;MAAEC,OAAO;MAAEC,SAAS,GAAG;IAAM,CAAC,GAAGH,OAAO,IAAI,CAAC,CAAC;IAC1D,IAAI;MACF,MAAMI,QAAQ,GAAGD,SAAS,GACtB,MAAM,IAAI,CAACE,eAAe,CAACP,MAAM,EAAEC,MAAM,EAAEE,IAAI,EAAEC,OAAO,CAAC,GACzD,MAAM,IAAI,CAACI,WAAW,CAACR,MAAM,EAAEC,MAAM,EAAEE,IAAI,EAAEC,OAAO,CAAC;MAEzD,OAAOE,QAAQ;IACjB,CAAC,CAAC,OAAOG,KAAK,EAAE;MACdC,OAAO,CAACC,GAAG,CAAC,mBAAmB,EAAEF,KAAK,CAAC;MACvC,MAAMA,KAAK;IACb;EACF;EAEA,MAAcD,WAAWA,CACvBR,MAAc,EACdC,MAAc,EACdE,IAA0B,EAC1BC,OAA6B,EACf;IACd,MAAMQ,aAAa,GAAG;MACpB,IAAI,MAAM,IAAI,CAACd,aAAa,CAACe,eAAe,CAAC,CAAC,CAAC;MAC/C,IAAIT,OAAO,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAACP,cAAc,CAACiB,OAAO,CAAC;MACjCC,GAAG,EAAEd,MAAM;MACXD,MAAM,EAAEA,MAAM;MACdG,IAAI,EAAEA,IAAI;MACVC,OAAO,EAAEQ;IACX,CAAC,CAAC;EACJ;;EAEA;EACA,MAAcL,eAAeA,CAC3BP,MAAc,EACdC,MAAc,EACdE,IAA0B,EAC1BC,OAA6B,EACf;IACd;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;EAAA;AAEJ","ignoreList":[]}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// // Encryption.tsx
|
|
2
|
+
// // Tested with RN 0.73+.
|
|
3
|
+
|
|
4
|
+
// import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
5
|
+
// import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
// import * as base64js from 'base64-js';
|
|
7
|
+
// import { ServiceNames } from '../ServiceNames';
|
|
8
|
+
|
|
9
|
+
// type WebsiteKey = {
|
|
10
|
+
// kid: string;
|
|
11
|
+
// public: string; // PEM
|
|
12
|
+
// expiry: string; // ISO8601
|
|
13
|
+
// };
|
|
14
|
+
|
|
15
|
+
// const KEY_WEB = 'KEY_WEB';
|
|
16
|
+
// const KEY_WEB_EXPIRY = 'KEY_WEB_EXPIRY';
|
|
17
|
+
|
|
18
|
+
// const GCM_NONCE_LEN = 12; // 12-byte IV
|
|
19
|
+
// const GCM_TAG_LEN = 16; // 16-byte auth tag
|
|
20
|
+
// const AES_KEY_LEN = 256; // bits
|
|
21
|
+
|
|
22
|
+
// // ---------- Base64 helpers ----------
|
|
23
|
+
// const bytesToB64 = (bytes: Uint8Array): string => base64js.fromByteArray(bytes);
|
|
24
|
+
|
|
25
|
+
// const b64ToBytes = (b64: string): Uint8Array => base64js.toByteArray(b64);
|
|
26
|
+
|
|
27
|
+
// // ---------- UTF-8 helpers ----------
|
|
28
|
+
// const utf8Encode = (s: string): Uint8Array => new TextEncoder().encode(s);
|
|
29
|
+
|
|
30
|
+
// const utf8Decode = (bytes: Uint8Array): string =>
|
|
31
|
+
// new TextDecoder().decode(bytes);
|
|
32
|
+
|
|
33
|
+
// // ---------- AES-256-GCM ----------
|
|
34
|
+
|
|
35
|
+
// /** Generate a random AES-256-GCM CryptoKey (extractable for raw export). */
|
|
36
|
+
// export async function generateAESKey(): Promise<CryptoKey> {
|
|
37
|
+
// return await crypto.subtle.generateKey(
|
|
38
|
+
// { name: 'AES-GCM', length: AES_KEY_LEN },
|
|
39
|
+
// true, // extractable to raw for Base64 export
|
|
40
|
+
// ['encrypt', 'decrypt']
|
|
41
|
+
// );
|
|
42
|
+
// }
|
|
43
|
+
|
|
44
|
+
// /** Export AES key bytes → Base64 (to match your RSA input). */
|
|
45
|
+
// export async function exportAESKeyBase64(key: CryptoKey): Promise<string> {
|
|
46
|
+
// const raw = new Uint8Array(await crypto.subtle.exportKey('raw', key));
|
|
47
|
+
// return bytesToB64(raw);
|
|
48
|
+
// }
|
|
49
|
+
|
|
50
|
+
// /**
|
|
51
|
+
// * Encrypt plaintext with AES-GCM and return Base64( IV || ciphertext || tag )
|
|
52
|
+
// * Exactly matches your Flutter packing:
|
|
53
|
+
// * - IV: 12 bytes
|
|
54
|
+
// * - SubtleCrypto returns ciphertext||tag; we prepend IV and then Base64 the whole blob.
|
|
55
|
+
// */
|
|
56
|
+
// export async function encryptAES(
|
|
57
|
+
// plaintext: string,
|
|
58
|
+
// key: CryptoKey
|
|
59
|
+
// ): Promise<string> {
|
|
60
|
+
// const iv = crypto.getRandomValues(new Uint8Array(GCM_NONCE_LEN));
|
|
61
|
+
// const ptBytes = utf8Encode(plaintext);
|
|
62
|
+
|
|
63
|
+
// const ctWithTag = new Uint8Array(
|
|
64
|
+
// await crypto.subtle.encrypt(
|
|
65
|
+
// { name: 'AES-GCM', iv }, // 96-bit nonce
|
|
66
|
+
// key,
|
|
67
|
+
// ptBytes
|
|
68
|
+
// )
|
|
69
|
+
// );
|
|
70
|
+
// // Pack IV || (ciphertext||tag)
|
|
71
|
+
// const out = new Uint8Array(iv.length + ctWithTag.length);
|
|
72
|
+
// out.set(iv, 0);
|
|
73
|
+
// out.set(ctWithTag, iv.length);
|
|
74
|
+
// return bytesToB64(out);
|
|
75
|
+
// }
|
|
76
|
+
|
|
77
|
+
// /**
|
|
78
|
+
// * Decrypt Base64( IV || ciphertext || tag ) to plaintext.
|
|
79
|
+
// * Splits IV (12), tag (16) and feeds ciphertext||tag to AES-GCM.
|
|
80
|
+
// */
|
|
81
|
+
// export async function decryptAES(
|
|
82
|
+
// b64Data: string,
|
|
83
|
+
// key: CryptoKey
|
|
84
|
+
// ): Promise<string> {
|
|
85
|
+
// const data = b64ToBytes(b64Data);
|
|
86
|
+
// if (data.length < GCM_NONCE_LEN + GCM_TAG_LEN + 1) {
|
|
87
|
+
// throw new Error('Invalid GCM payload length');
|
|
88
|
+
// }
|
|
89
|
+
// const iv = data.slice(0, GCM_NONCE_LEN);
|
|
90
|
+
// const ctPlusTag = data.slice(GCM_NONCE_LEN); // subtle needs ciphertext||tag
|
|
91
|
+
// const pt = new Uint8Array(
|
|
92
|
+
// await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ctPlusTag)
|
|
93
|
+
// );
|
|
94
|
+
// return utf8Decode(pt);
|
|
95
|
+
// }
|
|
96
|
+
|
|
97
|
+
// // ---------- RSA-OAEP (SHA-256) ----------
|
|
98
|
+
|
|
99
|
+
// /** Parse PEM public key and import as CryptoKey (RSA-OAEP with SHA-256). */
|
|
100
|
+
// async function importRsaPublicKeyFromPem(pem: string): Promise<CryptoKey> {
|
|
101
|
+
// // Tolerate PEMs with/without headers
|
|
102
|
+
// const clean = pem
|
|
103
|
+
// .replace(/-----BEGIN PUBLIC KEY-----/g, '')
|
|
104
|
+
// .replace(/-----END PUBLIC KEY-----/g, '')
|
|
105
|
+
// .replace(/\s+/g, '');
|
|
106
|
+
// const der = b64ToBytes(clean);
|
|
107
|
+
// return await crypto.subtle.importKey(
|
|
108
|
+
// 'spki',
|
|
109
|
+
// der,
|
|
110
|
+
// { name: 'RSA-OAEP', hash: 'SHA-256' },
|
|
111
|
+
// false,
|
|
112
|
+
// ['encrypt']
|
|
113
|
+
// );
|
|
114
|
+
// }
|
|
115
|
+
|
|
116
|
+
// /**
|
|
117
|
+
// * RSA-OAEP(SHA-256) encrypts the UTF-8 bytes of the **Base64(AES key)** string.
|
|
118
|
+
// * Returns Base64 ciphertext.
|
|
119
|
+
// */
|
|
120
|
+
// export async function encryptAESKeyWithRSA(
|
|
121
|
+
// aesKeyBase64: string,
|
|
122
|
+
// publicKeyPem: string
|
|
123
|
+
// ): Promise<string> {
|
|
124
|
+
// const pub = await importRsaPublicKeyFromPem(publicKeyPem);
|
|
125
|
+
// const data = utf8Encode(aesKeyBase64);
|
|
126
|
+
// const enc = new Uint8Array(
|
|
127
|
+
// await crypto.subtle.encrypt({ name: 'RSA-OAEP' }, pub, data)
|
|
128
|
+
// );
|
|
129
|
+
// return bytesToB64(enc);
|
|
130
|
+
// }
|
|
131
|
+
|
|
132
|
+
// // ---------- Website key fetch / cache ----------
|
|
133
|
+
|
|
134
|
+
// /**
|
|
135
|
+
// * Fetches & caches the server public key.
|
|
136
|
+
// * Accepts two shapes (same as your Flutter):
|
|
137
|
+
// * A) { "<kid>": { kid, public, expiry } }
|
|
138
|
+
// * B) { kid, public, expiry }
|
|
139
|
+
// */
|
|
140
|
+
// export async function getWebsiteKey(): Promise<WebsiteKey> {
|
|
141
|
+
// const cachedJson = await AsyncStorage.getItem(KEY_WEB);
|
|
142
|
+
// const cachedExpiry = await AsyncStorage.getItem(KEY_WEB_EXPIRY);
|
|
143
|
+
|
|
144
|
+
// if (cachedJson && cachedExpiry) {
|
|
145
|
+
// try {
|
|
146
|
+
// const expiry = new Date(cachedExpiry);
|
|
147
|
+
// if (new Date() < expiry) {
|
|
148
|
+
// return JSON.parse(cachedJson) as WebsiteKey;
|
|
149
|
+
// }
|
|
150
|
+
// } catch {
|
|
151
|
+
// // ignore and refetch
|
|
152
|
+
// }
|
|
153
|
+
// }
|
|
154
|
+
// const txnId = uuidv4();
|
|
155
|
+
// const resp = await fetch(ServiceNames.WEBSITE_KEYS, {
|
|
156
|
+
// method: 'GET',
|
|
157
|
+
// headers: {
|
|
158
|
+
// 'X-Txn-ID': txnId,
|
|
159
|
+
// },
|
|
160
|
+
// });
|
|
161
|
+
|
|
162
|
+
// if (!resp.ok) {
|
|
163
|
+
// throw new Error(`Website keys fetch failed: ${resp.status}`);
|
|
164
|
+
// }
|
|
165
|
+
// const raw = await resp.json();
|
|
166
|
+
// console.log('Fetched website key', { txnId, raw });
|
|
167
|
+
|
|
168
|
+
// let obj: any;
|
|
169
|
+
// if (
|
|
170
|
+
// raw &&
|
|
171
|
+
// typeof raw === 'object' &&
|
|
172
|
+
// !(
|
|
173
|
+
// Object.prototype.hasOwnProperty.call(raw, 'kid') &&
|
|
174
|
+
// (Object.prototype.hasOwnProperty.call(raw, 'public') ||
|
|
175
|
+
// Object.prototype.hasOwnProperty.call(raw, 'public_key'))
|
|
176
|
+
// )
|
|
177
|
+
// ) {
|
|
178
|
+
// // Assume single-entry map keyed by KID
|
|
179
|
+
// const values = Object.values(raw);
|
|
180
|
+
// if (!values.length || typeof values[0] !== 'object') {
|
|
181
|
+
// throw new Error('Unexpected keyset response shape');
|
|
182
|
+
// }
|
|
183
|
+
// obj = values[0];
|
|
184
|
+
// } else {
|
|
185
|
+
// obj = raw;
|
|
186
|
+
// }
|
|
187
|
+
|
|
188
|
+
// const kid: string | undefined = obj.kid ?? obj.KID;
|
|
189
|
+
// const publicKey: string | undefined = obj.public ?? obj.public_key;
|
|
190
|
+
// const expiry: string | undefined = obj.expiry ?? obj.exp ?? obj.expiresAt;
|
|
191
|
+
|
|
192
|
+
// if (!kid || !publicKey || !expiry) {
|
|
193
|
+
// throw new Error('Missing kid/public/expiry in website key response');
|
|
194
|
+
// }
|
|
195
|
+
|
|
196
|
+
// const normalized: WebsiteKey = { kid, public: publicKey, expiry };
|
|
197
|
+
|
|
198
|
+
// await AsyncStorage.setItem(KEY_WEB, JSON.stringify(normalized));
|
|
199
|
+
// await AsyncStorage.setItem(KEY_WEB_EXPIRY, expiry);
|
|
200
|
+
|
|
201
|
+
// return normalized;
|
|
202
|
+
// }
|
|
203
|
+
|
|
204
|
+
// // ---------- Optional: Hybrid helpers (one-liners) ----------
|
|
205
|
+
|
|
206
|
+
// export type HybridEnvelope = {
|
|
207
|
+
// kid: string;
|
|
208
|
+
// rsaWrappedAESKey: string; // Base64 RSA(OAEP) of Base64(AES key)
|
|
209
|
+
// cipherData: string; // Base64( IV || ciphertext || tag )
|
|
210
|
+
// };
|
|
211
|
+
|
|
212
|
+
// export async function encryptHybrid(
|
|
213
|
+
// plaintext: string
|
|
214
|
+
// ): Promise<HybridEnvelope> {
|
|
215
|
+
// // 1) fetch server key
|
|
216
|
+
// const { kid, public: publicPem } = await getWebsiteKey();
|
|
217
|
+
|
|
218
|
+
// // 2) generate AES key & encrypt data
|
|
219
|
+
// const aesKey = await generateAESKey();
|
|
220
|
+
// const cipherData = await encryptAES(plaintext, aesKey);
|
|
221
|
+
|
|
222
|
+
// // 3) export AES key to Base64 and RSA-wrap it
|
|
223
|
+
// const aesKeyB64 = await exportAESKeyBase64(aesKey);
|
|
224
|
+
// const rsaWrappedAESKey = await encryptAESKeyWithRSA(aesKeyB64, publicPem);
|
|
225
|
+
|
|
226
|
+
// return { kid, rsaWrappedAESKey, cipherData };
|
|
227
|
+
// }
|
|
228
|
+
|
|
229
|
+
// /**
|
|
230
|
+
// * Decrypt using an already-imported AES key (symmetric path).
|
|
231
|
+
// * Use this for local decrypts (e.g., testing) or when the server sends you encrypted data
|
|
232
|
+
// * and you already have the AES key.
|
|
233
|
+
// */
|
|
234
|
+
// export async function decryptHybridLocal(
|
|
235
|
+
// cipherData: string,
|
|
236
|
+
// aesKey: CryptoKey
|
|
237
|
+
// ): Promise<string> {
|
|
238
|
+
// return await decryptAES(cipherData, aesKey);
|
|
239
|
+
// }
|
|
240
|
+
"use strict";
|
|
241
|
+
//# sourceMappingURL=Encryption.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../../../src","sources":["helpers/network/Encryption.tsx"],"mappings":"AAAA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA","ignoreList":[]}
|
|
@@ -36,8 +36,8 @@ export class PartnerLibrary {
|
|
|
36
36
|
await PartnerLibrary.instance._setup(hostName, options.whitelistedDomains, options.deviceBindingEnabled);
|
|
37
37
|
PartnerLibrary.intialized = true;
|
|
38
38
|
} catch (error) {
|
|
39
|
-
console.error(
|
|
40
|
-
throw new Error(
|
|
39
|
+
console.error('Initialization failed: ', error);
|
|
40
|
+
throw new Error('Initialization failed');
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
async _setup(hostName, whitelistedDomains, deviceBindingEnabled) {
|
|
@@ -47,23 +47,20 @@ export class PartnerLibrary {
|
|
|
47
47
|
deviceBinding: deviceBindingEnabled
|
|
48
48
|
});
|
|
49
49
|
this._analyticsLogger = new AnalyticsLogger();
|
|
50
|
-
this._analyticsLogger.logEvent({
|
|
51
|
-
"event": "REACT_NATIVE_INTIALIZED"
|
|
52
|
-
});
|
|
50
|
+
// this._analyticsLogger.logEvent({ event: 'REACT_NATIVE_INTIALIZED' });
|
|
53
51
|
}
|
|
54
52
|
async open(module, token, WebViewCallbackFunction) {
|
|
55
|
-
this._analyticsLogger.logEvent({
|
|
56
|
-
|
|
57
|
-
});
|
|
53
|
+
// this._analyticsLogger.logEvent({ event: 'REACT_NATIVE_OPEN_FN_CALLED' });
|
|
54
|
+
|
|
58
55
|
if (!PartnerLibrary.intialized) {
|
|
59
56
|
throw new Error('PartnerLibrary not initialized. Call init() first.');
|
|
60
57
|
}
|
|
61
58
|
try {
|
|
62
|
-
let bank =
|
|
63
|
-
if (module.includes(
|
|
64
|
-
const startIndex = module.indexOf(
|
|
59
|
+
let bank = '';
|
|
60
|
+
if (module.includes('banking/')) {
|
|
61
|
+
const startIndex = module.indexOf('banking/') + 'banking/'.length;
|
|
65
62
|
const temp = module.substring(startIndex);
|
|
66
|
-
const endIndex = temp.indexOf(
|
|
63
|
+
const endIndex = temp.indexOf('/');
|
|
67
64
|
bank = endIndex === -1 ? temp : temp.substring(0, endIndex);
|
|
68
65
|
}
|
|
69
66
|
return this._loginAndNavigateToWebView(module, bank, token, WebViewCallbackFunction);
|
|
@@ -73,42 +70,42 @@ export class PartnerLibrary {
|
|
|
73
70
|
}
|
|
74
71
|
}
|
|
75
72
|
async _checkDeviceBinding(bank, url, WebViewCallbackFunction) {
|
|
76
|
-
this._analyticsLogger.logEvent({
|
|
77
|
-
|
|
78
|
-
});
|
|
79
|
-
|
|
73
|
+
// this._analyticsLogger.logEvent({
|
|
74
|
+
// event: 'REACT_NATIVE_DEVICE_BINDING_CALLED',
|
|
75
|
+
// });
|
|
76
|
+
|
|
77
|
+
console.log('SDK:LOG: entered in check device binding');
|
|
80
78
|
if (LibraryConstants.deviceBindingEnabled) {
|
|
81
79
|
// TODO: Build the device binding flow
|
|
82
80
|
return Promise.resolve(/*#__PURE__*/_jsx(_Fragment, {}));
|
|
83
81
|
} else {
|
|
84
|
-
console.log(
|
|
82
|
+
console.log('SDK:LOG: calling setup device session');
|
|
85
83
|
return this._setupDeviceSession(bank, url, WebViewCallbackFunction);
|
|
86
84
|
}
|
|
87
85
|
}
|
|
88
86
|
async _loginAndNavigateToWebView(module, bank, token, WebViewCallbackFunction) {
|
|
89
87
|
// console.log("PartnerLibrary._loginAndNavigateToWebView - LibraryConstants.hostName:", LibraryConstants.hostName);
|
|
90
88
|
try {
|
|
91
|
-
this._analyticsLogger.logEvent({
|
|
92
|
-
"event": "REACT_NATIVE_LOGIN_FN_CALLED"
|
|
93
|
-
});
|
|
89
|
+
// this._analyticsLogger.logEvent({ event: 'REACT_NATIVE_LOGIN_FN_CALLED' });
|
|
94
90
|
let tokenResponse;
|
|
95
91
|
const url = ServiceNames.LOGIN_URL;
|
|
96
|
-
console.log(
|
|
92
|
+
console.log('SDK:LOG: ', url);
|
|
97
93
|
tokenResponse = await this._apiCall.callAPI('POST', ServiceNames.LOGIN_URL, {
|
|
98
94
|
body: {
|
|
99
|
-
|
|
95
|
+
token: token
|
|
100
96
|
}
|
|
101
97
|
});
|
|
102
|
-
this._analyticsLogger.logEvent({
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
|
|
98
|
+
// this._analyticsLogger.logEvent({
|
|
99
|
+
// event: 'REACT_NATIVE_LOGIN_FN_RESPONSE :',
|
|
100
|
+
// response: tokenResponse,
|
|
101
|
+
// });
|
|
102
|
+
|
|
103
|
+
if (tokenResponse?.data?.code === 'USER_TOKEN_EXPIRED') {
|
|
104
|
+
console.log('SDK:LOG Token expired');
|
|
108
105
|
return Promise.resolve(/*#__PURE__*/_jsx(_Fragment, {}));
|
|
109
106
|
}
|
|
110
107
|
if (tokenResponse && tokenResponse.data && typeof tokenResponse.data === 'object' && tokenResponse.data !== null && 'RATE_LIMIT_USER' in tokenResponse.data) {
|
|
111
|
-
console.log(
|
|
108
|
+
console.log('SDK:LOG: rate limit user');
|
|
112
109
|
}
|
|
113
110
|
|
|
114
111
|
// console.log("Checking login success condition:", {
|
|
@@ -116,31 +113,31 @@ export class PartnerLibrary {
|
|
|
116
113
|
// code: tokenResponse?.data?.code
|
|
117
114
|
// });
|
|
118
115
|
|
|
119
|
-
if (tokenResponse?.data?.code ===
|
|
120
|
-
console.log(
|
|
116
|
+
if (tokenResponse?.data?.code === 'USER_LOGIN_SUCCESS') {
|
|
117
|
+
console.log('SDK:LOG: User login success');
|
|
121
118
|
this.fetchAndSetTheme();
|
|
122
119
|
return this._checkDeviceBinding(bank, module, WebViewCallbackFunction);
|
|
123
120
|
} else {
|
|
124
|
-
console.log(
|
|
121
|
+
console.log('SDK:LOG: Login not successful. Token Response:', tokenResponse);
|
|
125
122
|
return Promise.resolve(/*#__PURE__*/_jsx(_Fragment, {}));
|
|
126
123
|
}
|
|
127
124
|
} catch (e) {
|
|
128
|
-
console.error('Error during login:', e);
|
|
125
|
+
console.error('SDK:LOG: Error during login:', e);
|
|
129
126
|
throw e;
|
|
130
127
|
}
|
|
131
128
|
}
|
|
132
129
|
async _setupDeviceSession(bank, url, WebViewCallbackFunction) {
|
|
133
130
|
try {
|
|
134
|
-
console.log(
|
|
131
|
+
console.log('SDK:LOG: in setup device session');
|
|
135
132
|
const deviceInfo = await DeviceInfoManager.getDeviceInfo();
|
|
136
133
|
const appVersion = deviceInfo['app_version'] || 'unknown';
|
|
137
134
|
if (__DEV__) {
|
|
138
|
-
console.log(
|
|
139
|
-
console.log(
|
|
135
|
+
console.log('Device Info:', deviceInfo);
|
|
136
|
+
console.log('App Version:', appVersion);
|
|
140
137
|
}
|
|
141
|
-
console.log(
|
|
138
|
+
console.log('SDK:LOG device uuid is ');
|
|
142
139
|
const response = await this._apiCall.callAPI('POST', ServiceNames.DEVICE_SESSION.params({
|
|
143
|
-
|
|
140
|
+
partner: bank
|
|
144
141
|
}), {
|
|
145
142
|
body: {
|
|
146
143
|
[Constants.MANUFACTURER]: deviceInfo[Constants.MANUFACTURER],
|
|
@@ -153,25 +150,26 @@ export class PartnerLibrary {
|
|
|
153
150
|
});
|
|
154
151
|
//console.log("response from setup device session is : ", response)
|
|
155
152
|
if (response && response.data && typeof response.data === 'object' && response.data !== null && 'RATE_LIMIT_USER' in response.data) {
|
|
156
|
-
console.log(
|
|
153
|
+
console.log('SDK:LOG: rate limit user');
|
|
157
154
|
}
|
|
158
155
|
if (response?.status === 200) {
|
|
159
156
|
return this._openWebView(url, WebViewCallbackFunction);
|
|
160
157
|
} else {
|
|
161
|
-
console.warn('Error setting up device session:', response);
|
|
158
|
+
console.warn('SDK:LOG: Error setting up device session:', response);
|
|
162
159
|
return this._openWebView(url, WebViewCallbackFunction);
|
|
163
160
|
}
|
|
164
161
|
} catch (e) {
|
|
165
|
-
console.error('Error setting up device session:', e);
|
|
162
|
+
console.error('SDK:LOG: Error setting up device session:', e);
|
|
166
163
|
throw e;
|
|
167
164
|
}
|
|
168
165
|
}
|
|
169
166
|
async _openWebView(url, WebViewCallbackFunction) {
|
|
170
|
-
console.log(
|
|
171
|
-
console.log(
|
|
172
|
-
this._analyticsLogger.logEvent({
|
|
173
|
-
|
|
174
|
-
});
|
|
167
|
+
console.log('SDK:LOG: entered in open web view');
|
|
168
|
+
console.log('SDK:LOG: url is : ', LibraryConstants.hostName + url);
|
|
169
|
+
// this._analyticsLogger.logEvent({
|
|
170
|
+
// event: 'REACT_NATIVE_WEBVIEW_OPEN_CALLED',
|
|
171
|
+
// });
|
|
172
|
+
|
|
175
173
|
return /*#__PURE__*/_jsx(SafeAreaView, {
|
|
176
174
|
style: {
|
|
177
175
|
flex: 1
|
|
@@ -181,17 +179,17 @@ export class PartnerLibrary {
|
|
|
181
179
|
onCallback: WebViewCallbackFunction,
|
|
182
180
|
whitelistedUrls: LibraryConstants.whitelistedDomains,
|
|
183
181
|
hostName: LibraryConstants.hostName,
|
|
184
|
-
onPageFinished: () => console.log('WebView page finished loading')
|
|
182
|
+
onPageFinished: () => console.log('SDK:LOG: WebView page finished loading')
|
|
185
183
|
})
|
|
186
184
|
});
|
|
187
185
|
}
|
|
188
186
|
async fetchAndSetTheme() {
|
|
189
187
|
try {
|
|
190
|
-
console.log(
|
|
188
|
+
console.log('SDK:LOG: Fetching theme from API');
|
|
191
189
|
const themeResponse = await this._apiCall.callAPI('GET', ServiceNames.THEME_URL);
|
|
192
190
|
const theme = themeResponse?.data;
|
|
193
|
-
if (theme && theme[
|
|
194
|
-
const rgbValues = theme[
|
|
191
|
+
if (theme && theme['--color-primary-500']) {
|
|
192
|
+
const rgbValues = theme['--color-primary-500'].split(' ').map(Number);
|
|
195
193
|
if (rgbValues.length === 3) {
|
|
196
194
|
const [r, g, b] = rgbValues;
|
|
197
195
|
|
|
@@ -202,15 +200,15 @@ export class PartnerLibrary {
|
|
|
202
200
|
|
|
203
201
|
StatusBar.setBackgroundColor(LibraryConstants.primaryColor);
|
|
204
202
|
StatusBar.setBarStyle('light-content');
|
|
205
|
-
console.log(
|
|
203
|
+
console.log('SDK:LOG: Theme color set successfully:', LibraryConstants.primaryColor);
|
|
206
204
|
} else {
|
|
207
|
-
console.warn(
|
|
205
|
+
console.warn('Invalid RGB values in theme response');
|
|
208
206
|
}
|
|
209
207
|
} else {
|
|
210
|
-
console.warn(
|
|
208
|
+
console.warn('--color-primary-500 not found in theme response');
|
|
211
209
|
}
|
|
212
210
|
} catch (e) {
|
|
213
|
-
console.error(
|
|
211
|
+
console.error('Error Fetching theme: ', e);
|
|
214
212
|
throw e;
|
|
215
213
|
}
|
|
216
214
|
}
|