Skip to content

Comments

2.2.0#257

Merged
jakubuid merged 29 commits intomainfrom
develop
Feb 11, 2026
Merged

2.2.0#257
jakubuid merged 29 commits intomainfrom
develop

Conversation

@jakubuid
Copy link
Collaborator

Description

Resolves # (issue)

How Has This Been Tested?

Due Dilligence

  • Breaking change
  • Requires a documentation update

jakubuid and others added 29 commits January 29, 2026 16:41
Add #include directive to load Configuration.local.xcconfig which is
already in .gitignore. This allows developers to set PROJECT_ID and
other sensitive values locally without modifying tracked files.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add webfactory/ssh-agent step to setup SSH for Match authentication
- Remove GH_TOKEN and GH_USER dependencies from release workflow
- Remove git_basic_authorization from Fastfile (SSH handles auth)
- Remove TOKEN parameter from Makefile
- Set match to readonly mode to avoid push failures
- Add update_code_signing_settings to configure Xcode to use Match profiles
- Fix MATCH_GIT_URL env variable name in Fastfile

This aligns with the working react-native-examples configuration.

Note: Requires adding MATCH_SSH_KEY secret to the repository.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat: add support for local configuration overrides
The sample wallet was displaying "ISO" instead of the actual currency
symbol (e.g., EUR) because NumberFormatter with .currency style doesn't
recognize crypto token symbols or non-standard currency codes.

Changed to use .decimal number style and append amount.display.assetSymbol
directly, which properly displays both fiat currencies and crypto tokens.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
fix: use correct currency symbol in Pay amount display
- Remove com.walletconnect.walletapp.PNDecryptionService from .env.WalletApp
- Remove from Fastfile provisioningProfiles export options

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ookup

- Remove PNDecryptionService extension from being embedded in WalletApp
- Use match's lane_context to get actual profile name with timestamp
- PNDecryptionService target still exists but is no longer a dependency

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use the profile name from match output instead of hardcoded values
to handle profiles with timestamps in their names.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
fix: add update_code_signing_settings to Fastlane release workflow
- Add webviewDataCollection flow step when collectData.url is present
- Create PayDataCollectionWebView component with JS bridge (iOSWallet)
- Handle IC_COMPLETE and IC_ERROR messages from WebView
- Display payment result info (txId, token amount) on success screen
- Update Yttrium dependency to 0.10.28

Based on Kotlin PR #276

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change handler from 'iOSWallet' to 'payDataCollectionComplete' to match
the IC page's expected interface for iOS WKWebView communication.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Show a centered ProgressView with "Loading..." text while the IC
page is loading. The loader is hidden once the page finishes loading.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update Yttrium dependency from 0.10.25 to 0.10.30
- Add getPublicKey() method to TonAccountStorage for hex-encoded Ed25519 public key
- Add getStateInitBoc() method to TonAccountStorage using new Yttrium API
- Include ton_getPublicKey and ton_getStateInit in session properties during proposal approval

Reference: reown-com/reown-kotlin#279

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat(ton): add publicKey and stateInit to session properties
Add support for prefilling IC WebView form fields based on schema's
required fields. Encodes user data (fullName, dob) as Base64 JSON
and appends as prefill query parameter to WebView URL.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds deprecation annotation to CollectDataAction.fields property.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When collectData is nil, the pay flow now automatically advances to the
confirmation screen instead of showing the intro screen. Back navigation
from confirmation now dismisses the modal when intro was skipped.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
fix(pay): skip intro screen when data collection not required
- Make WebView full screen, respect top safe area for notch
- Add close button to WebView
- Open Terms/Privacy links in Safari
- Move verified badge to merchant icon
- Add pobAddress to prefill fields
- Persist user-entered form data when going back
- Fix back navigation from confirmation to WebView

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolved conflict in PayPresenter.swift goBack() - kept WebView
navigation while adopting dismiss behavior from develop.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat(pay): add WebView-based Information Capture for Pay SDK
@claude
Copy link

claude bot commented Feb 11, 2026

Claude finished @jakubuid's task in 2m 9s —— View job


PR Review Complete

Reviewed PR #257 (2.2.0 release) - develop → main


Issues Found

Issue 1: Unvalidated JavaScript message data in WebView handler

ID: paydatacoll-unvalidated-message-7f4a
File: Example/WalletApp/PresentationLayer/Wallet/Pay/PayDataCollectionWebView.swift:100
Severity: HIGH
Category: security

WebView message handler accepts arbitrary dictionary data from JavaScript without validating data types or sanitizing values before using them. Malicious web content could inject unexpected data types or XSS payloads.

Recommendation: Add input validation and type checking:

guard let body = message.body as? [String: Any],
      let type = body["type"] as? String,
      type.rangeOfCharacter(from: CharacterSet.alphanumerics.inverted.subtracting(CharacterSet(charactersIn: "_"))) == nil else {
    print("💳 [PayWebView] Invalid message format: \(message.body)")
    onError("Invalid message format")
    return
}

// Validate string fields
if let fullName = body["fullName"] as? String {
    guard fullName.count <= 256 else { return onError("Invalid name length") }
}
if let dob = body["dob"] as? String {
    guard dob.matches(regex: "^\\d{4}-\\d{2}-\\d{2}$") else { return onError("Invalid date format") }
}

Issue 2: Missing URL validation for WebView loads

ID: paydatacoll-url-validation-3c8b
File: Example/WalletApp/PresentationLayer/Wallet/Pay/PayDataCollectionWebView.swift:76
Severity: HIGH
Category: security

WebView loads arbitrary URLs without validating the scheme or domain. If collectData.url from API response is compromised or modified, malicious URLs could be loaded.

Recommendation: Add URL validation before loading:

// Validate URL before loading
guard ["https", "wss"].contains(url.scheme?.lowercased()),
      let host = url.host,
      !host.isEmpty else {
    context.coordinator.onError("Invalid URL scheme or host")
    return webView
}

// Optionally validate against allowlist of trusted domains
let trustedDomains = ["reown.com", "walletconnect.com", "walletconnect.org"]
guard trustedDomains.contains(where: { host.hasSuffix($0) }) else {
    context.coordinator.onError("Untrusted domain")
    return webView
}

webView.load(URLRequest(url: url))

Issue 3: Hardcoded sensitive test data in production code

ID: paypresente-hardcoded-test-data-9a2f
File: Example/WalletApp/PresentationLayer/Wallet/Pay/PayPresenter.swift:22
Severity: MEDIUM
Category: code_quality

Test data ("Test User", "1990-01-15", "New York, USA") hardcoded as defaults for IC form prefill. This is marked as "PoC" but exists in production code path.

Recommendation: Remove hardcoded test values or move them to debug-only configuration:

#if DEBUG
private static let defaultPrefillFullName = "Test User"
private static let defaultPrefillDob = "1990-01-15"
private static let defaultPrefillPobAddress = "New York, USA"
#else
private static let defaultPrefillFullName: String? = nil
private static let defaultPrefillDob: String? = nil
private static let defaultPrefillPobAddress: String? = nil
#endif

Issue 4: Weak error handling in certificate script

ID: createcerti-weak-error-handling-b1c4
File: scripts/create-certificates.sh:66
Severity: MEDIUM
Category: code_quality

Certificate creation script suppresses stderr when creating branches and doesn't distinguish between "branch exists" errors and permission/network errors, making debugging difficult.

Recommendation: Improve error detection and messaging:

if ! CREATE_OUTPUT=$(gh api repos/${CERTS_REPO}/git/refs \
  -f ref="refs/heads/${BRANCH_NAME}" \
  -f sha="${MASTER_SHA}" 2>&1); then
  if echo "$CREATE_OUTPUT" | grep -q "already exists"; then
    echo "❌ Error: Branch ${BRANCH_NAME} already exists"
  elif echo "$CREATE_OUTPUT" | grep -q "Not Found"; then
    echo "❌ Error: Repository ${CERTS_REPO} not found or inaccessible"
  else
    echo "❌ Error: Failed to create branch: $CREATE_OUTPUT"
  fi
  exit 1
fi

Issue 5: Unvalidated Base64 decode in prefill parameter

ID: paypresente-unvalidated-base64-8d3a
File: Example/WalletApp/PresentationLayer/Wallet/Pay/PayPresenter.swift:181
Severity: MEDIUM
Category: security

Schema JSON parsed without validation. Malformed schema from API could cause crashes or unexpected behavior. JSON parsing errors are silently ignored.

Recommendation: Add error logging and validation:

guard let schemaData = schema.data(using: .utf8) else {
    print("💳 [Pay] Warning: Invalid schema encoding")
    return nil
}

guard let schemaJson = try? JSONSerialization.jsonObject(with: schemaData) as? [String: Any] else {
    print("💳 [Pay] Warning: Schema is not valid JSON")
    return nil
}

guard let requiredArray = schemaJson["required"] as? [String], !requiredArray.isEmpty else {
    print("💳 [Pay] Warning: Schema missing 'required' array")
    return nil
}

Issue 6: Race condition in WebView isLoading state

ID: paydatacoll-race-condition-5e7b
File: Example/WalletApp/PresentationLayer/Wallet/Pay/PayDataCollectionWebView.swift:151
Severity: LOW
Category: code_quality

Multiple navigation delegate methods update isLoading state with DispatchQueue.main.async. If navigation events fire rapidly, final state may be incorrect.

Recommendation: Use synchronous main actor updates or track navigation state explicitly:

@MainActor
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
    isLoading = true
}

@MainActor
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    isLoading = false
}

Automated Checks

✅ No external domain URLs detected in changed files
✅ No static resource cache-control issues detected
✅ No GitHub Actions workflow security issues (workflow uses manual trigger only, no PR triggers)


Summary

Found 6 issues: 2 HIGH severity (WebView security), 3 MEDIUM severity (test data, error handling, validation), 1 LOW severity (race condition). Primary concerns are WebView message injection and URL validation. Recommend addressing HIGH severity issues before release.


@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
7.1% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@jakubuid jakubuid merged commit f243746 into main Feb 11, 2026
13 of 17 checks passed
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.

1 participant