castle-rb 3.4.2 → 3.5.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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/castle/client.rb +4 -1
- data/lib/castle/configuration.rb +2 -2
- data/lib/castle/context/default.rb +1 -1
- data/lib/castle/errors.rb +3 -0
- data/lib/castle/extractors/client_id.rb +2 -3
- data/lib/castle/version.rb +1 -1
- data/spec/lib/castle/client_spec.rb +19 -11
- data/spec/lib/castle/commands/authenticate_spec.rb +3 -3
- data/spec/lib/castle/commands/identify_spec.rb +3 -3
- data/spec/lib/castle/commands/track_spec.rb +3 -3
- data/spec/lib/castle/extractors/client_id_spec.rb +21 -6
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6376098ba7a5b711d926fe187c38d2ed31a68b7ddf53024f2d51a81a14482604
|
4
|
+
data.tar.gz: b4ca1f4dbd10607b5c5bfad6a9b7528d3ebb8ebf7a2b6fd1287af08333b110d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70c04aa5f1d0f3f4af5789a7aad877380b3d82fafbd935ec746bd40aab904c110bea4410d161c48521fee108a5212c7d81b8a00b465b82940e7f6f9c48236f26
|
7
|
+
data.tar.gz: 345383199ba415d699f97f1ebf242d21dc8e1eb921a4c60f6366464a1e6bc5b5ac0680d7010e6f2b4b9ff5366393c9fd9b70237951ac7b013328e05af3af11b7
|
data/README.md
CHANGED
data/lib/castle/client.rb
CHANGED
@@ -17,6 +17,7 @@ module Castle
|
|
17
17
|
|
18
18
|
def to_options(options = {})
|
19
19
|
options[:timestamp] ||= Castle::Utils::Timestamp.call
|
20
|
+
warn '[DEPRECATION] use user_traits instead of traits key' if options.key?(:traits)
|
20
21
|
options
|
21
22
|
end
|
22
23
|
|
@@ -80,7 +81,9 @@ module Castle
|
|
80
81
|
options = Castle::Utils.deep_symbolize_keys(options || {})
|
81
82
|
add_timestamp_if_necessary(options)
|
82
83
|
command = Castle::Commands::Impersonate.new(@context).build(options)
|
83
|
-
@api.request(command)
|
84
|
+
@api.request(command).tap do |response|
|
85
|
+
raise Castle::ImpersonationFailed unless response[:success]
|
86
|
+
end
|
84
87
|
end
|
85
88
|
|
86
89
|
def disable_tracking
|
data/lib/castle/configuration.rb
CHANGED
@@ -65,8 +65,8 @@ module Castle
|
|
65
65
|
/^(\w+)=$/ =~ method_name
|
66
66
|
end
|
67
67
|
|
68
|
-
def method_missing(
|
69
|
-
raise Castle::ConfigurationError, "there is no such a config #{
|
68
|
+
def method_missing(setting, *_args)
|
69
|
+
raise Castle::ConfigurationError, "there is no such a config #{setting}"
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
@@ -4,7 +4,7 @@ module Castle
|
|
4
4
|
module Context
|
5
5
|
class Default
|
6
6
|
def initialize(request, cookies = nil)
|
7
|
-
@client_id = Extractors::ClientId.new(request, cookies || request.cookies).call
|
7
|
+
@client_id = Extractors::ClientId.new(request, cookies || request.cookies).call
|
8
8
|
@headers = Extractors::Headers.new(request).call
|
9
9
|
@request_ip = Extractors::IP.new(request).call
|
10
10
|
end
|
data/lib/castle/errors.rb
CHANGED
data/lib/castle/version.rb
CHANGED
@@ -36,13 +36,14 @@ describe Castle::Client do
|
|
36
36
|
let(:time_now) { Time.now }
|
37
37
|
let(:time_auto) { time_now.utc.iso8601(3) }
|
38
38
|
let(:time_user) { (Time.now - 10_000).utc.iso8601(3) }
|
39
|
+
let(:response_body) { {}.to_json }
|
39
40
|
|
40
41
|
before do
|
41
42
|
Timecop.freeze(time_now)
|
42
43
|
stub_const('Castle::VERSION', '2.2.0')
|
43
44
|
stub_request(:any, /api.castle.io/).with(
|
44
45
|
basic_auth: ['', 'secret']
|
45
|
-
).to_return(status: 200, body:
|
46
|
+
).to_return(status: 200, body: response_body, headers: {})
|
46
47
|
end
|
47
48
|
|
48
49
|
after { Timecop.return }
|
@@ -65,8 +66,8 @@ describe Castle::Client do
|
|
65
66
|
end
|
66
67
|
|
67
68
|
describe 'to_options' do
|
68
|
-
let(:options) { { user_id: '1234',
|
69
|
-
let(:result) { { user_id: '1234',
|
69
|
+
let(:options) { { user_id: '1234', user_traits: { name: 'Jo' } } }
|
70
|
+
let(:result) { { user_id: '1234', user_traits: { name: 'Jo' }, timestamp: time_auto } }
|
70
71
|
|
71
72
|
it do
|
72
73
|
expect(described_class.to_options(options)).to eql(result)
|
@@ -79,29 +80,36 @@ describe Castle::Client do
|
|
79
80
|
{ user_id: '1234', timestamp: time_auto, sent_at: time_auto,
|
80
81
|
impersonator: impersonator, context: context }
|
81
82
|
end
|
83
|
+
let(:response_body) { { success: true }.to_json }
|
82
84
|
let(:options) { { user_id: '1234', impersonator: impersonator } }
|
83
85
|
|
84
|
-
before { client.impersonate(options) }
|
85
|
-
|
86
86
|
context 'when used with symbol keys' do
|
87
|
+
before { client.impersonate(options) }
|
88
|
+
|
87
89
|
it do
|
88
90
|
assert_requested :post, 'https://api.castle.io/v1/impersonate', times: 1 do |req|
|
89
91
|
JSON.parse(req.body) == JSON.parse(request_body.to_json)
|
90
92
|
end
|
91
93
|
end
|
92
94
|
end
|
95
|
+
|
96
|
+
context 'when request is not successful' do
|
97
|
+
let(:response_body) { {}.to_json }
|
98
|
+
|
99
|
+
it { expect { client.impersonate(options) }.to raise_error(Castle::ImpersonationFailed) }
|
100
|
+
end
|
93
101
|
end
|
94
102
|
|
95
103
|
describe 'identify' do
|
96
104
|
let(:request_body) do
|
97
105
|
{ user_id: '1234', timestamp: time_auto,
|
98
|
-
sent_at: time_auto, context: context,
|
106
|
+
sent_at: time_auto, context: context, user_traits: { name: 'Jo' } }
|
99
107
|
end
|
100
108
|
|
101
109
|
before { client.identify(options) }
|
102
110
|
|
103
111
|
context 'when used with symbol keys' do
|
104
|
-
let(:options) { { user_id: '1234',
|
112
|
+
let(:options) { { user_id: '1234', user_traits: { name: 'Jo' } } }
|
105
113
|
|
106
114
|
it do
|
107
115
|
assert_requested :post, 'https://api.castle.io/v1/identify', times: 1 do |req|
|
@@ -111,9 +119,9 @@ describe Castle::Client do
|
|
111
119
|
|
112
120
|
context 'when passed timestamp in options and no defined timestamp' do
|
113
121
|
let(:client) { client_with_no_timestamp }
|
114
|
-
let(:options) { { user_id: '1234',
|
122
|
+
let(:options) { { user_id: '1234', user_traits: { name: 'Jo' }, timestamp: time_user } }
|
115
123
|
let(:request_body) do
|
116
|
-
{ user_id: '1234',
|
124
|
+
{ user_id: '1234', user_traits: { name: 'Jo' }, context: context,
|
117
125
|
timestamp: time_user, sent_at: time_auto }
|
118
126
|
end
|
119
127
|
|
@@ -128,7 +136,7 @@ describe Castle::Client do
|
|
128
136
|
let(:client) { client_with_user_timestamp }
|
129
137
|
let(:request_body) do
|
130
138
|
{ user_id: '1234', timestamp: time_user, sent_at: time_auto,
|
131
|
-
context: context,
|
139
|
+
context: context, user_traits: { name: 'Jo' } }
|
132
140
|
end
|
133
141
|
|
134
142
|
it do
|
@@ -140,7 +148,7 @@ describe Castle::Client do
|
|
140
148
|
end
|
141
149
|
|
142
150
|
context 'when used with string keys' do
|
143
|
-
let(:options) { { 'user_id' => '1234', '
|
151
|
+
let(:options) { { 'user_id' => '1234', 'user_traits' => { 'name' => 'Jo' } } }
|
144
152
|
|
145
153
|
it do
|
146
154
|
assert_requested :post, 'https://api.castle.io/v1/identify', times: 1 do |req|
|
@@ -37,10 +37,10 @@ describe Castle::Commands::Authenticate do
|
|
37
37
|
it { expect(command.data).to be_eql(command_data) }
|
38
38
|
end
|
39
39
|
|
40
|
-
context 'with
|
41
|
-
let(:payload) { default_payload.merge(
|
40
|
+
context 'with user_traits' do
|
41
|
+
let(:payload) { default_payload.merge(user_traits: { test: '1' }) }
|
42
42
|
let(:command_data) do
|
43
|
-
default_payload.merge(
|
43
|
+
default_payload.merge(user_traits: { test: '1' }, context: context)
|
44
44
|
end
|
45
45
|
|
46
46
|
it { expect(command.method).to be_eql(:post) }
|
@@ -26,10 +26,10 @@ describe Castle::Commands::Identify do
|
|
26
26
|
it { expect(command.data).to be_eql(command_data) }
|
27
27
|
end
|
28
28
|
|
29
|
-
context 'with
|
30
|
-
let(:payload) { default_payload.merge(
|
29
|
+
context 'with user_traits' do
|
30
|
+
let(:payload) { default_payload.merge(user_traits: { test: '1' }) }
|
31
31
|
let(:command_data) do
|
32
|
-
default_payload.merge(
|
32
|
+
default_payload.merge(user_traits: { test: '1' }, context: context)
|
33
33
|
end
|
34
34
|
|
35
35
|
it { expect(command.method).to be_eql(:post) }
|
@@ -48,10 +48,10 @@ describe Castle::Commands::Track do
|
|
48
48
|
it { expect(command.data).to be_eql(command_data) }
|
49
49
|
end
|
50
50
|
|
51
|
-
context 'with
|
52
|
-
let(:payload) { default_payload.merge(
|
51
|
+
context 'with user_traits' do
|
52
|
+
let(:payload) { default_payload.merge(user_traits: { test: '1' }) }
|
53
53
|
let(:command_data) do
|
54
|
-
default_payload.merge(
|
54
|
+
default_payload.merge(user_traits: { test: '1' }, context: context)
|
55
55
|
end
|
56
56
|
|
57
57
|
it { expect(command.method).to be_eql(:post) }
|
@@ -3,7 +3,8 @@
|
|
3
3
|
describe Castle::Extractors::ClientId do
|
4
4
|
subject(:extractor) { described_class.new(request, cookies) }
|
5
5
|
|
6
|
-
let(:
|
6
|
+
let(:client_id_cookie) { 'abcd' }
|
7
|
+
let(:client_id_header) { 'abcde' }
|
7
8
|
let(:cookies) { request.cookies }
|
8
9
|
let(:request) { Rack::Request.new(env) }
|
9
10
|
let(:env) do
|
@@ -14,12 +15,12 @@ describe Castle::Extractors::ClientId do
|
|
14
15
|
let(:headers) do
|
15
16
|
{
|
16
17
|
'HTTP_X_FORWARDED_FOR' => '1.2.3.4',
|
17
|
-
'HTTP_COOKIE' => "__cid=#{
|
18
|
+
'HTTP_COOKIE' => "__cid=#{client_id_cookie};other=efgh"
|
18
19
|
}
|
19
20
|
end
|
20
21
|
|
21
22
|
it do
|
22
|
-
expect(extractor.call
|
23
|
+
expect(extractor.call).to eql(client_id_cookie)
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
@@ -27,12 +28,12 @@ describe Castle::Extractors::ClientId do
|
|
27
28
|
let(:headers) do
|
28
29
|
{
|
29
30
|
'HTTP_X_FORWARDED_FOR' => '1.2.3.4',
|
30
|
-
'HTTP_X_CASTLE_CLIENT_ID' =>
|
31
|
+
'HTTP_X_CASTLE_CLIENT_ID' => client_id_header
|
31
32
|
}
|
32
33
|
end
|
33
34
|
|
34
35
|
it 'appends the client_id' do
|
35
|
-
expect(extractor.call
|
36
|
+
expect(extractor.call).to eql(client_id_header)
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
@@ -41,7 +42,21 @@ describe Castle::Extractors::ClientId do
|
|
41
42
|
let(:headers) { {} }
|
42
43
|
|
43
44
|
it do
|
44
|
-
expect(extractor.call
|
45
|
+
expect(extractor.call).to eql('')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with X-Castle-Client-Id header and cookies client' do
|
50
|
+
let(:headers) do
|
51
|
+
{
|
52
|
+
'HTTP_X_FORWARDED_FOR' => '1.2.3.4',
|
53
|
+
'HTTP_X_CASTLE_CLIENT_ID' => client_id_header,
|
54
|
+
'HTTP_COOKIE' => "__cid=#{client_id_cookie};other=efgh"
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'appends the client_id' do
|
59
|
+
expect(extractor.call).to eql(client_id_header)
|
45
60
|
end
|
46
61
|
end
|
47
62
|
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: 3.
|
4
|
+
version: 3.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johan Brissmyr
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-04-18 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Castle protects your users from account compromise
|
14
14
|
email: johan@castle.io
|
@@ -101,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
101
|
version: '0'
|
102
102
|
requirements: []
|
103
103
|
rubyforge_project:
|
104
|
-
rubygems_version: 2.7.
|
104
|
+
rubygems_version: 2.7.4
|
105
105
|
signing_key:
|
106
106
|
specification_version: 4
|
107
107
|
summary: Castle
|