Skip to content

chore: deeplink non-whitelist params confirmation dialog - #9527

Merged
pravusjif merged 5 commits into
devfrom
chore/deeplink-non-whitelist-params-confirmation-dialog
Aug 3, 2026
Merged

chore: deeplink non-whitelist params confirmation dialog#9527
pravusjif merged 5 commits into
devfrom
chore/deeplink-non-whitelist-params-confirmation-dialog

Conversation

@pravusjif

@pravusjif pravusjif commented Jul 30, 2026

Copy link
Copy Markdown
Member

The deep-link allowlist (deny-by-default) silently drops any param that is not explicitly permitted, which broke the daily debug workflows that rely on deep links (dclenv, skip-version-check, etc.). This PR adds a confirmation dialog at application start — styled like the "Update Required" screen — that enumerates the denied params with a one-line description of what each one does and lets the user either exit or explicitly accept the risk and continue with those params applied. App-arg (argv) launches are unaffected; only the deep-link path is gated.

The dialog is modelled on a browser certificate warning: Exit Application is the highlighted default, and continuing takes two deliberate steps — Advanced only reveals the responsibility statement plus a de-emphasised Continue Anyway (Unsafe) button, so the warning cannot be dismissed with a single reflex click.

Technical description

  • ApplicationParametersParser: denied deep-link params are now captured (key + value) into DeniedDeepLinkParams instead of being lost; ApplyDeniedDeepLinkParams() merges them into the app-args on consent. New ProcessDeepLinkParameters(string, Dictionary?) overload collects them; the runtime bridge path (DeepLink.cs) is unchanged and still silently drops.
  • MainSceneLoader: the dialog runs right after InitializeDeepLinks(), before any consumer reads the app-args (environment, launch settings, containers, version check), so consented params actually take effect. Since the MVC manager doesn't exist yet at that point, the prefab is instantiated directly (same pattern as the single-instance popup) and awaited via UniTaskCompletionSource. Exit calls ExitUtils.Exit().
  • New DCL/ApplicationGuards/ApplicationDeepLinkGuard/: DeepLinkParamsWarningView + DeepLinkParamsWarningScreen.prefab (cloned from VersionUpdateScreen.prefab; three buttons — Exit as the red primary, Advanced, and a hidden Continue). Hardening: rich text is disabled on the description and control characters are flattened, so a crafted link cannot inject TMP markup or fake dialog lines; values are truncated, and the list is capped at 6 entries (with a count of the rest) so a padded link cannot push the warning over the buttons.
  • New DeepLinkParamDescriptions (next to DeepLinkAllowlist): key → one-line, plain-language effect used by the dialog, with an explicit "not recognized by this version" fallback.
  • Wiring: serialized prefab reference on MainSceneLoader (Main.unity) + Addressables entry in the UI group.
  • Fail-safe: the dialog runs before the splash screen exists, so a prefab-load failure would leave the launch on a black screen. Loading is wrapped — on failure it is reported and the launch continues with the params dropped (the behaviour before this dialog existed).
  • Interaction with the version guard: the dialog is upstream of it, so consenting to a link carrying skip-version-check skips the "Update Required" screen; without denied params the version guard behaves as before.

QA Test Instructions

  1. Download the build from this PR
  2. Go to your local DecentralandLauncherLight/Latest/ directory and rename the explorer in there (suggestion: just add -original at the end)
  3. Place the build you downloaded next to the renamed one
  4. open a deep link with currently unsupported params, some examples:
    • decentraland://?realm=pravus.dcl.eth&skip-version-check=true&self-preview-builder-collections=a2041268-189e-4cef-902d-70272aed077c
    • decentraland://?skip-version-check=true&self-preview-builder-collections=3062136a-065d-4d94-b28c-f57d6ef04860,371a0f06-d200-42ab-97d2-620188fc1bbf,a2041268-189e-4cef-902d-70272aed077c&position=100,100&skip-auth-screen=true
    • decentraland://?realm=sdk7testscenes.dcl.eth&position=88,-10&dclenv=zone&skip-version-check=true&multi-instance=true
  5. Confirm that you see the denied deep link params confirmation dialog with a message about the dangers of continuing
  6. Confirm that the unsupported params are ennumerated with their valye and a short description
  7. Confirm that the "Exit Application" button is the suggested one, and confirm that using it closes the Explorer
  8. Repeat from step 2 onwards but this time confirm that clicking on "ADVANCED" changes that button to "CONTINUE ANYWAY (UNSAFE)" and the text on top reinforces the danger.

Screenshot 2026-07-31 at 7 00 35 PMScreenshot 2026-07-31 at 7 00 42 PM

@pravusjif pravusjif self-assigned this Jul 30, 2026
@pravusjif pravusjif added the 0-critical Critical issues label Jul 30, 2026
@pravusjif pravusjif moved this from Todo to In Progress in Explorer Alpha Jul 30, 2026
@pravusjif pravusjif added the force-build Used to trigger a build on draft PR label Jul 30, 2026
@pravusjif pravusjif changed the title chore: deeeplink non-whitelist params confirmation dialog chore: deeplink non-whitelist params confirmation dialog Jul 30, 2026
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

badge

Warnings count reduced: 14034 => 14010

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

badge

All Unity tests passed ✅

TESTS SUITE Result Passed Failed Skipped
EditMode ✅ Passed 24340 0 13
PlayMode ✅ Passed 236 0 5

@pravusjif pravusjif added force-build Used to trigger a build on draft PR Mac Only Issue only happens on Mac builds and removed force-build Used to trigger a build on draft PR labels Jul 30, 2026
@pravusjif
pravusjif requested a review from mikhail-dcl July 31, 2026 01:04
@pravusjif
pravusjif marked this pull request as ready for review July 31, 2026 01:05
@pravusjif
pravusjif requested review from a team as code owners July 31, 2026 01:05
@github-actions
github-actions Bot requested a review from anicalbano July 31, 2026 01:05
@decentraland-bot
decentraland-bot self-requested a review July 31, 2026 01:05

@decentraland-bot decentraland-bot left a comment

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.

PR Review — chore: deeplink non-whitelist params confirmation dialog

STEP 1 — Context & Scope

Loaded CLAUDE.md, review-instructions.md. Inspected the full diff across 10 changed files (+2555 −38), cloned the PR branch, and read the surrounding files in full: ApplicationParametersParser.cs, MainSceneLoader.cs, DeepLinkParamsWarningView.cs, ViewBase.cs, and the existing ApplicationGuards/ directory. Verified the prefab YAML to confirm rich-text and TMP settings. Searched for all consumers of DeniedDeepLinkParams / ApplyDeniedDeepLinkParams across the codebase.

STEP 2 — Root-cause check

PASS. The deep-link allowlist previously dropped denied params silently, which broke debug workflows that rely on deep-link flags (dclenv, skip-version-check, etc.). The PR replaces the silent drop with an explicit user consent dialog — the user can exit or accept the risk. This is the correct fix: instead of losing params or blindly accepting them, the user makes an informed decision. The allowlisted-param path (Tier 1 and Tier 2 in ProcessDeepLinkParameters) is unchanged.

STEP 3 — Design & integration

PASS.

Owner search — DeepLinkParamsWarningView: This is a stateless UI view (extends ViewBase, IView) placed in DCL/ApplicationGuards/ApplicationDeepLinkGuard/ — consistent with existing guards: MinimumSpecsScreenView, LauncherRedirectionScreenView, LivekitHealthGuardView, BlockedScreenView. The view holds no persistent state; it receives params via SetDeniedParams(), formats them for display, and exposes two buttons. The lifecycle is fully owned by MainSceneLoader.ShowDeniedDeepLinkParamsConfirmationAsync, following the same pattern as the existing ShowSingleRunningInstancePopupAsync. No duplicate lifecycle.

Owner search — deniedDeepLinkParams: Lives on ApplicationParametersParser as a private Dictionary exposed as IReadOnlyDictionary via the [AutoInterface]-generated IAppArgs interface. The parser is the natural owner — it processes the deep link, knows which params passed/failed the allowlist, and owns the merge of accepted params into appParameters. The data flow is clean: parser captures → MainSceneLoader shows dialog → parser merges on consent.

Placement: The dialog runs immediately after InitializeDeepLinks() and before any consumer reads app-args (environment, launch settings, containers, version check). The AddressablesProvisioner was hoisted earlier in the flow to be available for the dialog — this is a lightweight constructor with no side effects.

Teardown/consumption trace:

  • popup.ContinueButton.onClick.AddListener(...) / popup.ExitButton.onClick.AddListener(...) — on Continue, Destroy(popup.gameObject) cleans up both listeners. On Exit, ExitUtils.Exit() terminates the process. On cancellation (ct fires), AttachExternalCancellation throws, but ct is destroyCancellationToken so Unity handles cleanup. ✅
  • UniTaskCompletionSource<bool> decision — consumed by await decision.Task, completes on button click. ✅
  • deniedDeepLinkParams — populated in InitializeDeepLinks(), cleared in ApplyDeniedDeepLinkParams() on consent, or left unmerged if the user exits. ✅

STEP 4 — Member audit

DeniedDeepLinkParams (property on ApplicationParametersParser): 2 production consumers (MainSceneLoader lines 227 and 495) + 3 test consumers. Legitimate public API for the consent flow; not single-use since it is checked both to decide whether to show the dialog and to populate the dialog content.

ApplyDeniedDeepLinkParams() (method): 1 production consumer (MainSceneLoader line 505) + 1 test consumer. Legitimate public method; the consent semantics require a separate method from the constructor/init path.

ContinueButton / ExitButton / SetDeniedParams() on DeepLinkParamsWarningView: 1 production consumer each (MainSceneLoader). Standard for view components — the consumer is the presenting code.

No issues found — no single-use merges needed, no absent-vs-false conflation, no redundant guards.

STEP 5 — Line-level review

P2 findings:

  1. [P2] Key display length not capped (DeepLinkParamsWarningView.cs:48) — AppendSingleLine(sb, key, key.Length) passes key.Length as maxLength, so keys are never truncated. A crafted deep link with an extremely long query-param name (e.g. hundreds of chars) would produce an unwieldy dialog. Values are correctly capped at MAX_SHOWN_VALUE_LENGTH (48); keys should be capped similarly. The TMP auto-sizing (m_enableAutoSizing: 1, min 10pt) partially mitigates this, but a very long key would still reduce readability. See inline comment with suggestion.

Security verification (per security-review skill):

  • TMP injection: ✅ Verified m_isRichText: 0 on the Description TMP component (fileID: 8007467556033942281 in the prefab YAML). Rich text disabled — tags like <b>, <color> render as literal text.
  • Control character injection:AppendSingleLine flattens all control characters to spaces, preventing fake line entries or UI manipulation.
  • Value truncation: ✅ Values capped at 48 chars with ... ellipsis.
  • No secrets committed:
  • No auth/authz changes:
  • Input handling: ✅ Deep link params are untrusted input; sanitization is thorough (three layers: allowlist gate → control-char flattening → rich-text disabled).

Additional observations (non-blocking, informational):

  • The #if UNITY_EDITOR restructuring in ShouldForceSingleRunningInstance is functionally equivalent and eliminates the unreachable-code path in editor builds. Clean.
  • The simulatedMemory simplification, ctcancellationToken rename, splashScreensplash rename, and switch → ternary refactoring are all correct and improve readability.
  • The // ReSharper disable additions (UnusedMember.Local on Unity lifecycle methods, EmptyGeneralCatchClause, InconsistentNaming on DTO field) follow project conventions.
  • The fallback in ShowDeniedDeepLinkParamsConfirmationAsync when the prefab fails to load (return true → skip dialog, keep params dropped) correctly preserves pre-dialog behavior.
  • Tests cover the three main scenarios: capture-without-apply, apply-on-consent, and no-denied-params. Good coverage.

STEP 6 — Complexity

COMPLEX — Introduces new public API surface on ApplicationParametersParser/IAppArgs, new addressable prefab with serialized reference on MainSceneLoader, and modifies the startup flow ordering (hoisted AddressablesProvisioner, added a consent gate before any app-arg consumer).

STEP 7 — QA assessment

YES — Runtime code with a new user-facing UI dialog at application startup; affects deep-link launch behavior.

STEP 8 — Non-blocking warnings

⚠️ Main scene modified (Explorer/Assets/Scenes/Main.unity). This file is rarely changed intentionally — the deepLinkParamsWarningPopupPrefab serialized reference addition is expected; the useLocalAssetBundles: 0 line appears to be a Unity editor serialization side-effect from opening the scene.


REVIEW_RESULT: PASS ✅
COMPLEXITY: COMPLEX
COMPLEXITY_REASON: Adds new public API surface to IAppArgs, new addressable prefab, and modifies the startup flow ordering in MainSceneLoader.
QA_REQUIRED: YES


Reviewed by Jarvis 🤖 · Requested by decentraland-bot via GitHub

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Jarvis reviewed this PR and found no blocking issues, but assessed it as complex — human DEV review is still required before merging.

@pravusjif pravusjif removed force-build Used to trigger a build on draft PR Mac Only Issue only happens on Mac builds 0-critical Critical issues labels Jul 31, 2026
@pravusjif pravusjif added the 1-high High severity issues label Jul 31, 2026
@pravusjif pravusjif moved this from In Progress to With QA / Awaiting Review in Explorer Alpha Aug 1, 2026

@DafGreco DafGreco left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✔️ PR reviewed and approved by QA on both platforms following instructions playing both happy and un-happy path

Regressions for this ticket had been performed in order to verify that the normal flow is working as expected:

  • [ ✔️] Backpack and wearables in world
  • [✔️ ] Emotes in world and in backpack
  • [✔️ ] Teleport with map/coordinates/Jump In
  • [ ✔️] Chat and multiplayer
  • [ ✔️] Profile card
  • [ ✔️] Camera
  • [ ✔️] Skybox

Evidence :

Image Image Image Image

@github-project-automation github-project-automation Bot moved this from With QA / Awaiting Review to In Progress in Explorer Alpha Aug 3, 2026
@pravusjif
pravusjif merged commit 24156b5 into dev Aug 3, 2026
29 of 33 checks passed
@pravusjif
pravusjif deleted the chore/deeplink-non-whitelist-params-confirmation-dialog branch August 3, 2026 12:57
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Explorer Alpha Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1-high High severity issues

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants