# frozen_string_literal: true

require “rails_helper”

RSpec.describe “ContentSecurity”, type: :request do

describe "HTTP Headers" do
  context "after sign in" do
    before do
      sign_in create(:user)
    end

    it "includes all expected secure headers", :aggregate_failures do
      get url_for_user_dashboard

      # Cookies
      session_cookie = cookies.get_cookie("<%= session_name %>")
      expect(session_cookie).to be_http_only
      expect(session_cookie.to_h["SameSite"]).to eq("Lax")

      # Security Headers
      expect(response.headers["X-Frame-Options"]).to eq "SAMEORIGIN"
      expect(response.headers["X-XSS-Protection"]).to eq "1; mode=block"
      expect(response.headers["X-Content-Type-Options"]).to eq "nosniff"
      expect(response.headers["X-Download-Options"]).to eq "noopen"
      expect(response.headers["X-Permitted-Cross-Domain-Policies"]).to eq "none"
      expect(response.headers["Referrer-Policy"]).to eq "strict-origin-when-cross-origin"

      # Content Security Policy
      content_security_policy = response.headers["Content-Security-Policy"]
      expect(content_security_policy).to have_content("default-src 'none';")
      expect(content_security_policy).to have_content("connect-src 'self';")
      expect(content_security_policy).to have_content("font-src 'self'<% if font_hosts.any? %> <%= font_hosts.join(' ') %><% end %>;")
      expect(content_security_policy).to have_content("img-src 'self' data: https:<% if image_hosts.any? %> <%= image_hosts.join(' ') %><% end %>;")
      expect(content_security_policy).to have_content("object-src 'none';")
      expect(content_security_policy).to have_content("script-src 'self'<% if script_hosts.any? %> <%= script_hosts.join(' ') %><% end %>;")
      expect(content_security_policy).to have_content("style-src 'self'<% if style_hosts.any? %> <%= style_hosts.join(' ') %><% end %>;")
      expect(content_security_policy).to have_content("block-all-mixed-content;")
      expect(content_security_policy).to have_content("upgrade-insecure-requests;")
      expect(content_security_policy).to have_content("report-uri /csp_violations")

      # Content Security Policy should not require any unsafe exceptions
      expect(content_security_policy).not_to have_content("unsafe")
    end
  end
end

describe "POST /csp_violations" do
  context "with a csp violations" do
    let(:csp_violation) do
      {
        "csp-report": {
          "document-uri": "http://example.com/signup.html",
          "referrer": "",
          "blocked-uri": "http://example.com/css/style.css",
          "violated-directive": "style-src cdn.example.com",
          "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /csp_violations"
        }
      }.to_json
    end

    it "responds with ok" do
      post "/csp_violations", params: csp_violation, headers: { "CONTENT_TYPE" => "application/json" }

      expect(response).to have_http_status(:ok)
      expect(response.body).to be_blank
    end
  end

  context "with an invalid payload" do
    let(:invalid_csp_violation) do
      {}.to_json
    end

    it "responds with ok" do
      post "/csp_violations", params: invalid_csp_violation, headers: { "CONTENT_TYPE" => "application/json" }

      expect(response).to have_http_status(:ok)
      expect(response.body).to be_blank
    end
  end
end

end