1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
require_relative "../test_helper"
require "rack/test"

require "pro_tacts/tailscale_auth"

class TailscaleAuthTest < Minitest::Test
  include Rack::Test::Methods

  # Records what the middleware passed through, so a refused request can be
  # distinguished from one the app merely ignored.
  class Spy
    attr_reader :env

    def call(env)
      @env = env
      [200, { "Content-Type" => "text/plain" }, ["reached the app"]]
    end
  end

  def setup
    @spy = Spy.new
    @app = ProTacts::TailscaleAuth.new(@spy)
  end

  attr_reader :app

  def test_request_with_an_identity_reaches_the_app
    header "Tailscale-User-Login", "alpha@example.com"

    get "/"

    assert_equal 200, last_response.status
    assert_equal "reached the app", last_response.body
  end

  def test_identity_is_available_to_the_app
    header "Tailscale-User-Login", "alpha@example.com"

    get "/"

    assert_equal "alpha@example.com", @spy.env[ProTacts::TailscaleAuth::IDENTITY]
  end

  def test_request_without_an_identity_is_refused
    get "/"

    assert_equal 403, last_response.status
    assert_nil @spy.env
  end

  def test_request_with_an_empty_identity_is_refused
    header "Tailscale-User-Login", ""

    get "/"

    assert_equal 403, last_response.status
    assert_nil @spy.env
  end

  def test_request_with_a_blank_identity_is_refused
    header "Tailscale-User-Login", "   "

    get "/"

    assert_equal 403, last_response.status
    assert_nil @spy.env
  end

  def test_refusal_explains_itself_in_plain_text
    get "/"

    assert_equal "text/plain", last_response["Content-Type"]
    assert_includes last_response.body, "Tailscale"
  end

  # Every route is gated, not just the address book: an unauthenticated
  # request must not learn whether a path exists.
  def test_refusal_covers_every_path
    %w[/ /.well-known/carddav /dav/ /dav/principal/ /dav/addressbook/].each do |path|
      get path

      assert_equal 403, last_response.status, path
    end
  end
end