diff --git a/internal/rpc/convert_users.go b/internal/rpc/convert_users.go index 8f27212b..80dd6381 100644 --- a/internal/rpc/convert_users.go +++ b/internal/rpc/convert_users.go @@ -13,13 +13,24 @@ func tgSelfUser(u domain.User) *tg.User { if u.Deleted { return &tg.User{ID: u.ID, Deleted: true} } + phone := u.Phone + if u.SignupEmail != "" { + // Self view only: an email-signup account's users.phone is a random, + // meaningless "888" display number (see internal/domain/emailphone.go + // and cmd/createuser) -- showing the real signup email in its place is + // what the account's own My Account / Edit Profile screen should + // display. Never do this in tgUser (how *other* viewers see this + // account): the phone field there is already privacy-gated, and this + // would leak the email past that gate to anyone allowed to see a phone. + phone = u.SignupEmail + } out := &tg.User{ ID: u.ID, AccessHash: u.AccessHash, FirstName: u.FirstName, LastName: u.LastName, Username: u.Username, - Phone: u.Phone, + Phone: phone, Self: true, Verified: u.Verified, Scam: u.Scam, diff --git a/internal/rpc/convert_users_test.go b/internal/rpc/convert_users_test.go new file mode 100644 index 00000000..7c33c288 --- /dev/null +++ b/internal/rpc/convert_users_test.go @@ -0,0 +1,51 @@ +package rpc + +import ( + "testing" + + "telesrv/internal/domain" +) + +// TestTgSelfUserShowsSignupEmailInPlaceOfDisplayPhone locks in that an +// email-signup account's own "My Account" view shows the real signup email +// instead of the meaningless random "888" display phone (see +// internal/domain/emailphone.go, cmd/createuser) -- matching what an +// official client's Edit Profile screen is expected to display. +func TestTgSelfUserShowsSignupEmailInPlaceOfDisplayPhone(t *testing.T) { + u := domain.User{ + ID: 42, + FirstName: "Ducky", + Phone: "88890942435", + SignupEmail: "ducky@zio.sh", + } + out := tgSelfUser(u) + if out.Phone != "ducky@zio.sh" { + t.Fatalf("tgSelfUser.Phone = %q, want signup email %q", out.Phone, "ducky@zio.sh") + } +} + +// TestTgSelfUserKeepsPhoneWithoutSignupEmail confirms an ordinary phone +// account's self view is unaffected. +func TestTgSelfUserKeepsPhoneWithoutSignupEmail(t *testing.T) { + u := domain.User{ID: 42, FirstName: "Real", Phone: "15550001234"} + out := tgSelfUser(u) + if out.Phone != "15550001234" { + t.Fatalf("tgSelfUser.Phone = %q, want unchanged phone %q", out.Phone, "15550001234") + } +} + +// TestTgUserNeverLeaksSignupEmail confirms the privacy boundary: how *other* +// viewers see this account must never substitute the email for the phone -- +// only the account's own self view (tgSelfUser) does that. +func TestTgUserNeverLeaksSignupEmail(t *testing.T) { + u := domain.User{ + ID: 42, + FirstName: "Ducky", + Phone: "88890942435", + SignupEmail: "ducky@zio.sh", + } + out := tgUser(u) + if out.Phone != "88890942435" { + t.Fatalf("tgUser.Phone = %q, want raw display phone %q (email must not leak to other viewers)", out.Phone, "88890942435") + } +}