Skip to content

WebView2 based login and launch (#29) - #41

Merged
anon5r merged 5 commits into
mainfrom
feature/webview2-login
Sep 23, 2026
Merged

anon5r merged 5 commits into
mainfrom
feature/webview2-login

Conversation

@anon5r

@anon5r anon5r commented Sep 23, 2026

Copy link
Copy Markdown
Owner

Implements the WebView2-based login for #29, from a handoff patch prepared in another session.

What this does

KONAMI's login moved to its own OAuth flow, so the old approach (HttpClient + AngleSharp posting to the login form, credentials in Credential Manager) stopped working. Instead of reproducing that flow, this shows the official login page in a WebView2 and rides the resulting cookie session to open the launch page and read the launch URI.

File Role
Web/LaunchPageClassifier.cs Pure logic classifying a URL as Login / TermsOfService / PrivacyConfirmation / LaunchPage / Unknown, plus the launch-URI regex (konaste.xxx://login, bm2dxinf://login — same condition as the old LauncherLoginPage)
Web/WebLaunchSession.cs The core, depending only on CoreWebView2. Opens the launch page and reads the launch.selector element's href from the DOM rather than clicking it. Detects the maintenance banner. If the href never appears, reveals the window so the user can click, and captures the URI via LaunchingExternalUriScheme
Forms/WebViewHostForm.cs WinForms host. Opens at Opacity = 0 and only reveals itself when user interaction is needed or 20s elapse. UserDataFolder is %LocalAppData%\KsGameLauncher\WebView2 so single-file publish doesn't try to write next to the exe
Web/WebLauncher.cs StartAppAsync(AppInfo) / LogoutAsync(). Launching still goes through the registry and Process.Start(path, uri)
Tests/LaunchPageClassifierTests.cs 14 tests for classification and URI validation

Login detection deliberately keys on "we are on a different host from the launch page" rather than pinning AuthorizeDomain (account.konami.net), so it survives changes to the OAuth domain or redirect chain.

Program.cs also changes: the URI launch mode (konaste.*://launch/<id>) now runs on the UI thread via Application.Idle instead of a separate STA thread, because WebView2 only works on a thread with a message loop.

Follow-ups cleared here

The patch had never been compiled. It built and passed on the first try; the second commit covers the follow-ups that don't need a real Konaste account:

  • Nullable warnings (TODO 1) — RunUriActionOnce didn't match the EventHandler signature (object? sender), and the TryCreate out parameter was declared non-nullable.
  • Password autofill (TODO 3) — WebView2 disables both settings by default, so every login would have meant retyping credentials. Enabled IsPasswordAutosaveEnabled / IsGeneralAutofillEnabled.
  • GameRegistry.GetLauncherPath (TODO 7) — OpenSubKey returns null rather than throwing when the scheme isn't registered, which is the normal state for a game that isn't installed, and the result was dereferenced unguarded. WebLauncher calls this immediately before launching, so the crash sat directly on the new launch path. Also guarded the trailing " \"%1\"" strip, which used a fixed length and would throw on a shorter value, and made the return type nullable to match the caller.
  • Localized messages (TODO 8) — moved the hardcoded English WebView2 runtime message into Strings.resx, along with the two other hardcoded messages in WebLauncher for consistency.

Note: Strings.Designer.cs is generated by a Visual Studio design-time tool and is not regenerated by dotnet build, so the properties were added by hand to match the new resx entries. Added tests covering that correspondence — an entry missing on the resx side returns null at runtime rather than failing the build, so nothing else would catch it.

Still open — needs your machine

  • TODO 2: verify on real hardware. Watch the [WebLaunch] navigate: / page: debug output for whether login returns to the launch page, whether the #login>div>a.link-btn selector is still valid, and whether the flow depends on popups or window.opener. If it uses window.opener + postMessage, NewWindowRequested needs to assign a separate WebView2 to e.NewWindow instead of navigating in place.
  • TODO 4: passkeys. WebView2's WebAuthn goes through the native Windows API. Worth checking against https://webauthn.io first, and whether the Windows passkey dialog can appear while the host window is still transparent (WebView2Feedback #5460).
  • TODO 5 / 6: removing the old login code and clearing saved Credential Manager passwords are explicitly gated on TODO 2, so they're untouched here. Launcher.cs's HttpClient login path, the OTP dialog and Settings.Cookies are all still in place, which also means this can be reverted by pointing the two call sites back.

Test plan

  • dotnet build KsGameLauncher.sln — 0 errors, no warnings in the new code
  • dotnet test — 45/45 passed (25 existing + 14 from the patch + 6 added here)
  • Verified the new resource strings resolve at runtime (ja-JP returns the Japanese text, not null)
  • Real-device verification of the login and launch flow (TODO 2 / 4 above)

anon5r and others added 4 commits September 23, 2026 08:48
The only launch profile had jsWebView2Debugging enabled, which makes
Visual Studio attach a JavaScript/Edge debug adapter for scripts running
inside a WebView2 control. No WebView2 control is instantiated yet -
WebView2 is currently only pulled in at runtime by AutoUpdater.NET's
changelog viewer - so the adapter has nothing to attach to. It exits
with code 0 before connecting, and the debug session reports "could not
start the debug adapter" / "cannot launch browser: browser process
exited with code 0 before connecting to the debug server ... verify
runtimeExecutable".

The flag is still wanted for the WebView2-based login work (#29), so
rather than dropping it, the default profile is now plain and the
WebView2 JS debugging variant is kept as a second profile that can be
selected from the Visual Studio launch dropdown once a WebView2 control
actually exists.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The handoff patch had never been compiled. It built and passed on the
first try, so this only covers the follow-ups that do not need a real
Konaste account.

Nullable warnings (TODO 1): RunUriActionOnce did not match the
EventHandler signature (object? sender) and declared the TryCreate out
parameter as non-nullable.

Password autofill (TODO 3): WebView2 disables both settings by default,
so every login would have required typing the credentials again. Enabled
IsPasswordAutosaveEnabled and IsGeneralAutofillEnabled right after
EnsureCoreWebView2Async.

GameRegistry.GetLauncherPath (TODO 7): OpenSubKey returns null rather
than throwing when the scheme is not registered, which is the normal
state for a game that is not installed, and the result was dereferenced
unguarded. WebLauncher calls this immediately before launching, so the
crash sat directly on the new launch path. Also guarded the trailing
" \"%1\"" strip, which used a fixed length and would throw on a shorter
value, and made the return type nullable to match the caller.

Localized messages (TODO 8): moved the hardcoded English WebView2
runtime message into Strings.resx, along with the two other hardcoded
messages in WebLauncher for consistency.

Note that Strings.Designer.cs is generated by a Visual Studio design
time tool and is not regenerated by dotnet build, so the properties had
to be added by hand to match the new resx entries. Added tests covering
that correspondence, since an entry missing from the resx side returns
null at runtime instead of failing the build.

Build is clean and all 45 tests pass. TODO 2 and 4 need a real Konaste
account and a physical device, and TODO 5 and 6 are gated on TODO 2.
Debug logs from a session on the WebView2 branch show what the adapter
actually does: it launches KsGameLauncher2.exe as if it were the browser,
polls http://localhost:<port>/json/version for a CDP target, and after a
30 second timeout reports "Could not find any debuggable target" and
tears the session down. Because it is configured with
cleanUp: "wholeBrowser" and killBehavior: "forceful", that teardown kills
the app, which exits with 0xFFFFFFFF.

This app creates its WebView2 lazily, only when a game is launched, so
with this flag on the default profile the app is killed roughly 30
seconds after every debug start whether or not anything was clicked.

The flag is still useful once a WebView2 exists, so the profile stays,
but its name now says that a game has to be opened before the adapter
gives up. launchSettings.json is strict JSON, so the name is the only
place to put that.
@anon5r anon5r self-assigned this Sep 23, 2026
@anon5r
anon5r merged commit 3ee6d19 into main Sep 23, 2026
2 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