2023-01-27 21:37:20 +00:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2021-02-05 23:23:01 +00:00
|
|
|
|
|
|
|
// Package persist contains the Persist type.
|
|
|
|
package persist
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2022-11-29 20:00:40 +00:00
|
|
|
"reflect"
|
2021-02-05 23:23:01 +00:00
|
|
|
|
2022-11-09 05:58:10 +00:00
|
|
|
"tailscale.com/tailcfg"
|
2021-09-03 20:17:46 +00:00
|
|
|
"tailscale.com/types/key"
|
2021-02-05 23:23:01 +00:00
|
|
|
"tailscale.com/types/structs"
|
|
|
|
)
|
|
|
|
|
2022-10-21 23:05:43 +00:00
|
|
|
//go:generate go run tailscale.com/cmd/viewer -type=Persist
|
2021-02-05 23:23:01 +00:00
|
|
|
|
|
|
|
// Persist is the JSON type stored on disk on nodes to remember their
|
2022-11-14 12:29:49 +00:00
|
|
|
// settings between runs. This is stored as part of ipn.Prefs and is
|
|
|
|
// persisted per ipn.LoginProfile.
|
2021-02-05 23:23:01 +00:00
|
|
|
type Persist struct {
|
|
|
|
_ structs.Incomparable
|
|
|
|
|
|
|
|
// LegacyFrontendPrivateMachineKey is here temporarily
|
|
|
|
// (starting 2020-09-28) during migration of Windows users'
|
|
|
|
// machine keys from frontend storage to the backend. On the
|
|
|
|
// first LocalBackend.Start call, the backend will initialize
|
|
|
|
// the real (backend-owned) machine key from the frontend's
|
|
|
|
// provided value (if non-zero), picking a new random one if
|
|
|
|
// needed. This field should be considered read-only from GUI
|
|
|
|
// frontends. The real value should not be written back in
|
|
|
|
// this field, lest the frontend persist it to disk.
|
2021-09-03 20:17:46 +00:00
|
|
|
LegacyFrontendPrivateMachineKey key.MachinePrivate `json:"PrivateMachineKey"`
|
2021-02-05 23:23:01 +00:00
|
|
|
|
2021-10-28 16:50:58 +00:00
|
|
|
PrivateNodeKey key.NodePrivate
|
|
|
|
OldPrivateNodeKey key.NodePrivate // needed to request key rotation
|
2022-11-09 05:58:10 +00:00
|
|
|
UserProfile tailcfg.UserProfile
|
2022-11-14 12:29:49 +00:00
|
|
|
NetworkLockKey key.NLPrivate
|
2022-11-17 14:05:02 +00:00
|
|
|
NodeID tailcfg.StableNodeID
|
2022-11-29 20:00:40 +00:00
|
|
|
|
|
|
|
// DisallowedTKAStateIDs stores the tka.State.StateID values which
|
|
|
|
// this node will not operate network lock on. This is used to
|
|
|
|
// prevent bootstrapping TKA onto a key authority which was forcibly
|
|
|
|
// disabled.
|
|
|
|
DisallowedTKAStateIDs []string `json:",omitempty"`
|
2021-02-05 23:23:01 +00:00
|
|
|
}
|
|
|
|
|
2022-10-23 07:48:12 +00:00
|
|
|
// PublicNodeKey returns the public key for the node key.
|
|
|
|
func (p *Persist) PublicNodeKey() key.NodePublic {
|
|
|
|
return p.PrivateNodeKey.Public()
|
|
|
|
}
|
|
|
|
|
2024-03-21 19:19:57 +00:00
|
|
|
// PublicNodeKeyOK returns the public key for the node key.
|
|
|
|
//
|
|
|
|
// Unlike PublicNodeKey, it returns ok=false if there is no node private key
|
|
|
|
// instead of panicking.
|
|
|
|
func (p *Persist) PublicNodeKeyOK() (pub key.NodePublic, ok bool) {
|
|
|
|
if p.PrivateNodeKey.IsZero() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return p.PrivateNodeKey.Public(), true
|
|
|
|
}
|
|
|
|
|
2022-11-10 14:43:59 +00:00
|
|
|
// PublicNodeKey returns the public key for the node key.
|
2024-03-21 19:19:57 +00:00
|
|
|
//
|
|
|
|
// It panics if there is no node private key. See PublicNodeKeyOK.
|
2022-11-10 14:43:59 +00:00
|
|
|
func (p PersistView) PublicNodeKey() key.NodePublic {
|
|
|
|
return p.ж.PublicNodeKey()
|
|
|
|
}
|
|
|
|
|
2024-03-21 19:19:57 +00:00
|
|
|
// PublicNodeKeyOK returns the public key for the node key.
|
|
|
|
//
|
|
|
|
// Unlike PublicNodeKey, it returns ok=false if there is no node private key
|
|
|
|
// instead of panicking.
|
|
|
|
func (p PersistView) PublicNodeKeyOK() (_ key.NodePublic, ok bool) {
|
|
|
|
return p.ж.PublicNodeKeyOK()
|
|
|
|
}
|
|
|
|
|
2022-11-10 14:43:59 +00:00
|
|
|
func (p PersistView) Equals(p2 PersistView) bool {
|
|
|
|
return p.ж.Equals(p2.ж)
|
|
|
|
}
|
|
|
|
|
2022-11-29 20:00:40 +00:00
|
|
|
func nilIfEmpty[E any](s []E) []E {
|
|
|
|
if len(s) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2021-02-05 23:23:01 +00:00
|
|
|
func (p *Persist) Equals(p2 *Persist) bool {
|
|
|
|
if p == nil && p2 == nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if p == nil || p2 == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return p.LegacyFrontendPrivateMachineKey.Equal(p2.LegacyFrontendPrivateMachineKey) &&
|
|
|
|
p.PrivateNodeKey.Equal(p2.PrivateNodeKey) &&
|
|
|
|
p.OldPrivateNodeKey.Equal(p2.OldPrivateNodeKey) &&
|
2023-07-23 21:48:03 +00:00
|
|
|
p.UserProfile.Equal(&p2.UserProfile) &&
|
2022-11-17 14:05:02 +00:00
|
|
|
p.NetworkLockKey.Equal(p2.NetworkLockKey) &&
|
2022-11-29 20:00:40 +00:00
|
|
|
p.NodeID == p2.NodeID &&
|
|
|
|
reflect.DeepEqual(nilIfEmpty(p.DisallowedTKAStateIDs), nilIfEmpty(p2.DisallowedTKAStateIDs))
|
2021-02-05 23:23:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Persist) Pretty() string {
|
2021-09-03 20:17:46 +00:00
|
|
|
var (
|
|
|
|
mk key.MachinePublic
|
2021-10-28 16:50:58 +00:00
|
|
|
ok, nk key.NodePublic
|
2021-09-03 20:17:46 +00:00
|
|
|
)
|
2021-02-05 23:23:01 +00:00
|
|
|
if !p.LegacyFrontendPrivateMachineKey.IsZero() {
|
|
|
|
mk = p.LegacyFrontendPrivateMachineKey.Public()
|
|
|
|
}
|
|
|
|
if !p.OldPrivateNodeKey.IsZero() {
|
|
|
|
ok = p.OldPrivateNodeKey.Public()
|
|
|
|
}
|
|
|
|
if !p.PrivateNodeKey.IsZero() {
|
2022-10-23 07:48:12 +00:00
|
|
|
nk = p.PublicNodeKey()
|
2021-02-05 23:23:01 +00:00
|
|
|
}
|
|
|
|
return fmt.Sprintf("Persist{lm=%v, o=%v, n=%v u=%#v}",
|
2023-08-04 00:38:28 +00:00
|
|
|
mk.ShortString(), ok.ShortString(), nk.ShortString(), p.UserProfile.LoginName)
|
2021-02-05 23:23:01 +00:00
|
|
|
}
|