From 9c52ed2eb2cd73b93e3fb550ff1236045381f994 Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Mon, 15 Jun 2026 13:27:07 +0100 Subject: [PATCH 1/2] DROID-77263: reject empty login ID in dummybridge login An empty username persisted a UserLogin with ID=="". With split portals enabled, the empty receiver makes GetPortalByKey fail on every startup. Substitute a random ID for empty usernames so the login ID can never be empty, while keeping the form's "anything goes" contract. Co-Authored-By: Claude Opus 4.8 (1M context) --- pkg/connector/login.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pkg/connector/login.go b/pkg/connector/login.go index d805e38..86609c3 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "go.mau.fi/util/jsontime" "go.mau.fi/util/random" @@ -148,8 +149,17 @@ func (dl *DummyLogin) SubmitUserInput(ctx context.Context, input map[string]stri if input["password"] == "incorrectpassword" { return nil, fmt.Errorf("incorrect password") } + username := input["username"] + if username == "" { + // The login form advertises "anything goes and it's used as the ID", so an empty + // username must keep working. Persisting a UserLogin with an empty ID is unsafe though: + // with split portals enabled, an empty receiver makes GetPortalByKey fail and crashes + // the host app on every startup (DROID-77263). Generate a random ID instead so the login + // ID can never be empty. + username = "dummy-" + strings.ToLower(random.String(12)) + } login, err := dl.User.NewLogin(ctx, &database.UserLogin{ - ID: networkid.UserLoginID(input["username"]), + ID: networkid.UserLoginID(username), RemoteName: input["password"], RemoteProfile: status.RemoteProfile{ Name: input["password"], From 32b981c9a39fc1e70cf0a308e7c95ecb46396100 Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Mon, 15 Jun 2026 13:27:08 +0100 Subject: [PATCH 2/2] DROID-77263: report bridge state instead of panicking in Connect A bare panic(err) in the portal-generation goroutine turned any persistent error into a boot-loop crash of the host app. Report an UNKNOWN_ERROR bridge state and return instead, so a bad login can never crash the host. Co-Authored-By: Claude Opus 4.8 (1M context) --- pkg/connector/client.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 378b3d4..24acebe 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -117,7 +117,17 @@ func (dc *DummyClient) Connect(ctx context.Context) { ); errors.Is(err, context.Canceled) { return } else if err != nil { - panic(err) + // Never panic here: a persistent error (e.g. an empty login ID failing + // GetPortalByKey under split portals) would otherwise boot-loop crash the + // host app on every startup (DROID-77263). Report a bridge-state error and + // stop generating instead. + log.Err(err).Msg("Failed to generate portal after login") + dc.UserLogin.BridgeState.Send(status.BridgeState{ + StateEvent: status.StateUnknownError, + Error: "dummy-generate-portal-failed", + Message: err.Error(), + }) + return } } }()