@sanctum-key/react-native-sdk 1.0.54 → 1.0.56

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanctum-key/react-native-sdk",
3
- "version": "1.0.54",
3
+ "version": "1.0.56",
4
4
  "description": "Sanctum Key React Native SDK",
5
5
  "main": "build/src/index.js",
6
6
  "types": "build/src/index.d.ts",
@@ -50,6 +50,7 @@
50
50
  "@zxing/browser": "^0.2.0",
51
51
  "@zxing/library": "^0.22.0",
52
52
  "axios": "^1.11.0",
53
+ "crypto-js": "^4.2.0",
53
54
  "expo-blur": "~15.0.8",
54
55
  "i18n-js": "4.5.1",
55
56
  "iconsax-react-nativejs": "^0.0.8",
@@ -58,6 +59,7 @@
58
59
  "zustand": "^5.0.8"
59
60
  },
60
61
  "devDependencies": {
62
+ "@types/crypto-js": "^4.2.2",
61
63
  "@types/react": "~19.1.0",
62
64
  "copyfiles": "^2.4.1",
63
65
  "expo": "~54.0.0",
@@ -1 +1 @@
1
- {"version":3,"file":"WebKYCEntry.d.ts","sourceRoot":"","sources":["../../../src/web/WebKYCEntry.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAoC,GAAG,EAAE,MAAM,OAAO,CAAC;AAQrE,UAAU,gBAAgB;IACxB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AA2DD,wBAAgB,WAAW,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE,gBAAgB,GAAG,GAAG,CAAC,OAAO,CAgO3G;AAYD,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"WebKYCEntry.d.ts","sourceRoot":"","sources":["../../../src/web/WebKYCEntry.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAoC,GAAG,EAAE,MAAM,OAAO,CAAC;AASrE,UAAU,gBAAgB;IACxB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AA6ED,wBAAgB,WAAW,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE,gBAAgB,GAAG,GAAG,CAAC,OAAO,CAoP3G;AAYD,eAAe,WAAW,CAAC"}
@@ -4,8 +4,19 @@ import { useI18n } from '../hooks/useI18n';
4
4
  import { TemplateKYCExample } from '../components/TemplateKYCExample';
5
5
  import { isCallbackUrlAllowed } from '../config/allowedDomains';
6
6
  import KYCConfig from '../config/KYCConfig';
7
- const postWebhook = async (url, payload, timeoutMs = 5000) => {
7
+ import CryptoJS from 'crypto-js'; // 🚨 IMPORT ADDED
8
+ // 🚨 MODIFIED: Accepts the webhook secret to generate the signature
9
+ const postWebhook = async (url, payload, secret, timeoutMs = 5000) => {
8
10
  const body = JSON.stringify(payload);
11
+ const headers = {
12
+ 'Content-Type': 'application/json',
13
+ };
14
+ // 🚨 Generate HMAC SHA-256 Signature if secret is provided
15
+ if (secret) {
16
+ const signature = CryptoJS.HmacSHA256(body, secret).toString(CryptoJS.enc.Hex);
17
+ headers['x-sanctumkey-signature'] = signature;
18
+ console.log("🔒 Generated Webhook Signature:", signature);
19
+ }
9
20
  const postWithTimeout = async (init) => {
10
21
  const controller = new AbortController();
11
22
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
@@ -18,7 +29,7 @@ const postWebhook = async (url, payload, timeoutMs = 5000) => {
18
29
  };
19
30
  if (typeof window !== 'undefined') {
20
31
  try {
21
- const response = await postWithTimeout({ headers: { 'Content-Type': 'application/json' }, body, keepalive: true });
32
+ const response = await postWithTimeout({ headers, body, keepalive: true });
22
33
  if (!response.ok)
23
34
  throw new Error(`Webhook failed with status ${response.status}`);
24
35
  return;
@@ -26,11 +37,17 @@ const postWebhook = async (url, payload, timeoutMs = 5000) => {
26
37
  catch (error) {
27
38
  if (error instanceof Error && error.name === 'AbortError')
28
39
  throw error;
29
- await postWithTimeout({ mode: 'no-cors', headers: { 'Content-Type': 'text/plain;charset=UTF-8' }, body, keepalive: true });
40
+ // Fallback for CORS issues, though signature headers might be stripped in 'no-cors' mode
41
+ await postWithTimeout({
42
+ mode: 'no-cors',
43
+ headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
44
+ body,
45
+ keepalive: true
46
+ });
30
47
  return;
31
48
  }
32
49
  }
33
- const response = await postWithTimeout({ headers: { 'Content-Type': 'application/json' }, body });
50
+ const response = await postWithTimeout({ headers, body });
34
51
  if (!response.ok)
35
52
  throw new Error(`Webhook failed with status ${response.status}`);
36
53
  };
@@ -88,7 +105,14 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }) {
88
105
  }
89
106
  if (window.parent !== window) {
90
107
  const targetOrigin = new URL(return_url).origin;
91
- window.parent.postMessage({ type: 'kyc_result', status: params.status, kyc_id: params.kyc_id, message: params.message, processing_state: params.processing_state, verification_steps: params.verification_steps }, targetOrigin);
108
+ window.parent.postMessage({
109
+ type: 'kyc_result',
110
+ status: params.status,
111
+ kyc_id: params.kyc_id,
112
+ message: params.message,
113
+ processing_state: params.processing_state,
114
+ verification_steps: params.verification_steps
115
+ }, targetOrigin);
92
116
  }
93
117
  else {
94
118
  window.location.href = return_url;
@@ -104,21 +128,12 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }) {
104
128
  const isStillProcessing = data?.isProcessing || data?.session?.isProcessing;
105
129
  if (urlParams.push_url) {
106
130
  try {
107
- // 1. Locate the actual backend payload from the Context state
108
131
  const backendResult = data?.verification?.result || data?.result?.result || data?.result || data;
109
- // 2. Safely extract session ID
110
- const finalSessionId = data?.session?.session_id ||
111
- backendResult?.session_id ||
112
- backendResult?.data?.session_id ||
113
- urlParams.kyc_id ||
114
- 'unknown';
115
- // 3. Extract the core data payload
132
+ const finalSessionId = data?.session?.session_id || backendResult?.session_id || backendResult?.data?.session_id || urlParams.kyc_id || 'unknown';
116
133
  let parsedKycData = {};
117
134
  if (backendResult?.data) {
118
135
  try {
119
- parsedKycData = typeof backendResult.data === 'string'
120
- ? JSON.parse(backendResult.data)
121
- : backendResult.data;
136
+ parsedKycData = typeof backendResult.data === 'string' ? JSON.parse(backendResult.data) : backendResult.data;
122
137
  }
123
138
  catch (e) {
124
139
  console.warn("Could not parse backendResult.data JSON");
@@ -143,11 +158,11 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }) {
143
158
  const hasValidSessionId = finalSessionId && finalSessionId !== 'unknown';
144
159
  const hasValidData = parsedKycData && Object.keys(parsedKycData).length > 0;
145
160
  if (!hasValidSessionId || !hasValidData) {
146
- console.log("Webhook Blocked: Payload contains no data or session_id is unknown.", JSON.stringify(verificationState));
161
+ console.log("Webhook Blocked: Payload contains no data or session_id is unknown.");
147
162
  }
148
163
  else {
149
- console.log("Pushing Webhook Payload:", JSON.stringify(verificationState, null, 2));
150
- await postWebhook(urlParams.push_url, verificationState, 5000);
164
+ // 🚨 MODIFIED: Passing urlParams.secret
165
+ await postWebhook(urlParams.push_url, verificationState, urlParams.secret, 5000);
151
166
  }
152
167
  }
153
168
  catch (err) {
@@ -155,17 +170,12 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }) {
155
170
  }
156
171
  }
157
172
  setIsAnalyzing(false);
158
- // Always redirect the user back to your main app/website, regardless of webhook success/block
159
173
  redirectToReturnUrl({
160
174
  status: data?.verification?.status === 'failed' ? 'error' : 'completed',
161
175
  kyc_id: data?.session?.session_id || urlParams.kyc_id,
162
176
  message: 'KYC process concluded',
163
177
  processing_state: isStillProcessing ? 'analyzing' : 'completed',
164
- verification_steps: {
165
- document_analyzed: true,
166
- selfie_analyzed: true,
167
- liveness_checked: true
168
- },
178
+ verification_steps: { document_analyzed: true, selfie_analyzed: true, liveness_checked: true },
169
179
  });
170
180
  onComplete?.(data);
171
181
  }, [redirectToReturnUrl, urlParams, onComplete]);
@@ -179,7 +189,8 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }) {
179
189
  setIsAnalyzing(false);
180
190
  if (urlParams.push_url) {
181
191
  try {
182
- await postWebhook(urlParams.push_url, { status: 'cancelled', result: null, reference_id: urlParams.reference_id }, 5000);
192
+ // 🚨 MODIFIED: Passing urlParams.secret
193
+ await postWebhook(urlParams.push_url, { status: 'cancelled', result: null, reference_id: urlParams.reference_id }, urlParams.secret, 5000);
183
194
  }
184
195
  catch (err) {
185
196
  console.warn('Failed to push data to webhook URL:', err);
@@ -187,18 +198,19 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }) {
187
198
  }
188
199
  redirectToReturnUrl({ status: 'cancelled', kyc_id: urlParams.kyc_id, message: 'KYC process was cancelled', processing_state: 'pending' });
189
200
  onCancel?.();
190
- }, [redirectToReturnUrl, urlParams.kyc_id, urlParams.push_url, urlParams.reference_id, onCancel]);
201
+ }, [redirectToReturnUrl, urlParams.kyc_id, urlParams.push_url, urlParams.reference_id, urlParams.secret, onCancel]);
191
202
  const handleSessionSave = useCallback(async (sessionId) => {
192
203
  if (urlParams.save_session_url) {
193
204
  try {
194
- await postWebhook(urlParams.save_session_url, { status: 'session_created', reference_id: urlParams.reference_id, result: { session_id: sessionId, kyc_id: sessionId } }, 5000);
205
+ // 🚨 MODIFIED: Passing urlParams.secret
206
+ await postWebhook(urlParams.save_session_url, { status: 'session_created', reference_id: urlParams.reference_id, result: { session_id: sessionId, kyc_id: sessionId } }, urlParams.secret, 5000);
195
207
  }
196
208
  catch (err) {
197
209
  console.warn('Failed to push session data:', err);
198
210
  }
199
211
  }
200
212
  onSessionSave?.(sessionId);
201
- }, [urlParams.save_session_url, urlParams.reference_id, onSessionSave]);
213
+ }, [urlParams.save_session_url, urlParams.reference_id, urlParams.secret, onSessionSave]);
202
214
  useEffect(() => {
203
215
  try {
204
216
  const params = parseUrlParams();
@@ -228,14 +240,20 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }) {
228
240
  <Text style={styles.analyzingSubtext}>This may take a few moments</Text>
229
241
  </View>
230
242
  </View>)}
231
- <TemplateKYCExample onComplete={handleComplete} onCancel={handleCancel} onError={handleError} language={urlParams.lang || 'en'} API_KEY={urlParams.token} templateId={urlParams.template_id} env={urlParams.env || 'PRODUCTION'} serverEnv={urlParams.server_env} existingSessionId={urlParams.kyc_id} // Successfully passes session_id down
232
- initialComponentIndex={(() => {
243
+ {/* Overlay UI unchanged */}
244
+ <TemplateKYCExample
245
+ // ...Props unchanged...
246
+ onComplete={handleComplete} onCancel={handleCancel} onError={handleError} language={urlParams.lang || 'en'} API_KEY={urlParams.token} templateId={urlParams.template_id} env={urlParams.env || 'PRODUCTION'} serverEnv={urlParams.server_env} existingSessionId={urlParams.kyc_id} initialComponentIndex={(() => {
233
247
  const raw = urlParams.component_index ?? urlParams.step;
234
248
  if (raw == null || raw === '')
235
249
  return undefined;
236
250
  const index = parseInt(raw, 10);
237
251
  return Number.isNaN(index) ? undefined : index;
238
- })()} initialCountryResume={urlParams.country && urlParams.document_type ? { code: urlParams.country, documentType: urlParams.document_type, region: urlParams.region || undefined } : undefined} referenceId={urlParams.reference_id} onSessionSave={handleSessionSave}/>
252
+ })()} initialCountryResume={urlParams.country && urlParams.document_type ? {
253
+ code: urlParams.country,
254
+ documentType: urlParams.document_type,
255
+ region: urlParams.region || undefined
256
+ } : undefined} referenceId={urlParams.reference_id} onSessionSave={handleSessionSave}/>
239
257
  </SafeAreaView>);
240
258
  }
241
259
  const styles = StyleSheet.create({
@@ -1 +1 @@
1
- {"version":3,"file":"WebKYCEntry.js","sourceRoot":"","sources":["../../../src/web/WebKYCEntry.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useState, useCallback, JSX } from 'react';\nimport { View, Text, StyleSheet, SafeAreaView, ActivityIndicator } from 'react-native';\nimport { useI18n } from '../hooks/useI18n';\nimport { TemplateKYCExample } from '../components/TemplateKYCExample';\nimport { isCallbackUrlAllowed } from '../config/allowedDomains';\nimport KYCConfig from '../config/KYCConfig';\nimport { BackendEnvironment } from '../types/env.types';\n\ninterface WebKYCEntryProps {\n onComplete?: (data: any) => void;\n onError?: (error: string) => void;\n onCancel?: () => void;\n onSessionSave?: (sessionId: string) => void;\n}\n\ninterface URLParams {\n token?: string;\n return_url?: string;\n push_url?: string;\n save_session_url?: string;\n reference_id?: string;\n lang?: string;\n theme?: string;\n kyc_id?: string;\n secret?: string;\n env?: 'PRODUCTION' | 'SANDBOX';\n template_id?: string;\n server_env?: BackendEnvironment;\n step?: string;\n component_index?: string;\n country?: string;\n document_type?: string;\n region?: string;\n // 🚨 NEW: Added explicitly for the mobile handoff\n session_id?: string; \n resume?: boolean;\n}\n\ninterface VerificationSteps {\n document_analyzed?: boolean;\n selfie_analyzed?: boolean;\n liveness_checked?: boolean;\n}\n\nconst postWebhook = async (url: string, payload: unknown, timeoutMs: number = 5000) => {\n const body = JSON.stringify(payload);\n const postWithTimeout = async (init: RequestInit) => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n try {\n return await fetch(url, { method: 'POST', ...init, signal: controller.signal });\n } finally {\n clearTimeout(timeoutId);\n }\n };\n\n if (typeof window !== 'undefined') {\n try {\n const response = await postWithTimeout({ headers: { 'Content-Type': 'application/json' }, body, keepalive: true });\n if (!response.ok) throw new Error(`Webhook failed with status ${response.status}`);\n return;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') throw error;\n await postWithTimeout({ mode: 'no-cors', headers: { 'Content-Type': 'text/plain;charset=UTF-8' }, body, keepalive: true });\n return;\n }\n }\n\n const response = await postWithTimeout({ headers: { 'Content-Type': 'application/json' }, body });\n if (!response.ok) throw new Error(`Webhook failed with status ${response.status}`);\n};\n\nexport function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }: WebKYCEntryProps): JSX.Element {\n const { setLocale } = useI18n();\n const [urlParams, setUrlParams] = useState<URLParams>({});\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [isAnalyzing, setIsAnalyzing] = useState(false);\n\n const parseUrlParams = useCallback((): URLParams => {\n if (typeof window === 'undefined') return {};\n\n const rawUrl = window.location.href;\n console.log(\"Raw URL intercepted:\", rawUrl);\n \n const paramsString = rawUrl.replace(/^[^?#]*[?#]/, '').replace(/[?#]/g, '&');\n\n const urlParams = new URLSearchParams(paramsString);\n\n const getParam = (key: string) => urlParams.get(key) || undefined;\n\n const envParam = getParam('env');\n const validEnv = envParam === 'SANDBOX' || envParam === 'PRODUCTION' ? envParam : 'PRODUCTION';\n const serverEnvParam = getParam('server_env');\n const validServerEnv: BackendEnvironment = serverEnvParam === 'TEST' || serverEnvParam === 'PRODUCTION' ? (serverEnvParam as BackendEnvironment) : 'PRODUCTION';\n\n return {\n token: getParam('token'),\n return_url: getParam('return_url'),\n push_url: getParam('push_url'),\n save_session_url: getParam('save_session_url') || getParam('saveSessionUrl'),\n reference_id: getParam('reference_id'),\n lang: getParam('lang') || 'en',\n theme: getParam('theme') || 'light',\n kyc_id: getParam('kyc_id') || getParam('session_id'), \n secret: getParam('secret'),\n env: validEnv,\n template_id: getParam('template_id'),\n server_env: validServerEnv,\n step: getParam('step'),\n component_index: getParam('component_index'),\n country: getParam('country'),\n document_type: getParam('document_type'),\n region: getParam('region'),\n resume: getParam('resume') === 'true',\n };\n }, []);\n\n const redirectToReturnUrl = useCallback(async (params: { status: 'completed' | 'cancelled' | 'error'; kyc_id?: string; message?: string; processing_state?: 'analyzing' | 'completed' | 'pending'; verification_steps?: VerificationSteps; }) => {\n const { return_url } = urlParams;\n if (!return_url) { console.warn('No return_url provided'); return; }\n try {\n const validation = isCallbackUrlAllowed(return_url);\n if (!validation.allowed) {\n console.error('Callback URL validation failed:', validation.reason);\n setError(`Security Error: ${validation.reason}`);\n return;\n }\n if (window.parent !== window) {\n const targetOrigin = new URL(return_url).origin;\n window.parent.postMessage({ type: 'kyc_result', status: params.status, kyc_id: params.kyc_id, message: params.message, processing_state: params.processing_state, verification_steps: params.verification_steps }, targetOrigin);\n } else {\n window.location.href = return_url;\n }\n } catch (error) {\n console.error('Error during redirect:', error);\n setError('Failed to redirect to callback URL');\n }\n }, [urlParams]);\n\n const handleComplete = useCallback(async (data: any) => {\n console.log('KYC completed, raw state:', data);\n const isStillProcessing = data?.isProcessing || data?.session?.isProcessing;\n\n if (urlParams.push_url) {\n try {\n // 1. Locate the actual backend payload from the Context state\n const backendResult = data?.verification?.result || data?.result?.result || data?.result || data;\n\n // 2. Safely extract session ID\n const finalSessionId = \n data?.session?.session_id || \n backendResult?.session_id || \n backendResult?.data?.session_id || \n urlParams.kyc_id || \n 'unknown';\n\n // 3. Extract the core data payload\n let parsedKycData: any = {};\n if (backendResult?.data) {\n try {\n parsedKycData = typeof backendResult.data === 'string' \n ? JSON.parse(backendResult.data) \n : backendResult.data;\n } catch (e) {\n console.warn(\"Could not parse backendResult.data JSON\");\n }\n }\n\n if (parsedKycData && typeof parsedKycData === 'object' && parsedKycData[finalSessionId]) {\n const nested = parsedKycData[finalSessionId];\n if (nested?.data) {\n parsedKycData = typeof nested.data === 'string' ? JSON.parse(nested.data) : nested.data;\n } else {\n parsedKycData = nested;\n }\n }\n\n const verificationState = {\n session_id: finalSessionId,\n reference_id: urlParams.reference_id || backendResult?.referenceId || null,\n status: backendResult?.status || data?.verification?.status || 'completed',\n message: backendResult?.message || backendResult?.reason || backendResult?.issues?.[0] || 'Verification finished.',\n data: parsedKycData || {}\n };\n\n const hasValidSessionId = finalSessionId && finalSessionId !== 'unknown';\n const hasValidData = parsedKycData && Object.keys(parsedKycData).length > 0;\n\n if (!hasValidSessionId || !hasValidData) {\n console.log(\"Webhook Blocked: Payload contains no data or session_id is unknown.\", JSON.stringify(verificationState));\n } else {\n console.log(\"Pushing Webhook Payload:\", JSON.stringify(verificationState, null, 2));\n await postWebhook(urlParams.push_url, verificationState, 5000);\n }\n\n } catch (err) {\n console.warn('Failed to construct or push data to webhook URL:', err);\n }\n }\n\n setIsAnalyzing(false);\n \n // Always redirect the user back to your main app/website, regardless of webhook success/block\n redirectToReturnUrl({\n status: data?.verification?.status === 'failed' ? 'error' : 'completed',\n kyc_id: data?.session?.session_id || urlParams.kyc_id,\n message: 'KYC process concluded',\n processing_state: isStillProcessing ? 'analyzing' : 'completed',\n verification_steps: {\n document_analyzed: true,\n selfie_analyzed: true,\n liveness_checked: true\n },\n });\n \n onComplete?.(data);\n }, [redirectToReturnUrl, urlParams, onComplete]);\n\n const handleError = useCallback((error: string) => {\n console.error('KYC error:', error);\n setIsAnalyzing(false);\n redirectToReturnUrl({ status: 'error', kyc_id: urlParams.kyc_id, message: error, processing_state: 'pending' });\n onError?.(error);\n }, [redirectToReturnUrl, urlParams.kyc_id, onError]);\n\n const handleCancel = useCallback(async () => {\n setIsAnalyzing(false);\n if (urlParams.push_url) {\n try {\n await postWebhook(urlParams.push_url, { status: 'cancelled', result: null, reference_id: urlParams.reference_id }, 5000);\n } catch (err) { console.warn('Failed to push data to webhook URL:', err); }\n }\n redirectToReturnUrl({ status: 'cancelled', kyc_id: urlParams.kyc_id, message: 'KYC process was cancelled', processing_state: 'pending' });\n onCancel?.();\n }, [redirectToReturnUrl, urlParams.kyc_id, urlParams.push_url, urlParams.reference_id, onCancel]);\n\n const handleSessionSave = useCallback(async (sessionId: string) => {\n if (urlParams.save_session_url) {\n try {\n await postWebhook(urlParams.save_session_url, { status: 'session_created', reference_id: urlParams.reference_id, result: { session_id: sessionId, kyc_id: sessionId } }, 5000);\n } catch (err) { console.warn('Failed to push session data:', err); }\n }\n onSessionSave?.(sessionId);\n }, [urlParams.save_session_url, urlParams.reference_id, onSessionSave]);\n\n useEffect(() => {\n try {\n const params = parseUrlParams();\n setUrlParams(params);\n if (params.lang) setLocale(params.lang);\n if (params.server_env) KYCConfig.setBackendEnvironment(params.server_env);\n setIsLoading(false);\n } catch (error) {\n setError('Error parsing URL parameters');\n setIsLoading(false);\n }\n }, [parseUrlParams, setLocale]);\n\n if (isLoading) return <View style={styles.container}><Text style={styles.loadingText}>Loading KYC process...</Text></View>;\n if (error) return <View style={styles.container}><Text style={styles.errorText}>Error: {error}</Text></View>;\n if (!urlParams.token) return <View style={styles.container}><Text style={styles.errorText}>No token provided in URL parameters</Text></View>;\n\n return (\n <SafeAreaView style={styles.container}>\n {isAnalyzing && (\n <View style={styles.analyzingOverlay}>\n <View style={styles.analyzingContainer}>\n <ActivityIndicator size=\"large\" color=\"#2DBD60\" />\n <Text style={styles.analyzingText}>Analyzing verification data...</Text>\n <Text style={styles.analyzingSubtext}>This may take a few moments</Text>\n </View>\n </View>\n )}\n <TemplateKYCExample\n onComplete={handleComplete}\n onCancel={handleCancel}\n onError={handleError}\n language={urlParams.lang || 'en'}\n API_KEY={urlParams.token}\n templateId={urlParams.template_id}\n env={urlParams.env || 'PRODUCTION'}\n serverEnv={urlParams.server_env}\n existingSessionId={urlParams.kyc_id} // Successfully passes session_id down\n initialComponentIndex={(() => {\n const raw = urlParams.component_index ?? urlParams.step;\n if (raw == null || raw === '') return undefined;\n const index = parseInt(raw, 10);\n return Number.isNaN(index) ? undefined : index;\n })()}\n initialCountryResume={urlParams.country && urlParams.document_type ? { code: urlParams.country, documentType: urlParams.document_type, region: urlParams.region || undefined } : undefined}\n referenceId={urlParams.reference_id}\n onSessionSave={handleSessionSave}\n />\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n container: { flex: 1, backgroundColor: '#f5f5f5', overflow: 'visible' as any },\n loadingText: { fontSize: 18, textAlign: 'center', marginTop: 50, color: '#666' },\n errorText: { fontSize: 16, textAlign: 'center', marginTop: 50, color: '#dc2626', paddingHorizontal: 20 },\n analyzingOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0, 0, 0, 0.7)', justifyContent: 'center', alignItems: 'center', zIndex: 9999 },\n analyzingContainer: { backgroundColor: 'white', borderRadius: 12, padding: 32, alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 8, elevation: 8 },\n analyzingText: { fontSize: 18, fontWeight: '600', color: '#333', marginTop: 16, textAlign: 'center' },\n analyzingSubtext: { fontSize: 14, color: '#666', marginTop: 8, textAlign: 'center' },\n});\n\nexport default WebKYCEntry;"]}
1
+ {"version":3,"file":"WebKYCEntry.js","sourceRoot":"","sources":["../../../src/web/WebKYCEntry.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useState, useCallback, JSX } from 'react';\nimport { View, Text, StyleSheet, SafeAreaView, ActivityIndicator } from 'react-native';\nimport { useI18n } from '../hooks/useI18n';\nimport { TemplateKYCExample } from '../components/TemplateKYCExample';\nimport { isCallbackUrlAllowed } from '../config/allowedDomains';\nimport KYCConfig from '../config/KYCConfig';\nimport { BackendEnvironment } from '../types/env.types';\nimport CryptoJS from 'crypto-js'; // 🚨 IMPORT ADDED\n\ninterface WebKYCEntryProps {\n onComplete?: (data: any) => void;\n onError?: (error: string) => void;\n onCancel?: () => void;\n onSessionSave?: (sessionId: string) => void;\n}\n\ninterface URLParams {\n token?: string;\n return_url?: string;\n push_url?: string;\n save_session_url?: string;\n reference_id?: string;\n lang?: string;\n theme?: string;\n kyc_id?: string;\n secret?: string;\n env?: 'PRODUCTION' | 'SANDBOX';\n template_id?: string;\n server_env?: BackendEnvironment;\n step?: string;\n component_index?: string;\n country?: string;\n document_type?: string;\n region?: string;\n session_id?: string;\n resume?: boolean;\n}\n\ninterface VerificationSteps {\n document_analyzed?: boolean;\n selfie_analyzed?: boolean;\n liveness_checked?: boolean;\n}\n\n// 🚨 MODIFIED: Accepts the webhook secret to generate the signature\nconst postWebhook = async (url: string, payload: unknown, secret?: string, timeoutMs: number = 5000) => {\n const body = JSON.stringify(payload);\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // 🚨 Generate HMAC SHA-256 Signature if secret is provided\n if (secret) {\n const signature = CryptoJS.HmacSHA256(body, secret).toString(CryptoJS.enc.Hex);\n headers['x-sanctumkey-signature'] = signature;\n console.log(\"🔒 Generated Webhook Signature:\", signature);\n }\n\n const postWithTimeout = async (init: RequestInit) => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n try {\n return await fetch(url, { method: 'POST', ...init, signal: controller.signal });\n } finally {\n clearTimeout(timeoutId);\n }\n };\n\n if (typeof window !== 'undefined') {\n try {\n const response = await postWithTimeout({ headers, body, keepalive: true });\n if (!response.ok) throw new Error(`Webhook failed with status ${response.status}`);\n return;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') throw error;\n // Fallback for CORS issues, though signature headers might be stripped in 'no-cors' mode\n await postWithTimeout({ \n mode: 'no-cors', \n headers: { 'Content-Type': 'text/plain;charset=UTF-8' }, \n body, \n keepalive: true \n });\n return;\n }\n }\n\n const response = await postWithTimeout({ headers, body });\n if (!response.ok) throw new Error(`Webhook failed with status ${response.status}`);\n};\n\nexport function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }: WebKYCEntryProps): JSX.Element {\n const { setLocale } = useI18n();\n const [urlParams, setUrlParams] = useState<URLParams>({});\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [isAnalyzing, setIsAnalyzing] = useState(false);\n\n const parseUrlParams = useCallback((): URLParams => {\n if (typeof window === 'undefined') return {};\n const rawUrl = window.location.href;\n console.log(\"Raw URL intercepted:\", rawUrl);\n \n const paramsString = rawUrl.replace(/^[^?#]*[?#]/, '').replace(/[?#]/g, '&');\n const urlParams = new URLSearchParams(paramsString);\n const getParam = (key: string) => urlParams.get(key) || undefined;\n \n const envParam = getParam('env');\n const validEnv = envParam === 'SANDBOX' || envParam === 'PRODUCTION' ? envParam : 'PRODUCTION';\n \n const serverEnvParam = getParam('server_env');\n const validServerEnv: BackendEnvironment = serverEnvParam === 'TEST' || serverEnvParam === 'PRODUCTION' ? (serverEnvParam as BackendEnvironment) : 'PRODUCTION';\n \n return {\n token: getParam('token'),\n return_url: getParam('return_url'),\n push_url: getParam('push_url'),\n save_session_url: getParam('save_session_url') || getParam('saveSessionUrl'),\n reference_id: getParam('reference_id'),\n lang: getParam('lang') || 'en',\n theme: getParam('theme') || 'light',\n kyc_id: getParam('kyc_id') || getParam('session_id'),\n secret: getParam('secret'),\n env: validEnv,\n template_id: getParam('template_id'),\n server_env: validServerEnv,\n step: getParam('step'),\n component_index: getParam('component_index'),\n country: getParam('country'),\n document_type: getParam('document_type'),\n region: getParam('region'),\n resume: getParam('resume') === 'true',\n };\n }, []);\n\n const redirectToReturnUrl = useCallback(async (params: {\n status: 'completed' | 'cancelled' | 'error';\n kyc_id?: string;\n message?: string;\n processing_state?: 'analyzing' | 'completed' | 'pending';\n verification_steps?: VerificationSteps;\n }) => {\n const { return_url } = urlParams;\n if (!return_url) {\n console.warn('No return_url provided');\n return;\n }\n\n try {\n const validation = isCallbackUrlAllowed(return_url);\n if (!validation.allowed) {\n console.error('Callback URL validation failed:', validation.reason);\n setError(`Security Error: ${validation.reason}`);\n return;\n }\n\n if (window.parent !== window) {\n const targetOrigin = new URL(return_url).origin;\n window.parent.postMessage({\n type: 'kyc_result',\n status: params.status,\n kyc_id: params.kyc_id,\n message: params.message,\n processing_state: params.processing_state,\n verification_steps: params.verification_steps\n }, targetOrigin);\n } else {\n window.location.href = return_url;\n }\n } catch (error) {\n console.error('Error during redirect:', error);\n setError('Failed to redirect to callback URL');\n }\n }, [urlParams]);\n\n const handleComplete = useCallback(async (data: any) => {\n console.log('KYC completed, raw state:', data);\n const isStillProcessing = data?.isProcessing || data?.session?.isProcessing;\n\n if (urlParams.push_url) {\n try {\n const backendResult = data?.verification?.result || data?.result?.result || data?.result || data;\n const finalSessionId = data?.session?.session_id || backendResult?.session_id || backendResult?.data?.session_id || urlParams.kyc_id || 'unknown';\n \n let parsedKycData: any = {};\n if (backendResult?.data) {\n try {\n parsedKycData = typeof backendResult.data === 'string' ? JSON.parse(backendResult.data) : backendResult.data;\n } catch (e) {\n console.warn(\"Could not parse backendResult.data JSON\");\n }\n }\n \n if (parsedKycData && typeof parsedKycData === 'object' && parsedKycData[finalSessionId]) {\n const nested = parsedKycData[finalSessionId];\n if (nested?.data) {\n parsedKycData = typeof nested.data === 'string' ? JSON.parse(nested.data) : nested.data;\n } else {\n parsedKycData = nested;\n }\n }\n\n const verificationState = {\n session_id: finalSessionId,\n reference_id: urlParams.reference_id || backendResult?.referenceId || null,\n status: backendResult?.status || data?.verification?.status || 'completed',\n message: backendResult?.message || backendResult?.reason || backendResult?.issues?.[0] || 'Verification finished.',\n data: parsedKycData || {}\n };\n\n const hasValidSessionId = finalSessionId && finalSessionId !== 'unknown';\n const hasValidData = parsedKycData && Object.keys(parsedKycData).length > 0;\n\n if (!hasValidSessionId || !hasValidData) {\n console.log(\"Webhook Blocked: Payload contains no data or session_id is unknown.\");\n } else {\n // 🚨 MODIFIED: Passing urlParams.secret\n await postWebhook(urlParams.push_url, verificationState, urlParams.secret, 5000);\n }\n } catch (err) {\n console.warn('Failed to construct or push data to webhook URL:', err);\n }\n }\n\n setIsAnalyzing(false);\n redirectToReturnUrl({\n status: data?.verification?.status === 'failed' ? 'error' : 'completed',\n kyc_id: data?.session?.session_id || urlParams.kyc_id,\n message: 'KYC process concluded',\n processing_state: isStillProcessing ? 'analyzing' : 'completed',\n verification_steps: { document_analyzed: true, selfie_analyzed: true, liveness_checked: true },\n });\n onComplete?.(data);\n }, [redirectToReturnUrl, urlParams, onComplete]);\n\n const handleError = useCallback((error: string) => {\n console.error('KYC error:', error);\n setIsAnalyzing(false);\n redirectToReturnUrl({ status: 'error', kyc_id: urlParams.kyc_id, message: error, processing_state: 'pending' });\n onError?.(error);\n }, [redirectToReturnUrl, urlParams.kyc_id, onError]);\n\n const handleCancel = useCallback(async () => {\n setIsAnalyzing(false);\n if (urlParams.push_url) {\n try {\n // 🚨 MODIFIED: Passing urlParams.secret\n await postWebhook(\n urlParams.push_url, \n { status: 'cancelled', result: null, reference_id: urlParams.reference_id }, \n urlParams.secret, \n 5000\n );\n } catch (err) {\n console.warn('Failed to push data to webhook URL:', err);\n }\n }\n \n redirectToReturnUrl({ status: 'cancelled', kyc_id: urlParams.kyc_id, message: 'KYC process was cancelled', processing_state: 'pending' });\n onCancel?.();\n }, [redirectToReturnUrl, urlParams.kyc_id, urlParams.push_url, urlParams.reference_id, urlParams.secret, onCancel]);\n\n const handleSessionSave = useCallback(async (sessionId: string) => {\n if (urlParams.save_session_url) {\n try {\n // 🚨 MODIFIED: Passing urlParams.secret\n await postWebhook(\n urlParams.save_session_url, \n { status: 'session_created', reference_id: urlParams.reference_id, result: { session_id: sessionId, kyc_id: sessionId } }, \n urlParams.secret, \n 5000\n );\n } catch (err) {\n console.warn('Failed to push session data:', err);\n }\n }\n onSessionSave?.(sessionId);\n }, [urlParams.save_session_url, urlParams.reference_id, urlParams.secret, onSessionSave]);\n\n useEffect(() => {\n try {\n const params = parseUrlParams();\n setUrlParams(params);\n if (params.lang) setLocale(params.lang);\n if (params.server_env) KYCConfig.setBackendEnvironment(params.server_env);\n setIsLoading(false);\n } catch (error) {\n setError('Error parsing URL parameters');\n setIsLoading(false);\n }\n }, [parseUrlParams, setLocale]);\n\n if (isLoading) return <View style={styles.container}><Text style={styles.loadingText}>Loading KYC process...</Text></View>;\n if (error) return <View style={styles.container}><Text style={styles.errorText}>Error: {error}</Text></View>;\n if (!urlParams.token) return <View style={styles.container}><Text style={styles.errorText}>No token provided in URL parameters</Text></View>;\n\n return (\n <SafeAreaView style={styles.container}>\n {isAnalyzing && (\n <View style={styles.analyzingOverlay}>\n <View style={styles.analyzingContainer}>\n <ActivityIndicator size=\"large\" color=\"#2DBD60\" />\n <Text style={styles.analyzingText}>Analyzing verification data...</Text>\n <Text style={styles.analyzingSubtext}>This may take a few moments</Text>\n </View>\n </View>\n )}\n {/* Overlay UI unchanged */}\n <TemplateKYCExample\n // ...Props unchanged...\n onComplete={handleComplete}\n onCancel={handleCancel}\n onError={handleError}\n language={urlParams.lang || 'en'}\n API_KEY={urlParams.token}\n templateId={urlParams.template_id}\n env={urlParams.env || 'PRODUCTION'}\n serverEnv={urlParams.server_env}\n existingSessionId={urlParams.kyc_id}\n initialComponentIndex={(() => {\n const raw = urlParams.component_index ?? urlParams.step;\n if (raw == null || raw === '') return undefined;\n const index = parseInt(raw, 10);\n return Number.isNaN(index) ? undefined : index;\n })()}\n initialCountryResume={urlParams.country && urlParams.document_type ? { \n code: urlParams.country, \n documentType: urlParams.document_type, \n region: urlParams.region || undefined \n } : undefined}\n referenceId={urlParams.reference_id}\n onSessionSave={handleSessionSave}\n />\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n container: { flex: 1, backgroundColor: '#f5f5f5', overflow: 'visible' as any },\n loadingText: { fontSize: 18, textAlign: 'center', marginTop: 50, color: '#666' },\n errorText: { fontSize: 16, textAlign: 'center', marginTop: 50, color: '#dc2626', paddingHorizontal: 20 },\n analyzingOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0, 0, 0, 0.7)', justifyContent: 'center', alignItems: 'center', zIndex: 9999 },\n analyzingContainer: { backgroundColor: 'white', borderRadius: 12, padding: 32, alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 8, elevation: 8 },\n analyzingText: { fontSize: 18, fontWeight: '600', color: '#333', marginTop: 16, textAlign: 'center' },\n analyzingSubtext: { fontSize: 14, color: '#666', marginTop: 8, textAlign: 'center' },\n});\n\nexport default WebKYCEntry;"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanctum-key/react-native-sdk",
3
- "version": "1.0.54",
3
+ "version": "1.0.56",
4
4
  "description": "Sanctum Key React Native SDK",
5
5
  "main": "build/src/index.js",
6
6
  "types": "build/src/index.d.ts",
@@ -50,6 +50,7 @@
50
50
  "@zxing/browser": "^0.2.0",
51
51
  "@zxing/library": "^0.22.0",
52
52
  "axios": "^1.11.0",
53
+ "crypto-js": "^4.2.0",
53
54
  "expo-blur": "~15.0.8",
54
55
  "i18n-js": "4.5.1",
55
56
  "iconsax-react-nativejs": "^0.0.8",
@@ -58,6 +59,7 @@
58
59
  "zustand": "^5.0.8"
59
60
  },
60
61
  "devDependencies": {
62
+ "@types/crypto-js": "^4.2.2",
61
63
  "@types/react": "~19.1.0",
62
64
  "copyfiles": "^2.4.1",
63
65
  "expo": "~54.0.0",
@@ -5,6 +5,7 @@ import { TemplateKYCExample } from '../components/TemplateKYCExample';
5
5
  import { isCallbackUrlAllowed } from '../config/allowedDomains';
6
6
  import KYCConfig from '../config/KYCConfig';
7
7
  import { BackendEnvironment } from '../types/env.types';
8
+ import CryptoJS from 'crypto-js'; // 🚨 IMPORT ADDED
8
9
 
9
10
  interface WebKYCEntryProps {
10
11
  onComplete?: (data: any) => void;
@@ -31,8 +32,7 @@ interface URLParams {
31
32
  country?: string;
32
33
  document_type?: string;
33
34
  region?: string;
34
- // 🚨 NEW: Added explicitly for the mobile handoff
35
- session_id?: string;
35
+ session_id?: string;
36
36
  resume?: boolean;
37
37
  }
38
38
 
@@ -42,8 +42,21 @@ interface VerificationSteps {
42
42
  liveness_checked?: boolean;
43
43
  }
44
44
 
45
- const postWebhook = async (url: string, payload: unknown, timeoutMs: number = 5000) => {
45
+ // 🚨 MODIFIED: Accepts the webhook secret to generate the signature
46
+ const postWebhook = async (url: string, payload: unknown, secret?: string, timeoutMs: number = 5000) => {
46
47
  const body = JSON.stringify(payload);
48
+
49
+ const headers: Record<string, string> = {
50
+ 'Content-Type': 'application/json',
51
+ };
52
+
53
+ // 🚨 Generate HMAC SHA-256 Signature if secret is provided
54
+ if (secret) {
55
+ const signature = CryptoJS.HmacSHA256(body, secret).toString(CryptoJS.enc.Hex);
56
+ headers['x-sanctumkey-signature'] = signature;
57
+ console.log("🔒 Generated Webhook Signature:", signature);
58
+ }
59
+
47
60
  const postWithTimeout = async (init: RequestInit) => {
48
61
  const controller = new AbortController();
49
62
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
@@ -56,17 +69,23 @@ const postWebhook = async (url: string, payload: unknown, timeoutMs: number = 50
56
69
 
57
70
  if (typeof window !== 'undefined') {
58
71
  try {
59
- const response = await postWithTimeout({ headers: { 'Content-Type': 'application/json' }, body, keepalive: true });
72
+ const response = await postWithTimeout({ headers, body, keepalive: true });
60
73
  if (!response.ok) throw new Error(`Webhook failed with status ${response.status}`);
61
74
  return;
62
75
  } catch (error) {
63
76
  if (error instanceof Error && error.name === 'AbortError') throw error;
64
- await postWithTimeout({ mode: 'no-cors', headers: { 'Content-Type': 'text/plain;charset=UTF-8' }, body, keepalive: true });
77
+ // Fallback for CORS issues, though signature headers might be stripped in 'no-cors' mode
78
+ await postWithTimeout({
79
+ mode: 'no-cors',
80
+ headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
81
+ body,
82
+ keepalive: true
83
+ });
65
84
  return;
66
85
  }
67
86
  }
68
87
 
69
- const response = await postWithTimeout({ headers: { 'Content-Type': 'application/json' }, body });
88
+ const response = await postWithTimeout({ headers, body });
70
89
  if (!response.ok) throw new Error(`Webhook failed with status ${response.status}`);
71
90
  };
72
91
 
@@ -79,21 +98,19 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }: We
79
98
 
80
99
  const parseUrlParams = useCallback((): URLParams => {
81
100
  if (typeof window === 'undefined') return {};
82
-
83
101
  const rawUrl = window.location.href;
84
102
  console.log("Raw URL intercepted:", rawUrl);
85
103
 
86
104
  const paramsString = rawUrl.replace(/^[^?#]*[?#]/, '').replace(/[?#]/g, '&');
87
-
88
105
  const urlParams = new URLSearchParams(paramsString);
89
-
90
106
  const getParam = (key: string) => urlParams.get(key) || undefined;
91
-
107
+
92
108
  const envParam = getParam('env');
93
109
  const validEnv = envParam === 'SANDBOX' || envParam === 'PRODUCTION' ? envParam : 'PRODUCTION';
110
+
94
111
  const serverEnvParam = getParam('server_env');
95
112
  const validServerEnv: BackendEnvironment = serverEnvParam === 'TEST' || serverEnvParam === 'PRODUCTION' ? (serverEnvParam as BackendEnvironment) : 'PRODUCTION';
96
-
113
+
97
114
  return {
98
115
  token: getParam('token'),
99
116
  return_url: getParam('return_url'),
@@ -102,7 +119,7 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }: We
102
119
  reference_id: getParam('reference_id'),
103
120
  lang: getParam('lang') || 'en',
104
121
  theme: getParam('theme') || 'light',
105
- kyc_id: getParam('kyc_id') || getParam('session_id'),
122
+ kyc_id: getParam('kyc_id') || getParam('session_id'),
106
123
  secret: getParam('secret'),
107
124
  env: validEnv,
108
125
  template_id: getParam('template_id'),
@@ -116,9 +133,19 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }: We
116
133
  };
117
134
  }, []);
118
135
 
119
- const redirectToReturnUrl = useCallback(async (params: { status: 'completed' | 'cancelled' | 'error'; kyc_id?: string; message?: string; processing_state?: 'analyzing' | 'completed' | 'pending'; verification_steps?: VerificationSteps; }) => {
136
+ const redirectToReturnUrl = useCallback(async (params: {
137
+ status: 'completed' | 'cancelled' | 'error';
138
+ kyc_id?: string;
139
+ message?: string;
140
+ processing_state?: 'analyzing' | 'completed' | 'pending';
141
+ verification_steps?: VerificationSteps;
142
+ }) => {
120
143
  const { return_url } = urlParams;
121
- if (!return_url) { console.warn('No return_url provided'); return; }
144
+ if (!return_url) {
145
+ console.warn('No return_url provided');
146
+ return;
147
+ }
148
+
122
149
  try {
123
150
  const validation = isCallbackUrlAllowed(return_url);
124
151
  if (!validation.allowed) {
@@ -126,9 +153,17 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }: We
126
153
  setError(`Security Error: ${validation.reason}`);
127
154
  return;
128
155
  }
156
+
129
157
  if (window.parent !== window) {
130
158
  const targetOrigin = new URL(return_url).origin;
131
- window.parent.postMessage({ type: 'kyc_result', status: params.status, kyc_id: params.kyc_id, message: params.message, processing_state: params.processing_state, verification_steps: params.verification_steps }, targetOrigin);
159
+ window.parent.postMessage({
160
+ type: 'kyc_result',
161
+ status: params.status,
162
+ kyc_id: params.kyc_id,
163
+ message: params.message,
164
+ processing_state: params.processing_state,
165
+ verification_steps: params.verification_steps
166
+ }, targetOrigin);
132
167
  } else {
133
168
  window.location.href = return_url;
134
169
  }
@@ -144,29 +179,18 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }: We
144
179
 
145
180
  if (urlParams.push_url) {
146
181
  try {
147
- // 1. Locate the actual backend payload from the Context state
148
182
  const backendResult = data?.verification?.result || data?.result?.result || data?.result || data;
149
-
150
- // 2. Safely extract session ID
151
- const finalSessionId =
152
- data?.session?.session_id ||
153
- backendResult?.session_id ||
154
- backendResult?.data?.session_id ||
155
- urlParams.kyc_id ||
156
- 'unknown';
157
-
158
- // 3. Extract the core data payload
183
+ const finalSessionId = data?.session?.session_id || backendResult?.session_id || backendResult?.data?.session_id || urlParams.kyc_id || 'unknown';
184
+
159
185
  let parsedKycData: any = {};
160
186
  if (backendResult?.data) {
161
187
  try {
162
- parsedKycData = typeof backendResult.data === 'string'
163
- ? JSON.parse(backendResult.data)
164
- : backendResult.data;
188
+ parsedKycData = typeof backendResult.data === 'string' ? JSON.parse(backendResult.data) : backendResult.data;
165
189
  } catch (e) {
166
190
  console.warn("Could not parse backendResult.data JSON");
167
191
  }
168
192
  }
169
-
193
+
170
194
  if (parsedKycData && typeof parsedKycData === 'object' && parsedKycData[finalSessionId]) {
171
195
  const nested = parsedKycData[finalSessionId];
172
196
  if (nested?.data) {
@@ -188,32 +212,24 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }: We
188
212
  const hasValidData = parsedKycData && Object.keys(parsedKycData).length > 0;
189
213
 
190
214
  if (!hasValidSessionId || !hasValidData) {
191
- console.log("Webhook Blocked: Payload contains no data or session_id is unknown.", JSON.stringify(verificationState));
215
+ console.log("Webhook Blocked: Payload contains no data or session_id is unknown.");
192
216
  } else {
193
- console.log("Pushing Webhook Payload:", JSON.stringify(verificationState, null, 2));
194
- await postWebhook(urlParams.push_url, verificationState, 5000);
217
+ // 🚨 MODIFIED: Passing urlParams.secret
218
+ await postWebhook(urlParams.push_url, verificationState, urlParams.secret, 5000);
195
219
  }
196
-
197
220
  } catch (err) {
198
221
  console.warn('Failed to construct or push data to webhook URL:', err);
199
222
  }
200
223
  }
201
224
 
202
225
  setIsAnalyzing(false);
203
-
204
- // Always redirect the user back to your main app/website, regardless of webhook success/block
205
226
  redirectToReturnUrl({
206
227
  status: data?.verification?.status === 'failed' ? 'error' : 'completed',
207
228
  kyc_id: data?.session?.session_id || urlParams.kyc_id,
208
229
  message: 'KYC process concluded',
209
230
  processing_state: isStillProcessing ? 'analyzing' : 'completed',
210
- verification_steps: {
211
- document_analyzed: true,
212
- selfie_analyzed: true,
213
- liveness_checked: true
214
- },
231
+ verification_steps: { document_analyzed: true, selfie_analyzed: true, liveness_checked: true },
215
232
  });
216
-
217
233
  onComplete?.(data);
218
234
  }, [redirectToReturnUrl, urlParams, onComplete]);
219
235
 
@@ -228,21 +244,38 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }: We
228
244
  setIsAnalyzing(false);
229
245
  if (urlParams.push_url) {
230
246
  try {
231
- await postWebhook(urlParams.push_url, { status: 'cancelled', result: null, reference_id: urlParams.reference_id }, 5000);
232
- } catch (err) { console.warn('Failed to push data to webhook URL:', err); }
247
+ // 🚨 MODIFIED: Passing urlParams.secret
248
+ await postWebhook(
249
+ urlParams.push_url,
250
+ { status: 'cancelled', result: null, reference_id: urlParams.reference_id },
251
+ urlParams.secret,
252
+ 5000
253
+ );
254
+ } catch (err) {
255
+ console.warn('Failed to push data to webhook URL:', err);
256
+ }
233
257
  }
258
+
234
259
  redirectToReturnUrl({ status: 'cancelled', kyc_id: urlParams.kyc_id, message: 'KYC process was cancelled', processing_state: 'pending' });
235
260
  onCancel?.();
236
- }, [redirectToReturnUrl, urlParams.kyc_id, urlParams.push_url, urlParams.reference_id, onCancel]);
261
+ }, [redirectToReturnUrl, urlParams.kyc_id, urlParams.push_url, urlParams.reference_id, urlParams.secret, onCancel]);
237
262
 
238
263
  const handleSessionSave = useCallback(async (sessionId: string) => {
239
264
  if (urlParams.save_session_url) {
240
265
  try {
241
- await postWebhook(urlParams.save_session_url, { status: 'session_created', reference_id: urlParams.reference_id, result: { session_id: sessionId, kyc_id: sessionId } }, 5000);
242
- } catch (err) { console.warn('Failed to push session data:', err); }
266
+ // 🚨 MODIFIED: Passing urlParams.secret
267
+ await postWebhook(
268
+ urlParams.save_session_url,
269
+ { status: 'session_created', reference_id: urlParams.reference_id, result: { session_id: sessionId, kyc_id: sessionId } },
270
+ urlParams.secret,
271
+ 5000
272
+ );
273
+ } catch (err) {
274
+ console.warn('Failed to push session data:', err);
275
+ }
243
276
  }
244
277
  onSessionSave?.(sessionId);
245
- }, [urlParams.save_session_url, urlParams.reference_id, onSessionSave]);
278
+ }, [urlParams.save_session_url, urlParams.reference_id, urlParams.secret, onSessionSave]);
246
279
 
247
280
  useEffect(() => {
248
281
  try {
@@ -272,7 +305,9 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }: We
272
305
  </View>
273
306
  </View>
274
307
  )}
308
+ {/* Overlay UI unchanged */}
275
309
  <TemplateKYCExample
310
+ // ...Props unchanged...
276
311
  onComplete={handleComplete}
277
312
  onCancel={handleCancel}
278
313
  onError={handleError}
@@ -281,14 +316,18 @@ export function WebKYCEntry({ onComplete, onError, onCancel, onSessionSave }: We
281
316
  templateId={urlParams.template_id}
282
317
  env={urlParams.env || 'PRODUCTION'}
283
318
  serverEnv={urlParams.server_env}
284
- existingSessionId={urlParams.kyc_id} // Successfully passes session_id down
319
+ existingSessionId={urlParams.kyc_id}
285
320
  initialComponentIndex={(() => {
286
321
  const raw = urlParams.component_index ?? urlParams.step;
287
322
  if (raw == null || raw === '') return undefined;
288
323
  const index = parseInt(raw, 10);
289
324
  return Number.isNaN(index) ? undefined : index;
290
325
  })()}
291
- initialCountryResume={urlParams.country && urlParams.document_type ? { code: urlParams.country, documentType: urlParams.document_type, region: urlParams.region || undefined } : undefined}
326
+ initialCountryResume={urlParams.country && urlParams.document_type ? {
327
+ code: urlParams.country,
328
+ documentType: urlParams.document_type,
329
+ region: urlParams.region || undefined
330
+ } : undefined}
292
331
  referenceId={urlParams.reference_id}
293
332
  onSessionSave={handleSessionSave}
294
333
  />