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 9 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"
loginMethodPrefKey = "loginmethod"
customLoginServerPrefKey = "customloginserver"
exitNodePrefKey = "exitnode"
exitAllowLANPrefKey = "exitallowlan"
)
const (

@ -175,6 +175,7 @@ type RouteAllEvent struct {
type ConnectEvent struct {
Enable bool
SettingsRestoreEvent
}
type CopyEvent struct {
@ -199,11 +200,14 @@ type SetLoginServerEvent struct {
URL string
}
type WebAuthEvent struct {
SettingsRestoreEvent
}
// UIEvent types.
type (
ReauthEvent struct{}
BugEvent struct{}
WebAuthEvent struct{}
GoogleAuthEvent struct{}
LogoutEvent struct{}
OSSLicensesEvent struct{}
@ -211,6 +215,42 @@ type (
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
// by GoogleSignInOptions.Builder.requestIdToken.
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)
case ExitAllowLANEvent:
state.Prefs.ExitNodeAllowLANAccess = bool(e)
a.store.WriteBool(exitAllowLANPrefKey, true)
go b.backend.SetPrefs(state.Prefs)
case WebAuthEvent:
if !signingIn {
go a.localAPI.Login(ctx, a.backend)
setCustomServer, setExitNode, setAllowLANAccess := a.restoreSettings(&e, state, service)
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:
state.Prefs.ControlURL = e.URL
a.store.WriteString(customLoginServerPrefKey, e.URL)
b.backend.SetPrefs(state.Prefs)
// Need to restart to force the login URL to be regenerated
// 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.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:
state.Prefs.ExitNodeID = e.ID
go b.backend.SetPrefs(state.Prefs)
a.store.WriteString(exitNodePrefKey, string(e.ID))
state.updateExitNodes()
a.notify(state)
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 {
files, err := b.WaitingFiles()
if err != nil {
@ -1290,6 +1383,7 @@ func (a *App) processUIEvents(w *app.Window, events []UIEvent, act jni.Object, s
case ExitAllowLANEvent:
requestBackend(e)
case WebAuthEvent:
a.decorateEventWithStoredSettings(&e, state)
a.store.WriteString(loginMethodPrefKey, loginMethodWeb)
requestBackend(e)
case SetLoginServerEvent:
@ -1299,11 +1393,7 @@ func (a *App) processUIEvents(w *app.Window, events []UIEvent, act jni.Object, s
a.signOut()
requestBackend(e)
case ConnectEvent:
if srv, _ := a.store.ReadString(customLoginServerPrefKey, ""); srv != state.backend.Prefs.ControlURL {
requestBackend(SetLoginServerEvent{URL: srv})
// wait a moment for the backend to restart
<-time.After(200 * time.Millisecond)
}
a.decorateEventWithStoredSettings(&e, state)
requestBackend(e)
case RouteAllEvent:
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) {
go func() {
var totalSize int64

Loading…
Cancel
Save