Add ability to choose a custom coordination server

Signed-off-by: Trevor Bergeron <mal@sec.gd>
pull/58/head
Trevor Bergeron 3 years ago committed by Brad Fitzpatrick
parent 4f17005954
commit d8aedf721a

@ -56,8 +56,9 @@ type settingsFunc func(*router.Config, *dns.OSConfig) error
const defaultMTU = 1280 // minimalMTU from wgengine/userspace.go const defaultMTU = 1280 // minimalMTU from wgengine/userspace.go
const ( const (
logPrefKey = "privatelogid" logPrefKey = "privatelogid"
loginMethodPrefKey = "loginmethod" loginMethodPrefKey = "loginmethod"
customLoginServerPrefKey = "customloginserver"
) )
const ( const (

@ -181,6 +181,10 @@ type FileSendEvent struct {
Updates func(FileSendInfo) Updates func(FileSendInfo)
} }
type SetLoginServerEvent struct {
URL string
}
// UIEvent types. // UIEvent types.
type ( type (
ToggleEvent struct{} ToggleEvent struct{}
@ -430,6 +434,12 @@ func (a *App) runBackend() error {
go b.backend.StartLoginInteractive() go b.backend.StartLoginInteractive()
signingIn = true signingIn = true
} }
case SetLoginServerEvent:
state.Prefs.ControlURL = e.URL
b.backend.SetPrefs(state.Prefs)
// A hack to get around ipnlocal's inability to update
// ControlURL after Start()... Can we re-init instead?
os.Exit(0)
case LogoutEvent: case LogoutEvent:
go b.backend.Logout() go b.backend.Logout()
case ConnectEvent: case ConnectEvent:
@ -1108,6 +1118,9 @@ func (a *App) processUIEvents(w *app.Window, events []UIEvent, act jni.Object, s
case WebAuthEvent: case WebAuthEvent:
a.store.WriteString(loginMethodPrefKey, loginMethodWeb) a.store.WriteString(loginMethodPrefKey, loginMethodWeb)
requestBackend(e) requestBackend(e)
case SetLoginServerEvent:
a.store.WriteString(customLoginServerPrefKey, e.URL)
requestBackend(e)
case LogoutEvent: case LogoutEvent:
a.signOut() a.signOut()
requestBackend(e) requestBackend(e)

@ -62,6 +62,11 @@ type UI struct {
signinType signinType signinType signinType
setLoginServer bool
loginServer widget.Editor
loginServerSave widget.Clickable
loginServerCancel widget.Clickable
self widget.Clickable self widget.Clickable
peers []widget.Clickable peers []widget.Clickable
@ -91,12 +96,13 @@ type UI struct {
dismiss Dismiss dismiss Dismiss
show bool show bool
copy widget.Clickable useLoginServer widget.Clickable
reauth widget.Clickable copy widget.Clickable
bug widget.Clickable reauth widget.Clickable
beExit widget.Clickable bug widget.Clickable
exits widget.Clickable beExit widget.Clickable
logout widget.Clickable exits widget.Clickable
logout widget.Clickable
} }
// The current pop-up message, if any // The current pop-up message, if any
@ -238,6 +244,7 @@ func newUI(store *stateStore) (*UI, error) {
ui.root.Axis = layout.Vertical ui.root.Axis = layout.Vertical
ui.intro.list.Axis = layout.Vertical ui.intro.list.Axis = layout.Vertical
ui.search.SingleLine = true ui.search.SingleLine = true
ui.loginServer.SingleLine = true
ui.exitDialog.list.Axis = layout.Vertical ui.exitDialog.list.Axis = layout.Vertical
ui.shareDialog.list.Axis = layout.Vertical ui.shareDialog.list.Axis = layout.Vertical
return ui, nil return ui, nil
@ -338,6 +345,21 @@ func (ui *UI) layout(gtx layout.Context, sysIns system.Insets, state *clientStat
events = append(events, WebAuthEvent{}) events = append(events, WebAuthEvent{})
} }
if ui.loginServerSave.Clicked() {
text := ui.loginServer.Text()
ui.showMessage(gtx, "Login server saved, relaunch the app")
events = append(events, SetLoginServerEvent{URL: text})
}
if ui.loginServerCancel.Clicked() {
ui.setLoginServer = false
}
if ui.menuClicked(&ui.menu.useLoginServer) {
ui.setLoginServer = true
savedLoginServer, _ := ui.store.ReadString(customLoginServerPrefKey, "")
ui.loginServer.SetText(savedLoginServer)
}
if ui.menuClicked(&ui.menu.copy) && localAddr != "" { if ui.menuClicked(&ui.menu.copy) && localAddr != "" {
events = append(events, CopyEvent{Text: localAddr}) events = append(events, CopyEvent{Text: localAddr})
ui.showCopied(gtx, localAddr) ui.showCopied(gtx, localAddr)
@ -496,7 +518,7 @@ func (ui *UI) layout(gtx layout.Context, sysIns system.Insets, state *clientStat
// 3-dots menu. // 3-dots menu.
if ui.menu.show { if ui.menu.show {
ui.layoutMenu(gtx, sysIns, expiry, exitID != "" || len(state.backend.Exits) > 0) ui.layoutMenu(gtx, sysIns, expiry, exitID != "" || len(state.backend.Exits) > 0, needsLogin)
} }
if ui.qr.show { if ui.qr.show {
@ -627,6 +649,43 @@ func (ui *UI) layoutSignIn(gtx layout.Context, state *BackendState) layout.Dimen
) )
border := widget.Border{Color: rgb(textColor), CornerRadius: unit.Dp(4), Width: unit.Px(1)} border := widget.Border{Color: rgb(textColor), CornerRadius: unit.Dp(4), Width: unit.Px(1)}
if ui.setLoginServer {
return layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle}.Layout(gtx,
layout.Rigid(func(gtx C) D {
return layout.Inset{Bottom: unit.Dp(16)}.Layout(gtx, func(gtx C) D {
return Background{Color: rgb(0xe3e2ea), CornerRadius: unit.Dp(8)}.Layout(gtx, func(gtx C) D {
return layout.UniformInset(unit.Dp(8)).Layout(gtx, func(gtx C) D {
return layout.Flex{Alignment: layout.Middle}.Layout(gtx,
layout.Flexed(1,
material.Editor(ui.theme, &ui.loginServer, "https://controlplane.tailscale.com").Layout,
),
)
})
})
})
}),
layout.Rigid(func(gtx C) D {
return layout.Inset{Bottom: unit.Dp(16)}.Layout(gtx, func(gtx C) D {
return border.Layout(gtx, func(gtx C) D {
button := material.Button(ui.theme, &ui.loginServerSave, "Save and restart")
button.Background = color.NRGBA{} // transparent
button.Color = rgb(textColor)
return button.Layout(gtx)
})
})
}),
layout.Rigid(func(gtx C) D {
return border.Layout(gtx, func(gtx C) D {
button := material.Button(ui.theme, &ui.loginServerCancel, "Cancel")
button.Background = color.NRGBA{} // transparent
button.Color = rgb(textColor)
return button.Layout(gtx)
})
}),
)
}
return layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle}.Layout(gtx, return layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle}.Layout(gtx,
layout.Rigid(func(gtx C) D { layout.Rigid(func(gtx C) D {
if !googleSignInEnabled() { if !googleSignInEnabled() {
@ -1029,7 +1088,7 @@ func layoutDialog(gtx layout.Context, w layout.Widget) layout.Dimensions {
} }
// layoutMenu lays out the menu activated by the 3 dots button. // layoutMenu lays out the menu activated by the 3 dots button.
func (ui *UI) layoutMenu(gtx layout.Context, sysIns system.Insets, expiry time.Time, showExits bool) { func (ui *UI) layoutMenu(gtx layout.Context, sysIns system.Insets, expiry time.Time, showExits bool, needsLogin bool) {
ui.menu.dismiss.Add(gtx, color.NRGBA{}) ui.menu.dismiss.Add(gtx, color.NRGBA{})
if ui.menu.dismiss.Dismissed(gtx) { if ui.menu.dismiss.Dismissed(gtx) {
ui.menu.show = false ui.menu.show = false
@ -1040,6 +1099,18 @@ func (ui *UI) layoutMenu(gtx layout.Context, sysIns system.Insets, expiry time.T
}.Layout(gtx, func(gtx C) D { }.Layout(gtx, func(gtx C) D {
return layout.NE.Layout(gtx, func(gtx C) D { return layout.NE.Layout(gtx, func(gtx C) D {
menu := &ui.menu menu := &ui.menu
if ui.setLoginServer {
return D{}
}
if needsLogin {
items := []menuItem{
{title: "Use login server", btn: &menu.useLoginServer},
}
return layoutMenu(ui.theme, gtx, items, func(gtx C) D {
l := material.Caption(ui.theme, "Advanced settings")
return l.Layout(gtx)
})
}
items := []menuItem{ items := []menuItem{
{title: "Copy my IP address", btn: &menu.copy}, {title: "Copy my IP address", btn: &menu.copy},
} }
@ -1201,9 +1272,6 @@ func (ui *UI) layoutTop(gtx layout.Context, sysIns system.Insets, state *Backend
}) })
}), }),
layout.Rigid(func(gtx C) D { layout.Rigid(func(gtx C) D {
if state.State <= ipn.NeedsLogin {
return D{}
}
btn := material.IconButton(ui.theme, &ui.menu.open, ui.icons.more, "Open menu") btn := material.IconButton(ui.theme, &ui.menu.open, ui.icons.more, "Open menu")
btn.Color = rgb(white) btn.Color = rgb(white)
btn.Background = color.NRGBA{} btn.Background = color.NRGBA{}

Loading…
Cancel
Save