From f9719adf0448d662ccf6d34eab0aa956050a1d35 Mon Sep 17 00:00:00 2001 From: Ada Vale <104856138+AdaInTheLab@users.noreply.github.com> Date: Wed, 17 Jun 2026 03:21:35 -0400 Subject: [PATCH 1/2] =?UTF-8?q?fix(web):=20drop=20Autofac=20OWIN=20middlew?= =?UTF-8?q?are=20=E2=80=94=20Mono=20lacks=20IAsyncDisposable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit app.UseAutofacMiddleware / UseAutofacWebApi register Autofac.Integration.Owin's per-request lifetime-scope injector, which disposes the scope via `await using` → IAsyncDisposable.DisposeAsync(). 7D2D's Mono runtime doesn't implement that method, so it threw MissingMethodException at JIT in front of the whole pipeline — taking down EVERY /api/* request on Linux/Mono. Rely instead on Web API's own AutofacWebApiDependencyResolver (already set), which creates + disposes the per-request scope SYNCHRONOUSLY via IDisposable.Dispose() (which Mono has). InstancePerRequest registrations still resolve correctly (same RequestLifetimeScopeTag). Verified live: authed GET /api/users → 200. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/KitsuneCommand/Web/OwinStartup.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/KitsuneCommand/Web/OwinStartup.cs b/src/KitsuneCommand/Web/OwinStartup.cs index 14c3fe3..35f74f2 100644 --- a/src/KitsuneCommand/Web/OwinStartup.cs +++ b/src/KitsuneCommand/Web/OwinStartup.cs @@ -125,8 +125,16 @@ public void Configuration(IAppBuilder app) config.EnsureInitialized(); - app.UseAutofacMiddleware(_container); - app.UseAutofacWebApi(config); + // NOTE: deliberately NOT using app.UseAutofacMiddleware / app.UseAutofacWebApi. + // Those register Autofac.Integration.Owin's per-request lifetime-scope injector, + // which disposes the scope with `await using` → IAsyncDisposable.DisposeAsync(). + // 7D2D's Mono runtime does not implement that method, so it throws + // MissingMethodException at JIT in front of the whole pipeline — taking down EVERY + // /api/* request on Linux/Mono. Web API's own AutofacWebApiDependencyResolver (set + // above) creates and disposes the per-request lifetime scope SYNCHRONOUSLY via + // IDisposable.Dispose(), which Mono has. InstancePerRequest registrations still + // resolve correctly (same RequestLifetimeScopeTag). Do not re-add the injector + // without confirming Mono gained IAsyncDisposable support. app.UseWebApi(config); } } From 98836c3814a13999b2976efaa8629f536a8ef533 Mon Sep 17 00:00:00 2001 From: Ada Vale <104856138+AdaInTheLab@users.noreply.github.com> Date: Wed, 17 Jun 2026 03:21:35 -0400 Subject: [PATCH 2/2] fix(auth): normalize login username to match stored accounts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UserController.Create stores username as Trim().ToLowerInvariant(), but HandleLogin passed the raw typed username to GetByUsername, and SQLite compares TEXT case-sensitively — so a username created/typed as "KCAdmin" was stored "kcadmin" and never matched at login (presented as the admin password "rotating" / not working). Normalize the login username the same way. Verified: "KCAdmin" → 200. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/KitsuneCommand/Web/WebServerHost.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/KitsuneCommand/Web/WebServerHost.cs b/src/KitsuneCommand/Web/WebServerHost.cs index e099330..b81d65a 100644 --- a/src/KitsuneCommand/Web/WebServerHost.cs +++ b/src/KitsuneCommand/Web/WebServerHost.cs @@ -205,7 +205,10 @@ private void HandleLogin(HttpListenerContext ctx) body = reader.ReadToEnd(); var loginReq = JsonConvert.DeserializeObject(body); - string username = loginReq?.username; + // Normalize to match how accounts are stored: UserController.Create lowercases + + // trims the username, and SQLite compares TEXT case-sensitively. Without this, a + // username created/typed as "KCAdmin" is stored "kcadmin" and never matches at login. + string username = loginReq?.username?.Trim().ToLowerInvariant(); string password = loginReq?.password; if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))