| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- // Copyright (c) Tailscale Inc & AUTHORS
- // SPDX-License-Identifier: BSD-3-Clause
- package localapi
- import (
- "bytes"
- "encoding/json"
- "io"
- "net/http"
- "net/http/httptest"
- "net/netip"
- "net/url"
- "strings"
- "testing"
- "tailscale.com/client/tailscale/apitype"
- "tailscale.com/hostinfo"
- "tailscale.com/ipn/ipnlocal"
- "tailscale.com/tailcfg"
- "tailscale.com/tstest"
- )
- func TestValidHost(t *testing.T) {
- tests := []struct {
- host string
- valid bool
- }{
- {"", true},
- {apitype.LocalAPIHost, true},
- {"localhost:9109", false},
- {"127.0.0.1:9110", false},
- {"[::1]:9111", false},
- {"100.100.100.100:41112", false},
- {"10.0.0.1:41112", false},
- {"37.16.9.210:41112", false},
- }
- for _, test := range tests {
- t.Run(test.host, func(t *testing.T) {
- h := &Handler{}
- if got := h.validHost(test.host); got != test.valid {
- t.Errorf("validHost(%q)=%v, want %v", test.host, got, test.valid)
- }
- })
- }
- }
- func TestSetPushDeviceToken(t *testing.T) {
- tstest.Replace(t, &validLocalHostForTesting, true)
- h := &Handler{
- PermitWrite: true,
- b: &ipnlocal.LocalBackend{},
- }
- s := httptest.NewServer(h)
- defer s.Close()
- c := s.Client()
- want := "my-test-device-token"
- body, err := json.Marshal(apitype.SetPushDeviceTokenRequest{PushDeviceToken: want})
- if err != nil {
- t.Fatal(err)
- }
- req, err := http.NewRequest("POST", s.URL+"/localapi/v0/set-push-device-token", bytes.NewReader(body))
- if err != nil {
- t.Fatal(err)
- }
- res, err := c.Do(req)
- if err != nil {
- t.Fatal(err)
- }
- body, err = io.ReadAll(res.Body)
- if err != nil {
- t.Fatal(err)
- }
- if res.StatusCode != 200 {
- t.Errorf("res.StatusCode=%d, want 200. body: %s", res.StatusCode, body)
- }
- if got := hostinfo.New().PushDeviceToken; got != want {
- t.Errorf("hostinfo.PushDeviceToken=%q, want %q", got, want)
- }
- }
- type whoIsBackend struct {
- whoIs func(ipp netip.AddrPort) (n tailcfg.NodeView, u tailcfg.UserProfile, ok bool)
- peerCaps map[netip.Addr]tailcfg.PeerCapMap
- }
- func (b whoIsBackend) WhoIs(ipp netip.AddrPort) (n tailcfg.NodeView, u tailcfg.UserProfile, ok bool) {
- return b.whoIs(ipp)
- }
- func (b whoIsBackend) PeerCaps(ip netip.Addr) tailcfg.PeerCapMap {
- return b.peerCaps[ip]
- }
- // Tests that the WhoIs handler accepts either IPs or IP:ports.
- //
- // From https://github.com/tailscale/tailscale/pull/9714 (a PR that is effectively a bug report)
- func TestWhoIsJustIP(t *testing.T) {
- h := &Handler{
- PermitRead: true,
- }
- for _, input := range []string{"100.101.102.103", "127.0.0.1:123"} {
- rec := httptest.NewRecorder()
- t.Run(input, func(t *testing.T) {
- b := whoIsBackend{
- whoIs: func(ipp netip.AddrPort) (n tailcfg.NodeView, u tailcfg.UserProfile, ok bool) {
- if !strings.Contains(input, ":") {
- want := netip.MustParseAddrPort("100.101.102.103:0")
- if ipp != want {
- t.Fatalf("backend called with %v; want %v", ipp, want)
- }
- }
- return (&tailcfg.Node{
- ID: 123,
- Addresses: []netip.Prefix{
- netip.MustParsePrefix("100.101.102.103/32"),
- },
- }).View(),
- tailcfg.UserProfile{ID: 456, DisplayName: "foo"},
- true
- },
- peerCaps: map[netip.Addr]tailcfg.PeerCapMap{
- netip.MustParseAddr("100.101.102.103"): map[tailcfg.PeerCapability][]tailcfg.RawMessage{
- "foo": {`"bar"`},
- },
- },
- }
- h.serveWhoIsWithBackend(rec, httptest.NewRequest("GET", "/v0/whois?addr="+url.QueryEscape(input), nil), b)
- var res apitype.WhoIsResponse
- if err := json.Unmarshal(rec.Body.Bytes(), &res); err != nil {
- t.Fatal(err)
- }
- if got, want := res.Node.ID, tailcfg.NodeID(123); got != want {
- t.Errorf("res.Node.ID=%v, want %v", got, want)
- }
- if got, want := res.UserProfile.DisplayName, "foo"; got != want {
- t.Errorf("res.UserProfile.DisplayName=%q, want %q", got, want)
- }
- if got, want := len(res.CapMap), 1; got != want {
- t.Errorf("capmap size=%v, want %v", got, want)
- }
- })
- }
- }
|