From 013ad3128c23c598e20761746dda2c64aef6eeea Mon Sep 17 00:00:00 2001 From: Seongmin Lee Date: Sun, 25 Jan 2026 08:15:02 +0000 Subject: [PATCH] appview: don't trust `oauth.ClientSessionData` `oauth.ClientSessionData.HostURL` is not validated after first session creation. If user switches the PDS while logged in, `.HostURL` will still point to old PDS, showing account management options for `tngl.sh` users. This can confuse users to accidentally put account in odd state (activated in both PDSes) Instead, always resolve Handles and PDS hosts on-demand. Technically `HostURL` is used on creating authorized atpclient, but that's ok because request to old PDS will reject the request. Ideally we should revoke user sessions on `#account` event, indigo currently doesn't support DID based revoking. Signed-off-by: Seongmin Lee --- appview/ingester.go | 7 ++++++- appview/oauth/accounts.go | 7 ------- appview/oauth/accounts_test.go | 2 +- appview/oauth/oauth.go | 2 -- appview/pages/funcmap.go | 7 +++++++ appview/pages/templates/user/settings/profile.html | 9 +++++---- appview/settings/danger.go | 24 +++++++++++++++--------- appview/settings/settings.go | 67 ++++++++++++++++++++++++++++++++++++++++++------------------------- appview/state/router.go | 13 +++++++------ 9 file(s) changed, 83 insertion(s)(+), 55 deletion(s)(-) diff --git a/appview/ingester.go b/appview/ingester.go --- a/appview/ingester.go +++ b/appview/ingester.go @@ -51,7 +51,12 @@ l := i.Logger.With("kind", e.Kind) switch e.Kind { case jmodels.EventKindAccount: - if !e.Account.Active && *e.Account.Status == "deactivated" { + // TODO: sync account state to db + if e.Account.Active { + break + } + // TODO: revoke sessions by DID + if *e.Account.Status == "deactivated" { err = i.IdResolver.InvalidateIdent(ctx, e.Account.Did) } case jmodels.EventKindIdentity: diff --git a/appview/oauth/accounts.go b/appview/oauth/accounts.go --- a/appview/oauth/accounts.go +++ b/appview/oauth/accounts.go @@ -34,13 +34,6 @@ } return m.Active.Did } -func (m *MultiAccountUser) Pds() string { - if m.Active == nil { - return "" - } - return m.Active.Pds -} - func (o *OAuth) GetAccounts(r *http.Request) *AccountRegistry { session, err := o.SessStore.Get(r, AccountsName) if err != nil || session.IsNew { diff --git a/appview/oauth/accounts_test.go b/appview/oauth/accounts_test.go --- a/appview/oauth/accounts_test.go +++ b/appview/oauth/accounts_test.go @@ -249,7 +249,7 @@ func TestMultiAccountUser_Did(t *testing.T) { t.Run("with active user", func(t *testing.T) { user := &MultiAccountUser{ - Active: &User{Did: "did:plc:test", Pds: "https://bsky.social"}, + Active: &User{Did: "did:plc:test"}, } if user.Did() != "did:plc:test" { t.Errorf("Did() = %s, want did:plc:test", user.Did()) diff --git a/appview/oauth/oauth.go b/appview/oauth/oauth.go --- a/appview/oauth/oauth.go +++ b/appview/oauth/oauth.go @@ -239,7 +239,6 @@ } type User struct { Did string - Pds string } func (o *OAuth) GetUser(r *http.Request) *User { @@ -250,7 +249,6 @@ } return &User{ Did: sess.Data.AccountDID.String(), - Pds: sess.Data.HostURL, } } diff --git a/appview/pages/funcmap.go b/appview/pages/funcmap.go --- a/appview/pages/funcmap.go +++ b/appview/pages/funcmap.go @@ -81,6 +81,13 @@ } return identity.Handle.String() }, + "resolvePds": func(s string) string { + identity, err := p.resolver.ResolveIdent(context.Background(), s) + if err != nil { + return "" + } + return identity.PDSEndpoint() + }, "ownerSlashRepo": func(repo *models.Repo) string { ownerId, err := p.resolver.ResolveIdent(context.Background(), repo.Did) if err != nil { diff --git a/appview/pages/templates/user/settings/profile.html b/appview/pages/templates/user/settings/profile.html --- a/appview/pages/templates/user/settings/profile.html +++ b/appview/pages/templates/user/settings/profile.html @@ -49,7 +49,7 @@ {{ .LoggedInUser.Did }}
Personal Data Server (PDS) - {{ .LoggedInUser.Pds }} + {{ resolvePds .LoggedInUser.Did }}
{{ if and .IsTnglSh .HandleOpen }} @@ -132,9 +132,10 @@ {{ end }} {{ define "accountActions" }} + {{ $isDeactivated := (and .IsTnglSh .IsDeactivated) }}

Account

- {{ if .IsDeactivated }} + {{ if $isDeactivated }}
Your account is deactivated. Your profile and repositories are currently inaccessible. Reactivate to restore access.
@@ -147,7 +148,7 @@ class="btn flex items-center gap-2 text-sm cursor-pointer"> {{ i "key" "size-4" }} change password - {{ if .IsDeactivated }} + {{ if $isDeactivated }}
- {{ if .IsDeactivated }} + {{ if $isDeactivated }}