Authenticate users via Tailscale Serve identity headers
Assisted-by: Claude Opus 4.6 via pi
diff --git a/lib/web.rb b/lib/web.rb
index b6306de..c6955f9 100644
--- a/lib/web.rb
+++ b/lib/web.rb
@@ -5,9 +5,22 @@ require "roda"
require_relative "views/series/new"
class Web < Roda
- plugin :static, ["/css", "/js"]
+ plugin :halt
+ plugin :static, %w[ /css /js ]
+
+ def current_user
+ login = env["HTTP_TAILSCALE_USER_LOGIN"]
+ return unless login
+
+ {
+ login: login,
+ name: env["HTTP_TAILSCALE_USER_NAME"],
+ }
+ end
route do |r|
+ r.halt 403 unless current_user
+
r.root do
Views::Series::New.new.call
end
diff --git a/test/test_web.rb b/test/test_web.rb
index 002ae86..d101d86 100644
--- a/test/test_web.rb
+++ b/test/test_web.rb
@@ -11,10 +11,24 @@ class TestWeb < Minitest::Test
def app = Web.app
def test_root_shows_new_series_form
- get "/"
-
+ get "/", {}, tailscale_headers
assert last_response.ok?
assert_includes last_response.body, '<form method="post" action="/series">'
assert_includes last_response.body, 'name="name"'
end
+
+ def test_root_requires_tailscale_user
+ get "/"
+ assert_equal 403, last_response.status
+ end
+
+ private
+
+ def tailscale_headers(login: "alice@example.com", name: "Alice", profile_pic: "https://example.com/alice.jpg")
+ {
+ "HTTP_TAILSCALE_USER_LOGIN" => login,
+ "HTTP_TAILSCALE_USER_NAME" => name,
+ "HTTP_TAILSCALE_USER_PROFILE_PIC" => profile_pic
+ }
+ end
end