2023-01-27 21:37:20 +00:00
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
2022-11-09 05:58:10 +00:00
package ipnlocal
import (
2024-05-06 22:22:17 +00:00
"encoding/json"
2022-11-17 14:05:02 +00:00
"fmt"
2023-04-14 23:13:06 +00:00
"os/user"
2023-02-07 05:18:21 +00:00
"strconv"
2022-11-09 05:58:10 +00:00
"testing"
2023-08-05 01:50:39 +00:00
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
2024-04-22 22:55:25 +00:00
"tailscale.com/clientupdate"
2024-05-06 22:22:17 +00:00
"tailscale.com/envknob"
2024-05-03 14:59:22 +00:00
"tailscale.com/health"
2022-11-09 05:58:10 +00:00
"tailscale.com/ipn"
"tailscale.com/ipn/store/mem"
2022-11-16 11:17:36 +00:00
"tailscale.com/tailcfg"
"tailscale.com/types/key"
2022-11-09 05:58:10 +00:00
"tailscale.com/types/logger"
2024-05-06 22:22:17 +00:00
"tailscale.com/types/opt"
2022-11-09 05:58:10 +00:00
"tailscale.com/types/persist"
2023-08-05 01:50:39 +00:00
"tailscale.com/util/must"
2022-11-09 05:58:10 +00:00
)
2022-11-22 13:34:28 +00:00
func TestProfileCurrentUserSwitch ( t * testing . T ) {
store := new ( mem . Store )
2024-05-03 14:59:22 +00:00
pm , err := newProfileManagerWithGOOS ( store , logger . Discard , new ( health . Tracker ) , "linux" )
2022-11-22 13:34:28 +00:00
if err != nil {
t . Fatal ( err )
}
id := 0
newProfile := func ( t * testing . T , loginName string ) ipn . PrefsView {
id ++
t . Helper ( )
pm . NewProfile ( )
p := pm . CurrentPrefs ( ) . AsStruct ( )
p . Persist = & persist . Persist {
NodeID : tailcfg . StableNodeID ( fmt . Sprint ( id ) ) ,
PrivateNodeKey : key . NewNode ( ) ,
UserProfile : tailcfg . UserProfile {
ID : tailcfg . UserID ( id ) ,
LoginName : loginName ,
} ,
}
2023-11-17 02:40:23 +00:00
if err := pm . SetPrefs ( p . View ( ) , ipn . NetworkProfile { } ) ; err != nil {
2022-11-22 13:34:28 +00:00
t . Fatal ( err )
}
return p . View ( )
}
2022-11-25 14:11:06 +00:00
pm . SetCurrentUserID ( "user1" )
2022-11-22 13:34:28 +00:00
newProfile ( t , "user1" )
cp := pm . currentProfile
pm . DeleteProfile ( cp . ID )
if pm . currentProfile == nil {
t . Fatal ( "currentProfile is nil" )
} else if pm . currentProfile . ID != "" {
t . Fatalf ( "currentProfile.ID = %q, want empty" , pm . currentProfile . ID )
}
2023-01-04 17:34:31 +00:00
if ! pm . CurrentPrefs ( ) . Equals ( defaultPrefs ) {
2022-11-22 13:34:28 +00:00
t . Fatalf ( "CurrentPrefs() = %v, want emptyPrefs" , pm . CurrentPrefs ( ) . Pretty ( ) )
}
2024-05-03 14:59:22 +00:00
pm , err = newProfileManagerWithGOOS ( store , logger . Discard , new ( health . Tracker ) , "linux" )
2022-11-22 13:34:28 +00:00
if err != nil {
t . Fatal ( err )
}
2022-11-25 14:11:06 +00:00
pm . SetCurrentUserID ( "user1" )
2022-11-22 13:34:28 +00:00
if pm . currentProfile == nil {
t . Fatal ( "currentProfile is nil" )
} else if pm . currentProfile . ID != "" {
t . Fatalf ( "currentProfile.ID = %q, want empty" , pm . currentProfile . ID )
}
2023-01-04 17:34:31 +00:00
if ! pm . CurrentPrefs ( ) . Equals ( defaultPrefs ) {
2022-11-22 13:34:28 +00:00
t . Fatalf ( "CurrentPrefs() = %v, want emptyPrefs" , pm . CurrentPrefs ( ) . Pretty ( ) )
}
}
2022-11-22 07:02:16 +00:00
func TestProfileList ( t * testing . T ) {
store := new ( mem . Store )
2024-05-03 14:59:22 +00:00
pm , err := newProfileManagerWithGOOS ( store , logger . Discard , new ( health . Tracker ) , "linux" )
2022-11-22 07:02:16 +00:00
if err != nil {
t . Fatal ( err )
}
id := 0
newProfile := func ( t * testing . T , loginName string ) ipn . PrefsView {
id ++
t . Helper ( )
pm . NewProfile ( )
p := pm . CurrentPrefs ( ) . AsStruct ( )
p . Persist = & persist . Persist {
NodeID : tailcfg . StableNodeID ( fmt . Sprint ( id ) ) ,
PrivateNodeKey : key . NewNode ( ) ,
UserProfile : tailcfg . UserProfile {
ID : tailcfg . UserID ( id ) ,
LoginName : loginName ,
} ,
}
2023-11-17 02:40:23 +00:00
if err := pm . SetPrefs ( p . View ( ) , ipn . NetworkProfile { } ) ; err != nil {
2022-11-22 07:02:16 +00:00
t . Fatal ( err )
}
return p . View ( )
}
checkProfiles := func ( t * testing . T , want ... string ) {
t . Helper ( )
got := pm . Profiles ( )
if len ( got ) != len ( want ) {
t . Fatalf ( "got %d profiles, want %d" , len ( got ) , len ( want ) )
}
for i , w := range want {
if got [ i ] . Name != w {
t . Errorf ( "got profile %d name %q, want %q" , i , got [ i ] . Name , w )
}
}
}
2022-11-25 14:11:06 +00:00
pm . SetCurrentUserID ( "user1" )
2022-11-22 07:02:16 +00:00
newProfile ( t , "alice" )
newProfile ( t , "bob" )
checkProfiles ( t , "alice" , "bob" )
2022-11-25 14:11:06 +00:00
pm . SetCurrentUserID ( "user2" )
2022-11-22 07:02:16 +00:00
checkProfiles ( t )
newProfile ( t , "carol" )
carol := pm . currentProfile
checkProfiles ( t , "carol" )
2022-11-25 14:11:06 +00:00
pm . SetCurrentUserID ( "user1" )
2022-11-22 07:02:16 +00:00
checkProfiles ( t , "alice" , "bob" )
if lp := pm . findProfileByKey ( carol . Key ) ; lp != nil {
t . Fatalf ( "found profile for user2 in user1's profile list" )
}
if lp := pm . findProfileByName ( carol . Name ) ; lp != nil {
t . Fatalf ( "found profile for user2 in user1's profile list" )
}
2022-11-25 14:11:06 +00:00
pm . SetCurrentUserID ( "user2" )
2022-11-22 07:02:16 +00:00
checkProfiles ( t , "carol" )
2023-08-05 01:50:39 +00:00
}
func TestProfileDupe ( t * testing . T ) {
newPersist := func ( user , node int ) * persist . Persist {
return & persist . Persist {
NodeID : tailcfg . StableNodeID ( fmt . Sprintf ( "node%d" , node ) ) ,
UserProfile : tailcfg . UserProfile {
ID : tailcfg . UserID ( user ) ,
LoginName : fmt . Sprintf ( "user%d@example.com" , user ) ,
} ,
}
2022-11-29 23:16:01 +00:00
}
2023-08-05 01:50:39 +00:00
user1Node1 := newPersist ( 1 , 1 )
user1Node2 := newPersist ( 1 , 2 )
user2Node1 := newPersist ( 2 , 1 )
user2Node2 := newPersist ( 2 , 2 )
user3Node3 := newPersist ( 3 , 3 )
reauth := func ( pm * profileManager , p * persist . Persist ) {
prefs := ipn . NewPrefs ( )
prefs . Persist = p
2023-11-17 02:40:23 +00:00
must . Do ( pm . SetPrefs ( prefs . View ( ) , ipn . NetworkProfile { } ) )
2022-11-29 23:16:01 +00:00
}
2023-08-05 01:50:39 +00:00
login := func ( pm * profileManager , p * persist . Persist ) {
pm . NewProfile ( )
reauth ( pm , p )
}
type step struct {
fn func ( pm * profileManager , p * persist . Persist )
p * persist . Persist
}
tests := [ ] struct {
name string
steps [ ] step
profs [ ] * persist . Persist
} {
{
name : "reauth-new-node" ,
steps : [ ] step {
{ login , user1Node1 } ,
{ reauth , user3Node3 } ,
} ,
profs : [ ] * persist . Persist {
user3Node3 ,
} ,
} ,
{
name : "reauth-same-node" ,
steps : [ ] step {
{ login , user1Node1 } ,
{ reauth , user1Node1 } ,
} ,
profs : [ ] * persist . Persist {
user1Node1 ,
} ,
} ,
{
name : "reauth-other-profile" ,
steps : [ ] step {
{ login , user1Node1 } ,
{ login , user2Node2 } ,
{ reauth , user1Node1 } ,
} ,
profs : [ ] * persist . Persist {
user1Node1 ,
2023-08-04 19:22:33 +00:00
user2Node2 ,
2023-08-05 01:50:39 +00:00
} ,
} ,
{
name : "reauth-replace-user" ,
steps : [ ] step {
{ login , user1Node1 } ,
{ login , user3Node3 } ,
{ reauth , user2Node1 } ,
} ,
profs : [ ] * persist . Persist {
user2Node1 ,
2023-08-04 19:22:33 +00:00
user3Node3 ,
2023-08-05 01:50:39 +00:00
} ,
} ,
{
name : "reauth-replace-node" ,
steps : [ ] step {
{ login , user1Node1 } ,
{ login , user3Node3 } ,
{ reauth , user1Node2 } ,
} ,
profs : [ ] * persist . Persist {
user1Node2 ,
2023-08-04 19:22:33 +00:00
user3Node3 ,
2023-08-05 01:50:39 +00:00
} ,
} ,
{
name : "login-same-node" ,
steps : [ ] step {
{ login , user1Node1 } ,
{ login , user3Node3 } , // random other profile
{ login , user1Node1 } ,
} ,
profs : [ ] * persist . Persist {
user1Node1 ,
user3Node3 ,
} ,
} ,
{
name : "login-replace-user" ,
steps : [ ] step {
{ login , user1Node1 } ,
{ login , user3Node3 } , // random other profile
{ login , user2Node1 } ,
} ,
profs : [ ] * persist . Persist {
user2Node1 ,
user3Node3 ,
} ,
} ,
{
name : "login-replace-node" ,
steps : [ ] step {
{ login , user1Node1 } ,
{ login , user3Node3 } , // random other profile
{ login , user1Node2 } ,
} ,
profs : [ ] * persist . Persist {
user1Node2 ,
user3Node3 ,
} ,
} ,
{
name : "login-new-node" ,
steps : [ ] step {
{ login , user1Node1 } ,
{ login , user2Node2 } ,
} ,
profs : [ ] * persist . Persist {
user1Node1 ,
user2Node2 ,
} ,
} ,
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
store := new ( mem . Store )
2024-05-03 14:59:22 +00:00
pm , err := newProfileManagerWithGOOS ( store , logger . Discard , new ( health . Tracker ) , "linux" )
2023-08-05 01:50:39 +00:00
if err != nil {
t . Fatal ( err )
}
for _ , s := range tc . steps {
s . fn ( pm , s . p )
}
profs := pm . Profiles ( )
var got [ ] * persist . Persist
for _ , p := range profs {
prefs , err := pm . loadSavedPrefs ( p . Key )
if err != nil {
t . Fatal ( err )
}
got = append ( got , prefs . Persist ( ) . AsStruct ( ) )
}
d := cmp . Diff ( tc . profs , got , cmpopts . SortSlices ( func ( a , b * persist . Persist ) bool {
if a . NodeID != b . NodeID {
return a . NodeID < b . NodeID
}
return a . UserProfile . ID < b . UserProfile . ID
} ) )
if d != "" {
t . Fatal ( d )
}
} )
}
}
2022-11-29 23:16:01 +00:00
2022-11-09 05:58:10 +00:00
// TestProfileManagement tests creating, loading, and switching profiles.
func TestProfileManagement ( t * testing . T ) {
store := new ( mem . Store )
2024-05-03 14:59:22 +00:00
pm , err := newProfileManagerWithGOOS ( store , logger . Discard , new ( health . Tracker ) , "linux" )
2022-11-09 05:58:10 +00:00
if err != nil {
t . Fatal ( err )
}
wantCurProfile := ""
wantProfiles := map [ string ] ipn . PrefsView {
2023-01-04 17:34:31 +00:00
"" : defaultPrefs ,
2022-11-09 05:58:10 +00:00
}
checkProfiles := func ( t * testing . T ) {
t . Helper ( )
prof := pm . CurrentProfile ( )
t . Logf ( "\tCurrentProfile = %q" , prof )
if prof . Name != wantCurProfile {
t . Fatalf ( "CurrentProfile = %q; want %q" , prof , wantCurProfile )
}
profiles := pm . Profiles ( )
wantLen := len ( wantProfiles )
if _ , ok := wantProfiles [ "" ] ; ok {
wantLen --
}
if len ( profiles ) != wantLen {
t . Fatalf ( "Profiles = %v; want %v" , profiles , wantProfiles )
}
p := pm . CurrentPrefs ( )
2024-04-22 22:55:25 +00:00
t . Logf ( "\tCurrentPrefs = %s" , p . Pretty ( ) )
2022-11-09 05:58:10 +00:00
if ! p . Valid ( ) {
t . Fatalf ( "CurrentPrefs = %v; want valid" , p )
}
if ! p . Equals ( wantProfiles [ wantCurProfile ] ) {
t . Fatalf ( "CurrentPrefs = %v; want %v" , p . Pretty ( ) , wantProfiles [ wantCurProfile ] . Pretty ( ) )
}
for _ , p := range profiles {
got , err := pm . loadSavedPrefs ( p . Key )
if err != nil {
t . Fatal ( err )
}
// Use Hostname as a proxy for all prefs.
2022-11-16 11:17:36 +00:00
if ! got . Equals ( wantProfiles [ p . Name ] ) {
t . Fatalf ( "Prefs for profile %q =\n got=%+v\nwant=%v" , p , got . Pretty ( ) , wantProfiles [ p . Name ] . Pretty ( ) )
2022-11-09 05:58:10 +00:00
}
}
}
2022-11-16 11:17:36 +00:00
logins := make ( map [ string ] tailcfg . UserID )
2022-11-17 14:05:02 +00:00
nodeIDs := make ( map [ string ] tailcfg . StableNodeID )
2022-11-09 05:58:10 +00:00
setPrefs := func ( t * testing . T , loginName string ) ipn . PrefsView {
2022-11-16 11:17:36 +00:00
t . Helper ( )
2022-11-09 05:58:10 +00:00
p := pm . CurrentPrefs ( ) . AsStruct ( )
2022-11-17 14:05:02 +00:00
uid := logins [ loginName ]
if uid . IsZero ( ) {
uid = tailcfg . UserID ( len ( logins ) + 1 )
logins [ loginName ] = uid
}
nid := nodeIDs [ loginName ]
if nid . IsZero ( ) {
nid = tailcfg . StableNodeID ( fmt . Sprint ( len ( nodeIDs ) + 1 ) )
nodeIDs [ loginName ] = nid
2022-11-16 11:17:36 +00:00
}
2022-11-09 05:58:10 +00:00
p . Persist = & persist . Persist {
2022-11-16 11:17:36 +00:00
PrivateNodeKey : key . NewNode ( ) ,
UserProfile : tailcfg . UserProfile {
2022-11-17 14:05:02 +00:00
ID : uid ,
2022-11-16 11:17:36 +00:00
LoginName : loginName ,
} ,
2022-11-17 14:05:02 +00:00
NodeID : nid ,
2022-11-09 05:58:10 +00:00
}
2023-11-17 02:40:23 +00:00
if err := pm . SetPrefs ( p . View ( ) , ipn . NetworkProfile { } ) ; err != nil {
2022-11-09 05:58:10 +00:00
t . Fatal ( err )
}
return p . View ( )
}
t . Logf ( "Check initial state from empty store" )
checkProfiles ( t )
{
t . Logf ( "Set prefs for default profile" )
wantProfiles [ "user@1.example.com" ] = setPrefs ( t , "user@1.example.com" )
wantCurProfile = "user@1.example.com"
delete ( wantProfiles , "" )
}
checkProfiles ( t )
t . Logf ( "Create new profile" )
pm . NewProfile ( )
wantCurProfile = ""
2023-01-04 17:34:31 +00:00
wantProfiles [ "" ] = defaultPrefs
2022-11-09 05:58:10 +00:00
checkProfiles ( t )
{
t . Logf ( "Set prefs for test profile" )
wantProfiles [ "user@2.example.com" ] = setPrefs ( t , "user@2.example.com" )
wantCurProfile = "user@2.example.com"
delete ( wantProfiles , "" )
}
checkProfiles ( t )
t . Logf ( "Recreate profile manager from store" )
// Recreate the profile manager to ensure that it can load the profiles
// from the store at startup.
2024-05-03 14:59:22 +00:00
pm , err = newProfileManagerWithGOOS ( store , logger . Discard , new ( health . Tracker ) , "linux" )
2022-11-09 05:58:10 +00:00
if err != nil {
t . Fatal ( err )
}
checkProfiles ( t )
t . Logf ( "Delete default profile" )
if err := pm . DeleteProfile ( pm . findProfileByName ( "user@1.example.com" ) . ID ) ; err != nil {
t . Fatal ( err )
}
delete ( wantProfiles , "user@1.example.com" )
checkProfiles ( t )
t . Logf ( "Recreate profile manager from store after deleting default profile" )
// Recreate the profile manager to ensure that it can load the profiles
// from the store at startup.
2024-05-03 14:59:22 +00:00
pm , err = newProfileManagerWithGOOS ( store , logger . Discard , new ( health . Tracker ) , "linux" )
2022-11-09 05:58:10 +00:00
if err != nil {
t . Fatal ( err )
}
checkProfiles ( t )
2022-11-16 11:17:36 +00:00
2022-11-17 14:05:02 +00:00
t . Logf ( "Create new profile - 2" )
2022-11-16 11:17:36 +00:00
pm . NewProfile ( )
wantCurProfile = ""
2023-01-04 17:34:31 +00:00
wantProfiles [ "" ] = defaultPrefs
2022-11-16 11:17:36 +00:00
checkProfiles ( t )
t . Logf ( "Login with the existing profile" )
wantProfiles [ "user@2.example.com" ] = setPrefs ( t , "user@2.example.com" )
delete ( wantProfiles , "" )
wantCurProfile = "user@2.example.com"
checkProfiles ( t )
2022-11-17 14:05:02 +00:00
t . Logf ( "Tag the current the profile" )
nodeIDs [ "tagged-node.2.ts.net" ] = nodeIDs [ "user@2.example.com" ]
wantProfiles [ "tagged-node.2.ts.net" ] = setPrefs ( t , "tagged-node.2.ts.net" )
delete ( wantProfiles , "user@2.example.com" )
wantCurProfile = "tagged-node.2.ts.net"
checkProfiles ( t )
t . Logf ( "Relogin" )
wantProfiles [ "user@2.example.com" ] = setPrefs ( t , "user@2.example.com" )
delete ( wantProfiles , "tagged-node.2.ts.net" )
wantCurProfile = "user@2.example.com"
checkProfiles ( t )
2024-04-22 22:55:25 +00:00
if ! clientupdate . CanAutoUpdate ( ) {
t . Logf ( "Save an invalid AutoUpdate pref value" )
prefs := pm . CurrentPrefs ( ) . AsStruct ( )
prefs . AutoUpdate . Apply . Set ( true )
if err := pm . SetPrefs ( prefs . View ( ) , ipn . NetworkProfile { } ) ; err != nil {
t . Fatal ( err )
}
if ! pm . CurrentPrefs ( ) . AutoUpdate ( ) . Apply . EqualBool ( true ) {
t . Fatal ( "SetPrefs failed to save auto-update setting" )
}
// Re-load profiles to trigger migration for invalid auto-update value.
2024-05-03 14:59:22 +00:00
pm , err = newProfileManagerWithGOOS ( store , logger . Discard , new ( health . Tracker ) , "linux" )
2024-04-22 22:55:25 +00:00
if err != nil {
t . Fatal ( err )
}
checkProfiles ( t )
if pm . CurrentPrefs ( ) . AutoUpdate ( ) . Apply . EqualBool ( true ) {
t . Fatal ( "invalid auto-update setting persisted after reload" )
}
}
2022-11-09 05:58:10 +00:00
}
// TestProfileManagementWindows tests going into and out of Unattended mode on
// Windows.
func TestProfileManagementWindows ( t * testing . T ) {
2023-04-14 23:13:06 +00:00
u , err := user . Current ( )
if err != nil {
t . Fatal ( err )
2023-04-14 18:09:21 +00:00
}
2023-04-14 23:13:06 +00:00
uid := ipn . WindowsUserID ( u . Uid )
2023-04-14 18:09:21 +00:00
2022-11-09 05:58:10 +00:00
store := new ( mem . Store )
2024-05-03 14:59:22 +00:00
pm , err := newProfileManagerWithGOOS ( store , logger . Discard , new ( health . Tracker ) , "windows" )
2022-11-09 05:58:10 +00:00
if err != nil {
t . Fatal ( err )
}
wantCurProfile := ""
wantProfiles := map [ string ] ipn . PrefsView {
2023-01-04 17:34:31 +00:00
"" : defaultPrefs ,
2022-11-09 05:58:10 +00:00
}
checkProfiles := func ( t * testing . T ) {
t . Helper ( )
prof := pm . CurrentProfile ( )
t . Logf ( "\tCurrentProfile = %q" , prof )
if prof . Name != wantCurProfile {
t . Fatalf ( "CurrentProfile = %q; want %q" , prof , wantCurProfile )
}
if p := pm . CurrentPrefs ( ) ; ! p . Equals ( wantProfiles [ wantCurProfile ] ) {
t . Fatalf ( "CurrentPrefs = %+v; want %+v" , p . Pretty ( ) , wantProfiles [ wantCurProfile ] . Pretty ( ) )
}
}
2022-11-16 11:17:36 +00:00
logins := make ( map [ string ] tailcfg . UserID )
2022-11-09 05:58:10 +00:00
setPrefs := func ( t * testing . T , loginName string , forceDaemon bool ) ipn . PrefsView {
2022-11-16 11:17:36 +00:00
id := logins [ loginName ]
if id . IsZero ( ) {
id = tailcfg . UserID ( len ( logins ) + 1 )
logins [ loginName ] = id
}
2022-11-09 05:58:10 +00:00
p := pm . CurrentPrefs ( ) . AsStruct ( )
p . ForceDaemon = forceDaemon
p . Persist = & persist . Persist {
2022-11-16 11:17:36 +00:00
UserProfile : tailcfg . UserProfile {
ID : id ,
LoginName : loginName ,
} ,
2023-02-07 05:18:21 +00:00
NodeID : tailcfg . StableNodeID ( strconv . Itoa ( int ( id ) ) ) ,
2022-11-09 05:58:10 +00:00
}
2023-11-17 02:40:23 +00:00
if err := pm . SetPrefs ( p . View ( ) , ipn . NetworkProfile { } ) ; err != nil {
2022-11-09 05:58:10 +00:00
t . Fatal ( err )
}
return p . View ( )
}
t . Logf ( "Check initial state from empty store" )
checkProfiles ( t )
{
t . Logf ( "Set user1 as logged in user" )
2023-04-14 23:13:06 +00:00
if err := pm . SetCurrentUserID ( uid ) ; err != nil {
t . Fatalf ( "can't set user id: %s" , err )
2022-11-09 05:58:10 +00:00
}
checkProfiles ( t )
t . Logf ( "Save prefs for user1" )
wantProfiles [ "default" ] = setPrefs ( t , "default" , false )
wantCurProfile = "default"
}
checkProfiles ( t )
{
t . Logf ( "Create new profile" )
pm . NewProfile ( )
wantCurProfile = ""
2023-01-04 17:34:31 +00:00
wantProfiles [ "" ] = defaultPrefs
2022-11-09 05:58:10 +00:00
checkProfiles ( t )
t . Logf ( "Save as test profile" )
wantProfiles [ "test" ] = setPrefs ( t , "test" , false )
wantCurProfile = "test"
checkProfiles ( t )
}
t . Logf ( "Recreate profile manager from store, should reset prefs" )
// Recreate the profile manager to ensure that it can load the profiles
// from the store at startup.
2024-05-03 14:59:22 +00:00
pm , err = newProfileManagerWithGOOS ( store , logger . Discard , new ( health . Tracker ) , "windows" )
2022-11-09 05:58:10 +00:00
if err != nil {
t . Fatal ( err )
}
wantCurProfile = ""
2023-01-04 17:34:31 +00:00
wantProfiles [ "" ] = defaultPrefs
2022-11-09 05:58:10 +00:00
checkProfiles ( t )
{
t . Logf ( "Set user1 as current user" )
2023-04-14 23:13:06 +00:00
if err := pm . SetCurrentUserID ( uid ) ; err != nil {
2022-11-09 05:58:10 +00:00
t . Fatal ( err )
}
wantCurProfile = "test"
}
checkProfiles ( t )
{
t . Logf ( "set unattended mode" )
wantProfiles [ "test" ] = setPrefs ( t , "test" , true )
}
2023-04-14 23:13:06 +00:00
if pm . CurrentUserID ( ) != uid {
t . Fatalf ( "CurrentUserID = %q; want %q" , pm . CurrentUserID ( ) , uid )
2022-11-09 05:58:10 +00:00
}
// Recreate the profile manager to ensure that it starts with test profile.
2024-05-03 14:59:22 +00:00
pm , err = newProfileManagerWithGOOS ( store , logger . Discard , new ( health . Tracker ) , "windows" )
2022-11-09 05:58:10 +00:00
if err != nil {
t . Fatal ( err )
}
checkProfiles ( t )
2023-04-14 23:13:06 +00:00
if pm . CurrentUserID ( ) != uid {
t . Fatalf ( "CurrentUserID = %q; want %q" , pm . CurrentUserID ( ) , uid )
2022-11-09 05:58:10 +00:00
}
}
2024-05-06 22:22:17 +00:00
func TestProfileBackfillStatefulFiltering ( t * testing . T ) {
envknob . Setenv ( "TS_DEBUG_PROFILES" , "true" )
tests := [ ] struct {
noSNAT bool
noStateful opt . Bool
want bool
} {
// Default: NoSNAT is false, NoStatefulFiltering is false, so
// we want it to stay false.
{ false , "false" , false } ,
// NoSNAT being set to true and NoStatefulFiltering being false
// should result in NoStatefulFiltering still being false,
// since it was explicitly set.
{ true , "false" , false } ,
// If NoSNAT is false, and NoStatefulFiltering is unset, we
// backfill it to 'false'.
{ false , "" , false } ,
// If NoSNAT is true, and NoStatefulFiltering is unset, we
// backfill to 'true' to not break users of NoSNAT.
//
// In other words: if the user is not using SNAT, they almost
// certainly also don't want to use stateful filtering.
{ true , "" , true } ,
// However, if the user specifies both NoSNAT and stateful
// filtering, don't change that.
{ true , "true" , true } ,
{ false , "true" , true } ,
}
for _ , tt := range tests {
t . Run ( fmt . Sprintf ( "noSNAT=%v,noStateful=%q" , tt . noSNAT , tt . noStateful ) , func ( t * testing . T ) {
prefs := ipn . NewPrefs ( )
prefs . Persist = & persist . Persist {
NodeID : tailcfg . StableNodeID ( "node1" ) ,
UserProfile : tailcfg . UserProfile {
ID : tailcfg . UserID ( 1 ) ,
LoginName : "user1@example.com" ,
} ,
}
prefs . NoSNAT = tt . noSNAT
prefs . NoStatefulFiltering = tt . noStateful
// Make enough of a state store to load the prefs.
const profileName = "profile1"
bn := must . Get ( json . Marshal ( map [ string ] any {
string ( ipn . CurrentProfileStateKey ) : [ ] byte ( profileName ) ,
string ( ipn . KnownProfilesStateKey ) : must . Get ( json . Marshal ( map [ ipn . ProfileID ] * ipn . LoginProfile {
profileName : {
ID : "profile1-id" ,
Key : profileName ,
} ,
} ) ) ,
profileName : prefs . ToBytes ( ) ,
} ) )
store := new ( mem . Store )
err := store . LoadFromJSON ( [ ] byte ( bn ) )
if err != nil {
t . Fatal ( err )
}
ht := new ( health . Tracker )
pm , err := newProfileManagerWithGOOS ( store , t . Logf , ht , "linux" )
if err != nil {
t . Fatal ( err )
}
// Get the current profile and verify that we backfilled our
// StatefulFiltering boolean.
pf := pm . CurrentPrefs ( )
if ! pf . NoStatefulFiltering ( ) . EqualBool ( tt . want ) {
2024-05-07 17:28:22 +00:00
t . Fatalf ( "got NoStatefulFiltering=%q, want %v" , pf . NoStatefulFiltering ( ) , tt . want )
2024-05-06 22:22:17 +00:00
}
} )
}
}
2024-05-07 17:28:22 +00:00
// TestDefaultPrefs tests that defaultPrefs is just NewPrefs with
// LoggedOut=true (the Prefs we use before connecting to control). We shouldn't
// be putting any defaulting there, and instead put all defaults in NewPrefs.
func TestDefaultPrefs ( t * testing . T ) {
p1 := ipn . NewPrefs ( )
p1 . LoggedOut = true
p1 . WantRunning = false
p2 := defaultPrefs
if ! p1 . View ( ) . Equals ( p2 ) {
t . Errorf ( "defaultPrefs is %s, want %s; defaultPrefs should only modify WantRunning and LoggedOut, all other defaults should be in ipn.NewPrefs." , p2 . Pretty ( ) , p1 . Pretty ( ) )
}
}