castle-rb 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40234604d033086c79d951cbec5a52902df4ccda433eff1749c20cfeaca114d6
4
- data.tar.gz: e46b4d91acbcf6c370de3a0804d3f9e75ad86bc181b40e2727e92d5d63579953
3
+ metadata.gz: d0d6aa4996eb091692c0a7dfcf9658b2b26fb011cfa94103604a79e60d401ac0
4
+ data.tar.gz: 8e7eb4c21cf3edd7a3845fc946857dd25ad1031d75dfa8cf8cb8b911b928eebe
5
5
  SHA512:
6
- metadata.gz: d70f1b03fb44e3d23afcb03ca83165f5b521a53269f34d2ed63740cc181e110da3692db50d6f701477a24430262d08859a71f7faeae8867c8962242d7421545d
7
- data.tar.gz: b4a32a603c55df97450e59f936677d5b56387b8d4bf145d4355ca7f5ec606c557d00da72a92bb3f2b641d93a3d3f6e21b9f9412fff35f1840c43db66789b3b6c
6
+ metadata.gz: 9bdf75588225fd282a36d1e37c1ee3eb69ecfab3f3e50a2c27d695f8c7c7ad1a2bccdb8b097dbe9ff361c17481c9449808d9c26adf56924eb249a18ffb2e9a71
7
+ data.tar.gz: '089b2507cd099a863b9592c8a194f5971f2126a7ff2892d0f211ace1a9b06261872a9a13d98a72b617f59815d70d87a4c49ca9e348c06031554a3a8cbe905140'
@@ -29,15 +29,15 @@
29
29
  castle/configuration
30
30
  castle/failover_auth_response
31
31
  castle/client
32
- castle/header_filter
33
- castle/header_formatter
32
+ castle/headers_filter
33
+ castle/headers_formatter
34
34
  castle/secure_mode
35
35
  castle/extractors/client_id
36
36
  castle/extractors/headers
37
37
  castle/extractors/ip
38
38
  castle/api/response
39
39
  castle/api/request
40
- castle/api/request/build
40
+ castle/api/session
41
41
  castle/review
42
42
  castle/api
43
43
  ].each(&method(:require))
@@ -54,7 +54,7 @@ module Castle
54
54
  end
55
55
 
56
56
  def config
57
- @config ||= Castle::Configuration.new
57
+ Configuration.instance
58
58
  end
59
59
 
60
60
  def api_secret=(api_secret)
@@ -17,16 +17,16 @@ module Castle
17
17
  private_constant :HANDLED_ERRORS
18
18
 
19
19
  class << self
20
+ # @param command [String]
21
+ # @param headers [Hash]
20
22
  def request(command, headers = {})
21
23
  raise Castle::ConfigurationError, 'configuration is not valid' unless Castle.config.valid?
22
24
 
23
25
  begin
24
- Castle::API::Response.call(
25
- Castle::API::Request.call(
26
- command,
27
- Castle.config.api_secret,
28
- headers
29
- )
26
+ Castle::API::Request.call(
27
+ command,
28
+ Castle.config.api_secret,
29
+ headers
30
30
  )
31
31
  rescue *HANDLED_ERRORS => e
32
32
  # @note We need to initialize the error, as the original error is a cause for this
@@ -35,6 +35,12 @@ module Castle
35
35
  raise Castle::RequestError.new(e) # rubocop:disable Style/RaiseArgs
36
36
  end
37
37
  end
38
+
39
+ # @param command [String]
40
+ # @param headers [Hash]
41
+ def call(command, headers = {})
42
+ Castle::API::Response.call(request(command, headers))
43
+ end
38
44
  end
39
45
  end
40
46
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Castle
4
- # this class is responsible for making requests to api
5
4
  module API
5
+ # this class is responsible for making requests to api
6
6
  module Request
7
7
  # Default headers that we add to passed ones
8
8
  DEFAULT_HEADERS = {
@@ -13,8 +13,8 @@ module Castle
13
13
 
14
14
  class << self
15
15
  def call(command, api_secret, headers)
16
- http.request(
17
- Castle::API::Request::Build.call(
16
+ Castle::API::Session.get.request(
17
+ build(
18
18
  command,
19
19
  headers.merge(DEFAULT_HEADERS),
20
20
  api_secret
@@ -22,14 +22,19 @@ module Castle
22
22
  )
23
23
  end
24
24
 
25
- def http
26
- http = Net::HTTP.new(Castle.config.host, Castle.config.port)
27
- http.read_timeout = Castle.config.request_timeout / 1000.0
28
- if Castle.config.port == 443
29
- http.use_ssl = true
30
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
25
+ def build(command, headers, api_secret)
26
+ request_obj = Net::HTTP.const_get(
27
+ command.method.to_s.capitalize
28
+ ).new("#{Castle.config.url_prefix}/#{command.path}", headers)
29
+
30
+ unless command.method == :get
31
+ request_obj.body = ::Castle::Utils.replace_invalid_characters(
32
+ command.data
33
+ ).to_json
31
34
  end
32
- http
35
+
36
+ request_obj.basic_auth('', api_secret)
37
+ request_obj
33
38
  end
34
39
  end
35
40
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ module Castle
6
+ module API
7
+ # this class keeps http config object
8
+ # and provides start/finish methods for persistent connection usage
9
+ # when there is a need of sending multiple requests at once
10
+ class Session
11
+ include Singleton
12
+
13
+ attr_accessor :http
14
+
15
+ def initialize
16
+ reset
17
+ end
18
+
19
+ def reset
20
+ @http = Net::HTTP.new(Castle.config.host, Castle.config.port)
21
+ @http.read_timeout = Castle.config.request_timeout / 1000.0
22
+
23
+ if Castle.config.port == 443
24
+ @http.use_ssl = true
25
+ @http.verify_mode = OpenSSL::SSL::VERIFY_PEER
26
+ end
27
+
28
+ @http
29
+ end
30
+
31
+ class << self
32
+ # @return [Net::HTTP]
33
+ def get
34
+ instance.http
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -44,7 +44,7 @@ module Castle
44
44
  add_timestamp_if_necessary(options)
45
45
  command = Castle::Commands::Authenticate.new(@context).build(options)
46
46
  begin
47
- Castle::API.request(command).merge(failover: false, failover_reason: nil)
47
+ Castle::API.call(command).merge(failover: false, failover_reason: nil)
48
48
  rescue Castle::RequestError, Castle::InternalServerError => e
49
49
  self.class.failover_response_or_raise(
50
50
  FailoverAuthResponse.new(options[:user_id], reason: e.to_s), e
@@ -60,7 +60,7 @@ module Castle
60
60
  add_timestamp_if_necessary(options)
61
61
 
62
62
  command = Castle::Commands::Identify.new(@context).build(options)
63
- Castle::API.request(command)
63
+ Castle::API.call(command)
64
64
  end
65
65
 
66
66
  def track(options = {})
@@ -71,14 +71,14 @@ module Castle
71
71
  add_timestamp_if_necessary(options)
72
72
 
73
73
  command = Castle::Commands::Track.new(@context).build(options)
74
- Castle::API.request(command)
74
+ Castle::API.call(command)
75
75
  end
76
76
 
77
77
  def impersonate(options = {})
78
78
  options = Castle::Utils.deep_symbolize_keys(options || {})
79
79
  add_timestamp_if_necessary(options)
80
80
  command = Castle::Commands::Impersonate.new(@context).build(options)
81
- Castle::API.request(command).tap do |response|
81
+ Castle::API.call(command).tap do |response|
82
82
  raise Castle::ImpersonationFailed unless response[:success]
83
83
  end
84
84
  end
@@ -3,9 +3,11 @@
3
3
  module Castle
4
4
  # manages configuration variables
5
5
  class Configuration
6
+ include Singleton
7
+
6
8
  HOST = 'api.castle.io'
7
9
  PORT = 443
8
- URL_PREFIX = 'v1'
10
+ URL_PREFIX = '/v1'
9
11
  FAILOVER_STRATEGY = :allow
10
12
  REQUEST_TIMEOUT = 500 # in milliseconds
11
13
  FAILOVER_STRATEGIES = %i[allow deny challenge throw].freeze
@@ -44,8 +46,12 @@ module Castle
44
46
  attr_reader :api_secret, :whitelisted, :blacklisted, :failover_strategy, :ip_headers, :trusted_proxies
45
47
 
46
48
  def initialize
47
- @formatter = Castle::HeaderFormatter.new
49
+ @formatter = Castle::HeadersFormatter
48
50
  @request_timeout = REQUEST_TIMEOUT
51
+ reset
52
+ end
53
+
54
+ def reset
49
55
  self.failover_strategy = FAILOVER_STRATEGY
50
56
  self.host = HOST
51
57
  self.port = PORT
@@ -4,7 +4,7 @@ module Castle
4
4
  module Context
5
5
  class Default
6
6
  def initialize(request, cookies = nil)
7
- @pre_headers = HeaderFilter.new(request).call
7
+ @pre_headers = HeadersFilter.new(request).call
8
8
  @cookies = cookies || request.cookies
9
9
  @request = request
10
10
  end
@@ -45,7 +45,13 @@ module Castle
45
45
  # @param ips [Array<String>]
46
46
  # @return [Array<String>]
47
47
  def remove_proxies(ips)
48
- ips.reject { |ip| @proxies.any? { |proxy| proxy.match(ip) } }
48
+ ips.reject { |ip| proxy?(ip) }
49
+ end
50
+
51
+ # @param ip [String]
52
+ # @return [Boolean]
53
+ def proxy?(ip)
54
+ @proxies.any? { |proxy| proxy.match(ip) }
49
55
  end
50
56
 
51
57
  # @param header [String]
@@ -2,23 +2,23 @@
2
2
 
3
3
  module Castle
4
4
  # used for preparing valuable headers list
5
- class HeaderFilter
5
+ class HeadersFilter
6
6
  # headers filter
7
7
  # HTTP_ - this is how Rack prefixes incoming HTTP headers
8
8
  # CONTENT_LENGTH - for responses without Content-Length or Transfer-Encoding header
9
9
  # REMOTE_ADDR - ip address header returned by web server
10
- VALUABLE_HEADERS = /^(
11
- HTTP_.*|
12
- CONTENT_LENGTH|
13
- REMOTE_ADDR
14
- )$/x.freeze
10
+ VALUABLE_HEADERS = /^
11
+ HTTP(?:_|-).*|
12
+ CONTENT(?:_|-)LENGTH|
13
+ REMOTE(?:_|-)ADDR
14
+ $/xi.freeze
15
15
 
16
16
  private_constant :VALUABLE_HEADERS
17
17
 
18
18
  # @param request [Rack::Request]
19
19
  def initialize(request)
20
20
  @request_env = request.env
21
- @formatter = HeaderFormatter.new
21
+ @formatter = HeadersFormatter
22
22
  end
23
23
 
24
24
  # Serialize HTTP headers
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Castle
4
+ # formats header name
5
+ class HeadersFormatter
6
+ class << self
7
+ # @param header [String]
8
+ # @return [String]
9
+ def call(header)
10
+ format(header.to_s.gsub(/^HTTP(?:_|-)/i, ''))
11
+ end
12
+
13
+ private
14
+
15
+ # @param header [String]
16
+ # @return [String]
17
+ def format(header)
18
+ header.split(/_|-/).map(&:capitalize).join('-')
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Castle
4
- VERSION = '4.0.0'
4
+ VERSION = '4.1.0'
5
5
  end
@@ -4,57 +4,69 @@ describe Castle::API::Request do
4
4
  describe '#call' do
5
5
  subject(:call) { described_class.call(command, api_secret, headers) }
6
6
 
7
+ let(:session) { instance_double('Castle::API::Session') }
7
8
  let(:http) { instance_double('Net::HTTP') }
8
- let(:request_build) { instance_double('Castle::API::Request::Build') }
9
9
  let(:command) { Castle::Commands::Track.new({}).build(event: '$login.succeeded') }
10
10
  let(:headers) { {} }
11
11
  let(:api_secret) { 'secret' }
12
+ let(:request_build) { {} }
12
13
  let(:expected_headers) { { 'Content-Type' => 'application/json' } }
13
14
 
14
15
  before do
15
- allow(described_class).to receive(:http).and_return(http)
16
- allow(http).to receive(:request).with(request_build)
17
- allow(Castle::API::Request::Build).to receive(:call)
18
- .with(command, expected_headers, api_secret)
19
- .and_return(request_build)
16
+ allow(Castle::API::Session).to receive(:instance).and_return(session)
17
+ allow(session).to receive(:http).and_return(http)
18
+ allow(http).to receive(:request)
19
+ allow(described_class).to receive(:build).and_return(request_build)
20
20
  call
21
21
  end
22
22
 
23
23
  it do
24
- expect(Castle::API::Request::Build).to have_received(:call)
25
- .with(command, expected_headers, api_secret)
24
+ expect(described_class).to have_received(:build).with(command, expected_headers, api_secret)
26
25
  end
27
26
 
28
27
  it { expect(http).to have_received(:request).with(request_build) }
29
28
  end
30
29
 
31
- describe '#http' do
32
- subject(:http) { described_class.http }
30
+ describe '#build' do
31
+ subject(:build) { described_class.build(command, headers, api_secret) }
33
32
 
34
- context 'when ssl false' do
35
- before do
36
- Castle.config.host = 'localhost'
37
- Castle.config.port = 3002
38
- end
33
+ let(:headers) { { 'SAMPLE-HEADER' => '1' } }
34
+ let(:api_secret) { 'secret' }
39
35
 
40
- after do
41
- Castle.config.host = Castle::Configuration::HOST
42
- Castle.config.port = Castle::Configuration::PORT
43
- end
36
+ context 'when get' do
37
+ let(:command) { Castle::Commands::Review.build(review_id) }
38
+ let(:review_id) { SecureRandom.uuid }
44
39
 
45
- it { expect(http).to be_instance_of(Net::HTTP) }
46
- it { expect(http.address).to eq(Castle.config.host) }
47
- it { expect(http.port).to eq(Castle.config.port) }
48
- it { expect(http.use_ssl?).to be false }
49
- it { expect(http.verify_mode).to be_nil }
40
+ it { expect(build.body).to be_nil }
41
+ it { expect(build.method).to eql('GET') }
42
+ it { expect(build.path).to eql("/v1/#{command.path}") }
43
+ it { expect(build.to_hash).to have_key('authorization') }
44
+ it { expect(build.to_hash).to have_key('sample-header') }
45
+ it { expect(build.to_hash['sample-header']).to eql(['1']) }
50
46
  end
51
47
 
52
- context 'when ssl true' do
53
- it { expect(http).to be_instance_of(Net::HTTP) }
54
- it { expect(http.address).to eq(Castle.config.host) }
55
- it { expect(http.port).to eq(Castle.config.port) }
56
- it { expect(http.use_ssl?).to be true }
57
- it { expect(http.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER) }
48
+ context 'when post' do
49
+ let(:time) { Time.now.utc.iso8601(3) }
50
+ let(:command) do
51
+ Castle::Commands::Track.new({}).build(event: '$login.succeeded', name: "\xC4")
52
+ end
53
+ let(:expected_body) do
54
+ {
55
+ event: '$login.succeeded',
56
+ name: '�',
57
+ context: {},
58
+ sent_at: time
59
+ }
60
+ end
61
+
62
+ before { allow(Castle::Utils::Timestamp).to receive(:call).and_return(time) }
63
+
64
+ it { expect(build.body).to be_eql(expected_body.to_json) }
65
+ it { expect(build.method).to eql('POST') }
66
+ it { expect(build.path).to eql("/v1/#{command.path}") }
67
+ it { expect(build.to_hash).to have_key('authorization') }
68
+ it { expect(build.to_hash).to have_key('sample-header') }
69
+ it { expect(build.to_hash['sample-header']).to eql(['1']) }
58
70
  end
59
71
  end
60
72
  end
@@ -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
@@ -2,7 +2,7 @@
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
@@ -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
 
@@ -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',
@@ -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
 
@@ -1,16 +1,15 @@
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
7
  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',
12
+ 'http-ok' => 'OK',
14
13
  'HTTP_ACCEPT' => 'application/json',
15
14
  'HTTP_X_FORWARDED_FOR' => '1.2.3.4',
16
15
  'HTTP_USER_AGENT' => 'Mozilla 1234',
@@ -22,7 +21,7 @@ describe Castle::HeaderFilter do
22
21
  {
23
22
  'Accept' => 'application/json',
24
23
  'Authorization' => 'Basic 123456',
25
- 'Cookie' => "__cid=#{client_id};other=efgh",
24
+ 'Cookie' => '__cid=abcd;other=efgh',
26
25
  'Content-Length' => '0',
27
26
  'Ok' => 'OK',
28
27
  '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: 4.1.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: 2020-03-20 00:00:00.000000000 Z
11
+ date: 2020-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal
@@ -35,8 +35,8 @@ files:
35
35
  - lib/castle.rb
36
36
  - lib/castle/api.rb
37
37
  - lib/castle/api/request.rb
38
- - lib/castle/api/request/build.rb
39
38
  - lib/castle/api/response.rb
39
+ - lib/castle/api/session.rb
40
40
  - lib/castle/client.rb
41
41
  - lib/castle/command.rb
42
42
  - lib/castle/commands/authenticate.rb
@@ -54,8 +54,8 @@ files:
54
54
  - lib/castle/extractors/headers.rb
55
55
  - lib/castle/extractors/ip.rb
56
56
  - lib/castle/failover_auth_response.rb
57
- - lib/castle/header_filter.rb
58
- - lib/castle/header_formatter.rb
57
+ - lib/castle/headers_filter.rb
58
+ - lib/castle/headers_formatter.rb
59
59
  - lib/castle/review.rb
60
60
  - lib/castle/secure_mode.rb
61
61
  - lib/castle/support/hanami.rb
@@ -73,7 +73,6 @@ files:
73
73
  - spec/integration/rails/support/all.rb
74
74
  - spec/integration/rails/support/application.rb
75
75
  - spec/integration/rails/support/home_controller.rb
76
- - spec/lib/castle/api/request/build_spec.rb
77
76
  - spec/lib/castle/api/request_spec.rb
78
77
  - spec/lib/castle/api/response_spec.rb
79
78
  - spec/lib/castle/api_spec.rb
@@ -92,8 +91,8 @@ files:
92
91
  - spec/lib/castle/extractors/client_id_spec.rb
93
92
  - spec/lib/castle/extractors/headers_spec.rb
94
93
  - spec/lib/castle/extractors/ip_spec.rb
95
- - spec/lib/castle/header_filter_spec.rb
96
- - spec/lib/castle/header_formatter_spec.rb
94
+ - spec/lib/castle/headers_filter_spec.rb
95
+ - spec/lib/castle/headers_formatter_spec.rb
97
96
  - spec/lib/castle/review_spec.rb
98
97
  - spec/lib/castle/secure_mode_spec.rb
99
98
  - spec/lib/castle/utils/cloner_spec.rb
@@ -136,6 +135,7 @@ test_files:
136
135
  - spec/integration/rails/rails_spec.rb
137
136
  - spec/lib/castle_spec.rb
138
137
  - spec/lib/castle/review_spec.rb
138
+ - spec/lib/castle/headers_filter_spec.rb
139
139
  - spec/lib/castle/client_spec.rb
140
140
  - spec/lib/castle/context/default_spec.rb
141
141
  - spec/lib/castle/context/merger_spec.rb
@@ -143,15 +143,13 @@ test_files:
143
143
  - spec/lib/castle/api_spec.rb
144
144
  - spec/lib/castle/configuration_spec.rb
145
145
  - spec/lib/castle/version_spec.rb
146
- - spec/lib/castle/header_formatter_spec.rb
147
146
  - spec/lib/castle/utils/cloner_spec.rb
148
147
  - spec/lib/castle/utils/timestamp_spec.rb
149
148
  - spec/lib/castle/utils/merger_spec.rb
150
149
  - spec/lib/castle/command_spec.rb
150
+ - spec/lib/castle/headers_formatter_spec.rb
151
151
  - spec/lib/castle/api/request_spec.rb
152
152
  - 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
153
  - spec/lib/castle/commands/review_spec.rb
156
154
  - spec/lib/castle/commands/authenticate_spec.rb
157
155
  - spec/lib/castle/commands/track_spec.rb
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Castle
4
- module API
5
- # generate api request
6
- module Request
7
- module Build
8
- class << self
9
- def call(command, headers, api_secret)
10
- request = Net::HTTP.const_get(
11
- command.method.to_s.capitalize
12
- ).new("/#{Castle.config.url_prefix}/#{command.path}", headers)
13
-
14
- unless command.method == :get
15
- request.body = ::Castle::Utils.replace_invalid_characters(
16
- command.data
17
- ).to_json
18
- end
19
-
20
- request.basic_auth('', api_secret)
21
- request
22
- end
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Castle
4
- # formats header name
5
- class HeaderFormatter
6
- # @param header [String]
7
- # @return [String]
8
- def call(header)
9
- header.to_s.gsub(/^HTTP(?:_|-)/i, '').split(/_|-/).map(&:capitalize).join('-')
10
- end
11
- end
12
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::API::Request::Build do
4
- subject(:call) { described_class.call(command, headers, api_secret) }
5
-
6
- let(:headers) { { 'SAMPLE-HEADER' => '1' } }
7
- let(:api_secret) { 'secret' }
8
-
9
- describe 'call' do
10
- context 'when get' do
11
- let(:command) { Castle::Commands::Review.build(review_id) }
12
- let(:review_id) { SecureRandom.uuid }
13
-
14
- it { expect(call.body).to be_nil }
15
- it { expect(call.method).to eql('GET') }
16
- it { expect(call.path).to eql("/v1/#{command.path}") }
17
- it { expect(call.to_hash).to have_key('authorization') }
18
- it { expect(call.to_hash).to have_key('sample-header') }
19
- it { expect(call.to_hash['sample-header']).to eql(['1']) }
20
- end
21
-
22
- context 'when post' do
23
- let(:time) { Time.now.utc.iso8601(3) }
24
- let(:command) do
25
- Castle::Commands::Track.new({}).build(event: '$login.succeeded', name: "\xC4")
26
- end
27
- let(:expected_body) do
28
- {
29
- event: '$login.succeeded',
30
- name: '�',
31
- context: {},
32
- sent_at: time
33
- }
34
- end
35
-
36
- before { allow(Castle::Utils::Timestamp).to receive(:call).and_return(time) }
37
-
38
- it { expect(call.body).to be_eql(expected_body.to_json) }
39
- it { expect(call.method).to eql('POST') }
40
- it { expect(call.path).to eql("/v1/#{command.path}") }
41
- it { expect(call.to_hash).to have_key('authorization') }
42
- it { expect(call.to_hash).to have_key('sample-header') }
43
- it { expect(call.to_hash['sample-header']).to eql(['1']) }
44
- end
45
- end
46
- end