drillbit 2.11.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/drillbit.rb +1 -0
  5. data/lib/drillbit/accept_header.rb +1 -0
  6. data/lib/drillbit/authorizable_resource.rb +61 -60
  7. data/lib/drillbit/authorizers/parameters.rb +1 -0
  8. data/lib/drillbit/authorizers/parameters/filtering.rb +7 -6
  9. data/lib/drillbit/authorizers/parameters/inclusions.rb +6 -9
  10. data/lib/drillbit/authorizers/parameters/resource.rb +20 -19
  11. data/lib/drillbit/authorizers/query.rb +1 -0
  12. data/lib/drillbit/authorizers/scope.rb +5 -4
  13. data/lib/drillbit/compatibility/controllers.rb +1 -0
  14. data/lib/drillbit/configuration.rb +14 -16
  15. data/lib/drillbit/errors/invalid_api_request.rb +1 -0
  16. data/lib/drillbit/errors/invalid_request_body.rb +1 -0
  17. data/lib/drillbit/errors/invalid_subdomain.rb +1 -0
  18. data/lib/drillbit/errors/invalid_token.rb +1 -0
  19. data/lib/drillbit/errors/unpermitted_inclusions.rb +1 -0
  20. data/lib/drillbit/matchers/accept_header.rb +1 -0
  21. data/lib/drillbit/matchers/generic.rb +4 -3
  22. data/lib/drillbit/matchers/subdomain.rb +5 -6
  23. data/lib/drillbit/matchers/version.rb +3 -2
  24. data/lib/drillbit/middleware/api_request_validator.rb +4 -3
  25. data/lib/drillbit/middleware/parameter_parser.rb +1 -0
  26. data/lib/drillbit/middleware/token_processor.rb +1 -0
  27. data/lib/drillbit/parameters/filter.rb +12 -11
  28. data/lib/drillbit/parameters/index.rb +3 -2
  29. data/lib/drillbit/parameters/page.rb +1 -0
  30. data/lib/drillbit/parameters/sort.rb +1 -0
  31. data/lib/drillbit/requests/base.rb +1 -1
  32. data/lib/drillbit/requests/rack.rb +3 -0
  33. data/lib/drillbit/requests/rails.rb +1 -0
  34. data/lib/drillbit/resource.rb +1 -0
  35. data/lib/drillbit/resource/model.rb +5 -4
  36. data/lib/drillbit/resource/naming.rb +11 -10
  37. data/lib/drillbit/resource/processors/filtering.rb +1 -0
  38. data/lib/drillbit/resource/processors/indexing.rb +1 -0
  39. data/lib/drillbit/resource/processors/paging.rb +4 -3
  40. data/lib/drillbit/resource/processors/sorting.rb +1 -0
  41. data/lib/drillbit/responses/invalid_api_request.rb +3 -0
  42. data/lib/drillbit/responses/invalid_request_body.rb +3 -0
  43. data/lib/drillbit/responses/invalid_subdomain.rb +3 -0
  44. data/lib/drillbit/responses/invalid_token.rb +3 -0
  45. data/lib/drillbit/serializers/json_api.rb +12 -11
  46. data/lib/drillbit/tokens/base64.rb +1 -0
  47. data/lib/drillbit/tokens/base64s/invalid.rb +1 -0
  48. data/lib/drillbit/tokens/base64s/null.rb +1 -0
  49. data/lib/drillbit/tokens/invalid.rb +1 -0
  50. data/lib/drillbit/tokens/json_web_token.rb +6 -5
  51. data/lib/drillbit/tokens/json_web_tokens/invalid.rb +1 -0
  52. data/lib/drillbit/tokens/json_web_tokens/null.rb +1 -0
  53. data/lib/drillbit/tokens/json_web_tokens/password_reset.rb +1 -0
  54. data/lib/drillbit/tokens/null.rb +1 -0
  55. data/lib/drillbit/utilities/string.rb +1 -0
  56. data/lib/drillbit/version.rb +2 -1
  57. metadata +28 -94
  58. metadata.gz.sig +0 -0
  59. data/Rakefile +0 -2
  60. data/spec/drillbit/accept_header_spec.rb +0 -119
  61. data/spec/drillbit/authorizers/parameters/filtering_spec.rb +0 -101
  62. data/spec/drillbit/authorizers/parameters/resource_spec.rb +0 -12
  63. data/spec/drillbit/authorizers/parameters_spec.rb +0 -19
  64. data/spec/drillbit/authorizers/query_spec.rb +0 -24
  65. data/spec/drillbit/authorizers/scope_spec.rb +0 -21
  66. data/spec/drillbit/errors/invalid_api_request_spec.rb +0 -31
  67. data/spec/drillbit/errors/invalid_request_body_spec.rb +0 -25
  68. data/spec/drillbit/errors/invalid_subdomain_spec.rb +0 -30
  69. data/spec/drillbit/errors/invalid_token_spec.rb +0 -24
  70. data/spec/drillbit/invalid_subdomain_spec.rb +0 -45
  71. data/spec/drillbit/invalid_token_spec.rb +0 -44
  72. data/spec/drillbit/matchers/accept_header_spec.rb +0 -114
  73. data/spec/drillbit/matchers/subdomain_spec.rb +0 -78
  74. data/spec/drillbit/matchers/version_spec.rb +0 -86
  75. data/spec/drillbit/middleware/api_request_validator_spec.rb +0 -185
  76. data/spec/drillbit/middleware/parameter_parser_spec.rb +0 -200
  77. data/spec/drillbit/middleware/token_processor_spec.rb +0 -27
  78. data/spec/drillbit/requests/base_spec.rb +0 -37
  79. data/spec/drillbit/requests/rack_spec.rb +0 -252
  80. data/spec/drillbit/requests/rails_spec.rb +0 -264
  81. data/spec/drillbit/resource/model_spec.rb +0 -64
  82. data/spec/drillbit/resource/processors/filtering_spec.rb +0 -106
  83. data/spec/drillbit/resource/processors/indexing_spec.rb +0 -45
  84. data/spec/drillbit/resource/processors/paging_spec.rb +0 -74
  85. data/spec/drillbit/resource/processors/sorting_spec.rb +0 -66
  86. data/spec/drillbit/tokens/base64_spec.rb +0 -44
  87. data/spec/drillbit/tokens/json_web_token_spec.rb +0 -231
  88. data/spec/drillbit/tokens/json_web_tokens/password_reset_spec.rb +0 -43
  89. data/spec/fixtures/test_rsa_key +0 -27
  90. data/spec/fixtures/test_rsa_key.pub +0 -9
  91. data/spec/spec_helper.rb +0 -4
  92. data/spec/support/private_keys.rb +0 -42
@@ -1,101 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled'
3
- require 'drillbit/authorizers/parameters/filtering'
4
-
5
- module Drillbit
6
- module Authorizers
7
- class Parameters
8
- describe Filtering do
9
- let(:params) { { filter: { name: 'Bill', age: 26 } } }
10
-
11
- it 'can authorize new filter parameters', verify: false do
12
- filter_params = Filtering.new(action: 'index',
13
- token: '1234',
14
- user: '1234',
15
- issuer: 'my_issuer',
16
- params: params)
17
-
18
- allow(params).to receive(:permit)
19
-
20
- filter_params.send(:add_filterable_parameters, :name, :age)
21
- filter_params.call
22
-
23
- expect(params).to have_received(:permit).
24
- with(:sort,
25
- :token,
26
- :token_b64,
27
- :token_jwt,
28
- :format,
29
- :accept,
30
- :include,
31
- include(
32
- filter: include(:name, :age),
33
- ))
34
- end
35
-
36
- it 'can authorize parameters if they come in as arrays', verify: false do
37
- params = {
38
- filter: {
39
- name: 'Bill',
40
- ary: %w{hello},
41
- },
42
- }
43
- filter_params = Filtering.new(action: 'index',
44
- token: '1234',
45
- user: '1234',
46
- issuer: 'my_issuer',
47
- params: params)
48
-
49
- allow(params).to receive(:permit)
50
-
51
- filter_params.send(:add_filterable_parameters, :name, :ary)
52
- filter_params.call
53
-
54
- expect(params).to have_received(:permit).
55
- with(:sort,
56
- :token,
57
- :token_b64,
58
- :token_jwt,
59
- :format,
60
- :accept,
61
- :include,
62
- include(
63
- filter: include(:name, ary: []),
64
- ))
65
- end
66
-
67
- it 'has default authorized parameters', verify: false do
68
- filter_params = Filtering.new(action: 'index',
69
- token: '1234',
70
- user: '1234',
71
- issuer: 'my_issuer',
72
- params: params)
73
-
74
- allow(params).to receive(:permit)
75
-
76
- filter_params.call
77
-
78
- expect(params).to have_received(:permit).
79
- with(:sort,
80
- :token,
81
- :token_b64,
82
- :token_jwt,
83
- :format,
84
- :accept,
85
- :include,
86
- page: %i{
87
- number
88
- size
89
- offset
90
- limit
91
- cursor
92
- },
93
- filter: [
94
- :query,
95
- {},
96
- ])
97
- end
98
- end
99
- end
100
- end
101
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled'
3
- require 'drillbit/authorizers/parameters/resource'
4
-
5
- module Drillbit
6
- module Authorizers
7
- class Parameters
8
- describe Resource do
9
- end
10
- end
11
- end
12
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled'
3
- require 'drillbit/authorizers/parameters'
4
-
5
- module Drillbit
6
- module Authorizers
7
- describe Parameters do
8
- it 'defaults to nothing' do
9
- parameters = Parameters.new(action: 'index',
10
- token: '123',
11
- user: 'my_user',
12
- issuer: 'my_issuer',
13
- params: { foo: 'bar' })
14
-
15
- expect(parameters.call).to eql(foo: 'bar')
16
- end
17
- end
18
- end
19
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled'
3
- require 'drillbit/authorizers/query'
4
-
5
- module Drillbit
6
- module Authorizers
7
- describe Query do
8
- it 'does not authorize the resource by default' do
9
- authorizer = Query.new(action: 'index',
10
- token: '123',
11
- user: 'my_user',
12
- issuer: 'my_issuer',
13
- resource: 'my_resource',
14
- params: 'my_params')
15
-
16
- expect(authorizer).not_to be_able_to_index
17
- expect(authorizer).not_to be_able_to_show
18
- expect(authorizer).not_to be_able_to_create
19
- expect(authorizer).not_to be_able_to_update
20
- expect(authorizer).not_to be_able_to_destroy
21
- end
22
- end
23
- end
24
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled'
3
- require 'ostruct'
4
- require 'drillbit/authorizers/scope'
5
-
6
- module Drillbit
7
- module Authorizers
8
- describe Scope do
9
- it 'defaults to nothing' do
10
- scope = Scope.new(action: 'index',
11
- token: '123',
12
- user: Object.new,
13
- issuer: 'my_issuer',
14
- params: {},
15
- scope_root: OpenStruct.new(none: []))
16
-
17
- expect(scope.call).to be_empty
18
- end
19
- end
20
- end
21
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled/spec_helpers/rspeckled'
3
- require 'drillbit/errors/invalid_api_request'
4
-
5
- module Drillbit
6
- module Errors
7
- describe InvalidApiRequest do
8
- let(:error) { InvalidApiRequest.new }
9
-
10
- it 'has a status of 400' do
11
- expect(error.http_status).to eql 400
12
- end
13
-
14
- it 'has a code' do
15
- expect(error.code).to eql 'errors.invalid_api_request'
16
- end
17
-
18
- it 'can output the detail' do
19
- expect(error.detail).to eql 'The accept header that you passed in the ' \
20
- 'request cannot be parsed, please refer to ' \
21
- 'the documentation to verify.'
22
- end
23
-
24
- it 'can output the source' do
25
- error = InvalidApiRequest.new accept_header: 'foo'
26
-
27
- expect(error.source).to eql(accept_header: 'foo')
28
- end
29
- end
30
- end
31
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled/spec_helpers/rspeckled'
3
- require 'drillbit/errors/invalid_request_body'
4
-
5
- module Drillbit
6
- module Errors
7
- describe InvalidRequestBody do
8
- let(:error) { InvalidRequestBody.new }
9
-
10
- it 'has a status of 400' do
11
- expect(error.http_status).to eql 400
12
- end
13
-
14
- it 'has a code' do
15
- expect(error.code).to eql 'errors.invalid_request_body'
16
- end
17
-
18
- it 'can output the detail' do
19
- expect(error.detail).to eql \
20
- 'The information you attempted to send in the request cannot be parsed as ' \
21
- 'a valid JSON document.'
22
- end
23
- end
24
- end
25
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled/spec_helpers/rspeckled'
3
- require 'drillbit/errors/invalid_subdomain'
4
-
5
- module Drillbit
6
- module Errors
7
- describe InvalidSubdomain do
8
- let(:error) { InvalidSubdomain.new }
9
-
10
- it 'has a status of 404' do
11
- expect(error.http_status).to eql 404
12
- end
13
-
14
- it 'has a code' do
15
- expect(error.code).to eql 'errors.invalid_subdomain'
16
- end
17
-
18
- it 'can output the detail' do
19
- expect(error.detail).to eql \
20
- 'The subdomain you attempted to access is not valid. Please try again.'
21
- end
22
-
23
- it 'can output the source' do
24
- error = InvalidSubdomain.new http_host: 'foo'
25
-
26
- expect(error.source).to eql(http_host: 'foo')
27
- end
28
- end
29
- end
30
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled/spec_helpers/rspeckled'
3
- require 'drillbit/errors/invalid_token'
4
-
5
- module Drillbit
6
- module Errors
7
- describe InvalidToken do
8
- let(:error) { InvalidToken.new }
9
-
10
- it 'has a status of 401' do
11
- expect(error.http_status).to eql 401
12
- end
13
-
14
- it 'has a code' do
15
- expect(error.code).to eql 'errors.invalid_token'
16
- end
17
-
18
- it 'can output the detail' do
19
- expect(error.detail).to eql \
20
- 'Either the token you passed is invalid or is not allowed to perform this action.'
21
- end
22
- end
23
- end
24
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled/spec_helpers/rspeckled'
3
- require 'drillbit/responses/invalid_subdomain'
4
-
5
- module Drillbit
6
- module Responses
7
- describe InvalidSubdomain, singletons: Erratum::Configuration do
8
- it 'returns the proper response' do
9
- Erratum.configuration.url_mappings = {
10
- 'external_documentation_urls' => {
11
- 'errors.responses.invalid_subdomain' => 'http://example.com/foo',
12
- },
13
- 'developer_documentation_urls' => {
14
- 'errors.responses.invalid_subdomain' => 'http://example.com/foo',
15
- },
16
- }
17
-
18
- request = { 'HTTP_HOST' => 'api.example.com' }
19
- status, headers, response = InvalidSubdomain.call(request)
20
-
21
- expect(status).to eql 404
22
- expect(headers).to eql({})
23
- expect(JSON.load(response[0])).to include(
24
- 'errors' => [
25
- include(
26
- 'id' => match(/[a-f0-9\-]+/),
27
- 'links' => {
28
- 'about' => nil,
29
- 'documentation' => nil,
30
- },
31
- 'status' => 404,
32
- 'code' => 'errors.invalid_subdomain',
33
- 'title' => 'Invalid Subdomain',
34
- 'detail' => 'The subdomain you attempted to access is not valid.' \
35
- ' Please try again.',
36
- 'source' => {
37
- 'http_host' => 'api.example.com',
38
- },
39
- ),
40
- ],
41
- )
42
- end
43
- end
44
- end
45
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled/spec_helpers/rspeckled'
3
- require 'drillbit/responses/invalid_token'
4
-
5
- # rubocop:disable Metrics/LineLength
6
- module Drillbit
7
- module Responses
8
- describe InvalidToken, singletons: Erratum::Configuration do
9
- it 'returns the proper response' do
10
- Erratum.configuration.url_mappings = {
11
- 'external_documentation_urls' => {
12
- 'errors.responses.invalid_token' => 'http://example.com/foo',
13
- },
14
- 'developer_documentation_urls' => {
15
- 'errors.responses.invalid_token' => 'http://example.com/foo',
16
- },
17
- }
18
-
19
- request = { 'HTTP_HOST' => 'api.example.com' }
20
- status, headers, response = InvalidToken.call(request, application_name: 'my_app')
21
-
22
- expect(status).to eql 401
23
- expect(headers).to eql('WWW-Authenticate' => 'Token realm="my_app"')
24
- expect(JSON.load(response[0])).to include(
25
- 'errors' => [
26
- include(
27
- 'id' => match(/[a-f0-9\-]+/),
28
- 'links' => {
29
- 'about' => nil,
30
- 'documentation' => nil,
31
- },
32
- 'status' => 401,
33
- 'code' => 'errors.invalid_token',
34
- 'title' => 'Invalid or Unauthorized Token',
35
- 'detail' => 'Either the token you passed is invalid or is not allowed to ' \
36
- 'perform this action.',
37
- 'source' => {},
38
- ),
39
- ],
40
- )
41
- end
42
- end
43
- end
44
- end
@@ -1,114 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspeckled/spec_helpers/rspeckled'
3
- require 'drillbit/requests/base'
4
- require 'drillbit/matchers/accept_header'
5
-
6
- # rubocop:disable Metrics/LineLength
7
- module Drillbit
8
- module Matchers
9
- describe AcceptHeader do
10
- it 'matches if the subdomain is API and the accept header is valid' do
11
- env = {
12
- 'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=1.0.0',
13
- 'HTTP_X_APPLICATION_NAME' => 'westeros',
14
- }
15
- request = Requests::Base.resolve(env)
16
-
17
- matcher = AcceptHeader.new
18
-
19
- expect(matcher.matches?(request)).to be_a TrueClass
20
- end
21
-
22
- it 'matches if the subdomain is API and the accept header is passed in as ' \
23
- 'a parameter' do
24
-
25
- env = {
26
- 'QUERY_STRING' => 'accept=application/vnd.westeros+redkeep;version=1.0.0',
27
- 'HTTP_X_APPLICATION_NAME' => 'westeros',
28
- }
29
- request = Requests::Base.resolve(env)
30
-
31
- matcher = AcceptHeader.new
32
-
33
- expect(matcher.matches?(request)).to be_a TrueClass
34
- end
35
-
36
- it 'matches if the subdomain is API and the accept header is passed in as a ' \
37
- 'secondary parameter' do
38
-
39
- env = {
40
- 'QUERY_STRING' => 'first=my_param&accept=application/vnd.westeros+redkeep;' \
41
- 'version=1.0.0',
42
- 'HTTP_X_APPLICATION_NAME' => 'westeros',
43
- }
44
- request = Requests::Base.resolve(env)
45
-
46
- matcher = AcceptHeader.new
47
-
48
- expect(matcher.matches?(request)).to be_a TrueClass
49
- end
50
-
51
- it 'matches the header accept header if the subdomain is API and the accept header ' \
52
- 'is passed both as a valid header and as a parameter' do
53
-
54
- env = {
55
- 'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=1.0.0',
56
- 'QUERY_STRING' => 'accept=application/vnd.westeros+redkeep;version=2.0.0',
57
- 'HTTP_X_APPLICATION_NAME' => 'westeros',
58
- }
59
- request = Requests::Base.resolve(env)
60
-
61
- matcher = AcceptHeader.new
62
- matcher.matches?(request)
63
-
64
- expect(matcher.accept_header.version).to eql '1.0.0'
65
- end
66
-
67
- it 'matches the accept header parameter if the subdomain is API and the accept ' \
68
- 'header is passed both as an invalid header as well as as a parameter' do
69
-
70
- env = {
71
- 'HTTP_ACCEPT' => 'application/vndwesteros+redkeep;version=1.0.0',
72
- 'QUERY_STRING' => 'accept=application/vnd.westeros+redkeep;version=2.0.0',
73
- 'HTTP_X_APPLICATION_NAME' => 'westeros',
74
- }
75
- request = Requests::Base.resolve(env)
76
-
77
- matcher = AcceptHeader.new
78
- matcher.matches?(request)
79
-
80
- expect(matcher.accept_header.version).to eql '2.0.0'
81
- end
82
-
83
- it 'matches the accept header parameter if the subdomain is API and the accept ' \
84
- 'header is passed both as an invalid header as well as as a parameter' do
85
-
86
- env = {
87
- 'HTTP_ACCEPT' => 'application/vndwesteros+redkeep;version=1.0.0',
88
- 'QUERY_STRING' => '',
89
- 'HTTP_X_APPLICATION_NAME' => 'westeros',
90
- }
91
- request = Requests::Base.resolve(env)
92
-
93
- matcher = AcceptHeader.new
94
- matcher.matches?(request)
95
-
96
- expect(matcher.accept_header.raw_accept_header).to eql \
97
- 'application/vndwesteros+redkeep;version=1.0.0'
98
- end
99
-
100
- it 'does not match if the subdomain is API but the accept header is invalid' do
101
- env = {
102
- 'HTTP_ACCEPT' => 'application/vndwesteros+redkeep;version=1.0.0',
103
- 'QUERY_STRING' => '',
104
- 'HTTP_X_APPLICATION_NAME' => 'westeros',
105
- }
106
- request = Requests::Base.resolve(env)
107
-
108
- matcher = AcceptHeader.new
109
-
110
- expect(matcher.matches?(request)).to be_a FalseClass
111
- end
112
- end
113
- end
114
- end