Authenticate users via Tailscale Serve identity headers
Assisted-by: Claude Opus 4.6 via pi
change pqusmnsxymwpyqlqvqloxzynlunxqqko
commit 663ed8f65ddfa9c658080106fa72929b466b8f7f
author Alpha Chen <alpha@kejadlen.dev>
date
parent rxvmwuyo
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