Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion pkg/hoverclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,12 @@ func (c *Client) ensureLoginLocked(ctx context.Context) error {
"username": c.creds.Username,
"password": c.creds.Password,
"remember": false,
"token": "",
// token MUST be JSON null, not "". Hover's signin branches on this
// field for its "magic token" sign-in: a non-null token (even "")
// routes to magic-token validation, which fails an empty token with
// a generic "Invalid username or password." The browser sends null
// for password sign-in; match it exactly (verified via DevTools).
"token": nil,
})
if err != nil {
return fmt.Errorf("hover signin step 1: %w", err)
Expand Down
10 changes: 9 additions & 1 deletion pkg/hoverclient/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,16 @@ func TestClient_Login_UsesBrowserSigninShape(t *testing.T) {
t.Fatalf("Login: %v", err)
}

if _, ok := authBody["token"]; !ok {
// Regression guard (do not weaken to a key-presence check): token MUST
// be JSON null, not "". A non-null token — including the empty string —
// routes Hover's auth.json to its "magic token" sign-in path, which
// fails an empty token with a generic "Invalid username or password"
// even when username + password are correct. Sending "" cost a
// multi-day live debugging session. See client.go ensureLoginLocked.
if v, ok := authBody["token"]; !ok {
t.Fatalf("auth body missing token field: %#v", authBody)
} else if v != nil {
t.Fatalf("token must be JSON null, got %#v — a non-null token (incl. \"\") triggers magic-token signin and 401s with valid creds", v)
}
if got := headers.Get("Origin"); got != hoverHost {
t.Errorf("Origin = %q, want %q", got, hoverHost)
Expand Down