controlclient,health,ipnlocal,tailcfg: add DisplayMessage support

Updates tailscale/corp#27759

Signed-off-by: James Sanderson <jsanderson@tailscale.com>
This commit is contained in:
James Sanderson
2025-05-07 17:01:40 +01:00
committed by James 'zofrex' Sanderson
parent 5b670eb3a5
commit 11e83f9da5
7 changed files with 417 additions and 22 deletions

View File

@@ -5828,7 +5828,14 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
b.pauseOrResumeControlClientLocked()
if nm != nil {
b.health.SetControlHealth(nm.DisplayMessages)
messages := make(map[tailcfg.DisplayMessageID]tailcfg.DisplayMessage)
for id, msg := range nm.DisplayMessages {
if msg.PrimaryAction != nil && !b.validPopBrowserURL(msg.PrimaryAction.URL) {
msg.PrimaryAction = nil
}
messages[id] = msg
}
b.health.SetControlHealth(messages)
} else {
b.health.SetControlHealth(nil)
}

View File

@@ -5339,3 +5339,68 @@ func TestSrcCapPacketFilter(t *testing.T) {
t.Error("IsDrop() for node without cap = false, want true")
}
}
func TestDisplayMessages(t *testing.T) {
b := newTestLocalBackend(t)
// Pretend we're in a map poll so health updates get processed
ht := b.HealthTracker()
ht.SetIPNState("NeedsLogin", true)
ht.GotStreamedMapResponse()
b.setNetMapLocked(&netmap.NetworkMap{
DisplayMessages: map[tailcfg.DisplayMessageID]tailcfg.DisplayMessage{
"test-message": {
Title: "Testing",
},
},
})
state := ht.CurrentState()
_, ok := state.Warnings["test-message"]
if !ok {
t.Error("no warning found with id 'test-message'")
}
}
// TestDisplayMessagesURLFilter tests that we filter out any URLs that are not
// valid as a pop browser URL (see [LocalBackend.validPopBrowserURL]).
func TestDisplayMessagesURLFilter(t *testing.T) {
b := newTestLocalBackend(t)
// Pretend we're in a map poll so health updates get processed
ht := b.HealthTracker()
ht.SetIPNState("NeedsLogin", true)
ht.GotStreamedMapResponse()
b.setNetMapLocked(&netmap.NetworkMap{
DisplayMessages: map[tailcfg.DisplayMessageID]tailcfg.DisplayMessage{
"test-message": {
Title: "Testing",
Severity: tailcfg.SeverityHigh,
PrimaryAction: &tailcfg.DisplayMessageAction{
URL: "https://www.evil.com",
Label: "Phishing Link",
},
},
},
})
state := ht.CurrentState()
got, ok := state.Warnings["test-message"]
if !ok {
t.Fatal("no warning found with id 'test-message'")
}
want := health.UnhealthyState{
WarnableCode: "test-message",
Title: "Testing",
Severity: health.SeverityHigh,
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Unexpected message content (-want/+got):\n%s", diff)
}
}