diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 9899d504e..13d13718f 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -3224,7 +3224,7 @@ func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) ipn if !oldp.Persist().Valid() { b.logf("active login: %s", newLoginName) } else { - oldLoginName := oldp.Persist().UserProfile().LoginName() + oldLoginName := oldp.Persist().UserProfile().LoginName if oldLoginName != newLoginName { b.logf("active login: %q (changed from %q)", newLoginName, oldLoginName) } diff --git a/ipn/ipnlocal/state_test.go b/ipn/ipnlocal/state_test.go index 6e7791acd..403233a11 100644 --- a/ipn/ipnlocal/state_test.go +++ b/ipn/ipnlocal/state_test.go @@ -486,7 +486,7 @@ func TestStateMachine(t *testing.T) { c.Assert(nn[0].LoginFinished, qt.IsNotNil) c.Assert(nn[1].Prefs, qt.IsNotNil) c.Assert(nn[2].State, qt.IsNotNil) - c.Assert(nn[1].Prefs.Persist().UserProfile().LoginName(), qt.Equals, "user1") + c.Assert(nn[1].Prefs.Persist().UserProfile().LoginName, qt.Equals, "user1") c.Assert(ipn.NeedsMachineAuth, qt.Equals, *nn[2].State) c.Assert(ipn.NeedsMachineAuth, qt.Equals, b.State()) } @@ -675,7 +675,7 @@ func TestStateMachine(t *testing.T) { c.Assert(nn[1].Prefs.Persist(), qt.IsNotNil) c.Assert(nn[2].State, qt.IsNotNil) // Prefs after finishing the login, so LoginName updated. - c.Assert(nn[1].Prefs.Persist().UserProfile().LoginName(), qt.Equals, "user2") + c.Assert(nn[1].Prefs.Persist().UserProfile().LoginName, qt.Equals, "user2") c.Assert(nn[1].Prefs.LoggedOut(), qt.IsFalse) c.Assert(nn[1].Prefs.WantRunning(), qt.IsTrue) c.Assert(ipn.Starting, qt.Equals, *nn[2].State) @@ -816,7 +816,7 @@ func TestStateMachine(t *testing.T) { c.Assert(nn[1].Prefs, qt.IsNotNil) c.Assert(nn[2].State, qt.IsNotNil) // Prefs after finishing the login, so LoginName updated. - c.Assert(nn[1].Prefs.Persist().UserProfile().LoginName(), qt.Equals, "user3") + c.Assert(nn[1].Prefs.Persist().UserProfile().LoginName, qt.Equals, "user3") c.Assert(nn[1].Prefs.LoggedOut(), qt.IsFalse) c.Assert(nn[1].Prefs.WantRunning(), qt.IsTrue) c.Assert(ipn.Starting, qt.Equals, *nn[2].State) diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 96a1afda2..5a26697ff 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -106,7 +106,7 @@ type CapabilityVersion int // - 63: 2023-06-08: Client understands SSHAction.AllowRemotePortForwarding. // - 64: 2023-07-11: Client understands s/CapabilityTailnetLockAlpha/CapabilityTailnetLock // - 65: 2023-07-12: Client understands DERPMap.HomeParams + incremental DERPMap updates with params -// - 66: 2023-07-23: UserProfile.Groups added (available via WhoIs) +// - 66: 2023-07-23: UserProfile.Groups added (available via WhoIs) (removed in 87) // - 67: 2023-07-25: Client understands PeerCapMap // - 68: 2023-08-09: Client has dedicated updateRoutine; MapRequest.Stream true means ignore Hostinfo+Endpoints // - 69: 2023-08-16: removed Debug.LogHeap* + GoroutineDumpURL; added c2n /debug/logheap @@ -127,7 +127,8 @@ type CapabilityVersion int // - 84: 2024-01-04: Client understands SeamlessKeyRenewal // - 85: 2024-01-05: Client understands MaxKeyDuration // - 86: 2024-01-23: Client understands NodeAttrProbeUDPLifetime -const CurrentCapabilityVersion CapabilityVersion = 86 +// - 87: 2024-02-11: UserProfile.Groups removed (added in 66) +const CurrentCapabilityVersion CapabilityVersion = 87 type StableID string @@ -198,13 +199,6 @@ type UserProfile struct { // Roles exists for legacy reasons, to keep old macOS clients // happy. It JSON marshals as []. Roles emptyStructJSONSlice - - // Groups contains group identifiers for any group that this user is - // a part of and that the coordination server is configured to tell - // your node about. (Thus, it may be empty or incomplete.) - // There's no semantic difference between a nil and an empty list. - // The list is always sorted. - Groups []string `json:",omitempty"` } func (p *UserProfile) Equal(p2 *UserProfile) bool { @@ -217,8 +211,7 @@ func (p *UserProfile) Equal(p2 *UserProfile) bool { return p.ID == p2.ID && p.LoginName == p2.LoginName && p.DisplayName == p2.DisplayName && - p.ProfilePicURL == p2.ProfilePicURL && - (len(p.Groups) == 0 && len(p2.Groups) == 0 || reflect.DeepEqual(p.Groups, p2.Groups)) + p.ProfilePicURL == p2.ProfilePicURL } type emptyStructJSONSlice struct{} diff --git a/tailcfg/tailcfg_clone.go b/tailcfg/tailcfg_clone.go index 122e57edc..5e4d88243 100644 --- a/tailcfg/tailcfg_clone.go +++ b/tailcfg/tailcfg_clone.go @@ -586,7 +586,6 @@ func (src *UserProfile) Clone() *UserProfile { } dst := new(UserProfile) *dst = *src - dst.Groups = append(src.Groups[:0:0], src.Groups...) return dst } @@ -597,7 +596,6 @@ var _UserProfileCloneNeedsRegeneration = UserProfile(struct { DisplayName string ProfilePicURL string Roles emptyStructJSONSlice - Groups []string }{}) // Clone duplicates src into dst and reports whether it succeeded. diff --git a/tailcfg/tailcfg_view.go b/tailcfg/tailcfg_view.go index ac4d58030..a614318c1 100644 --- a/tailcfg/tailcfg_view.go +++ b/tailcfg/tailcfg_view.go @@ -1435,7 +1435,6 @@ func (v UserProfileView) LoginName() string { return v.ж.LoginName func (v UserProfileView) DisplayName() string { return v.ж.DisplayName } func (v UserProfileView) ProfilePicURL() string { return v.ж.ProfilePicURL } func (v UserProfileView) Roles() emptyStructJSONSlice { return v.ж.Roles } -func (v UserProfileView) Groups() views.Slice[string] { return views.SliceOf(v.ж.Groups) } func (v UserProfileView) Equal(v2 UserProfileView) bool { return v.ж.Equal(v2.ж) } // A compilation failure here means this code must be regenerated, with the command at the top of this file. @@ -1445,5 +1444,4 @@ var _UserProfileViewNeedsRegeneration = UserProfile(struct { DisplayName string ProfilePicURL string Roles emptyStructJSONSlice - Groups []string }{}) diff --git a/types/persist/persist_clone.go b/types/persist/persist_clone.go index 121d906ec..0d801c046 100644 --- a/types/persist/persist_clone.go +++ b/types/persist/persist_clone.go @@ -19,7 +19,6 @@ func (src *Persist) Clone() *Persist { } dst := new(Persist) *dst = *src - dst.UserProfile = *src.UserProfile.Clone() dst.DisallowedTKAStateIDs = append(src.DisallowedTKAStateIDs[:0:0], src.DisallowedTKAStateIDs...) return dst } diff --git a/types/persist/persist_view.go b/types/persist/persist_view.go index 8c3173a23..161cfbeec 100644 --- a/types/persist/persist_view.go +++ b/types/persist/persist_view.go @@ -65,12 +65,12 @@ func (v *PersistView) UnmarshalJSON(b []byte) error { func (v PersistView) LegacyFrontendPrivateMachineKey() key.MachinePrivate { return v.ж.LegacyFrontendPrivateMachineKey } -func (v PersistView) PrivateNodeKey() key.NodePrivate { return v.ж.PrivateNodeKey } -func (v PersistView) OldPrivateNodeKey() key.NodePrivate { return v.ж.OldPrivateNodeKey } -func (v PersistView) Provider() string { return v.ж.Provider } -func (v PersistView) UserProfile() tailcfg.UserProfileView { return v.ж.UserProfile.View() } -func (v PersistView) NetworkLockKey() key.NLPrivate { return v.ж.NetworkLockKey } -func (v PersistView) NodeID() tailcfg.StableNodeID { return v.ж.NodeID } +func (v PersistView) PrivateNodeKey() key.NodePrivate { return v.ж.PrivateNodeKey } +func (v PersistView) OldPrivateNodeKey() key.NodePrivate { return v.ж.OldPrivateNodeKey } +func (v PersistView) Provider() string { return v.ж.Provider } +func (v PersistView) UserProfile() tailcfg.UserProfile { return v.ж.UserProfile } +func (v PersistView) NetworkLockKey() key.NLPrivate { return v.ж.NetworkLockKey } +func (v PersistView) NodeID() tailcfg.StableNodeID { return v.ж.NodeID } func (v PersistView) DisallowedTKAStateIDs() views.Slice[string] { return views.SliceOf(v.ж.DisallowedTKAStateIDs) }