cmd/tailscale: notify user when VPN access is denied

When tailscale starts, any other active VPN service is automatically closed by the system.
However, if the other VPN service is configured to be always-on, we will be denied access
to set up a VPN. The user may not realize this case, so this change adds a notification
when we're denied access.

The failure mode is identical to the user denying access tthrough the system dialog
shown first time Tailscale starts, so the notification also mentions that case.

Fixes tailscale/tailscale#1017

Signed-off-by: Elias Naur <mail@eliasnaur.com>
pull/5/head
Elias Naur 4 years ago
parent 0363b565ee
commit 9db851a113

@ -22,6 +22,8 @@ var (
// onVPNClosed is notified when VpnService.prepare fails, or when // onVPNClosed is notified when VpnService.prepare fails, or when
// the a running VPN connection is closed. // the a running VPN connection is closed.
onVPNClosed = make(chan struct{}, 1) onVPNClosed = make(chan struct{}, 1)
// onVPNRevoked is notified whenever the VPN service is revoked.
onVPNRevoked = make(chan struct{}, 1)
// onConnect receives global IPNService references when // onConnect receives global IPNService references when
// a VPN connection is requested. // a VPN connection is requested.
@ -69,6 +71,13 @@ func notifyVPNPrepared() {
} }
} }
func notifyVPNRevoked() {
select {
case onVPNRevoked <- struct{}{}:
default:
}
}
func notifyVPNClosed() { func notifyVPNClosed() {
select { select {
case onVPNClosed <- struct{}{}: case onVPNClosed <- struct{}{}:
@ -125,6 +134,7 @@ func Java_com_tailscale_ipn_Peer_onActivityResult0(env *C.JNIEnv, cls C.jclass,
notifyVPNPrepared() notifyVPNPrepared()
} else { } else {
notifyVPNClosed() notifyVPNClosed()
notifyVPNRevoked()
} }
} }
} }

@ -559,6 +559,9 @@ func (a *App) runUI() error {
return err return err
} }
} }
case <-onVPNRevoked:
ui.NotifyRevoked()
w.Invalidate()
case e := <-w.Events(): case e := <-w.Events():
switch e := e.(type) { switch e := e.(type) {
case app.ViewEvent: case app.ViewEvent:

@ -286,7 +286,7 @@ func (ui *UI) layout(gtx layout.Context, sysIns system.Insets, state *clientStat
}) })
}) })
// "Copied" message. // Popup messages.
ui.layoutMessage(gtx, sysIns) ui.layoutMessage(gtx, sysIns)
// 3-dots menu. // 3-dots menu.
@ -306,6 +306,11 @@ func (ui *UI) layout(gtx layout.Context, sysIns system.Insets, state *clientStat
return ui.events return ui.events
} }
func (ui *UI) NotifyRevoked() {
ui.message.text = "VPN access denied or another VPN service is always-on"
ui.message.t0 = time.Now()
}
// Dismiss is a widget that detects pointer presses. // Dismiss is a widget that detects pointer presses.
type Dismiss struct { type Dismiss struct {
} }

Loading…
Cancel
Save