mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 19:11:08 +00:00
Stores: a game's web links reach Android - the hand-off was never packaged
EOS's browser flow never reached Android because the hand-off script was not in the APK: the build copies only usr/local/bin/droiddeck-*, steam-compatibility and usr/bin/** of the overlay into the assets, so usr/local/lib/droiddeck/browser/xdg-open was skipped, the session staged nothing, the wrapper left the PATH alone, and Wine's winebrowser ran the runtime's own xdg-open, which has no browser to open in a Steam session. GE-Proton's winebrowser is Wine's own: its Browsers list, then xdg-open by name, with no steam://openurl route. The script is now usr/local/bin/droiddeck-open-url: named as Wine's browser in the prefix by its absolute path, linked as xdg-open first on the game's PATH, and reading the session channel from a file when Wine does not pass BL_LAUNCH_DIR on. BL_DEBUG_BROWSER=1 adds Wine's shell and winebrowser traces. The Epic card offers Resolve Epic sign-in, Epic's account page behind its sign-in, where a pending corrective action is presented.
This commit is contained in:
1 parent
a844483080
commit
272cd60b19
8 files changed
+65
-17
No files matched your search
@@ -62,8 +62,8 @@ object SessionFiles {
|
||||
"usr/local/bin/droiddeck-steam-shortcuts" to "usr/local/bin/droiddeck-steam-shortcuts",
|
||||
// Asks the app for an Epic game's sign-in code at launch, from the compat tool (StoreLaunchRequests).
|
||||
"usr/local/bin/droiddeck-store-launch" to "usr/local/bin/droiddeck-store-launch",
|
||||
// A game's web links to Android's browser (winebrowser -> xdg-open), on game PATHs only.
|
||||
"usr/local/lib/droiddeck/browser/xdg-open" to "usr/local/lib/droiddeck/browser/xdg-open",
|
||||
// A game's web links to Android's browser (Wine's winebrowser starts it).
|
||||
"usr/local/bin/droiddeck-open-url" to "usr/local/bin/droiddeck-open-url",
|
||||
"usr/local/bin/droiddeck-steam-games" to "usr/local/bin/droiddeck-steam-games",
|
||||
"usr/local/bin/droiddeck-pad-defaults" to "usr/local/bin/droiddeck-pad-defaults",
|
||||
// Flatpak: the bwrap stand-in, the store's helper and setup, and the front end's launcher.
|
||||
|
||||
@@ -505,6 +505,9 @@ internal fun LaunchSettings(s: FrontEndState, a: FrontEndActions, host: MenuHost
|
||||
}
|
||||
}
|
||||
|
||||
/** Epic's account page behind its sign-in: signing in there presents any step the account still owes. */
|
||||
private const val EPIC_RESOLVE_URL = "https://www.epicgames.com/id/login?redirectUrl=https%3A%2F%2Fwww.epicgames.com%2Faccount%2Fpersonal"
|
||||
|
||||
/** The Epic card: sign-in, offline and overlay switches, read from and written to the game's sidecar. */
|
||||
@Composable
|
||||
private fun EpicLaunchCard(host: MenuHost, folder: java.io.File) {
|
||||
@@ -535,6 +538,14 @@ private fun EpicLaunchCard(host: MenuHost, folder: java.io.File) {
|
||||
MenuItem(stringResource(R.string.epic_eos), checked = options.eos, focusRequester = first) { set { it.copy(eos = !it.eos) } }
|
||||
MenuItem(stringResource(R.string.epic_offline), checked = options.offline) { set { it.copy(offline = !it.offline) } }
|
||||
MenuItem(stringResource(R.string.epic_overlay), checked = options.overlay) { set { it.copy(overlay = !it.overlay) } }
|
||||
// Epic asks some accounts to accept something once (privacy policy, EULA) before a game may
|
||||
// sign in - EOS's "corrective action". Signing in on Epic's site shows it.
|
||||
MenuItem(stringResource(R.string.epic_resolve), checked = false) {
|
||||
host.open = null
|
||||
runCatching {
|
||||
appContext.startActivity(android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse(EPIC_RESOLVE_URL)).addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2020,6 +2020,7 @@
|
||||
<string name="epic_eos">Epic sign-in (EOS)</string>
|
||||
<string name="epic_offline">Launch offline</string>
|
||||
<string name="epic_overlay">Epic overlay</string>
|
||||
<string name="epic_resolve">Resolve Epic sign-in</string>
|
||||
<string name="stores_eyebrow_installed">installed</string>
|
||||
<string name="stores_eyebrow_library">in your library</string>
|
||||
<string name="stores_eyebrow_store">store</string>
|
||||
|
||||
+16
-1
@@ -144,6 +144,21 @@ without it and Setup says "Stores engine not built").
|
||||
(`token`, `__token__`, `f_token`, `hdnts`, access/refresh/id tokens, `code=`) and Authorization /
|
||||
Cookie headers are blanked outside URLs too. `StoreLogTest` covers a GOG secure link and an Epic
|
||||
Akamai URL. The engine's own logcat lines (tag `EpicNative` etc.) are written on the native side.
|
||||
- **Why EOS's browser flow never reached Android:** the hand-off script was never in the APK. The
|
||||
build copies only `usr/local/bin/droiddeck-*`, `steam-compatibility` and `usr/bin/**` of the overlay
|
||||
into the assets, so `usr/local/lib/droiddeck/browser/xdg-open` was skipped, the session staged
|
||||
nothing, the wrapper did not put it on the PATH, and Wine's winebrowser ran the runtime's own
|
||||
`/usr/bin/xdg-open`, which has no browser to open in a Steam session. GE-Proton 11-7's winebrowser
|
||||
(Metalstorm's tool) is Wine's own - registry `Browsers` list, then `xdg-open` by name - with no
|
||||
steam://openurl route. The script is now `usr/local/bin/droiddeck-open-url`: named as Wine's
|
||||
browser in the prefix (`"Browsers"="/usr/local/bin/droiddeck-open-url,xdg-open"`, an absolute path
|
||||
that does not depend on Wine's PATH), linked as `xdg-open` first on the game's PATH, and reading
|
||||
the session channel from `/tmp/droiddeck-browser/launch-dir` when Wine does not pass
|
||||
`BL_LAUNCH_DIR` on. Whether EOS calls ShellExecute at all in its browser flow (rather than handing
|
||||
a verification URI and code to the game to show) is what the next run's `droiddeck xdg-open:` line,
|
||||
or `BL_DEBUG_BROWSER=1` in droiddeck-env (`WINEDEBUG=+shell,+winebrowser`), will show.
|
||||
- **Resolve Epic sign-in** (the Epic card): opens Epic's account page behind its sign-in in Android's
|
||||
browser, where a pending corrective action (privacy policy, EULA) is presented.
|
||||
- **Epic overlay off by default** (device A/B, Metalstorm: overlay pointer set → exits while
|
||||
loading, twice; off → signs in to its Starform account and runs at 118 fps). `EpicOptions.overlay`
|
||||
defaults to false; the sidecar's `epic` block carries `"v": 2`, and an older block (the old default
|
||||
@@ -186,7 +201,7 @@ without it and Setup says "Stores engine not built").
|
||||
(`STEAM_COMPAT_DATA_PATH/pfx/user.reg`, appended as DirectAudio's key is; a prefix Proton has not
|
||||
created yet gets it on the next launch). Logged as `epic overlay installed=<build> prefix=<appid>`.
|
||||
A game's web links now open on Android: Wine's browser is set to xdg-open, and on a game's PATH
|
||||
`/usr/local/lib/droiddeck/browser/xdg-open` hands http(s) addresses to the app, which opens them
|
||||
`droiddeck-open-url` hands http(s) addresses to the app, which opens them
|
||||
with Android's browser - so a device-code sign-in can be finished on the phone.
|
||||
- **Epic sign-in from Steam's own Play button (device, Metalstorm "Guest Account"):** the game was
|
||||
started from the Steam client, so the app never minted its exchange code - the code was only
|
||||
|
||||
+15
-6
@@ -1,11 +1,15 @@
|
||||
#!/usr/bin/python3
|
||||
"""xdg-open for games: a web address a game opens (Wine's winebrowser runs xdg-open) goes to
|
||||
Android's browser through the app, so an EOS device sign-in or a store page can be finished on
|
||||
the phone. On a game's PATH only (droiddeck-proton puts this directory first); anything that is not
|
||||
http(s), or with no session channel, goes on to the system's own xdg-open."""
|
||||
"""A game's web links to Android: Wine's winebrowser starts this (named as the browser in the
|
||||
prefix's HKCU\\Software\\Wine\\WineBrowser, and as xdg-open first on a game's PATH), and an
|
||||
http(s) address goes to the app, which opens it in Android's browser - so an EOS sign-in step or a
|
||||
store page can be finished on the phone. Anything else goes on to the system's own xdg-open.
|
||||
|
||||
The session channel is $BL_LAUNCH_DIR/stores; Wine may not pass that variable on to what it
|
||||
starts, so droiddeck-proton also leaves it in LAUNCH_DIR_FILE."""
|
||||
|
||||
import json
|
||||
import os
|
||||
LAUNCH_DIR_FILE = "/tmp/droiddeck-browser/launch-dir"
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
@@ -36,14 +40,19 @@ def main(argv):
|
||||
if url.startswith("steam://openurl/"):
|
||||
url = url[len("steam://openurl/"):]
|
||||
launch_dir = os.environ.get("BL_LAUNCH_DIR", "")
|
||||
if not launch_dir:
|
||||
try:
|
||||
launch_dir = open(LAUNCH_DIR_FILE).read().strip()
|
||||
except OSError:
|
||||
launch_dir = ""
|
||||
print("droiddeck xdg-open: %s" % where(url), file=sys.stderr, flush=True)
|
||||
if url.startswith(("https://", "http://")) and launch_dir:
|
||||
hand_over(url, launch_dir)
|
||||
return 0
|
||||
here = os.path.dirname(os.path.abspath(__file__))
|
||||
here = os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
for d in os.environ.get("PATH", "").split(os.pathsep):
|
||||
candidate = os.path.join(d, "xdg-open")
|
||||
if os.path.abspath(d) != here and os.access(candidate, os.X_OK):
|
||||
if os.access(candidate, os.X_OK) and os.path.realpath(candidate) != os.path.realpath(__file__) and os.path.abspath(d) != here:
|
||||
os.execv(candidate, [candidate] + argv)
|
||||
return 1
|
||||
|
||||
@@ -21,8 +21,8 @@ an earlier launch is never used.
|
||||
The game's prefix also gets the EOS overlay's pointer, HKCU\Software\Epic Games\EOS "OverlayPath"
|
||||
(the mechanism from Legendary's lfs/eos.py), naming the one copy the app keeps at OVERLAY_DIR; with
|
||||
it the game's EOS SDK can show Epic's own sign-in steps in game (a consent Epic asks for once per
|
||||
product) instead of waiting on a browser. Wine's browser is pointed at xdg-open, which this
|
||||
runtime's /usr/local/lib/droiddeck/browser/xdg-open hands to Android.
|
||||
product) instead of waiting on a browser. Wine's browser is set to droiddeck-open-url, which hands
|
||||
web addresses to Android.
|
||||
|
||||
droiddeck-store-launch <the arguments Steam gave the compat tool>
|
||||
"""
|
||||
@@ -40,6 +40,7 @@ TIMEOUT = 5.0
|
||||
STALE_SECONDS = 300
|
||||
OVERLAY_DIR = "/root/.local/share/droiddeck/epic-overlay"
|
||||
SERVER_WAIT = 8.0
|
||||
BROWSER = "/usr/local/bin/droiddeck-open-url"
|
||||
OVERLAY_DLL = "EOSOVH-Win64-Shipping.dll"
|
||||
EOS_KEY = "[Software\\\\Epic Games\\\\EOS]"
|
||||
BROWSER_KEY = "[Software\\\\Wine\\\\WineBrowser]"
|
||||
@@ -228,7 +229,9 @@ def provision_prefix(compat_data, overlay_dir=OVERLAY_DIR, overlay=False, wait=S
|
||||
return "prefix-not-created"
|
||||
# A wineserver still up for this prefix would write its own copy of user.reg over these lines.
|
||||
busy = not wait_for_server(pfx, wait)
|
||||
set_value(reg, BROWSER_KEY, "Browsers", "xdg-open")
|
||||
# winebrowser starts the first entry it can; an absolute path does not depend on the PATH Wine
|
||||
# hands it.
|
||||
set_value(reg, BROWSER_KEY, "Browsers", BROWSER + ",xdg-open")
|
||||
if not overlay:
|
||||
remove_value(reg, EOS_KEY, "OverlayPath")
|
||||
state = "overlay-off" if not has_value(reg, EOS_KEY, "OverlayPath") else "overlay-still-set"
|
||||
|
||||
@@ -103,9 +103,18 @@ TOOL_MANIFEST_VDF = """"manifest"
|
||||
BL_STORE_SETUP = """
|
||||
bl_store_launch() {
|
||||
[ "${verb:-}" = waitforexitandrun ] || return 0
|
||||
# A web address the game opens (Wine's winebrowser runs xdg-open) goes to Android's browser.
|
||||
if [ -x /usr/local/lib/droiddeck/browser/xdg-open ]; then
|
||||
PATH="/usr/local/lib/droiddeck/browser:$PATH"; export PATH
|
||||
# A web address the game opens (Wine's winebrowser runs xdg-open) goes to Android's browser:
|
||||
# droiddeck-open-url as xdg-open, first on the game's PATH, with the session channel left in a
|
||||
# file in case Wine does not pass BL_LAUNCH_DIR on. (The prefix also names it as Wine's browser.)
|
||||
if [ -x /usr/local/bin/droiddeck-open-url ]; then
|
||||
mkdir -p /tmp/droiddeck-browser
|
||||
ln -sfn /usr/local/bin/droiddeck-open-url /tmp/droiddeck-browser/xdg-open
|
||||
[ -n "${BL_LAUNCH_DIR:-}" ] && printf '%s\n' "$BL_LAUNCH_DIR" > /tmp/droiddeck-browser/launch-dir
|
||||
PATH="/tmp/droiddeck-browser:$PATH"; export PATH
|
||||
fi
|
||||
# BL_DEBUG_BROWSER=1 (droiddeck-env): Wine traces how the game opens a web address.
|
||||
if [ "${BL_DEBUG_BROWSER:-}" = 1 ]; then
|
||||
WINEDEBUG="${WINEDEBUG:+$WINEDEBUG,}+shell,+winebrowser"; export WINEDEBUG
|
||||
fi
|
||||
[ -x /usr/local/bin/droiddeck-store-launch ] || return 0
|
||||
/usr/local/bin/droiddeck-store-launch "$@" || true
|
||||
|
||||
@@ -132,7 +132,7 @@ class Prefix(unittest.TestCase):
|
||||
text = self.reg.read_text()
|
||||
self.assertIn('[Software\\\\Epic Games\\\\EOS] ', text)
|
||||
self.assertIn('"OverlayPath"="Z:' + str(self.overlay).replace('/', '\\\\') + '"', text)
|
||||
self.assertIn('"Browsers"="xdg-open"', text)
|
||||
self.assertIn('"Browsers"="/usr/local/bin/droiddeck-open-url,xdg-open"', text)
|
||||
# A second launch adds nothing: the last word already says so.
|
||||
store.provision_prefix(str(self.compat), str(self.overlay), overlay=True)
|
||||
self.assertEqual(text, self.reg.read_text())
|
||||
@@ -178,7 +178,7 @@ class Choices(unittest.TestCase):
|
||||
|
||||
class Browser(unittest.TestCase):
|
||||
def test_a_web_address_is_handed_to_the_app(self):
|
||||
xdg = load_path(BIN.parent / 'lib/droiddeck/browser/xdg-open', 'xdg_open')
|
||||
xdg = load_path(BIN / 'droiddeck-open-url', 'open_url')
|
||||
with tempfile.TemporaryDirectory() as root:
|
||||
os.environ['BL_LAUNCH_DIR'] = root
|
||||
try:
|
||||
|
||||
Reference in new issue
Block a user