banking_dcb_sdk_react_native 0.1.9
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/PartnerReactNativeSdk.podspec +31 -0
- package/README.md +14 -0
- package/android/build.gradle +100 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/java/com/partnerreactnativesdk/PartnerReactNativeSdkModule.kt +23 -0
- package/android/src/main/java/com/partnerreactnativesdk/PartnerReactNativeSdkPackage.kt +33 -0
- package/ios/PartnerReactNativeSdk.h +6 -0
- package/ios/PartnerReactNativeSdk.mm +29 -0
- package/lib/module/helpers/ServiceNames.js +135 -0
- package/lib/module/helpers/ServiceNames.js.map +1 -0
- package/lib/module/helpers/analytics/analytics_event_model.js +37 -0
- package/lib/module/helpers/analytics/analytics_event_model.js.map +1 -0
- package/lib/module/helpers/analytics/analytics_logger.js +73 -0
- package/lib/module/helpers/analytics/analytics_logger.js.map +1 -0
- package/lib/module/helpers/analytics/event_storage.js +35 -0
- package/lib/module/helpers/analytics/event_storage.js.map +1 -0
- package/lib/module/helpers/banking_dcb_react_native.js +297 -0
- package/lib/module/helpers/banking_dcb_react_native.js.map +1 -0
- package/lib/module/helpers/helper.js +4 -0
- package/lib/module/helpers/helper.js.map +1 -0
- package/lib/module/helpers/network/APICall.js +111 -0
- package/lib/module/helpers/network/APICall.js.map +1 -0
- package/lib/module/helpers/network/Encryption.js +148 -0
- package/lib/module/helpers/network/Encryption.js.map +1 -0
- package/lib/module/helpers/network/network_manager.js +112 -0
- package/lib/module/helpers/network/network_manager.js.map +1 -0
- package/lib/module/helpers/utils/Constants.js +12 -0
- package/lib/module/helpers/utils/Constants.js.map +1 -0
- package/lib/module/helpers/utils/LibraryConstants.js +115 -0
- package/lib/module/helpers/utils/LibraryConstants.js.map +1 -0
- package/lib/module/helpers/utils/deviceInfoManager.js +39 -0
- package/lib/module/helpers/utils/deviceInfoManager.js.map +1 -0
- package/lib/module/helpers/utils/headerManager.js +21 -0
- package/lib/module/helpers/utils/headerManager.js.map +1 -0
- package/lib/module/helpers/utils/themeManager.js +40 -0
- package/lib/module/helpers/utils/themeManager.js.map +1 -0
- package/lib/module/helpers/utils/webviewCallback.js +20 -0
- package/lib/module/helpers/utils/webviewCallback.js.map +1 -0
- package/lib/module/helpers/webview.js +314 -0
- package/lib/module/helpers/webview.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/helpers/ServiceNames.d.ts +51 -0
- package/lib/typescript/src/helpers/ServiceNames.d.ts.map +1 -0
- package/lib/typescript/src/helpers/analytics/analytics_event_model.d.ts +16 -0
- package/lib/typescript/src/helpers/analytics/analytics_event_model.d.ts.map +1 -0
- package/lib/typescript/src/helpers/analytics/analytics_logger.d.ts +17 -0
- package/lib/typescript/src/helpers/analytics/analytics_logger.d.ts.map +1 -0
- package/lib/typescript/src/helpers/analytics/event_storage.d.ts +8 -0
- package/lib/typescript/src/helpers/analytics/event_storage.d.ts.map +1 -0
- package/lib/typescript/src/helpers/banking_dcb_react_native.d.ts +33 -0
- package/lib/typescript/src/helpers/banking_dcb_react_native.d.ts.map +1 -0
- package/lib/typescript/src/helpers/helper.d.ts +1 -0
- package/lib/typescript/src/helpers/helper.d.ts.map +1 -0
- package/lib/typescript/src/helpers/network/APICall.d.ts +13 -0
- package/lib/typescript/src/helpers/network/APICall.d.ts.map +1 -0
- package/lib/typescript/src/helpers/network/Encryption.d.ts +24 -0
- package/lib/typescript/src/helpers/network/Encryption.d.ts.map +1 -0
- package/lib/typescript/src/helpers/network/network_manager.d.ts +21 -0
- package/lib/typescript/src/helpers/network/network_manager.d.ts.map +1 -0
- package/lib/typescript/src/helpers/utils/Constants.d.ts +10 -0
- package/lib/typescript/src/helpers/utils/Constants.d.ts.map +1 -0
- package/lib/typescript/src/helpers/utils/LibraryConstants.d.ts +24 -0
- package/lib/typescript/src/helpers/utils/LibraryConstants.d.ts.map +1 -0
- package/lib/typescript/src/helpers/utils/deviceInfoManager.d.ts +4 -0
- package/lib/typescript/src/helpers/utils/deviceInfoManager.d.ts.map +1 -0
- package/lib/typescript/src/helpers/utils/headerManager.d.ts +5 -0
- package/lib/typescript/src/helpers/utils/headerManager.d.ts.map +1 -0
- package/lib/typescript/src/helpers/utils/themeManager.d.ts +12 -0
- package/lib/typescript/src/helpers/utils/themeManager.d.ts.map +1 -0
- package/lib/typescript/src/helpers/utils/webviewCallback.d.ts +13 -0
- package/lib/typescript/src/helpers/utils/webviewCallback.d.ts.map +1 -0
- package/lib/typescript/src/helpers/webview.d.ts +21 -0
- package/lib/typescript/src/helpers/webview.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +5 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +170 -0
- package/react-native.config.js +12 -0
- package/src/helpers/ServiceNames.tsx +170 -0
- package/src/helpers/analytics/analytics_event_model.tsx +47 -0
- package/src/helpers/analytics/analytics_logger.tsx +91 -0
- package/src/helpers/analytics/event_storage.tsx +44 -0
- package/src/helpers/banking_dcb_react_native.tsx +413 -0
- package/src/helpers/helper.tsx +1 -0
- package/src/helpers/network/APICall.tsx +154 -0
- package/src/helpers/network/Encryption.tsx +179 -0
- package/src/helpers/network/network_manager.tsx +122 -0
- package/src/helpers/utils/Constants.tsx +10 -0
- package/src/helpers/utils/LibraryConstants.tsx +133 -0
- package/src/helpers/utils/deviceInfoManager.tsx +37 -0
- package/src/helpers/utils/headerManager.tsx +22 -0
- package/src/helpers/utils/themeManager.tsx +51 -0
- package/src/helpers/utils/webviewCallback.tsx +25 -0
- package/src/helpers/webview.tsx +410 -0
- package/src/index.tsx +5 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// Encryption.ts
|
|
2
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import * as base64js from 'base64-js';
|
|
5
|
+
import { ServiceNames } from '../ServiceNames';
|
|
6
|
+
|
|
7
|
+
import crypto from 'react-native-quick-crypto';
|
|
8
|
+
import { Buffer } from '@craftzdog/react-native-buffer';
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
randomBytes,
|
|
12
|
+
createCipheriv,
|
|
13
|
+
createDecipheriv,
|
|
14
|
+
publicEncrypt,
|
|
15
|
+
constants,
|
|
16
|
+
createPublicKey,
|
|
17
|
+
} = crypto;
|
|
18
|
+
|
|
19
|
+
type WebsiteKey = { kid: string; public: string; expiry: string };
|
|
20
|
+
|
|
21
|
+
const KEY_WEB = 'KEY_WEB';
|
|
22
|
+
const KEY_WEB_EXPIRY = 'KEY_WEB_EXPIRY';
|
|
23
|
+
const GCM_NONCE_LEN = 12; // 12-byte IV
|
|
24
|
+
const GCM_TAG_LEN = 16; // 16-byte tag
|
|
25
|
+
const AES_KEY_LEN_BYTES = 32; // 256 bits
|
|
26
|
+
|
|
27
|
+
// --- small utils ---
|
|
28
|
+
const bytesToB64 = (u8: Uint8Array) => base64js.fromByteArray(u8);
|
|
29
|
+
const b64ToBytes = (b64: string) => base64js.toByteArray(b64);
|
|
30
|
+
|
|
31
|
+
// ---------- AES-256-GCM ----------
|
|
32
|
+
|
|
33
|
+
/** Generate random 32-byte AES key */
|
|
34
|
+
export function generateAESKey(): Uint8Array {
|
|
35
|
+
return new Uint8Array(randomBytes(AES_KEY_LEN_BYTES));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Export AES key bytes -> Base64 (for RSA input) */
|
|
39
|
+
export function exportAESKeyBase64(keyBytes: Uint8Array): string {
|
|
40
|
+
return bytesToB64(keyBytes);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Encrypt plaintext -> Base64( IV || ciphertext || tag ) */
|
|
44
|
+
export function encryptAES(plaintext: string, keyBytes: Uint8Array): string {
|
|
45
|
+
const iv = new Uint8Array(randomBytes(GCM_NONCE_LEN));
|
|
46
|
+
const cipher = createCipheriv(
|
|
47
|
+
'aes-256-gcm',
|
|
48
|
+
Buffer.from(keyBytes),
|
|
49
|
+
Buffer.from(iv)
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const ct1 = cipher.update(plaintext, 'utf8');
|
|
53
|
+
const ct2 = cipher.final();
|
|
54
|
+
const ciphertext = Buffer.concat([ct1, ct2]);
|
|
55
|
+
|
|
56
|
+
const tag = cipher.getAuthTag(); // 16 bytes
|
|
57
|
+
|
|
58
|
+
const out = new Uint8Array(iv.length + ciphertext.length + tag.length);
|
|
59
|
+
out.set(iv, 0);
|
|
60
|
+
out.set(ciphertext, iv.length);
|
|
61
|
+
out.set(tag, iv.length + ciphertext.length);
|
|
62
|
+
|
|
63
|
+
return bytesToB64(out);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Decrypt Base64( IV || ciphertext || tag ) -> plaintext */
|
|
67
|
+
export function decryptAES(b64Data: string, keyBytes: Uint8Array): string {
|
|
68
|
+
const data = b64ToBytes(b64Data);
|
|
69
|
+
if (data.length < GCM_NONCE_LEN + GCM_TAG_LEN + 1) {
|
|
70
|
+
throw new Error('Invalid GCM payload length');
|
|
71
|
+
}
|
|
72
|
+
const iv = data.slice(0, GCM_NONCE_LEN);
|
|
73
|
+
const tag = data.slice(data.length - GCM_TAG_LEN);
|
|
74
|
+
const ct = data.slice(GCM_NONCE_LEN, data.length - GCM_TAG_LEN);
|
|
75
|
+
|
|
76
|
+
const decipher = createDecipheriv(
|
|
77
|
+
'aes-256-gcm',
|
|
78
|
+
Buffer.from(keyBytes),
|
|
79
|
+
Buffer.from(iv)
|
|
80
|
+
);
|
|
81
|
+
decipher.setAuthTag(Buffer.from(tag));
|
|
82
|
+
|
|
83
|
+
const pt1 = decipher.update(Buffer.from(ct));
|
|
84
|
+
const pt2 = decipher.final();
|
|
85
|
+
return Buffer.concat([pt1, pt2]).toString('utf8');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ---------- RSA-OAEP (SHA-256) ----------
|
|
89
|
+
|
|
90
|
+
/** RSA-OAEP(SHA-256) encrypt UTF-8 bytes of Base64(AES key) -> Base64 ciphertext */
|
|
91
|
+
export function encryptAESKeyWithRSA(
|
|
92
|
+
aesKeyBase64: string,
|
|
93
|
+
publicKeyPem: string
|
|
94
|
+
): string {
|
|
95
|
+
const buf = Buffer.from(aesKeyBase64, 'utf8');
|
|
96
|
+
const enc = publicEncrypt(
|
|
97
|
+
{
|
|
98
|
+
key: publicKeyPem,
|
|
99
|
+
padding: constants.RSA_PKCS1_OAEP_PADDING,
|
|
100
|
+
oaepHash: 'sha256',
|
|
101
|
+
},
|
|
102
|
+
buf
|
|
103
|
+
);
|
|
104
|
+
return enc.toString('base64');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ---------- Website key fetch / cache ----------
|
|
108
|
+
|
|
109
|
+
export async function getWebsiteKey(): Promise<WebsiteKey> {
|
|
110
|
+
// const cachedJson = await AsyncStorage.getItem(KEY_WEB);
|
|
111
|
+
// const cachedExpiry = await AsyncStorage.getItem(KEY_WEB_EXPIRY);
|
|
112
|
+
// if (cachedJson && cachedExpiry) {
|
|
113
|
+
// try {
|
|
114
|
+
// if (new Date() < new Date(cachedExpiry)) {
|
|
115
|
+
// return JSON.parse(cachedJson) as WebsiteKey;
|
|
116
|
+
// }
|
|
117
|
+
// } catch {
|
|
118
|
+
// /* ignore */
|
|
119
|
+
// }
|
|
120
|
+
// }
|
|
121
|
+
|
|
122
|
+
// const txnId = uuidv4();
|
|
123
|
+
const resp = await fetch(ServiceNames.WEBSITE_KEYS, {
|
|
124
|
+
method: 'GET',
|
|
125
|
+
// headers: { 'X-Txn-ID': txnId },
|
|
126
|
+
});
|
|
127
|
+
if (!resp.ok) throw new Error(`Website keys fetch failed: ${resp.status}`);
|
|
128
|
+
|
|
129
|
+
const raw = await resp.json();
|
|
130
|
+
console.log('Website keys response:', raw);
|
|
131
|
+
let obj: any;
|
|
132
|
+
if (
|
|
133
|
+
raw &&
|
|
134
|
+
typeof raw === 'object' &&
|
|
135
|
+
!(
|
|
136
|
+
Object.prototype.hasOwnProperty.call(raw, 'kid') &&
|
|
137
|
+
(Object.prototype.hasOwnProperty.call(raw, 'public') ||
|
|
138
|
+
Object.prototype.hasOwnProperty.call(raw, 'public_key'))
|
|
139
|
+
)
|
|
140
|
+
) {
|
|
141
|
+
const values = Object.values(raw);
|
|
142
|
+
if (!values.length || typeof values[0] !== 'object') {
|
|
143
|
+
throw new Error('Unexpected keyset response shape');
|
|
144
|
+
}
|
|
145
|
+
obj = values[0];
|
|
146
|
+
} else {
|
|
147
|
+
obj = raw;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const kid: string | undefined = obj.kid ?? obj.KID;
|
|
151
|
+
const publicKey: string | undefined = obj.public ?? obj.public_key;
|
|
152
|
+
const expiry: string | undefined = obj.expiry ?? obj.exp ?? obj.expiresAt;
|
|
153
|
+
if (!kid || !publicKey || !expiry)
|
|
154
|
+
throw new Error('Missing kid/public/expiry');
|
|
155
|
+
|
|
156
|
+
const normalized: WebsiteKey = { kid, public: publicKey, expiry };
|
|
157
|
+
await AsyncStorage.setItem(KEY_WEB, JSON.stringify(normalized));
|
|
158
|
+
await AsyncStorage.setItem(KEY_WEB_EXPIRY, expiry);
|
|
159
|
+
return normalized;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ---------- Optional: one-liners ----------
|
|
163
|
+
|
|
164
|
+
export type HybridEnvelope = {
|
|
165
|
+
kid: string;
|
|
166
|
+
rsaWrappedAESKey: string; // Base64 RSA(OAEP) of Base64(AES key)
|
|
167
|
+
cipherData: string; // Base64( IV || ciphertext || tag )
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export async function encryptHybrid(
|
|
171
|
+
plaintext: string
|
|
172
|
+
): Promise<HybridEnvelope> {
|
|
173
|
+
const { kid, public: publicPem } = await getWebsiteKey();
|
|
174
|
+
const aesKey = generateAESKey();
|
|
175
|
+
const cipherData = encryptAES(plaintext, aesKey);
|
|
176
|
+
const aesKeyB64 = exportAESKeyBase64(aesKey);
|
|
177
|
+
const rsaWrappedAESKey = encryptAESKeyWithRSA(aesKeyB64, publicPem);
|
|
178
|
+
return { kid, rsaWrappedAESKey, cipherData };
|
|
179
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import axios, { type AxiosInstance, type AxiosResponse, type AxiosRequestConfig } from 'axios';
|
|
2
|
+
|
|
3
|
+
class NetworkManager {
|
|
4
|
+
private static _instance: NetworkManager = new NetworkManager();
|
|
5
|
+
private _axios: AxiosInstance;
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
this._axios = axios.create();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
static getInstance(): NetworkManager {
|
|
12
|
+
return NetworkManager._instance;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async request({
|
|
16
|
+
url,
|
|
17
|
+
method,
|
|
18
|
+
body,
|
|
19
|
+
headers,
|
|
20
|
+
options,
|
|
21
|
+
}: {
|
|
22
|
+
url: string;
|
|
23
|
+
method: string;
|
|
24
|
+
body?: Record<string, any>;
|
|
25
|
+
headers?: Record<string, any>;
|
|
26
|
+
options?: AxiosRequestConfig;
|
|
27
|
+
}): Promise<AxiosResponse | null> {
|
|
28
|
+
try {
|
|
29
|
+
headers = headers || {};
|
|
30
|
+
options = options || { headers };
|
|
31
|
+
|
|
32
|
+
let response: AxiosResponse;
|
|
33
|
+
const config: AxiosRequestConfig = {
|
|
34
|
+
...options,
|
|
35
|
+
headers,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
switch (method.toUpperCase()) {
|
|
39
|
+
case 'POST':
|
|
40
|
+
response = await this._axios.post(url, body, config);
|
|
41
|
+
break;
|
|
42
|
+
case 'GET':
|
|
43
|
+
response = await this._axios.get(url, config);
|
|
44
|
+
break;
|
|
45
|
+
case 'PUT':
|
|
46
|
+
response = await this._axios.put(url, body, config);
|
|
47
|
+
break;
|
|
48
|
+
case 'PATCH':
|
|
49
|
+
response = await this._axios.patch(url, body, config);
|
|
50
|
+
break;
|
|
51
|
+
case 'DELETE':
|
|
52
|
+
response = await this._axios.delete(url, {
|
|
53
|
+
...config,
|
|
54
|
+
data: body,
|
|
55
|
+
});
|
|
56
|
+
break;
|
|
57
|
+
default:
|
|
58
|
+
throw new Error(`Method not supported: ${method}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return response;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (__DEV__) {
|
|
64
|
+
if (axios.isAxiosError(error)) {
|
|
65
|
+
if (!error.response) {
|
|
66
|
+
console.log("Network error:", error.message);
|
|
67
|
+
}
|
|
68
|
+
return error.response || null;
|
|
69
|
+
} else {
|
|
70
|
+
console.log("Unexpected error during network request:", error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async get(
|
|
78
|
+
url: string,
|
|
79
|
+
headers?: Record<string, any>,
|
|
80
|
+
options?: AxiosRequestConfig
|
|
81
|
+
): Promise<AxiosResponse | null> {
|
|
82
|
+
return this.request({ url, method: 'GET', headers, options });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async post(
|
|
86
|
+
url: string,
|
|
87
|
+
body: Record<string, any>,
|
|
88
|
+
headers?: Record<string, any>,
|
|
89
|
+
options?: AxiosRequestConfig
|
|
90
|
+
): Promise<AxiosResponse | null> {
|
|
91
|
+
return this.request({ url, method: 'POST', body, headers, options });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async put(
|
|
95
|
+
url: string,
|
|
96
|
+
body: Record<string, any>,
|
|
97
|
+
headers?: Record<string, any>,
|
|
98
|
+
options?: AxiosRequestConfig
|
|
99
|
+
): Promise<AxiosResponse | null> {
|
|
100
|
+
return this.request({ url, method: 'PUT', body, headers, options });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async patch(
|
|
104
|
+
url: string,
|
|
105
|
+
body: Record<string, any>,
|
|
106
|
+
headers?: Record<string, any>,
|
|
107
|
+
options?: AxiosRequestConfig
|
|
108
|
+
): Promise<AxiosResponse | null> {
|
|
109
|
+
return this.request({ url, method: 'PATCH', body, headers, options });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async delete(
|
|
113
|
+
url: string,
|
|
114
|
+
headers?: Record<string, any>,
|
|
115
|
+
body?: Record<string, any>,
|
|
116
|
+
options?: AxiosRequestConfig
|
|
117
|
+
): Promise<AxiosResponse | null> {
|
|
118
|
+
return this.request({ url, method: 'DELETE', body, headers, options });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export default NetworkManager;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
|
|
3
|
+
interface Color {
|
|
4
|
+
r: number;
|
|
5
|
+
g: number;
|
|
6
|
+
b: number;
|
|
7
|
+
a: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// interface ColorWithValues extends Color {
|
|
11
|
+
// withValues(params: { red: number; green: number; blue: number; alpha: number }): string;
|
|
12
|
+
// }
|
|
13
|
+
|
|
14
|
+
// Helper function for color handling
|
|
15
|
+
const hexToRgba = (hex: string): Color => {
|
|
16
|
+
const match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
17
|
+
|
|
18
|
+
if (match && match[1] && match[2] && match[3]) {
|
|
19
|
+
return {
|
|
20
|
+
r: parseInt(match[1], 16),
|
|
21
|
+
g: parseInt(match[2], 16),
|
|
22
|
+
b: parseInt(match[3], 16),
|
|
23
|
+
a: 1,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return { r: 0, g: 0, b: 0, a: 1 };
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
// const rgbaToHex = (color: Color): string => {
|
|
33
|
+
// return `#${color.r.toString(16).padStart(2, '0')}${color.g.toString(16).padStart(2, '0')}${color.b.toString(16).padStart(2, '0')}`;
|
|
34
|
+
// };
|
|
35
|
+
|
|
36
|
+
const rgbaToString = (color: Color): string => {
|
|
37
|
+
return `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export class LibraryConstants {
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
static deviceBindingEnabled: boolean = true;
|
|
44
|
+
|
|
45
|
+
// Primary color definition
|
|
46
|
+
private static _primaryColorHex: string = '#037EAB';
|
|
47
|
+
private static _primaryColorObj: Color = hexToRgba('#037EAB');
|
|
48
|
+
|
|
49
|
+
// static get primaryColor(): string {
|
|
50
|
+
// return this._primaryColorHex;
|
|
51
|
+
// }
|
|
52
|
+
|
|
53
|
+
static set primaryColor(value: string) {
|
|
54
|
+
this._primaryColorHex = value;
|
|
55
|
+
this._primaryColorObj = hexToRgba(value);
|
|
56
|
+
}
|
|
57
|
+
private static rgbToHex(r: number, g: number, b: number): string {
|
|
58
|
+
return `#${[r, g, b]
|
|
59
|
+
.map(x => {
|
|
60
|
+
const hex = x.toString(16);
|
|
61
|
+
return hex.length === 1 ? '0' + hex : hex;
|
|
62
|
+
})
|
|
63
|
+
.join('')}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static setPrimaryColorFromRGB(r: number, g: number, b: number): void {
|
|
67
|
+
this._primaryColorObj = { r, g, b, a: 1 };
|
|
68
|
+
this._primaryColorHex = LibraryConstants.rgbToHex(r, g, b);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
static secondaryColor: string = '#FFFFFF';
|
|
75
|
+
|
|
76
|
+
// Calculate disabled primary color (with 50% opacity)
|
|
77
|
+
static get primaryColorDisabled(): string {
|
|
78
|
+
return rgbaToString({
|
|
79
|
+
r: this._primaryColorObj.r,
|
|
80
|
+
g: this._primaryColorObj.g,
|
|
81
|
+
b: this._primaryColorObj.b,
|
|
82
|
+
a: 0.5
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static openExternally: string[] = [""];
|
|
87
|
+
static whitelistedUrlsAndroid: string[] = [];
|
|
88
|
+
static whitelistedUrlsIos: string[] = [];
|
|
89
|
+
static hostName: string = "";
|
|
90
|
+
static whitelistedDomains: string[] = [];
|
|
91
|
+
|
|
92
|
+
static init({
|
|
93
|
+
host,
|
|
94
|
+
// whitelistedAndroid,
|
|
95
|
+
// whitelistedIos,
|
|
96
|
+
whitelistedDomains,
|
|
97
|
+
deviceBinding,
|
|
98
|
+
}: {
|
|
99
|
+
host: string;
|
|
100
|
+
whitelistedDomains: string[]
|
|
101
|
+
// whitelistedAndroid?: string[];
|
|
102
|
+
// whitelistedIos?: string[];
|
|
103
|
+
deviceBinding?: boolean;
|
|
104
|
+
}): void {
|
|
105
|
+
this.hostName = host;
|
|
106
|
+
// if (whitelistedAndroid) this.whitelistedUrlsAndroid = whitelistedAndroid;
|
|
107
|
+
// if (whitelistedIos) this.whitelistedUrlsIos = whitelistedIos;
|
|
108
|
+
this.whitelistedDomains = whitelistedDomains;
|
|
109
|
+
if (deviceBinding !== undefined) this.deviceBindingEnabled = deviceBinding;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Helper method to get whitelisted URLs based on platform
|
|
113
|
+
// static getWhitelistedUrls(): string[] {
|
|
114
|
+
// return Platform.OS === 'ios' ? this.whitelistedUrlsIos : this.whitelistedUrlsAndroid;
|
|
115
|
+
// }
|
|
116
|
+
|
|
117
|
+
static getWhitelistedDomains(): string[] {
|
|
118
|
+
return this.whitelistedDomains;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static get primaryColor(): string {
|
|
122
|
+
if (Platform.OS === 'android') {
|
|
123
|
+
return rgbaToString(this._primaryColorObj);
|
|
124
|
+
}
|
|
125
|
+
return this._primaryColorHex;
|
|
126
|
+
}
|
|
127
|
+
static getPrimaryColorWithOpacity(opacity: number): string {
|
|
128
|
+
return rgbaToString({
|
|
129
|
+
...this._primaryColorObj,
|
|
130
|
+
a: opacity
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import DeviceInfo from 'react-native-device-info';
|
|
3
|
+
import { Constants } from './Constants';
|
|
4
|
+
|
|
5
|
+
export class DeviceInfoManager {
|
|
6
|
+
static async getDeviceInfo(): Promise<Record<string, string>> {
|
|
7
|
+
if (Platform.OS === 'android') {
|
|
8
|
+
let androidId = 'unknown';
|
|
9
|
+
try {
|
|
10
|
+
androidId = await DeviceInfo.getAndroidId();
|
|
11
|
+
} catch (e) {
|
|
12
|
+
if (__DEV__) {
|
|
13
|
+
console.log('Error getting android id:', e);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
[Constants.MANUFACTURER]: (await DeviceInfo.getManufacturer()) || 'unknown',
|
|
18
|
+
[Constants.MODEL]: DeviceInfo.getModel() || 'unknown',
|
|
19
|
+
[Constants.OS]: 'android',
|
|
20
|
+
[Constants.OS_VERSION]: DeviceInfo.getSystemVersion() || 'unknown',
|
|
21
|
+
[Constants.APP_VERSION]: DeviceInfo.getVersion() || 'unknown',
|
|
22
|
+
[Constants.DEVICE_UUID]: androidId,
|
|
23
|
+
};
|
|
24
|
+
} else if (Platform.OS === 'ios') {
|
|
25
|
+
return {
|
|
26
|
+
[Constants.MANUFACTURER]: 'Apple',
|
|
27
|
+
[Constants.MODEL]: DeviceInfo.getModel() || 'unknown',
|
|
28
|
+
[Constants.OS]: 'ios',
|
|
29
|
+
[Constants.OS_VERSION]: DeviceInfo.getSystemVersion() || 'unknown',
|
|
30
|
+
[Constants.APP_VERSION]: DeviceInfo.getVersion() || 'unknown',
|
|
31
|
+
[Constants.DEVICE_UUID]: (await DeviceInfo.getUniqueId()) || 'unknown',
|
|
32
|
+
};
|
|
33
|
+
} else {
|
|
34
|
+
throw new Error('Unsupported platform');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import DeviceInfo from 'react-native-device-info';
|
|
3
|
+
import { DeviceInfoManager } from './deviceInfoManager';
|
|
4
|
+
|
|
5
|
+
export class HeaderManager {
|
|
6
|
+
|
|
7
|
+
private deviceInfoManager = DeviceInfoManager;
|
|
8
|
+
|
|
9
|
+
async generateHeaders(isEncrypted: boolean = true): Promise<Record<string, string>> {
|
|
10
|
+
|
|
11
|
+
const deviceInfo = await this.deviceInfoManager.getDeviceInfo();
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
...deviceInfo,
|
|
15
|
+
app_version: DeviceInfo.getVersion() || 'unknown',
|
|
16
|
+
os: Platform.OS === 'android' ? 'Android' : 'iOS',
|
|
17
|
+
os_version: DeviceInfo.getSystemVersion() || 'unknown',
|
|
18
|
+
...(isEncrypted && { 'Content-Type': 'application/json;charset=utf-8' })
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
2
|
+
import { Platform, StatusBar, type StatusBarStyle } from "react-native";
|
|
3
|
+
import { Constants } from "./Constants";
|
|
4
|
+
import { LibraryConstants } from './LibraryConstants';
|
|
5
|
+
|
|
6
|
+
interface Theme {
|
|
7
|
+
primaryColor: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class ThemeManager {
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static async savePrimaryColor(color: string): Promise<void> {
|
|
18
|
+
console.log("Saving primary color:", color);
|
|
19
|
+
try {
|
|
20
|
+
await AsyncStorage.setItem(LibraryConstants.primaryColor, color);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error("Error saving primary color:", error);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static async loadPrimaryColor(): Promise<string | null> {
|
|
27
|
+
try {
|
|
28
|
+
return await AsyncStorage.getItem(LibraryConstants.primaryColor);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.error("Error loading primary color:", error);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
static getAppTheme(): Theme {
|
|
36
|
+
return {
|
|
37
|
+
primaryColor: Constants.PRIMARY_COLOR,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static configureStatusBar(): void {
|
|
42
|
+
StatusBar.setBackgroundColor(LibraryConstants.primaryColor);
|
|
43
|
+
StatusBar.setNetworkActivityIndicatorVisible(true);
|
|
44
|
+
const barStyle: StatusBarStyle = 'light-content';
|
|
45
|
+
StatusBar.setBarStyle(barStyle);
|
|
46
|
+
|
|
47
|
+
if (Platform.OS === 'android') {
|
|
48
|
+
StatusBar.setTranslucent(false);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export enum WebViewCallbackType {
|
|
2
|
+
|
|
3
|
+
Logout = "logout",
|
|
4
|
+
Redirect = "redirect"
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class WebViewCallback {
|
|
8
|
+
type: WebViewCallbackType;
|
|
9
|
+
status?: string | null;
|
|
10
|
+
|
|
11
|
+
private constructor(type: WebViewCallbackType, status?: string | null) {
|
|
12
|
+
this.type = type;
|
|
13
|
+
this.status = status;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static logout(): WebViewCallback {
|
|
17
|
+
return new WebViewCallback(WebViewCallbackType.Logout);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static redirect(status?: string | null): WebViewCallback {
|
|
21
|
+
return new WebViewCallback(WebViewCallbackType.Redirect, status);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type WebViewCallbackFunction = (callback: WebViewCallback) => void;
|