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