castle-rb 4.0.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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