Skip to content

Commit b97439f

Browse files
authored
chore: allow scene-console deeplink param (#9574)
1 parent d6edf07 commit b97439f

4 files changed

Lines changed: 42 additions & 37 deletions

File tree

Explorer/Assets/DCL/Infrastructure/Global/AppArgs/ApplicationParametersParser.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,8 @@ public static Dictionary<string, string> ProcessDeepLinkParameters(string deepLi
213213
}
214214

215215
// Tier 2 (SEC-019/020): the local-development params Creator Hub / sdk-commands attach to preview deep
216-
// links (local-scene, dclenv, hub, skip-auth-screen, landscape-terrain-enabled, multi-instance,
217-
// scene-console) are permitted only when the target realm is whitelisted — loopback, or a world listed in
216+
// links (local-scene, hub, skip-auth-screen, landscape-terrain-enabled, multi-instance, local-ab, mcp,
217+
// mcp-port) are permitted only when the target realm is whitelisted — loopback, or a world listed in
218218
// the deeplink-whitelisted-worlds feature flag. A remote-realm deep link from a web page cannot enable
219219
// them unless that exact world was explicitly whitelisted. Everything not in either tier is dropped.
220220
bool realmIsWhitelisted = output.TryGetValue(AppArgsFlags.REALM, out string? whitelistRealm)

Explorer/Assets/DCL/Infrastructure/Global/AppArgs/DeepLinkAllowlist.cs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,33 @@ namespace Global.AppArgs
77
/// <summary>
88
/// Deny-by-default allowlist of query params a <c>decentraland://</c> deep link may inject into app-args.
99
/// Shared by the cold-start argv path and the runtime bridge path (both funnel through
10-
/// <see cref="ApplicationParametersParser.ProcessDeepLinkParameters" />).
10+
/// <see cref="ApplicationParametersParser.ProcessDeepLinkParameters(string,System.Collections.Generic.Dictionary{string,string})" />).
1111
/// <para>
1212
/// A deep link is fully attacker-controllable — anyone can craft one and get a victim to open it — so
1313
/// params fall into three tiers:
1414
/// </para>
1515
/// <list type="bullet">
1616
/// <item>
1717
/// <b>Always permitted</b> — benign navigation / share / login intents whose worst case is already
18-
/// gated elsewhere (a consent prompt, a matching login token, a plain coordinate, or a closed
19-
/// Decentraland-owned enum): realm, position, community, signin, authRequestId, force-open-backpack,
20-
/// spawnpoint, dclenv, self-preview-builder-collections.
18+
/// gated elsewhere (a consent prompt, a matching login token, a plain coordinate, a closed
19+
/// Decentraland-owned enum, or a read-only log view): realm, position, community, signin,
20+
/// authRequestId, force-open-backpack, spawnpoint, dclenv, self-preview-builder-collections,
21+
/// scene-console.
2122
/// </item>
2223
/// <item>
2324
/// <b>Permitted only for a whitelisted realm</b> — the local-development params Creator Hub and the
24-
/// SDK (<c>sdk-commands</c>) attach to their preview deep links: local-scene, dclenv, hub,
25-
/// skip-auth-screen, landscape-terrain-enabled, multi-instance, scene-console, mcp, mcp-port. A realm
26-
/// is "whitelisted" when it is loopback (127.0.0.1 / localhost / [::1]) OR its world matches the
25+
/// SDK (<c>sdk-commands</c>) attach to their preview deep links: local-scene, hub, skip-auth-screen,
26+
/// landscape-terrain-enabled, multi-instance, local-ab, mcp, mcp-port. A realm is "whitelisted" when
27+
/// it is loopback (127.0.0.1 / localhost / [::1]) OR its world matches the
2728
/// <c>deeplink-whitelisted-worlds</c> feature flag (see <see cref="IsRealmWhitelisted" /> and
2829
/// <see cref="SetWhitelistedWorlds" />). A remote-realm deep link from a web page can never enable
2930
/// them unless that exact world was explicitly whitelisted. All but the MCP pair are individually
30-
/// low-harm — an analytics tag, a cosmetic toggle, an instance count, an env enum, a screen skip that
31-
/// still forces auth when no valid identity is cached, or the per-scene JS console — and the
32-
/// whitelisted-realm gate confines them to the dev context. <c>mcp</c>/<c>mcp-port</c> start an
33-
/// unauthenticated loopback control port and are the one non-low-harm pair in this set; they lean on
34-
/// the gate plus the server's own 127.0.0.1 bind and Origin check — see the per-key comment for what
35-
/// the gate does and does not cover.
31+
/// low-harm — an analytics tag, a cosmetic toggle, an instance count, a screen skip that still forces
32+
/// auth when no valid identity is cached, or asset loading pointed at the realm the link already
33+
/// targets — and the whitelisted-realm gate confines them to the dev context.
34+
/// <c>mcp</c>/<c>mcp-port</c> start an unauthenticated loopback control port and are the one
35+
/// non-low-harm pair in this set; they lean on the gate plus the server's own 127.0.0.1 bind and
36+
/// Origin check — see the per-key comment for what the gate does and does not cover.
3637
/// </item>
3738
/// <item>
3839
/// <b>Never permitted</b> — everything else, in particular params that launch code
@@ -93,6 +94,16 @@ public static class DeepLinkAllowlist
9394
// cannot point the client at attacker infrastructure. Worst case is a session in a Decentraland-owned test
9495
// environment, strictly less capable than the attacker-supplied REALM above.
9596
AppArgsFlags.ENVIRONMENT,
97+
98+
// Opens the per-scene JS console: a read-only view of the log lines the running scene already emits, and
99+
// Opens the debug menu with its informational widget categories — scene logs, performance, memory,
100+
// room and realm info, entity requests, analytics, and web request metrics. Not realm-gated (product
101+
// production realms and worlds to diagnose a deployed scene, which is exactly what the whitelisted-realm
102+
// tier below forbids. It unlocks no capability of its own: it loads no content, changes no endpoint, and
103+
// the menu it opens is restricted to the informational widget categories (see DebugUtilitiesContainer) —
104+
// the full debug panel still needs the never-permitted "debug". Worst case is a session logging verbosely
105+
// (ReportHub.EnforceUnconditionalVerboseLogs) with a log panel on screen.
106+
AppArgsFlags.SCENE_CONSOLE,
96107
};
97108

98109
// Local-development params Creator Hub / sdk-commands attach to preview deep links. Permitted ONLY when the
@@ -132,9 +143,6 @@ public static class DeepLinkAllowlist
132143
// the same gate; the value is clamped to 1024-65535 and falls back to the default port (McpServerPlugin).
133144
AppArgsFlags.MCP_PORT,
134145

135-
// Opens the per-scene JS console (dev tooling for inspecting a scene under development).
136-
AppArgsFlags.SCENE_CONSOLE,
137-
138146
// Local-scene development only: load the scene's asset bundles from the preview server instead of raw
139147
// GLTFs. A pure boolean — the optimized-assets base is derived from the realm itself
140148
// ({realm}/optimized-assets, see RealmLaunchSettings.LocalAssetBundlesBaseUrl), the same value this

Explorer/Assets/DCL/Infrastructure/Global/AppArgs/Tests/AppArgsTests.cs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public void DeepLinkKeepsEnvironmentForRealmlessLoginCallback()
9797
Assert.IsFalse(output.ContainsKey(AppArgsFlags.LOCAL_SCENE), "local-scene must still require a loopback realm");
9898
Assert.IsFalse(output.ContainsKey(AppArgsFlags.SKIP_AUTH_SCREEN), "skip-auth-screen must still require a loopback realm");
9999
Assert.IsFalse(output.ContainsKey(AppArgsFlags.MULTIPLE_RUNNING_INSTANCES), "multi-instance must still require a loopback realm");
100-
Assert.IsFalse(output.ContainsKey(AppArgsFlags.SCENE_CONSOLE), "scene-console must stay dropped for every realm");
100+
Assert.AreEqual("true", output.GetValueOrDefault(AppArgsFlags.SCENE_CONSOLE), "scene-console must survive without a realm: it is not realm-gated");
101101
}
102102

103103
[Test]
@@ -197,21 +197,18 @@ public void DeepLinkDropsMcpWithoutRealm()
197197
Assert.IsFalse(output.ContainsKey(AppArgsFlags.MCP_PORT), "mcp-port must be dropped when the link carries no realm at all");
198198
}
199199

200-
public void DeepLinkKeepsSceneConsoleForLoopbackRealm()
200+
// scene-console is always permitted: creators and QA need the scene log console against production realms and
201+
// worlds, and it unlocks no capability (read-only view of logs the scene already emits; the full debug panel
202+
// still needs the never-permitted `debug`).
203+
[TestCase("decentraland://?realm=http://127.0.0.1:8000&scene-console=true", TestName = "loopback realm")]
204+
[TestCase("decentraland://?realm=https://peer.decentraland.org&scene-console=true", TestName = "production catalyst realm")]
205+
[TestCase("decentraland://?realm=other-world.dcl.eth&scene-console=true", TestName = "non-whitelisted world realm")]
206+
[TestCase("decentraland://?scene-console=true", TestName = "no realm")]
207+
public void DeepLinkKeepsSceneConsoleForEveryRealm(string deepLink)
201208
{
202-
Dictionary<string, string> output = ApplicationParametersParser.ProcessDeepLinkParameters(
203-
"decentraland://?realm=http://127.0.0.1:8000&scene-console=true");
204-
205-
Assert.AreEqual("true", output.GetValueOrDefault(AppArgsFlags.SCENE_CONSOLE), "scene-console must survive for a loopback (local dev) realm");
206-
}
207-
208-
[Test]
209-
public void DeepLinkDropsSceneConsoleForRemoteRealm()
210-
{
211-
Dictionary<string, string> output = ApplicationParametersParser.ProcessDeepLinkParameters(
212-
"decentraland://?realm=https://peer.decentraland.org&scene-console=true");
209+
Dictionary<string, string> output = ApplicationParametersParser.ProcessDeepLinkParameters(deepLink);
213210

214-
Assert.IsFalse(output.ContainsKey(AppArgsFlags.SCENE_CONSOLE), "scene-console must be dropped for a non-whitelisted remote realm");
211+
Assert.AreEqual("true", output.GetValueOrDefault(AppArgsFlags.SCENE_CONSOLE), "scene-console must survive for every realm");
215212
}
216213

217214
[Test]
@@ -222,12 +219,12 @@ public void DeepLinkKeepsDevParamsForWhitelistedWorldRealm()
222219

223220
// Act
224221
Dictionary<string, string> output = ApplicationParametersParser.ProcessDeepLinkParameters(
225-
"decentraland://?realm=test-world.dcl.eth&local-scene=true&dclenv=zone&scene-console=true");
222+
"decentraland://?realm=test-world.dcl.eth&local-scene=true&dclenv=zone&mcp=true");
226223

227224
// Assert
228225
Assert.AreEqual("true", output.GetValueOrDefault(AppArgsFlags.LOCAL_SCENE), "local-scene must survive for a whitelisted world realm");
229226
Assert.AreEqual("zone", output.GetValueOrDefault(AppArgsFlags.ENVIRONMENT), "dclenv must survive for a whitelisted world realm");
230-
Assert.AreEqual("true", output.GetValueOrDefault(AppArgsFlags.SCENE_CONSOLE), "scene-console must survive for a whitelisted world realm");
227+
Assert.AreEqual("true", output.GetValueOrDefault(AppArgsFlags.MCP), "mcp must survive for a whitelisted world realm");
231228
}
232229

233230
[Test]
@@ -252,11 +249,11 @@ public void DeepLinkDropsDevParamsForNonWhitelistedWorldRealm()
252249

253250
// Act
254251
Dictionary<string, string> output = ApplicationParametersParser.ProcessDeepLinkParameters(
255-
"decentraland://?realm=other-world.dcl.eth&local-scene=true&scene-console=true");
252+
"decentraland://?realm=other-world.dcl.eth&local-scene=true&mcp=true");
256253

257254
// Assert
258255
Assert.IsFalse(output.ContainsKey(AppArgsFlags.LOCAL_SCENE), "local-scene must be dropped for a world that is not whitelisted");
259-
Assert.IsFalse(output.ContainsKey(AppArgsFlags.SCENE_CONSOLE), "scene-console must be dropped for a world that is not whitelisted");
256+
Assert.IsFalse(output.ContainsKey(AppArgsFlags.MCP), "mcp must be dropped for a world that is not whitelisted");
260257
}
261258

262259
// IsRealmWhitelisted gates BOTH the whitelisted-realm dev params and skipping the realm-change consent prompt

docs/app-arguments.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ For embedded links you will need to place value after `=` sign, instead of space
8686
## Scene & Environment Flags
8787

8888
### `scene-console`
89-
**Description:** Enables the scene console for debugging and development. Only available in debug mode or when running local scenes.
89+
**Description:** Enables the scene console (the debug menu's log view of the scene's own output) for debugging and development. Works for any realm — local scene development enables it implicitly, and the flag itself is accepted from deep links against production realms and worlds too, so creators and QA can inspect a deployed scene.
9090

9191
**Usage:**
9292
```bash

0 commit comments

Comments
 (0)