Skip to content

Conversation

@ganchoradkov
Copy link
Member

Summary

  • Add CollectDataWebView component that displays WalletConnect Pay's hosted form in a fullscreen WebView
  • When collectData.url is present in payment options, use WebView instead of native form
  • Handle IC_COMPLETE / IC_ERROR postMessage events from the WebView
  • Improved UX: X button in WebView navigates to confirm step (not closes entire modal)

Changes

flowchart TD
    A[Payment Link Received] --> B[Show Intro]
    B --> C{collectData.url exists?}
    C -->|Yes| D[Open WebView - Fullscreen]
    C -->|No| E[Show Native Form]
    D --> F{IC_COMPLETE message?}
    F -->|Yes| G[Move to Confirm Step]
    F -->|No - X pressed| G
    E --> G
    G --> H[Select Payment Option]
    H --> I[Sign & Confirm Payment]
Loading

Test Plan

  • Scan a WalletConnect Pay link that requires collect data
  • Verify WebView opens fullscreen after clicking "Let's start"
  • Complete the form in WebView
  • Verify automatic navigation to confirm step after form completion
  • Verify X button navigates to confirm step (not closes modal)
  • Test error handling when WebView fails to load

- Add CollectDataWebView component for WalletConnect Pay hosted form
- Use fullscreen WebView when collectData.url is available
- Handle IC_COMPLETE/IC_ERROR postMessage events from WebView
- X button in WebView navigates to confirm step (not closes modal)
- Add proper cleanup with isMountedRef to prevent memory leaks
- Add react-native-webview dependency
@vercel
Copy link

vercel bot commented Jan 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
react-native-examples Ready Ready Preview, Comment Jan 30, 2026 0:52am

Request Review

@claude
Copy link

claude bot commented Jan 30, 2026

Claude finished @ganchoradkov's task in 1m 7s —— View job


Code Review

Found 3 issue(s)

Issue 1: WebView security - missing origin whitelist

ID: collectdatawebview-origin-whitelist-a4f2
File: wallets/rn_cli_wallet/src/modals/PaymentOptionsModal/CollectDataWebView.tsx:126-140
Severity: HIGH
Category: security

Context:

  • Pattern: WebView accepts any URL without origin validation or whitelist
  • Risk: Malicious URL in collectData.url could load arbitrary external content
  • Impact: Phishing attacks, credential theft, or malicious script execution in payment flow
  • Trigger: If API response is compromised or MITM attack modifies collectData.url

Recommendation: Add origin whitelist to restrict allowed domains:

<WebView
  ref={webViewRef}
  source={{ uri: url }}
  originWhitelist={['https://pay.walletconnect.com', 'https://pay.reown.com']}
  // ... rest of props
/>

Issue 2: postMessage validation insufficient

ID: collectdatawebview-message-validation-7bc3
File: wallets/rn_cli_wallet/src/modals/PaymentOptionsModal/CollectDataWebView.tsx:77-109
Severity: MEDIUM
Category: security

Context:

  • Pattern: handleMessage only validates message structure, not origin
  • Risk: Any script in WebView can send IC_COMPLETE/IC_ERROR messages
  • Impact: Malicious scripts could bypass form completion, trigger false errors
  • Trigger: XSS in hosted form or compromised CDN serving form assets

Recommendation: Validate message origin before processing:

const handleMessage = useCallback((event: { nativeEvent: { data: string; url: string } }) => {
  if (!isMountedRef.current) return;
  
  const messageOrigin = new URL(event.nativeEvent.url).origin;
  const allowedOrigins = ['https://pay.walletconnect.com', 'https://pay.reown.com'];
  if (!allowedOrigins.includes(messageOrigin)) {
    LogStore.warn('Blocked postMessage from untrusted origin', 'CollectDataWebView', 'handleMessage', { origin: messageOrigin });
    return;
  }
  
  // ... rest of handler
}, [onComplete, onError]);

Issue 3: Type safety - unsafe type casting

ID: index-collectdata-type-cast-9e1a
File: wallets/rn_cli_wallet/src/modals/PaymentOptionsModal/index.tsx:45-47
Severity: LOW
Category: code_quality

Context:

  • Pattern: Type cast to access undocumented url property: (paymentData?.collectData as { url?: string } | undefined)?.url
  • Risk: Runtime errors if API shape changes, no compile-time safety
  • Impact: Silent failures, hard-to-debug issues when property added to types
  • Trigger: When @walletconnect/pay package adds url to CollectData type

Recommendation: Extend type properly or add runtime check:

// Option 1: Type extension (preferred)
interface CollectDataWithUrl extends CollectData {
  url?: string;
}
const collectDataUrl = (paymentData?.collectData as CollectDataWithUrl | undefined)?.url;

// Option 2: Add comment explaining temporary nature
const collectDataUrl = (
  // TEMP: url not yet in @walletconnect/pay types v1.x
  paymentData?.collectData as { url?: string } | undefined
)?.url;

Summary

Functional implementation with good error handling and UX flow. Critical security concern: WebView lacks origin restrictions allowing arbitrary URLs. Add originWhitelist and message origin validation before merging.

</Text>
</View>
)}
<WebView

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Review Issue: WebView security - missing origin whitelist

Severity: HIGH
Category: security
Tool: Claude Auto Review

Context:

  • Pattern: WebView accepts any URL without origin validation or whitelist
  • Risk: Malicious URL in collectData.url could load arbitrary external content
  • Impact: Phishing attacks, credential theft, or malicious script execution in payment flow
  • Trigger: If API response is compromised or MITM attack modifies collectData.url

Recommendation: Add origin whitelist to restrict allowed domains:

<WebView
  ref={webViewRef}
  source={{ uri: url }}
  originWhitelist={['https://pay.walletconnect.com', 'https://pay.reown.com']}
  // ... rest of props
/>

[onError],
);

const handleMessage = useCallback(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Review Issue: postMessage validation insufficient

Severity: MEDIUM
Category: security
Tool: Claude Auto Review

Context:

  • Pattern: handleMessage only validates message structure, not origin
  • Risk: Any script in WebView can send IC_COMPLETE/IC_ERROR messages
  • Impact: Malicious scripts could bypass form completion, trigger false errors
  • Trigger: XSS in hosted form or compromised CDN serving form assets

Recommendation: Validate message origin before processing:

const handleMessage = useCallback((event: { nativeEvent: { data: string; url: string } }) => {
  if (!isMountedRef.current) return;
  
  const messageOrigin = new URL(event.nativeEvent.url).origin;
  const allowedOrigins = ['https://pay.walletconnect.com', 'https://pay.reown.com'];
  if (!allowedOrigins.includes(messageOrigin)) {
    LogStore.warn('Blocked postMessage from untrusted origin', 'CollectDataWebView', 'handleMessage', { origin: messageOrigin });
    return;
  }
  
  // ... rest of handler
}, [onComplete, onError]);

const hasCollectData =
paymentData?.collectData && paymentData.collectData.fields.length > 0;
// The `url` property is a new addition to the API - cast to access it
const collectDataUrl = (

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Review Issue: Type safety - unsafe type casting

Severity: LOW
Category: code_quality
Tool: Claude Auto Review

Context:

  • Pattern: Type cast to access undocumented url property: (paymentData?.collectData as { url?: string } | undefined)?.url
  • Risk: Runtime errors if API shape changes, no compile-time safety
  • Impact: Silent failures, hard-to-debug issues when property added to types
  • Trigger: When @walletconnect/pay package adds url to CollectData type

Recommendation: Extend type properly or add runtime check:

// Option 1: Type extension (preferred)
interface CollectDataWithUrl extends CollectData {
  url?: string;
}
const collectDataUrl = (paymentData?.collectData as CollectDataWithUrl | undefined)?.url;

// Option 2: Add comment explaining temporary nature
const collectDataUrl = (
  // TEMP: url not yet in @walletconnect/pay types v1.x
  paymentData?.collectData as { url?: string } | undefined
)?.url;

Summary

Functional implementation with good error handling and UX flow. Critical security concern: WebView lacks origin restrictions allowing arbitrary URLs. Add originWhitelist and message origin validation before merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants