test: cover NotesController, received_log and StreamingExportController

This commit is contained in:
dualfroz committed 2026-09-10 12:37:02 +02:00
1 parent daa6632b39
commit 6290bede30
2 files changed
+201

No files matched your search

+118
View File
@@ -0,0 +1,118 @@
require 'minitest/autorun'
require 'prism'
require 'support'
class NotesController < Prism::Controller
protect_from_forgery except: [:token]
def self.received_log
@received_log ||= []
end
def token
html(csrf_token)
end
def create
self.class.received_log << params['title']
halt(201, JSON.generate(ok: true))
end
def write_cookie
cookies.signed[:uid] = 42
cookies.encrypted[:secret_note] = 'top secret'
halt(200, 'stored')
end
def read_cookie
halt(200, JSON.generate(uid: cookies.signed[:uid], note: cookies.encrypted[:secret_note]))
end
def read_raw_cookie
halt(200, JSON.generate(raw: cookies['uid']))
end
end
class SecureNotesApp < Prism::Application
enable_sessions(secret: 'notes-secret')
get '/notes/token', to: 'notes#token'
post '/notes', to: 'notes#create'
get '/notes/cookie', to: 'notes#write_cookie'
get '/notes/read_cookie', to: 'notes#read_cookie'
get '/notes/read_raw_cookie', to: 'notes#read_raw_cookie'
end
class ControllerSecurityTest < Minitest::Test
include TestSupport
def setup
NotesController.received_log.clear
end
def call(method, path, **opts)
SecureNotesApp.call(env_for(method, path, **opts))
end
def session_cookie_from(headers)
line = headers['Set-Cookie'].split("\n").find { |c| c.start_with?('prism.session=') }
line.split(';').first
end
def test_post_without_authenticity_token_is_rejected
status, = call('POST', '/notes', headers: { 'Content-Type' => 'application/x-www-form-urlencoded' },
body: 'title=hi')
assert_equal 422, status
assert_equal [], NotesController.received_log
end
def test_post_with_valid_authenticity_token_is_accepted
_, headers, body = call('GET', '/notes/token')
token = body.join
cookie = session_cookie_from(headers)
status, = call('POST', '/notes',
headers: { 'Content-Type' => 'application/x-www-form-urlencoded' },
cookies: cookie,
body: "title=hi&authenticity_token=#{CGI.escape(token)}")
assert_equal 201, status
assert_equal ['hi'], NotesController.received_log
end
def test_post_with_token_from_a_different_session_is_rejected
_, other_headers, other_body = call('GET', '/notes/token')
other_token = other_body.join
refute_nil session_cookie_from(other_headers)
_, first_headers, = call('GET', '/notes/token')
first_cookie = session_cookie_from(first_headers)
status, = call('POST', '/notes',
headers: { 'Content-Type' => 'application/x-www-form-urlencoded' },
cookies: first_cookie,
body: "title=hi&authenticity_token=#{CGI.escape(other_token)}")
assert_equal 422, status
end
def test_signed_and_encrypted_cookies_round_trip_through_a_real_request_cycle
_, write_headers, = call('GET', '/notes/cookie')
lines = write_headers['Set-Cookie'].split("\n")
cookie_header = lines.map { |line| line.split(';').first }.join('; ')
_, _, body = call('GET', '/notes/read_cookie', cookies: cookie_header)
parsed = JSON.parse(body.join)
assert_equal 42, parsed['uid']
assert_equal 'top secret', parsed['note']
end
def test_signed_cookie_value_is_not_stored_in_plaintext
_, write_headers, = call('GET', '/notes/cookie')
lines = write_headers['Set-Cookie'].split("\n")
cookie_header = lines.map { |line| line.split(';').first }.join('; ')
_, _, body = call('GET', '/notes/read_raw_cookie', cookies: cookie_header)
raw = JSON.parse(body.join)['raw']
refute_nil raw
refute_equal '42', raw
end
end