aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/test/dispatch/feature_policy_test.rb
blob: ebcc8a8b6dd7664866d862f960afcaae9a4e28cf (plain) (blame)
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# frozen_string_literal: true

require "abstract_unit"

class FeaturePolicyTest < ActiveSupport::TestCase
  def setup
    @policy = ActionDispatch::FeaturePolicy.new
  end

  def test_mappings
    @policy.midi :self
    assert_equal "midi 'self'", @policy.build

    @policy.midi :none
    assert_equal "midi 'none'", @policy.build
  end

  def test_multiple_sources_for_a_single_directive
    @policy.geolocation :self, "https://example.com"
    assert_equal "geolocation 'self' https://example.com", @policy.build
  end

  def test_single_directive_for_multiple_directives
    @policy.geolocation :self
    @policy.usb :none
    assert_equal "geolocation 'self'; usb 'none'", @policy.build
  end

  def test_multiple_directives_for_multiple_directives
    @policy.geolocation :self, "https://example.com"
    @policy.usb :none, "https://example.com"
    assert_equal "geolocation 'self' https://example.com; usb 'none' https://example.com", @policy.build
  end

  def test_invalid_directive_source
    exception = assert_raises(ArgumentError) do
      @policy.vr [:non_existent]
    end

    assert_equal "Invalid HTTP feature policy source: [:non_existent]", exception.message
  end
end

class FeaturePolicyIntegrationTest < ActionDispatch::IntegrationTest
  class PolicyController < ActionController::Base
    feature_policy only: :index do |f|
      f.gyroscope :none
    end

    feature_policy only: :sample_controller do |f|
      f.gyroscope nil
      f.usb       :self
    end

    feature_policy only: :multiple_directives do |f|
      f.gyroscope nil
      f.usb       :self
      f.autoplay  "https://example.com"
      f.payment   "https://secure.example.com"
    end

    def index
      head :ok
    end

    def sample_controller
      head :ok
    end

    def multiple_directives
      head :ok
    end
  end

  ROUTES = ActionDispatch::Routing::RouteSet.new
  ROUTES.draw do
    scope module: "feature_policy_integration_test" do
      get "/", to: "policy#index"
      get "/sample_controller", to: "policy#sample_controller"
      get "/multiple_directives", to: "policy#multiple_directives"
    end
  end

  POLICY = ActionDispatch::FeaturePolicy.new do |p|
    p.gyroscope :self
  end

  class PolicyConfigMiddleware
    def initialize(app)
      @app = app
    end

    def call(env)
      env["action_dispatch.feature_policy"] = POLICY
      env["action_dispatch.show_exceptions"] = false

      @app.call(env)
    end
  end

  APP = build_app(ROUTES) do |middleware|
    middleware.use PolicyConfigMiddleware
    middleware.use ActionDispatch::FeaturePolicy::Middleware
  end

  def app
    APP
  end

  def test_generates_feature_policy_header
    get "/"
    assert_policy "gyroscope 'none'"
  end

  def test_generates_per_controller_feature_policy_header
    get "/sample_controller"
    assert_policy "usb 'self'"
  end

  def test_generates_multiple_directives_feature_policy_header
    get "/multiple_directives"
    assert_policy "usb 'self'; autoplay https://example.com; payment https://secure.example.com"
  end

  private
    def env_config
      Rails.application.env_config
    end

    def feature_policy
      env_config["action_dispatch.feature_policy"]
    end

    def feature_policy=(policy)
      env_config["action_dispatch.feature_policy"] = policy
    end

    def assert_policy(expected)
      assert_response :success
      assert_equal expected, response.headers["Feature-Policy"]
    end
end