[0.9.12] Need to add handle the invalid request
denisoster opened this issue · 0 comments
denisoster commented
Need to add handle the invalid request
The bug report below shows the necessary cases
begin
require 'bundler/inline'
require 'bundler'
rescue LoadError => e
STDERR.puts 'Bundler version 1.10 or later is required. Please update your Bundler'
raise e
end
gemfile(true, ui: ENV['SILENT'] ? Bundler::UI::Silent.new : Bundler::UI::Shell.new) do
source 'https://rubygems.org'
gem 'rails', require: false
gem 'sqlite3', platform: :mri
gem 'byebug'
gem 'activerecord-jdbcsqlite3-adapter',
git: 'https://github.com/jruby/activerecord-jdbc-adapter',
platform: :jruby
if ENV['JSONAPI_RESOURCES_PATH']
gem 'jsonapi-resources', path: ENV['JSONAPI_RESOURCES_PATH'], require: false
else
gem 'jsonapi-resources', git: 'https://github.com/cerebris/jsonapi-resources', require: false
end
end
# prepare active_record database
require 'active_record'
class NullLogger < Logger
def initialize(*_args) end
def add(*_args, &_block) end
end
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = ENV['SILENT'] ? NullLogger.new : Logger.new(STDOUT)
ActiveRecord::Migration.verbose = !ENV['SILENT']
ActiveRecord::Schema.define do
# Add your schema here
create_table :authors, force: true do |t|
t.string :name
end
create_table :books, force: true do |t|
t.string :text
t.references :author
end
end
# create models
class Author < ActiveRecord::Base
has_many :books
end
class Comment < ActiveRecord::Base
belongs_to :author
end
# prepare rails app
require 'action_controller/railtie'
# require 'action_view/railtie'
require 'jsonapi-resources'
class ApplicationController < ActionController::Base
end
# prepare jsonapi resources and controllers
class AuthorsController < ApplicationController
include JSONAPI::ActsAsResourceController
end
class BooksController < ApplicationController
include JSONAPI::ActsAsResourceController
end
class AuthorResource < JSONAPI::Resource
attribute :name
has_many :books, polymorphic: true, class_name: 'Book'
end
class BookResource < JSONAPI::Resource
attribute :text
end
class TestApp < Rails::Application
config.root = File.dirname(__FILE__)
config.logger = ENV['SILENT'] ? NullLogger.new : Logger.new(STDOUT)
Rails.logger = config.logger
secrets.secret_token = 'secret_token'
secrets.secret_key_base = 'secret_key_base'
config.eager_load = false
end
Rails.application.configure do
config.hosts << 'example.org'
end
# initialize app
Rails.application.initialize!
JSONAPI.configure do |config|
config.json_key_format = :underscored_key
config.route_format = :underscored_key
end
# draw routes
Rails.application.routes.draw do
jsonapi_resources :authors, only: [:show, :update]
end
# prepare tests
require 'minitest/autorun'
require 'rack/test'
# Replace this with the code necessary to make your test fail.
class BugTest < Minitest::Test
include Rack::Test::Methods
def json_api_headers
{ 'Accept' => JSONAPI::MEDIA_TYPE, 'CONTENT_TYPE' => JSONAPI::MEDIA_TYPE }
end
def test_relationships_as_array
author = Author.create!
json_request = {
data: {
id: author.id.to_s,
type: 'authors',
relationships: []
}
}
patch "/authors/#{author.id}", json_request.to_json, json_api_headers
assert last_response.bad_request?
end
def test_relationships_as_nil
author = Author.create!
json_request = {
data: {
id: author.id.to_s,
type: 'authors',
relationships: nil
}
}
patch "/authors/#{author.id}", json_request.to_json, json_api_headers
assert last_response.bad_request?
end
def test_attributes_as_nil
author = Author.create!
json_request = {
data: {
id: author.id.to_s,
type: 'authors',
attributes: nil
}
}
patch "/authors/#{author.id}", json_request.to_json, json_api_headers
assert last_response.bad_request?
end
def test_relationship_name_in_attributes
author = Author.create!
json_request = {
data: {
id: author.id.to_s,
type: 'authors',
attributes: {
books: []
}
}
}
patch "/authors/#{author.id}", json_request.to_json, json_api_headers
assert last_response.bad_request?
end
private
def app
Rails.application
end
end
Solution:
Need update method verify_permitted_params
def verify_permitted_params(params, allowed_fields)
formatted_allowed_fields = allowed_fields.collect { |field| format_key(field).to_sym }
params_not_allowed = []
params.each do |key, value|
case key.to_s
when 'relationships'
raise JSONAPI::Exceptions::TypeMismatch.new(nil) unless value.is_a?(ActionController::Parameters) # ADDED THIS LINE
value.keys.each do |links_key|
unless formatted_allowed_fields.include?(links_key.to_sym)
if JSONAPI.configuration.raise_if_parameters_not_allowed
fail JSONAPI::Exceptions::ParameterNotAllowed.new(links_key)
else
params_not_allowed.push(links_key)
value.delete links_key
end
end
end
when 'attributes'
raise JSONAPI::Exceptions::TypeMismatch.new(nil) unless value.is_a?(ActionController::Parameters) # ADDED THIS LINE
attributes = formatted_allowed_fields - resource_klass._relationships.keys # ADDED THIS LINE
value.each do |attr_key, attr_value|
unless formatted_allowed_fields.include?(attr_key.to_sym)
if JSONAPI.configuration.raise_if_parameters_not_allowed
fail JSONAPI::Exceptions::ParameterNotAllowed.new(attr_key)
else
params_not_allowed.push(attr_key)
value.delete attr_key
end
end
end
when 'type'
when 'id'
unless formatted_allowed_fields.include?(:id)
if JSONAPI.configuration.raise_if_parameters_not_allowed
fail JSONAPI::Exceptions::ParameterNotAllowed.new(:id)
else
params_not_allowed.push(:id)
params.delete :id
end
end
else
if JSONAPI.configuration.raise_if_parameters_not_allowed
fail JSONAPI::Exceptions::ParameterNotAllowed.new(key)
else
params_not_allowed.push(key)
params.delete key
end
end
end
if params_not_allowed.length > 0
params_not_allowed_warnings = params_not_allowed.map do |param|
JSONAPI::Warning.new(code: JSONAPI::PARAM_NOT_ALLOWED,
title: 'Param not allowed',
detail: "#{param} is not allowed.")
end
self.warnings.concat(params_not_allowed_warnings)
end
end