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

@ -58,6 +58,7 @@ 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,6 +96,7 @@ type UI struct {
dismiss Dismiss dismiss Dismiss
show bool show bool
useLoginServer widget.Clickable
copy widget.Clickable copy widget.Clickable
reauth widget.Clickable reauth widget.Clickable
bug widget.Clickable bug widget.Clickable
@ -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