diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 0fb65a6bb..19db70739 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -3,7 +3,7 @@ package tailcfg -//go:generate go run tailscale.com/cmd/viewer --type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile --clonefunc +//go:generate go run tailscale.com/cmd/viewer --type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile --clonefunc import ( "bytes" @@ -949,6 +949,16 @@ func (st SignatureType) String() string { } } +// RegisterResponseAuth is the authentication information returned by the server +// in response to a RegisterRequest. +type RegisterResponseAuth struct { + _ structs.Incomparable + // One of Provider/LoginName, Oauth2Token, or AuthKey is set. + Provider, LoginName string + Oauth2Token *Oauth2Token + AuthKey string +} + // RegisterRequest is sent by a client to register the key for a node. // It is encoded to JSON, encrypted with golang.org/x/crypto/nacl/box, // using the local machine key, and sent to: @@ -967,13 +977,7 @@ type RegisterRequest struct { NodeKey key.NodePublic OldNodeKey key.NodePublic NLKey key.NLPublic - Auth struct { - _ structs.Incomparable - // One of Provider/LoginName, Oauth2Token, or AuthKey is set. - Provider, LoginName string - Oauth2Token *Oauth2Token - AuthKey string - } + Auth RegisterResponseAuth // Expiry optionally specifies the requested key expiry. // The server policy may override. // As a special case, if Expiry is in the past and NodeKey is @@ -1002,29 +1006,6 @@ type RegisterRequest struct { Signature []byte `json:",omitempty"` // as described by SignatureType } -// Clone makes a deep copy of RegisterRequest. -// The result aliases no memory with the original. -// -// TODO: extend cmd/cloner to generate this method. -func (req *RegisterRequest) Clone() *RegisterRequest { - if req == nil { - return nil - } - res := new(RegisterRequest) - *res = *req - if res.Hostinfo != nil { - res.Hostinfo = res.Hostinfo.Clone() - } - if res.Auth.Oauth2Token != nil { - tok := *res.Auth.Oauth2Token - res.Auth.Oauth2Token = &tok - } - res.DeviceCert = append(res.DeviceCert[:0:0], res.DeviceCert...) - res.Signature = append(res.Signature[:0:0], res.Signature...) - res.NodeKeySignature = append(res.NodeKeySignature[:0:0], res.NodeKeySignature...) - return res -} - // RegisterResponse is returned by the server in response to a RegisterRequest. type RegisterResponse struct { User User diff --git a/tailcfg/tailcfg_clone.go b/tailcfg/tailcfg_clone.go index e0930f2fe..577cfdb2c 100644 --- a/tailcfg/tailcfg_clone.go +++ b/tailcfg/tailcfg_clone.go @@ -286,6 +286,69 @@ var _RegisterResponseCloneNeedsRegeneration = RegisterResponse(struct { Error string }{}) +// Clone makes a deep copy of RegisterResponseAuth. +// The result aliases no memory with the original. +func (src *RegisterResponseAuth) Clone() *RegisterResponseAuth { + if src == nil { + return nil + } + dst := new(RegisterResponseAuth) + *dst = *src + if dst.Oauth2Token != nil { + dst.Oauth2Token = new(Oauth2Token) + *dst.Oauth2Token = *src.Oauth2Token + } + return dst +} + +// A compilation failure here means this code must be regenerated, with the command at the top of this file. +var _RegisterResponseAuthCloneNeedsRegeneration = RegisterResponseAuth(struct { + _ structs.Incomparable + Provider string + LoginName string + Oauth2Token *Oauth2Token + AuthKey string +}{}) + +// Clone makes a deep copy of RegisterRequest. +// The result aliases no memory with the original. +func (src *RegisterRequest) Clone() *RegisterRequest { + if src == nil { + return nil + } + dst := new(RegisterRequest) + *dst = *src + dst.Auth = *src.Auth.Clone() + dst.Hostinfo = src.Hostinfo.Clone() + dst.NodeKeySignature = append(src.NodeKeySignature[:0:0], src.NodeKeySignature...) + if dst.Timestamp != nil { + dst.Timestamp = new(time.Time) + *dst.Timestamp = *src.Timestamp + } + dst.DeviceCert = append(src.DeviceCert[:0:0], src.DeviceCert...) + dst.Signature = append(src.Signature[:0:0], src.Signature...) + return dst +} + +// A compilation failure here means this code must be regenerated, with the command at the top of this file. +var _RegisterRequestCloneNeedsRegeneration = RegisterRequest(struct { + _ structs.Incomparable + Version CapabilityVersion + NodeKey key.NodePublic + OldNodeKey key.NodePublic + NLKey key.NLPublic + Auth RegisterResponseAuth + Expiry time.Time + Followup string + Hostinfo *Hostinfo + Ephemeral bool + NodeKeySignature tkatype.MarshaledSignature + SignatureType SignatureType + Timestamp *time.Time + DeviceCert []byte + Signature []byte +}{}) + // Clone makes a deep copy of DERPHomeParams. // The result aliases no memory with the original. func (src *DERPHomeParams) Clone() *DERPHomeParams { @@ -530,7 +593,7 @@ var _UserProfileCloneNeedsRegeneration = UserProfile(struct { // Clone duplicates src into dst and reports whether it succeeded. // To succeed, must be of types <*T, *T> or <*T, **T>, -// where T is one of User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile. +// where T is one of User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile. func Clone(dst, src any) bool { switch src := src.(type) { case *User: @@ -596,6 +659,24 @@ func Clone(dst, src any) bool { *dst = src.Clone() return true } + case *RegisterResponseAuth: + switch dst := dst.(type) { + case *RegisterResponseAuth: + *dst = *src.Clone() + return true + case **RegisterResponseAuth: + *dst = src.Clone() + return true + } + case *RegisterRequest: + switch dst := dst.(type) { + case *RegisterRequest: + *dst = *src.Clone() + return true + case **RegisterRequest: + *dst = src.Clone() + return true + } case *DERPHomeParams: switch dst := dst.(type) { case *DERPHomeParams: diff --git a/tailcfg/tailcfg_view.go b/tailcfg/tailcfg_view.go index 6593454f6..b3e9c145b 100644 --- a/tailcfg/tailcfg_view.go +++ b/tailcfg/tailcfg_view.go @@ -20,7 +20,7 @@ import ( "tailscale.com/types/views" ) -//go:generate go run tailscale.com/cmd/cloner -clonefunc=true -type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile +//go:generate go run tailscale.com/cmd/cloner -clonefunc=true -type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile // View returns a readonly view of User. func (p *User) View() UserView { @@ -629,6 +629,158 @@ var _RegisterResponseViewNeedsRegeneration = RegisterResponse(struct { Error string }{}) +// View returns a readonly view of RegisterResponseAuth. +func (p *RegisterResponseAuth) View() RegisterResponseAuthView { + return RegisterResponseAuthView{ж: p} +} + +// RegisterResponseAuthView provides a read-only view over RegisterResponseAuth. +// +// Its methods should only be called if `Valid()` returns true. +type RegisterResponseAuthView struct { + // ж is the underlying mutable value, named with a hard-to-type + // character that looks pointy like a pointer. + // It is named distinctively to make you think of how dangerous it is to escape + // to callers. You must not let callers be able to mutate it. + ж *RegisterResponseAuth +} + +// Valid reports whether underlying value is non-nil. +func (v RegisterResponseAuthView) Valid() bool { return v.ж != nil } + +// AsStruct returns a clone of the underlying value which aliases no memory with +// the original. +func (v RegisterResponseAuthView) AsStruct() *RegisterResponseAuth { + if v.ж == nil { + return nil + } + return v.ж.Clone() +} + +func (v RegisterResponseAuthView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } + +func (v *RegisterResponseAuthView) UnmarshalJSON(b []byte) error { + if v.ж != nil { + return errors.New("already initialized") + } + if len(b) == 0 { + return nil + } + var x RegisterResponseAuth + if err := json.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +func (v RegisterResponseAuthView) Provider() string { return v.ж.Provider } +func (v RegisterResponseAuthView) LoginName() string { return v.ж.LoginName } +func (v RegisterResponseAuthView) Oauth2Token() *Oauth2Token { + if v.ж.Oauth2Token == nil { + return nil + } + x := *v.ж.Oauth2Token + return &x +} + +func (v RegisterResponseAuthView) AuthKey() string { return v.ж.AuthKey } + +// A compilation failure here means this code must be regenerated, with the command at the top of this file. +var _RegisterResponseAuthViewNeedsRegeneration = RegisterResponseAuth(struct { + _ structs.Incomparable + Provider string + LoginName string + Oauth2Token *Oauth2Token + AuthKey string +}{}) + +// View returns a readonly view of RegisterRequest. +func (p *RegisterRequest) View() RegisterRequestView { + return RegisterRequestView{ж: p} +} + +// RegisterRequestView provides a read-only view over RegisterRequest. +// +// Its methods should only be called if `Valid()` returns true. +type RegisterRequestView struct { + // ж is the underlying mutable value, named with a hard-to-type + // character that looks pointy like a pointer. + // It is named distinctively to make you think of how dangerous it is to escape + // to callers. You must not let callers be able to mutate it. + ж *RegisterRequest +} + +// Valid reports whether underlying value is non-nil. +func (v RegisterRequestView) Valid() bool { return v.ж != nil } + +// AsStruct returns a clone of the underlying value which aliases no memory with +// the original. +func (v RegisterRequestView) AsStruct() *RegisterRequest { + if v.ж == nil { + return nil + } + return v.ж.Clone() +} + +func (v RegisterRequestView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } + +func (v *RegisterRequestView) UnmarshalJSON(b []byte) error { + if v.ж != nil { + return errors.New("already initialized") + } + if len(b) == 0 { + return nil + } + var x RegisterRequest + if err := json.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +func (v RegisterRequestView) Version() CapabilityVersion { return v.ж.Version } +func (v RegisterRequestView) NodeKey() key.NodePublic { return v.ж.NodeKey } +func (v RegisterRequestView) OldNodeKey() key.NodePublic { return v.ж.OldNodeKey } +func (v RegisterRequestView) NLKey() key.NLPublic { return v.ж.NLKey } +func (v RegisterRequestView) Auth() RegisterResponseAuthView { return v.ж.Auth.View() } +func (v RegisterRequestView) Expiry() time.Time { return v.ж.Expiry } +func (v RegisterRequestView) Followup() string { return v.ж.Followup } +func (v RegisterRequestView) Hostinfo() HostinfoView { return v.ж.Hostinfo.View() } +func (v RegisterRequestView) Ephemeral() bool { return v.ж.Ephemeral } +func (v RegisterRequestView) NodeKeySignature() mem.RO { return mem.B(v.ж.NodeKeySignature) } +func (v RegisterRequestView) SignatureType() SignatureType { return v.ж.SignatureType } +func (v RegisterRequestView) Timestamp() *time.Time { + if v.ж.Timestamp == nil { + return nil + } + x := *v.ж.Timestamp + return &x +} + +func (v RegisterRequestView) DeviceCert() mem.RO { return mem.B(v.ж.DeviceCert) } +func (v RegisterRequestView) Signature() mem.RO { return mem.B(v.ж.Signature) } + +// A compilation failure here means this code must be regenerated, with the command at the top of this file. +var _RegisterRequestViewNeedsRegeneration = RegisterRequest(struct { + _ structs.Incomparable + Version CapabilityVersion + NodeKey key.NodePublic + OldNodeKey key.NodePublic + NLKey key.NLPublic + Auth RegisterResponseAuth + Expiry time.Time + Followup string + Hostinfo *Hostinfo + Ephemeral bool + NodeKeySignature tkatype.MarshaledSignature + SignatureType SignatureType + Timestamp *time.Time + DeviceCert []byte + Signature []byte +}{}) + // View returns a readonly view of DERPHomeParams. func (p *DERPHomeParams) View() DERPHomeParamsView { return DERPHomeParamsView{ж: p}