cmd/tailscale/main: restore persisted settings (#169)

Fixes tailscale/tailscale#10748
Fixes tailscale/corp#17470

Signed-off-by: kari-ts <kari@tailscale.com>
pull/183/head
kari-ts 3 months ago committed by GitHub
parent f23477e796
commit 01ec98f29a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

Binary file not shown.

@ -68,6 +68,8 @@ const (
logPrefKey = "privatelogid" logPrefKey = "privatelogid"
loginMethodPrefKey = "loginmethod" loginMethodPrefKey = "loginmethod"
customLoginServerPrefKey = "customloginserver" customLoginServerPrefKey = "customloginserver"
exitNodePrefKey = "exitnode"
exitAllowLANPrefKey = "exitallowlan"
) )
const ( const (

@ -175,6 +175,7 @@ type RouteAllEvent struct {
type ConnectEvent struct { type ConnectEvent struct {
Enable bool Enable bool
SettingsRestoreEvent
} }
type CopyEvent struct { type CopyEvent struct {
@ -199,11 +200,14 @@ type SetLoginServerEvent struct {
URL string URL string
} }
type WebAuthEvent struct {
SettingsRestoreEvent
}
// UIEvent types. // UIEvent types.
type ( type (
ReauthEvent struct{} ReauthEvent struct{}
BugEvent struct{} BugEvent struct{}
WebAuthEvent struct{}
GoogleAuthEvent struct{} GoogleAuthEvent struct{}
LogoutEvent struct{} LogoutEvent struct{}
OSSLicensesEvent struct{} OSSLicensesEvent struct{}
@ -211,6 +215,42 @@ type (
ExitAllowLANEvent bool ExitAllowLANEvent bool
) )
// RestoreEvent represents an event that might restore user settings persisted across sessions.
type RestoreEvent interface {
SetURL(url string)
GetURL() string
SetExitNodeID(exitNodeID tailcfg.StableNodeID)
GetExitNodeID() tailcfg.StableNodeID
SetExitAllowLAN(allowLAN bool)
GetExitAllowLAN() bool
}
type SettingsRestoreEvent struct {
// Custom server login URL
URL string
ExitNodeID tailcfg.StableNodeID
ExitAllowLAN bool
}
func (e *SettingsRestoreEvent) SetURL(url string) {
e.URL = url
}
func (e *SettingsRestoreEvent) GetURL() string {
return e.URL
}
func (e *SettingsRestoreEvent) SetExitNodeID(exitNodeID tailcfg.StableNodeID) {
e.ExitNodeID = exitNodeID
}
func (e *SettingsRestoreEvent) GetExitNodeID() tailcfg.StableNodeID {
return e.ExitNodeID
}
func (e *SettingsRestoreEvent) SetExitAllowLAN(allowLAN bool) {
e.ExitAllowLAN = allowLAN
}
func (e *SettingsRestoreEvent) GetExitAllowLAN() bool {
return e.ExitAllowLAN
}
// serverOAuthID is the OAuth ID of the tailscale-android server, used // serverOAuthID is the OAuth ID of the tailscale-android server, used
// by GoogleSignInOptions.Builder.requestIdToken. // by GoogleSignInOptions.Builder.requestIdToken.
const serverOAuthID = "744055068597-hv4opg0h7vskq1hv37nq3u26t8c15qk0.apps.googleusercontent.com" const serverOAuthID = "744055068597-hv4opg0h7vskq1hv37nq3u26t8c15qk0.apps.googleusercontent.com"
@ -472,14 +512,31 @@ func (a *App) runBackend(ctx context.Context) error {
go b.backend.SetPrefs(state.Prefs) go b.backend.SetPrefs(state.Prefs)
case ExitAllowLANEvent: case ExitAllowLANEvent:
state.Prefs.ExitNodeAllowLANAccess = bool(e) state.Prefs.ExitNodeAllowLANAccess = bool(e)
a.store.WriteBool(exitAllowLANPrefKey, true)
go b.backend.SetPrefs(state.Prefs) go b.backend.SetPrefs(state.Prefs)
case WebAuthEvent: case WebAuthEvent:
if !signingIn { if !signingIn {
go a.localAPI.Login(ctx, a.backend) setCustomServer, setExitNode, setAllowLANAccess := a.restoreSettings(&e, state, service)
signingIn = true signingIn = true
go func() {
if setCustomServer || setExitNode || setAllowLANAccess {
b.backend.SetPrefs(state.Prefs)
}
if setCustomServer {
// Need to restart to force the login URL to be regenerated
// with the new control URL. Start from a goroutine to avoid
// deadlock.
err := b.backend.Start(ipn.Options{})
if err != nil {
fatalErr(err)
}
}
b.backend.StartLoginInteractive()
}()
} }
case SetLoginServerEvent: case SetLoginServerEvent:
state.Prefs.ControlURL = e.URL state.Prefs.ControlURL = e.URL
a.store.WriteString(customLoginServerPrefKey, e.URL)
b.backend.SetPrefs(state.Prefs) b.backend.SetPrefs(state.Prefs)
// Need to restart to force the login URL to be regenerated // Need to restart to force the login URL to be regenerated
// with the new control URL. Start from a goroutine to avoid // with the new control URL. Start from a goroutine to avoid
@ -500,10 +557,23 @@ func (a *App) runBackend(ctx context.Context) error {
state.Prefs = ipn.NewPrefs() state.Prefs = ipn.NewPrefs()
} }
state.Prefs.WantRunning = e.Enable state.Prefs.WantRunning = e.Enable
go b.backend.SetPrefs(state.Prefs) setCustomServer, _, _ := a.restoreSettings(&e, state, service)
go func() {
b.backend.SetPrefs(state.Prefs)
if setCustomServer {
// Need to restart to force the login URL to be regenerated
// with the new control URL. Start from a goroutine to avoid
// deadlock.
err := b.backend.Start(ipn.Options{})
if err != nil {
fatalErr(err)
}
}
}()
case RouteAllEvent: case RouteAllEvent:
state.Prefs.ExitNodeID = e.ID state.Prefs.ExitNodeID = e.ID
go b.backend.SetPrefs(state.Prefs) go b.backend.SetPrefs(state.Prefs)
a.store.WriteString(exitNodePrefKey, string(e.ID))
state.updateExitNodes() state.updateExitNodes()
a.notify(state) a.notify(state)
if service != 0 { if service != 0 {
@ -588,6 +658,29 @@ func (a *App) runBackend(ctx context.Context) error {
} }
} }
func (a *App) restoreSettings(e RestoreEvent, state BackendState, service jni.Object) (bool, bool, bool) {
var setCustomServer bool
var setExitNode bool
var setAllowLANAccess bool
if URL := e.GetURL(); URL != "" {
state.Prefs.ControlURL = URL
setCustomServer = true
}
if nodeID := e.GetExitNodeID(); nodeID != "" {
state.Prefs.ExitNodeID = nodeID
state.updateExitNodes()
a.notify(state)
if service != 0 {
a.updateNotification(service, state.State, state.ExitStatus, state.Exit)
}
setExitNode = true
}
if e.GetExitAllowLAN() {
state.Prefs.ExitNodeAllowLANAccess = true
}
return setCustomServer, setExitNode, setAllowLANAccess
}
func (a *App) processWaitingFiles(b *ipnlocal.LocalBackend) error { func (a *App) processWaitingFiles(b *ipnlocal.LocalBackend) error {
files, err := b.WaitingFiles() files, err := b.WaitingFiles()
if err != nil { if err != nil {
@ -1290,6 +1383,7 @@ func (a *App) processUIEvents(w *app.Window, events []UIEvent, act jni.Object, s
case ExitAllowLANEvent: case ExitAllowLANEvent:
requestBackend(e) requestBackend(e)
case WebAuthEvent: case WebAuthEvent:
a.decorateEventWithStoredSettings(&e, state)
a.store.WriteString(loginMethodPrefKey, loginMethodWeb) a.store.WriteString(loginMethodPrefKey, loginMethodWeb)
requestBackend(e) requestBackend(e)
case SetLoginServerEvent: case SetLoginServerEvent:
@ -1299,11 +1393,7 @@ func (a *App) processUIEvents(w *app.Window, events []UIEvent, act jni.Object, s
a.signOut() a.signOut()
requestBackend(e) requestBackend(e)
case ConnectEvent: case ConnectEvent:
if srv, _ := a.store.ReadString(customLoginServerPrefKey, ""); srv != state.backend.Prefs.ControlURL { a.decorateEventWithStoredSettings(&e, state)
requestBackend(SetLoginServerEvent{URL: srv})
// wait a moment for the backend to restart
<-time.After(200 * time.Millisecond)
}
requestBackend(e) requestBackend(e)
case RouteAllEvent: case RouteAllEvent:
requestBackend(e) requestBackend(e)
@ -1323,6 +1413,24 @@ func (a *App) processUIEvents(w *app.Window, events []UIEvent, act jni.Object, s
} }
} }
func (a *App) decorateEventWithStoredSettings(e RestoreEvent, state *clientState) {
srv, _ := a.store.ReadString(customLoginServerPrefKey, "")
if srv != "" && srv != state.backend.Prefs.ControlURL {
e.SetURL(srv)
}
exitstr, _ := a.store.ReadString(exitNodePrefKey, "")
exitNodeID := tailcfg.StableNodeID(exitstr)
if exitNodeID != "" && exitNodeID != state.backend.Prefs.ExitNodeID {
e.SetExitNodeID(exitNodeID)
}
allowlan, _ := a.store.ReadBool(exitAllowLANPrefKey, false)
if allowlan {
e.SetExitAllowLAN(allowlan)
}
}
func (a *App) sendFiles(e FileSendEvent, files []File) { func (a *App) sendFiles(e FileSendEvent, files []File) {
go func() { go func() {
var totalSize int64 var totalSize int64

Loading…
Cancel
Save