castle-rb 4.0.0 → 4.1.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 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