castle-rb 4.0.0 → 5.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.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe Castle::API do
4
- subject(:request) { described_class.request(command) }
4
+ subject(:call) { described_class.call(command) }
5
5
 
6
6
  let(:command) { Castle::Commands::Track.new({}).build(event: '$login.succeeded') }
7
7
 
@@ -10,7 +10,7 @@ describe Castle::API do
10
10
 
11
11
  it do
12
12
  expect do
13
- request
13
+ call
14
14
  end.to raise_error(Castle::RequestError)
15
15
  end
16
16
  end
@@ -20,7 +20,7 @@ describe Castle::API do
20
20
 
21
21
  it do
22
22
  expect do
23
- request
23
+ call
24
24
  end.to raise_error(Castle::BadRequestError)
25
25
  end
26
26
  end
@@ -30,7 +30,7 @@ describe Castle::API do
30
30
 
31
31
  it do
32
32
  expect do
33
- request
33
+ call
34
34
  end.to raise_error(Castle::ConfigurationError)
35
35
  end
36
36
  end
@@ -82,10 +82,10 @@ describe Castle::Client do
82
82
  let(:impersonator) { 'test@castle.io' }
83
83
  let(:request_body) do
84
84
  { user_id: '1234', timestamp: time_auto, sent_at: time_auto,
85
- impersonator: impersonator, context: context }
85
+ properties: { impersonator: impersonator }, context: context }
86
86
  end
87
87
  let(:response_body) { { success: true }.to_json }
88
- let(:options) { { user_id: '1234', impersonator: impersonator } }
88
+ let(:options) { { user_id: '1234', properties: { impersonator: impersonator } } }
89
89
 
90
90
  context 'when used with symbol keys' do
91
91
  before { client.impersonate(options) }
@@ -36,9 +36,9 @@ describe Castle::Commands::Impersonate do
36
36
  end
37
37
 
38
38
  context 'with impersonator' do
39
- let(:payload) { default_payload.merge(impersonator: impersonator) }
39
+ let(:payload) { default_payload.merge(properties: { impersonator: impersonator }) }
40
40
  let(:command_data) do
41
- default_payload.merge(impersonator: impersonator, context: context)
41
+ default_payload.merge(properties: { impersonator: impersonator }, context: context)
42
42
  end
43
43
 
44
44
  it { expect(command.method).to be_eql(:post) }
@@ -2,30 +2,30 @@
2
2
 
3
3
  describe Castle::Configuration do
4
4
  subject(:config) do
5
- described_class.new
5
+ described_class.instance
6
6
  end
7
7
 
8
8
  describe 'host' do
9
9
  context 'with default' do
10
- it { expect(config.host).to be_eql('api.castle.io') }
10
+ it { expect(config.url.host).to be_eql('api.castle.io') }
11
11
  end
12
12
 
13
13
  context 'with setter' do
14
- before { config.host = 'api.castle.dev' }
14
+ before { config.url = 'http://api.castle.dev/v2' }
15
15
 
16
- it { expect(config.host).to be_eql('api.castle.dev') }
16
+ it { expect(config.url.host).to be_eql('api.castle.dev') }
17
17
  end
18
18
  end
19
19
 
20
20
  describe 'post' do
21
21
  context 'with default' do
22
- it { expect(config.port).to be_eql(443) }
22
+ it { expect(config.url.port).to be_eql(443) }
23
23
  end
24
24
 
25
25
  context 'with setter' do
26
- before { config.port = 3001 }
26
+ before { config.url = 'http://api.castle.dev:3001/v2' }
27
27
 
28
- it { expect(config.port).to be_eql(3001) }
28
+ it { expect(config.url.port).to be_eql(3001) }
29
29
  end
30
30
  end
31
31
 
@@ -38,6 +38,7 @@ describe Castle::Configuration do
38
38
  allow(ENV).to receive(:fetch).with(
39
39
  'CASTLE_API_SECRET', ''
40
40
  ).and_return(secret_key_env)
41
+ config.reset
41
42
  end
42
43
 
43
44
  it do
@@ -66,7 +67,7 @@ describe Castle::Configuration do
66
67
  end
67
68
 
68
69
  it do
69
- expect(config.api_secret).to be_eql('')
70
+ expect(config.api_secret).to be_eql('secret')
70
71
  end
71
72
  end
72
73
 
@@ -88,34 +89,34 @@ describe Castle::Configuration do
88
89
  end
89
90
  end
90
91
 
91
- describe 'whitelisted' do
92
+ describe 'allowlisted' do
92
93
  it do
93
- expect(config.whitelisted.size).to be_eql(0)
94
+ expect(config.allowlisted.size).to be_eql(0)
94
95
  end
95
96
 
96
97
  context 'with setter' do
97
98
  before do
98
- config.whitelisted = ['header']
99
+ config.allowlisted = ['header']
99
100
  end
100
101
 
101
102
  it do
102
- expect(config.whitelisted).to be_eql(['Header'])
103
+ expect(config.allowlisted).to be_eql(['Header'])
103
104
  end
104
105
  end
105
106
  end
106
107
 
107
- describe 'blacklisted' do
108
+ describe 'denylisted' do
108
109
  it do
109
- expect(config.blacklisted.size).to be_eql(0)
110
+ expect(config.denylisted.size).to be_eql(0)
110
111
  end
111
112
 
112
113
  context 'with setter' do
113
114
  before do
114
- config.blacklisted = ['header']
115
+ config.denylisted = ['header']
115
116
  end
116
117
 
117
118
  it do
118
- expect(config.blacklisted).to be_eql(['Header'])
119
+ expect(config.denylisted).to be_eql(['Header'])
119
120
  end
120
121
  end
121
122
  end
@@ -4,14 +4,14 @@ describe Castle::Context::Default do
4
4
  subject { described_class.new(request, nil) }
5
5
 
6
6
  let(:ip) { '1.2.3.4' }
7
- let(:cookie_id) { 'abcd' }
7
+ let(:client_id) { 'abcd' }
8
8
 
9
9
  let(:env) do
10
10
  Rack::MockRequest.env_for('/',
11
11
  'HTTP_X_FORWARDED_FOR' => ip,
12
12
  'HTTP_ACCEPT_LANGUAGE' => 'en',
13
13
  'HTTP_USER_AGENT' => 'test',
14
- 'HTTP_COOKIE' => "__cid=#{cookie_id};other=efgh")
14
+ 'HTTP_COOKIE' => "__cid=#{client_id};other=efgh")
15
15
  end
16
16
  let(:request) { Rack::Request.new(env) }
17
17
  let(:default_context) { subject.call }
@@ -34,6 +34,7 @@ describe Castle::Context::Default do
34
34
  it { expect(default_context[:origin]).to be_eql('web') }
35
35
  it { expect(default_context[:headers]).to be_eql(result_headers) }
36
36
  it { expect(default_context[:ip]).to be_eql(ip) }
37
+ it { expect(default_context[:client_id]).to be_eql(client_id) }
37
38
  it { expect(default_context[:library][:name]).to be_eql('castle-rb') }
38
39
  it { expect(default_context[:library][:version]).to be_eql(version) }
39
40
  it { expect(default_context[:user_agent]).to be_eql('test') }
@@ -3,7 +3,7 @@
3
3
  describe Castle::Extractors::ClientId do
4
4
  subject(:extractor) { described_class.new(formatted_headers, cookies) }
5
5
 
6
- let(:formatted_headers) { Castle::HeaderFilter.new(request).call }
6
+ let(:formatted_headers) { Castle::HeadersFilter.new(request).call }
7
7
  let(:client_id_cookie) { 'abcd' }
8
8
  let(:client_id_header) { 'abcde' }
9
9
  let(:cookies) { request.cookies }
@@ -3,7 +3,6 @@
3
3
  describe Castle::Extractors::Headers do
4
4
  subject(:headers) { described_class.new(formatted_headers).call }
5
5
 
6
- let(:client_id) { 'abcd' }
7
6
  let(:formatted_headers) do
8
7
  {
9
8
  'Content-Length' => '0',
@@ -17,11 +16,11 @@ describe Castle::Extractors::Headers do
17
16
  end
18
17
 
19
18
  after do
20
- Castle.config.whitelisted = %w[]
21
- Castle.config.blacklisted = %w[]
19
+ Castle.config.allowlisted = %w[]
20
+ Castle.config.denylisted = %w[]
22
21
  end
23
22
 
24
- context 'when whitelist is not set in the configuration' do
23
+ context 'when allowlist is not set in the configuration' do
25
24
  let(:result) do
26
25
  {
27
26
  'Accept' => 'application/json',
@@ -37,8 +36,8 @@ describe Castle::Extractors::Headers do
37
36
  it { expect(headers).to eq(result) }
38
37
  end
39
38
 
40
- context 'when whitelist is set in the configuration' do
41
- before { Castle.config.whitelisted = %w[Accept OK] }
39
+ context 'when allowlist is set in the configuration' do
40
+ before { Castle.config.allowlisted = %w[Accept OK] }
42
41
 
43
42
  let(:result) do
44
43
  {
@@ -55,7 +54,7 @@ describe Castle::Extractors::Headers do
55
54
  it { expect(headers).to eq(result) }
56
55
  end
57
56
 
58
- context 'when blacklist is set in the configuration' do
57
+ context 'when denylist is set in the configuration' do
59
58
  context 'with a User-Agent' do
60
59
  let(:result) do
61
60
  {
@@ -69,7 +68,7 @@ describe Castle::Extractors::Headers do
69
68
  }
70
69
  end
71
70
 
72
- before { Castle.config.blacklisted = %w[User-Agent] }
71
+ before { Castle.config.denylisted = %w[User-Agent] }
73
72
 
74
73
  it { expect(headers).to eq(result) }
75
74
  end
@@ -87,16 +86,16 @@ describe Castle::Extractors::Headers do
87
86
  }
88
87
  end
89
88
 
90
- before { Castle.config.blacklisted = %w[Accept] }
89
+ before { Castle.config.denylisted = %w[Accept] }
91
90
 
92
91
  it { expect(headers).to eq(result) }
93
92
  end
94
93
  end
95
94
 
96
- context 'when a header is both whitelisted and blacklisted' do
95
+ context 'when a header is both allowlisted and denylisted' do
97
96
  before do
98
- Castle.config.whitelisted = %w[Accept]
99
- Castle.config.blacklisted = %w[Accept]
97
+ Castle.config.allowlisted = %w[Accept]
98
+ Castle.config.denylisted = %w[Accept]
100
99
  end
101
100
 
102
101
  it do
@@ -4,6 +4,11 @@ describe Castle::Extractors::IP do
4
4
  subject(:extractor) { described_class.new(headers) }
5
5
 
6
6
  describe 'ip' do
7
+ after do
8
+ Castle.config.ip_headers = []
9
+ Castle.config.trusted_proxies = []
10
+ end
11
+
7
12
  context 'when regular ip' do
8
13
  let(:headers) { { 'X-Forwarded-For' => '1.2.3.5' } }
9
14
 
@@ -16,20 +21,20 @@ describe Castle::Extractors::IP do
16
21
  end
17
22
 
18
23
  context 'with uppercase format' do
19
- before { Castle.config.ip_headers = %w[CF_CONNECTING_IP] }
24
+ before { Castle.config.ip_headers = %w[CF_CONNECTING_IP X-Forwarded-For] }
20
25
 
21
26
  it { expect(extractor.call).to eql('1.2.3.4') }
22
27
  end
23
28
 
24
29
  context 'with regular format' do
25
- before { Castle.config.ip_headers = %w[Cf-Connecting-Ip] }
30
+ before { Castle.config.ip_headers = %w[Cf-Connecting-Ip X-Forwarded-For] }
26
31
 
27
32
  it { expect(extractor.call).to eql('1.2.3.4') }
28
33
  end
29
34
 
30
- context 'with value from trusted proxies' do
35
+ context 'with value from trusted proxies it get seconds header' do
31
36
  before do
32
- Castle.config.ip_headers = %w[Cf-Connecting-Ip]
37
+ Castle.config.ip_headers = %w[Cf-Connecting-Ip X-Forwarded-For]
33
38
  Castle.config.trusted_proxies = %w[1.2.3.4]
34
39
  end
35
40
 
@@ -39,16 +44,44 @@ describe Castle::Extractors::IP do
39
44
 
40
45
  context 'with all the trusted proxies' do
41
46
  let(:http_x_header) do
42
- '127.0.0.1,10.0.0.1,172.31.0.1,192.168.0.1,::1,fd00::,localhost,unix,unix:/tmp/sock'
47
+ '127.0.0.1,10.0.0.1,172.31.0.1,192.168.0.1'
43
48
  end
44
49
 
45
50
  let(:headers) { { 'Remote-Addr' => '127.0.0.1', 'X-Forwarded-For' => http_x_header } }
46
51
 
47
- it 'fallbacks to remote_addr even if trusted proxy' do
52
+ it 'fallbacks to first available header when all headers are marked trusted proxy' do
48
53
  expect(extractor.call).to eql('127.0.0.1')
49
54
  end
50
55
  end
51
56
 
57
+ context 'with trust_proxy_chain option' do
58
+ let(:http_x_header) do
59
+ '6.6.6.6, 2.2.2.3, 6.6.6.5'
60
+ end
61
+
62
+ let(:headers) { { 'Remote-Addr' => '6.6.6.4', 'X-Forwarded-For' => http_x_header } }
63
+
64
+ before { Castle.config.trust_proxy_chain = true }
65
+
66
+ it 'selects first available header' do
67
+ expect(extractor.call).to eql('6.6.6.6')
68
+ end
69
+ end
70
+
71
+ context 'with trusted_proxy_depth option' do
72
+ let(:http_x_header) do
73
+ '6.6.6.6, 2.2.2.3, 6.6.6.5'
74
+ end
75
+
76
+ let(:headers) { { 'Remote-Addr' => '6.6.6.4', 'X-Forwarded-For' => http_x_header } }
77
+
78
+ before { Castle.config.trusted_proxy_depth = 1 }
79
+
80
+ it 'selects first available header' do
81
+ expect(extractor.call).to eql('2.2.2.3')
82
+ end
83
+ end
84
+
52
85
  context 'when list of not trusted ips provided in X_FORWARDED_FOR' do
53
86
  let(:headers) do
54
87
  {
@@ -1,28 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- describe Castle::HeaderFilter do
3
+ describe Castle::HeadersFilter do
4
4
  subject(:headers) { described_class.new(request).call }
5
5
 
6
- let(:client_id) { 'abcd' }
7
6
  let(:env) do
8
- Rack::MockRequest.env_for(
7
+ result = Rack::MockRequest.env_for(
9
8
  '/',
10
9
  'Action-Dispatch.request.content-Type' => 'application/json',
11
10
  'HTTP_AUTHORIZATION' => 'Basic 123456',
12
- 'HTTP_COOKIE' => "__cid=#{client_id};other=efgh",
13
- 'HTTP_OK' => 'OK',
11
+ 'HTTP_COOKIE' => '__cid=abcd;other=efgh',
14
12
  'HTTP_ACCEPT' => 'application/json',
15
13
  'HTTP_X_FORWARDED_FOR' => '1.2.3.4',
16
14
  'HTTP_USER_AGENT' => 'Mozilla 1234',
17
15
  'TEST' => '1',
18
16
  'REMOTE_ADDR' => '1.2.3.4'
19
17
  )
18
+ result[:HTTP_OK] = 'OK'
19
+ result
20
20
  end
21
21
  let(:filtered) do
22
22
  {
23
23
  'Accept' => 'application/json',
24
24
  'Authorization' => 'Basic 123456',
25
- 'Cookie' => "__cid=#{client_id};other=efgh",
25
+ 'Cookie' => '__cid=abcd;other=efgh',
26
26
  'Content-Length' => '0',
27
27
  'Ok' => 'OK',
28
28
  'User-Agent' => 'Mozilla 1234',
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- describe Castle::HeaderFormatter do
4
- subject(:formatter) { described_class.new }
3
+ describe Castle::HeadersFormatter do
4
+ subject(:formatter) { described_class }
5
5
 
6
6
  it 'removes HTTP_' do
7
7
  expect(formatter.call('HTTP_X_TEST')).to be_eql('X-Test')
@@ -16,8 +16,7 @@ WebMock.disable_net_connect!(allow_localhost: true)
16
16
 
17
17
  RSpec.configure do |config|
18
18
  config.before do
19
- Castle.instance_variable_set(:@configuration, Castle::Configuration.new)
20
-
19
+ Castle.config.reset
21
20
  Castle.configure do |cfg|
22
21
  cfg.api_secret = 'secret'
23
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: castle-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johan Brissmyr
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-20 00:00:00.000000000 Z
11
+ date: 2020-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal
@@ -34,9 +34,10 @@ files:
34
34
  - lib/castle-rb.rb
35
35
  - lib/castle.rb
36
36
  - lib/castle/api.rb
37
+ - lib/castle/api/connection.rb
37
38
  - lib/castle/api/request.rb
38
- - lib/castle/api/request/build.rb
39
39
  - lib/castle/api/response.rb
40
+ - lib/castle/api/session.rb
40
41
  - lib/castle/client.rb
41
42
  - lib/castle/command.rb
42
43
  - lib/castle/commands/authenticate.rb
@@ -54,8 +55,8 @@ files:
54
55
  - lib/castle/extractors/headers.rb
55
56
  - lib/castle/extractors/ip.rb
56
57
  - lib/castle/failover_auth_response.rb
57
- - lib/castle/header_filter.rb
58
- - lib/castle/header_formatter.rb
58
+ - lib/castle/headers_filter.rb
59
+ - lib/castle/headers_formatter.rb
59
60
  - lib/castle/review.rb
60
61
  - lib/castle/secure_mode.rb
61
62
  - lib/castle/support/hanami.rb
@@ -73,9 +74,10 @@ files:
73
74
  - spec/integration/rails/support/all.rb
74
75
  - spec/integration/rails/support/application.rb
75
76
  - spec/integration/rails/support/home_controller.rb
76
- - spec/lib/castle/api/request/build_spec.rb
77
+ - spec/lib/castle/api/connection_spec.rb
77
78
  - spec/lib/castle/api/request_spec.rb
78
79
  - spec/lib/castle/api/response_spec.rb
80
+ - spec/lib/castle/api/session_spec.rb
79
81
  - spec/lib/castle/api_spec.rb
80
82
  - spec/lib/castle/client_spec.rb
81
83
  - spec/lib/castle/command_spec.rb
@@ -92,8 +94,8 @@ files:
92
94
  - spec/lib/castle/extractors/client_id_spec.rb
93
95
  - spec/lib/castle/extractors/headers_spec.rb
94
96
  - spec/lib/castle/extractors/ip_spec.rb
95
- - spec/lib/castle/header_filter_spec.rb
96
- - spec/lib/castle/header_formatter_spec.rb
97
+ - spec/lib/castle/headers_filter_spec.rb
98
+ - spec/lib/castle/headers_formatter_spec.rb
97
99
  - spec/lib/castle/review_spec.rb
98
100
  - spec/lib/castle/secure_mode_spec.rb
99
101
  - spec/lib/castle/utils/cloner_spec.rb
@@ -109,7 +111,7 @@ homepage: https://castle.io
109
111
  licenses:
110
112
  - MIT
111
113
  metadata: {}
112
- post_install_message:
114
+ post_install_message:
113
115
  rdoc_options: []
114
116
  require_paths:
115
117
  - lib
@@ -124,8 +126,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
126
  - !ruby/object:Gem::Version
125
127
  version: '0'
126
128
  requirements: []
127
- rubygems_version: 3.0.6
128
- signing_key:
129
+ rubygems_version: 3.1.3
130
+ signing_key:
129
131
  specification_version: 4
130
132
  summary: Castle
131
133
  test_files:
@@ -136,6 +138,7 @@ test_files:
136
138
  - spec/integration/rails/rails_spec.rb
137
139
  - spec/lib/castle_spec.rb
138
140
  - spec/lib/castle/review_spec.rb
141
+ - spec/lib/castle/headers_filter_spec.rb
139
142
  - spec/lib/castle/client_spec.rb
140
143
  - spec/lib/castle/context/default_spec.rb
141
144
  - spec/lib/castle/context/merger_spec.rb
@@ -143,15 +146,15 @@ test_files:
143
146
  - spec/lib/castle/api_spec.rb
144
147
  - spec/lib/castle/configuration_spec.rb
145
148
  - spec/lib/castle/version_spec.rb
146
- - spec/lib/castle/header_formatter_spec.rb
147
149
  - spec/lib/castle/utils/cloner_spec.rb
148
150
  - spec/lib/castle/utils/timestamp_spec.rb
149
151
  - spec/lib/castle/utils/merger_spec.rb
150
152
  - spec/lib/castle/command_spec.rb
153
+ - spec/lib/castle/headers_formatter_spec.rb
154
+ - spec/lib/castle/api/session_spec.rb
151
155
  - spec/lib/castle/api/request_spec.rb
156
+ - spec/lib/castle/api/connection_spec.rb
152
157
  - spec/lib/castle/api/response_spec.rb
153
- - spec/lib/castle/api/request/build_spec.rb
154
- - spec/lib/castle/header_filter_spec.rb
155
158
  - spec/lib/castle/commands/review_spec.rb
156
159
  - spec/lib/castle/commands/authenticate_spec.rb
157
160
  - spec/lib/castle/commands/track_spec.rb