Skip to content

feat: incoming message origin validation for android#475

Draft
michaeljsXu wants to merge 1 commit into
07-15-feat_incoming_mesage_origin_validation_for_webfrom
07-15-feat_incoming_message_origin_validation_for_android
Draft

feat: incoming message origin validation for android#475
michaeljsXu wants to merge 1 commit into
07-15-feat_incoming_mesage_origin_validation_for_webfrom
07-15-feat_incoming_message_origin_validation_for_android

Conversation

@michaeljsXu

Copy link
Copy Markdown
Contributor

What changes are you making?

How to test


Before you merge

Important

  • I've added tests to support my implementation
  • I have read and agree with the Contribution Guidelines
  • I have read and agree with the Code of Conduct
  • I've updated the relevant platform README (platforms/swift/README.md and/or platforms/android/README.md)

Releasing a new Swift version?
  • I have bumped the version in ShopifyCheckoutKit.podspec
  • I have bumped the version in platforms/swift/Sources/ShopifyCheckoutKit/ShopifyCheckoutKit.swift
  • I have updated the SwiftPM/CocoaPods version snippets in platforms/swift/README.md (major version only)
Releasing a new Embedded Checkout Protocol version?
  • I have bumped embeddedCheckoutProtocolAndroid in platforms/android/gradle/libs.versions.toml
  • I have updated protocol/languages/kotlin/embedded-checkout-protocol/api/embedded-checkout-protocol.api if the public API changed
Releasing a new Android version?
  • I have bumped checkoutKitAndroid in platforms/android/gradle/libs.versions.toml
  • I have updated the Gradle/Maven version snippets in platforms/android/README.md

Tip

See the Contributing documentation for the full release process per platform.

Assisted-By: devx/6d172f11-c70b-447c-9803-84d58a5e6c3a
@github-actions github-actions Bot added the #gsd:50662 Rebase Checkout Kit on UCP label Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

* Native checkout is open by default: leaving this empty trusts every origin. Once populated, the
* effective allowlist is these origins plus the cart URL origin and `shop.app` (including its
* subdomains). Entries may be exact origins (`https://example.com`), wildcard subdomains
* (`*.example.com`), or `"*"` to explicitly trust every origin.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It looks like this example is missing the scheme, so the parser ignores it. Could we use https://*.example.com here and in the matching OriginAllowlist.kt example?

var platform: Platform? = null,
var logLevel: LogLevel = LogLevel.WARN,
var preloading: Preloading = Preloading(),
var allowedMessageOrigins: Set<String> = emptySet(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These are public Kotlin API additions, but I could not find the matching API baseline update. Could we refresh platforms/android/lib/api/lib.api so the API check stays green?

val reason = "origin \"$sourceOrigin\" is not in the allowlist"
val callback = ShopifyCheckoutKit.configuration.onMessageRejected
if (callback != null) {
callback(RejectedMessage(origin = sourceOrigin, message = message, reason = reason))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could we protect this callback with try/catch? A merchant callback can throw here and escape the WebView listener. Logging the callback error and adding a small regression test would keep the rejection path best-effort.

val (scheme, suffix, port) = match.destructured
val suffixHost = suffix.lowercase()
return target.scheme.equals(scheme, ignoreCase = true) &&
port.ifEmpty { null } == target.port &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think default ports need normalization here. https://host:443 currently differs from the same browser origin serialized as https://host. Could we compare effective ports for cart, exact, and wildcard origins and cover :443 and :80 in tests?

private const val WILDCARD_ALL = "*"
private val SHOP_APP_PATTERNS = listOf(SHOP_APP_ORIGIN, "https://*.shop.app")

private val ORIGIN_PATTERN = Regex("""^([a-zA-Z][\w+.\-]*)://([^/:]+)(?::(\d+))?$""")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It looks like this regex cannot parse bracketed IPv6 hosts, which means a valid IPv6 cart or configured origin can be rejected. Would it be worth using a bracket-aware parser and adding default- and explicit-port IPv6 tests?

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

Labels

#gsd:50662 Rebase Checkout Kit on UCP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants