mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-10-08 15:50:08 +09:00
Admit paginated HTML and hydrate CSRF tokens outside presentation keys
This commit is contained in:
@@ -57,8 +57,9 @@ module CachedResponses
|
||||
ActiveSupport::JSON.encode([
|
||||
controller_path, request.fullpath, request.base_url, request.user_agent,
|
||||
request.headers["Accept"], request.headers["Turbo-Frame"], I18n.locale,
|
||||
Current.user.id, Current.session.token, session.to_hash,
|
||||
request.env["action_controller.csrf_token"],
|
||||
# Tokens are hydrated per request, including clients that replay an old
|
||||
# cookie. Their raw CSRF secret does not select a presentation variant.
|
||||
Current.user.id, Current.session.token, session.to_hash.except("_csrf_token"),
|
||||
cookies.to_h.except("_campfire_session", "session_token")
|
||||
])
|
||||
end
|
||||
|
||||
@@ -16,7 +16,10 @@ class MessagesController < ApplicationController
|
||||
# Creator, body and boost edits can change HTML without touching messages.
|
||||
# Masked CSRF tokens remain fresh while the presentation validator stays stable.
|
||||
fresh_when etag: Digest::SHA256.hexdigest(csrf_neutral_body(body, "")), template: false
|
||||
self.response_body = body unless performed?
|
||||
unless performed?
|
||||
response.content_type = "text/html"
|
||||
self.response_body = body
|
||||
end
|
||||
else
|
||||
head :no_content
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@ class CachedResponsesTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
host! "once.campfire.test"
|
||||
sign_in :david
|
||||
@login_cookie = cookies["_campfire_session"]
|
||||
@previous_forgery = ActionController::Base.allow_forgery_protection
|
||||
ActionController::Base.allow_forgery_protection = true
|
||||
@previous_cache = Rails.cache
|
||||
@@ -38,6 +39,31 @@ class CachedResponsesTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
test "pagination caches the completed HTML rather than silently bypassing admission" do
|
||||
get room_messages_url(@room)
|
||||
assert_response :success
|
||||
assert_equal "text/html", response.media_type
|
||||
MessagesController.any_instance.expects(:find_paged_messages).never
|
||||
get room_messages_url(@room)
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test "clients without a persisted CSRF session still reuse token-neutral HTML" do
|
||||
cookies["_campfire_session"] = @login_cookie
|
||||
get room_url(@room)
|
||||
first = css_select('meta[name="csrf-token"]').first["content"]
|
||||
cookies["_campfire_session"] = @login_cookie
|
||||
ResponseCache.instance.expects(:write).never
|
||||
get room_url(@room)
|
||||
second = css_select('meta[name="csrf-token"]').first["content"]
|
||||
assert_response :success
|
||||
assert_not_equal first, second
|
||||
assert_no_match /campfire-csrf-/, response.body
|
||||
post room_messages_url(@room, format: :turbo_stream), params: {
|
||||
authenticity_token: second, message: { body: "fresh replay token works", client_message_id: "cache-replay-token" } }
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test "cached tokens stay fresh and literal token-like text survives" do
|
||||
get room_url(@room)
|
||||
literal = css_select('meta[name="csrf-token"]').first["content"]
|
||||
|
||||
Reference in New Issue
Block a user