sift 4.5.1 → 4.6.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/.github/workflows/ci.yml +2 -2
- data/HISTORY +6 -0
- data/README.md +1 -1
- data/lib/sift/client/decision/apply_to.rb +7 -3
- data/lib/sift/client/decision.rb +7 -6
- data/lib/sift/client.rb +49 -32
- data/lib/sift/router.rb +7 -4
- data/lib/sift/version.rb +1 -1
- data/sift.gemspec +7 -5
- data/spec/unit/client/decision/apply_to_spec.rb +1 -1
- data/spec/unit/client/decision_spec.rb +1 -1
- data/spec/unit/client_validationapi_spec.rb +46 -0
- data/spec/unit/configuration_spec.rb +67 -0
- metadata +10 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f52238626726ed4acc2b903b57bc393b46b2e8df162a021abd0b94d084631acc
|
|
4
|
+
data.tar.gz: 4576e4a7bb68d34b9687a8cea83d7e767cb9d10aacbf354d6dcf6167cd0de89b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3b7c07547207731c7592c0a08f229adde8400511855ad54ed7ae86de0b891acbb7b4fa91b7666df2e4927a7f9483898554daa8658f28ed9d5e0a49875139a011
|
|
7
|
+
data.tar.gz: 3d3fd96f0ed512504cdd4f52f353ef9264ee74395b1c1af58c6d583c17114e3cdd971ec577397d28339ceea68e0d69c495e817bdb42dc16aac61a7b6e348f7a5
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -20,7 +20,7 @@ jobs:
|
|
|
20
20
|
runs-on: ubuntu-latest
|
|
21
21
|
strategy:
|
|
22
22
|
matrix:
|
|
23
|
-
ruby-version: ['2.
|
|
23
|
+
ruby-version: ['2.7', '3.1', '3.2', '3.3']
|
|
24
24
|
steps:
|
|
25
25
|
- uses: actions/checkout@v4
|
|
26
26
|
- name: Set up Ruby
|
|
@@ -36,7 +36,7 @@ jobs:
|
|
|
36
36
|
if: ${{ github.ref == 'refs/heads/master' }}
|
|
37
37
|
strategy:
|
|
38
38
|
matrix:
|
|
39
|
-
ruby-version: [
|
|
39
|
+
ruby-version: ['2.7', '3.1', '3.2', '3.3']
|
|
40
40
|
steps:
|
|
41
41
|
- uses: actions/checkout@v4
|
|
42
42
|
- name: Set up Ruby
|
data/HISTORY
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
=== 4.6.0 2026-02-10
|
|
2
|
+
- Bump the minimum version of httparty to 0.23.3 to ensure protection against CVE-2025-68696
|
|
3
|
+
- Refactor Client to use dedicated internal HTTP clients for different API endpoints
|
|
4
|
+
- Fix Verification API methods to use correct version parameter
|
|
5
|
+
- Increase minimum required version for Ruby to 2.7.0
|
|
6
|
+
|
|
1
7
|
=== 4.5.1 2025-04-07
|
|
2
8
|
- Fix Verification URLs
|
|
3
9
|
|
data/README.md
CHANGED
|
@@ -21,7 +21,7 @@ module Sift
|
|
|
21
21
|
time
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
attr_reader :decision_id, :configs, :getter, :api_key
|
|
24
|
+
attr_reader :decision_id, :configs, :getter, :api_key, :client_class
|
|
25
25
|
|
|
26
26
|
PROPERTIES.each do |attribute|
|
|
27
27
|
class_eval %{
|
|
@@ -31,11 +31,12 @@ module Sift
|
|
|
31
31
|
}
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def initialize(api_key, decision_id, configs)
|
|
34
|
+
def initialize(api_key, decision_id, configs, client_class = Sift::Client)
|
|
35
35
|
@api_key = api_key
|
|
36
36
|
@decision_id = decision_id
|
|
37
37
|
@configs = configs
|
|
38
38
|
@getter = Utils::HashGetter.new(configs)
|
|
39
|
+
@client_class = client_class
|
|
39
40
|
end
|
|
40
41
|
|
|
41
42
|
def run
|
|
@@ -58,7 +59,8 @@ module Sift
|
|
|
58
59
|
def send_request
|
|
59
60
|
Router.post(path, {
|
|
60
61
|
body: request_body,
|
|
61
|
-
headers: headers
|
|
62
|
+
headers: headers,
|
|
63
|
+
client_class: client_class
|
|
62
64
|
})
|
|
63
65
|
end
|
|
64
66
|
|
|
@@ -79,6 +81,8 @@ module Sift
|
|
|
79
81
|
validator.valid_order?
|
|
80
82
|
elsif applying_to_session?
|
|
81
83
|
validator.valid_session?
|
|
84
|
+
elsif applying_to_content?
|
|
85
|
+
validator.valid_content?
|
|
82
86
|
else
|
|
83
87
|
validator.valid_user?
|
|
84
88
|
end
|
data/lib/sift/client/decision.rb
CHANGED
|
@@ -10,11 +10,12 @@ module Sift
|
|
|
10
10
|
class Decision
|
|
11
11
|
FILTER_PARAMS = %w{ limit entity_type abuse_types from }
|
|
12
12
|
|
|
13
|
-
attr_reader :account_id, :api_key
|
|
13
|
+
attr_reader :account_id, :api_key, :client_class
|
|
14
14
|
|
|
15
|
-
def initialize(api_key, account_id)
|
|
15
|
+
def initialize(api_key, account_id, client_class = Sift::Client)
|
|
16
16
|
@account_id = account_id
|
|
17
17
|
@api_key = api_key
|
|
18
|
+
@client_class = client_class
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def list(options = {})
|
|
@@ -25,7 +26,8 @@ module Sift
|
|
|
25
26
|
else
|
|
26
27
|
Router.get(index_path, {
|
|
27
28
|
query: build_query(getter),
|
|
28
|
-
headers: auth_header
|
|
29
|
+
headers: auth_header,
|
|
30
|
+
client_class: client_class
|
|
29
31
|
})
|
|
30
32
|
end
|
|
31
33
|
end
|
|
@@ -44,7 +46,7 @@ module Sift
|
|
|
44
46
|
getter = Utils::HashGetter.new(configs)
|
|
45
47
|
configs[:account_id] = account_id
|
|
46
48
|
|
|
47
|
-
ApplyTo.new(api_key, getter.get(:decision_id), configs).run
|
|
49
|
+
ApplyTo.new(api_key, getter.get(:decision_id), configs, client_class).run
|
|
48
50
|
end
|
|
49
51
|
|
|
50
52
|
def index_path
|
|
@@ -54,7 +56,7 @@ module Sift
|
|
|
54
56
|
private
|
|
55
57
|
|
|
56
58
|
def request_next_page(path)
|
|
57
|
-
Router.get(path, headers: auth_header)
|
|
59
|
+
Router.get(path, headers: auth_header, client_class: client_class)
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
def auth_header
|
|
@@ -63,4 +65,3 @@ module Sift
|
|
|
63
65
|
end
|
|
64
66
|
end
|
|
65
67
|
end
|
|
66
|
-
|
data/lib/sift/client.rb
CHANGED
|
@@ -2,9 +2,6 @@ require "httparty"
|
|
|
2
2
|
require "multi_json"
|
|
3
3
|
require "base64"
|
|
4
4
|
|
|
5
|
-
require_relative "./client/decision"
|
|
6
|
-
require_relative "./error"
|
|
7
|
-
|
|
8
5
|
module Sift
|
|
9
6
|
|
|
10
7
|
# Represents the payload returned from a call through the track API
|
|
@@ -94,17 +91,36 @@ module Sift
|
|
|
94
91
|
API_ENDPOINT = ENV["SIFT_RUBY_API_URL"] || 'https://api.siftscience.com'
|
|
95
92
|
API3_ENDPOINT = ENV["SIFT_RUBY_API3_URL"] || 'https://api3.siftscience.com'
|
|
96
93
|
|
|
94
|
+
# Maintain backward compatibility for users who may rely on HTTParty methods
|
|
97
95
|
include HTTParty
|
|
98
96
|
base_uri API_ENDPOINT
|
|
99
97
|
|
|
100
98
|
attr_reader :api_key, :account_id
|
|
101
99
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
class << self
|
|
101
|
+
def build_auth_header(api_key)
|
|
102
|
+
{ "Authorization" => "Basic #{Base64.strict_encode64(api_key + ":")}" }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def user_agent
|
|
106
|
+
"sift-ruby/#{VERSION}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Factory methods for internal API executors that inherit from the current class context.
|
|
110
|
+
# This ensures that subclasses of Client propagate their HTTParty configuration
|
|
111
|
+
# to these internal clients.
|
|
105
112
|
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
def api_client
|
|
114
|
+
@api_client ||= Class.new(self) do
|
|
115
|
+
base_uri API_ENDPOINT
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def api3_client
|
|
120
|
+
@api3_client ||= Class.new(self) do
|
|
121
|
+
base_uri API3_ENDPOINT
|
|
122
|
+
end
|
|
123
|
+
end
|
|
108
124
|
end
|
|
109
125
|
|
|
110
126
|
# Constructor
|
|
@@ -256,7 +272,7 @@ module Sift
|
|
|
256
272
|
}
|
|
257
273
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
258
274
|
|
|
259
|
-
response = self.class.post(path, options)
|
|
275
|
+
response = self.class.api_client.post(path, options)
|
|
260
276
|
Response.new(response.body, response.code, response.response)
|
|
261
277
|
end
|
|
262
278
|
|
|
@@ -319,7 +335,7 @@ module Sift
|
|
|
319
335
|
}
|
|
320
336
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
321
337
|
|
|
322
|
-
response = self.class.get(Sift.score_api_path(user_id, version), options)
|
|
338
|
+
response = self.class.api_client.get(Sift.score_api_path(user_id, version), options)
|
|
323
339
|
Response.new(response.body, response.code, response.response)
|
|
324
340
|
end
|
|
325
341
|
|
|
@@ -364,6 +380,7 @@ module Sift
|
|
|
364
380
|
abuse_types = opts[:abuse_types]
|
|
365
381
|
api_key = opts[:api_key] || @api_key
|
|
366
382
|
timeout = opts[:timeout] || @timeout
|
|
383
|
+
version = opts[:version] || @version
|
|
367
384
|
include_score_percentiles = opts[:include_score_percentiles]
|
|
368
385
|
|
|
369
386
|
raise("user_id must be a non-empty string") if (!user_id.is_a? String) || user_id.to_s.empty?
|
|
@@ -382,7 +399,7 @@ module Sift
|
|
|
382
399
|
}
|
|
383
400
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
384
401
|
|
|
385
|
-
response = self.class.get(Sift.user_score_api_path(user_id,
|
|
402
|
+
response = self.class.api_client.get(Sift.user_score_api_path(user_id, version), options)
|
|
386
403
|
Response.new(response.body, response.code, response.response)
|
|
387
404
|
end
|
|
388
405
|
|
|
@@ -420,6 +437,7 @@ module Sift
|
|
|
420
437
|
abuse_types = opts[:abuse_types]
|
|
421
438
|
api_key = opts[:api_key] || @api_key
|
|
422
439
|
timeout = opts[:timeout] || @timeout
|
|
440
|
+
version = opts[:version] || @version
|
|
423
441
|
|
|
424
442
|
raise("user_id must be a non-empty string") if (!user_id.is_a? String) || user_id.to_s.empty?
|
|
425
443
|
raise("Bad api_key parameter") if api_key.empty?
|
|
@@ -434,7 +452,7 @@ module Sift
|
|
|
434
452
|
}
|
|
435
453
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
436
454
|
|
|
437
|
-
response = self.class.post(Sift.user_score_api_path(user_id,
|
|
455
|
+
response = self.class.api_client.post(Sift.user_score_api_path(user_id, version), options)
|
|
438
456
|
Response.new(response.body, response.code, response.response)
|
|
439
457
|
end
|
|
440
458
|
|
|
@@ -532,7 +550,7 @@ module Sift
|
|
|
532
550
|
}
|
|
533
551
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
534
552
|
|
|
535
|
-
response = self.class.delete(Sift.users_label_api_path(user_id, version), options)
|
|
553
|
+
response = self.class.api_client.delete(Sift.users_label_api_path(user_id, version), options)
|
|
536
554
|
Response.new(response.body, response.code, response.response)
|
|
537
555
|
end
|
|
538
556
|
|
|
@@ -569,8 +587,7 @@ module Sift
|
|
|
569
587
|
}
|
|
570
588
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
571
589
|
|
|
572
|
-
|
|
573
|
-
response = self.class.get(uri, options)
|
|
590
|
+
response = self.class.api3_client.get(Sift.workflow_status_path(account_id, run_id), options)
|
|
574
591
|
Response.new(response.body, response.code, response.response)
|
|
575
592
|
end
|
|
576
593
|
|
|
@@ -607,8 +624,7 @@ module Sift
|
|
|
607
624
|
}
|
|
608
625
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
609
626
|
|
|
610
|
-
|
|
611
|
-
response = self.class.get(uri, options)
|
|
627
|
+
response = self.class.api3_client.get(Sift.user_decisions_api_path(account_id, user_id), options)
|
|
612
628
|
Response.new(response.body, response.code, response.response)
|
|
613
629
|
end
|
|
614
630
|
|
|
@@ -645,8 +661,7 @@ module Sift
|
|
|
645
661
|
}
|
|
646
662
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
647
663
|
|
|
648
|
-
|
|
649
|
-
response = self.class.get(uri, options)
|
|
664
|
+
response = self.class.api3_client.get(Sift.order_decisions_api_path(account_id, order_id), options)
|
|
650
665
|
Response.new(response.body, response.code, response.response)
|
|
651
666
|
end
|
|
652
667
|
|
|
@@ -685,8 +700,7 @@ module Sift
|
|
|
685
700
|
}
|
|
686
701
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
687
702
|
|
|
688
|
-
|
|
689
|
-
response = self.class.get(uri, options)
|
|
703
|
+
response = self.class.api3_client.get(Sift.session_decisions_api_path(account_id, user_id, session_id), options)
|
|
690
704
|
Response.new(response.body, response.code, response.response)
|
|
691
705
|
end
|
|
692
706
|
|
|
@@ -725,8 +739,7 @@ module Sift
|
|
|
725
739
|
}
|
|
726
740
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
727
741
|
|
|
728
|
-
|
|
729
|
-
response = self.class.get(uri, options)
|
|
742
|
+
response = self.class.api3_client.get(Sift.content_decisions_api_path(account_id, user_id, content_id), options)
|
|
730
743
|
Response.new(response.body, response.code, response.response)
|
|
731
744
|
end
|
|
732
745
|
|
|
@@ -748,7 +761,7 @@ module Sift
|
|
|
748
761
|
|
|
749
762
|
def build_default_headers_post(api_key)
|
|
750
763
|
{
|
|
751
|
-
"Authorization" => "Basic #{Base64.
|
|
764
|
+
"Authorization" => "Basic #{Base64.strict_encode64(api_key+":")}",
|
|
752
765
|
"User-Agent" => "SiftScience/v#{@version} sift-ruby/#{VERSION}",
|
|
753
766
|
"Content-Type" => "application/json"
|
|
754
767
|
}
|
|
@@ -768,7 +781,7 @@ module Sift
|
|
|
768
781
|
:headers => build_default_headers_post(api_key)
|
|
769
782
|
}
|
|
770
783
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
771
|
-
response = self.class.post(Sift.verification_api_send_path(
|
|
784
|
+
response = self.class.api_client.post(Sift.verification_api_send_path(version), options)
|
|
772
785
|
Response.new(response.body, response.code, response.response)
|
|
773
786
|
end
|
|
774
787
|
|
|
@@ -787,7 +800,7 @@ module Sift
|
|
|
787
800
|
}
|
|
788
801
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
789
802
|
|
|
790
|
-
response = self.class.post(Sift.verification_api_resend_path(
|
|
803
|
+
response = self.class.api_client.post(Sift.verification_api_resend_path(version), options)
|
|
791
804
|
Response.new(response.body, response.code, response.response)
|
|
792
805
|
end
|
|
793
806
|
|
|
@@ -806,7 +819,7 @@ module Sift
|
|
|
806
819
|
}
|
|
807
820
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
808
821
|
|
|
809
|
-
response = self.class.post(Sift.verification_api_check_path(
|
|
822
|
+
response = self.class.api_client.post(Sift.verification_api_check_path(version), options)
|
|
810
823
|
Response.new(response.body, response.code, response.response)
|
|
811
824
|
end
|
|
812
825
|
|
|
@@ -831,7 +844,7 @@ module Sift
|
|
|
831
844
|
:basic_auth => { :username => api_key, :password => "" }
|
|
832
845
|
}
|
|
833
846
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
834
|
-
response = self.class.post(
|
|
847
|
+
response = self.class.api_client.post(Sift.psp_merchant_api_path(account_id), options)
|
|
835
848
|
Response.new(response.body, response.code, response.response)
|
|
836
849
|
end
|
|
837
850
|
|
|
@@ -858,7 +871,7 @@ module Sift
|
|
|
858
871
|
:basic_auth => { :username => api_key, :password => "" }
|
|
859
872
|
}
|
|
860
873
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
861
|
-
response = self.class.put(
|
|
874
|
+
response = self.class.api_client.put(Sift.psp_merchant_id_api_path(account_id, merchant_id), options)
|
|
862
875
|
Response.new(response.body, response.code, response.response)
|
|
863
876
|
end
|
|
864
877
|
|
|
@@ -882,7 +895,7 @@ module Sift
|
|
|
882
895
|
:basic_auth => { :username => api_key, :password => "" }
|
|
883
896
|
}
|
|
884
897
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
885
|
-
response = self.class.get(
|
|
898
|
+
response = self.class.api_client.get(Sift.psp_merchant_id_api_path(account_id, merchant_id), options)
|
|
886
899
|
Response.new(response.body, response.code, response.response)
|
|
887
900
|
end
|
|
888
901
|
|
|
@@ -911,7 +924,7 @@ module Sift
|
|
|
911
924
|
:query => query
|
|
912
925
|
}
|
|
913
926
|
options.merge!(:timeout => timeout) unless timeout.nil?
|
|
914
|
-
response = self.class.get(
|
|
927
|
+
response = self.class.api_client.get(Sift.psp_merchant_api_path(account_id), options)
|
|
915
928
|
Response.new(response.body, response.code, response.response)
|
|
916
929
|
end
|
|
917
930
|
|
|
@@ -926,7 +939,7 @@ module Sift
|
|
|
926
939
|
end
|
|
927
940
|
|
|
928
941
|
def decision_instance
|
|
929
|
-
@decision_instance ||= Decision.new(api_key, account_id)
|
|
942
|
+
@decision_instance ||= Decision.new(api_key, account_id, self.class)
|
|
930
943
|
end
|
|
931
944
|
|
|
932
945
|
def delete_nils(properties)
|
|
@@ -943,4 +956,8 @@ module Sift
|
|
|
943
956
|
end
|
|
944
957
|
end
|
|
945
958
|
end
|
|
959
|
+
|
|
960
|
+
require_relative "./client/decision"
|
|
961
|
+
require_relative "./error"
|
|
962
|
+
|
|
946
963
|
end
|
data/lib/sift/router.rb
CHANGED
|
@@ -2,20 +2,23 @@ require_relative "./version"
|
|
|
2
2
|
require_relative "./client"
|
|
3
3
|
|
|
4
4
|
module Sift
|
|
5
|
-
class Router
|
|
6
|
-
include HTTParty
|
|
5
|
+
class Router < Client
|
|
7
6
|
|
|
8
7
|
class << self
|
|
9
8
|
def get(path, options = {})
|
|
9
|
+
client_class = options.delete(:client_class) || Sift::Client
|
|
10
|
+
options[:base_uri] = nil
|
|
10
11
|
serialize_body(options)
|
|
11
12
|
add_default_headers(options)
|
|
12
|
-
wrap_response(
|
|
13
|
+
wrap_response(client_class.api3_client.get(path, options))
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def post(path, options = {})
|
|
17
|
+
client_class = options.delete(:client_class) || Sift::Client
|
|
18
|
+
options[:base_uri] = nil
|
|
16
19
|
serialize_body(options)
|
|
17
20
|
add_default_headers(options)
|
|
18
|
-
wrap_response(
|
|
21
|
+
wrap_response(client_class.api3_client.post(path, options))
|
|
19
22
|
end
|
|
20
23
|
|
|
21
24
|
def serialize_body(options)
|
data/lib/sift/version.rb
CHANGED
data/sift.gemspec
CHANGED
|
@@ -7,10 +7,10 @@ Gem::Specification.new do |s|
|
|
|
7
7
|
s.version = Sift::VERSION
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
|
9
9
|
s.authors = ["Fred Sadaghiani", "Yoav Schatzberg", "Jacob Burnim"]
|
|
10
|
-
s.email = ["support@
|
|
11
|
-
s.homepage = "http://
|
|
12
|
-
s.summary = %q{Sift
|
|
13
|
-
s.description = %q{Sift
|
|
10
|
+
s.email = ["support@sift.com"]
|
|
11
|
+
s.homepage = "http://sift.com"
|
|
12
|
+
s.summary = %q{Sift Ruby API Gem}
|
|
13
|
+
s.description = %q{Sift Ruby API. Please see http://sift.com for more details.}
|
|
14
14
|
|
|
15
15
|
s.rubyforge_project = "sift"
|
|
16
16
|
|
|
@@ -19,6 +19,8 @@ Gem::Specification.new do |s|
|
|
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
20
20
|
s.require_paths = ["lib"]
|
|
21
21
|
|
|
22
|
+
s.required_ruby_version = '>= 2.7.0'
|
|
23
|
+
|
|
22
24
|
# Gems that must be intalled for sift to compile and build
|
|
23
25
|
s.add_development_dependency "rspec", "~> 3.5"
|
|
24
26
|
s.add_development_dependency "rspec_junit_formatter"
|
|
@@ -26,7 +28,7 @@ Gem::Specification.new do |s|
|
|
|
26
28
|
s.add_development_dependency "webmock", ">= 1.16.0", "< 2"
|
|
27
29
|
|
|
28
30
|
# Gems that must be intalled for sift to work
|
|
29
|
-
s.add_dependency "httparty", ">= 0.
|
|
31
|
+
s.add_dependency "httparty", ">= 0.23.3"
|
|
30
32
|
s.add_dependency "multi_json", ">= 1.0"
|
|
31
33
|
|
|
32
34
|
s.add_development_dependency("rake")
|
|
@@ -88,4 +88,50 @@ describe Sift::Client do
|
|
|
88
88
|
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
+
# Regression tests for verification API version bug fix
|
|
92
|
+
# These tests ensure verification methods use verification_version (1.1)
|
|
93
|
+
# instead of the events API version (205)
|
|
94
|
+
|
|
95
|
+
it "Uses verification API version (1.1) not events API version (205) for verification_send" do
|
|
96
|
+
api_key = "test_key"
|
|
97
|
+
response_json = { :status => 0, :error_message => "OK"}
|
|
98
|
+
|
|
99
|
+
# Should call v1.1, NOT v205
|
|
100
|
+
stub_request(:post, "https://test_key:@api.siftscience.com/v1.1/verification/send")
|
|
101
|
+
.to_return(:status => 200, :body => MultiJson.dump(response_json))
|
|
102
|
+
|
|
103
|
+
# Client defaults: version=205 (events), verification_version=1.1
|
|
104
|
+
response = Sift::Client.new(:api_key => api_key).verification_send(valid_send_properties)
|
|
105
|
+
|
|
106
|
+
expect(response.ok?).to eq(true)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "Uses verification API version (1.1) not events API version (205) for verification_resend" do
|
|
110
|
+
api_key = "test_key"
|
|
111
|
+
response_json = { :status => 0, :error_message => "OK"}
|
|
112
|
+
|
|
113
|
+
# Should call v1.1, NOT v205
|
|
114
|
+
stub_request(:post, "https://test_key:@api.siftscience.com/v1.1/verification/resend")
|
|
115
|
+
.to_return(:status => 200, :body => MultiJson.dump(response_json))
|
|
116
|
+
|
|
117
|
+
# Client defaults: version=205 (events), verification_version=1.1
|
|
118
|
+
response = Sift::Client.new(:api_key => api_key).verification_resend(valid_resend_properties)
|
|
119
|
+
|
|
120
|
+
expect(response.ok?).to eq(true)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "Uses verification API version (1.1) not events API version (205) for verification_check" do
|
|
124
|
+
api_key = "test_key"
|
|
125
|
+
response_json = { :status => 0, :error_message => "OK"}
|
|
126
|
+
|
|
127
|
+
# Should call v1.1, NOT v205
|
|
128
|
+
stub_request(:post, "https://test_key:@api.siftscience.com/v1.1/verification/check")
|
|
129
|
+
.to_return(:status => 200, :body => MultiJson.dump(response_json))
|
|
130
|
+
|
|
131
|
+
# Client defaults: version=205 (events), verification_version=1.1
|
|
132
|
+
response = Sift::Client.new(:api_key => api_key).verification_check(valid_check_properties)
|
|
133
|
+
|
|
134
|
+
expect(response.ok?).to eq(true)
|
|
135
|
+
end
|
|
136
|
+
|
|
91
137
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
|
+
require "sift"
|
|
3
|
+
require "logger"
|
|
4
|
+
|
|
5
|
+
describe "Sift::Client Configuration Patterns" do
|
|
6
|
+
let(:api_key) { "test_api_key" }
|
|
7
|
+
|
|
8
|
+
it "propagates global Sift::Client configuration to internal clients" do
|
|
9
|
+
Sift::Client.default_timeout 5
|
|
10
|
+
|
|
11
|
+
# Internal executors should inherit this
|
|
12
|
+
expect(Sift::Client.api_client.default_options[:timeout]).to eq(5)
|
|
13
|
+
expect(Sift::Client.api3_client.default_options[:timeout]).to eq(5)
|
|
14
|
+
|
|
15
|
+
# Reset
|
|
16
|
+
Sift::Client.default_timeout 2
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "allows independent subclass configurations" do
|
|
20
|
+
class SubclassA < Sift::Client; end
|
|
21
|
+
class SubclassB < Sift::Client; end
|
|
22
|
+
|
|
23
|
+
SubclassA.default_timeout 10
|
|
24
|
+
SubclassB.default_timeout 20
|
|
25
|
+
|
|
26
|
+
expect(SubclassA.api_client.default_options[:timeout]).to eq(10)
|
|
27
|
+
expect(SubclassB.api_client.default_options[:timeout]).to eq(20)
|
|
28
|
+
|
|
29
|
+
# Ensure they didn't leak to parent
|
|
30
|
+
expect(Sift::Client.api_client.default_options[:timeout]).to be <= 5
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "propagates complex settings like loggers to subclasses" do
|
|
34
|
+
class LoggingClient < Sift::Client; end
|
|
35
|
+
|
|
36
|
+
logger = Logger.new(nil)
|
|
37
|
+
LoggingClient.logger logger, :debug, :curl
|
|
38
|
+
|
|
39
|
+
expect(LoggingClient.api_client.default_options[:logger]).to eq(logger)
|
|
40
|
+
expect(LoggingClient.api_client.default_options[:log_level]).to eq(:debug)
|
|
41
|
+
expect(LoggingClient.api_client.default_options[:log_format]).to eq(:curl)
|
|
42
|
+
|
|
43
|
+
# Ensure Sift::Client remains untouched
|
|
44
|
+
expect(Sift::Client.api_client.default_options[:logger]).to be_nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "respects inheritance chain for Decisions and Router" do
|
|
48
|
+
class DecisionClient < Sift::Client; end
|
|
49
|
+
DecisionClient.default_timeout 15
|
|
50
|
+
|
|
51
|
+
client = DecisionClient.new(api_key: api_key, account_id: "acc")
|
|
52
|
+
|
|
53
|
+
# Verify the executor used by the Router is the one from DecisionClient
|
|
54
|
+
expect(DecisionClient.api3_client.default_options[:timeout]).to eq(15)
|
|
55
|
+
|
|
56
|
+
# We want to ensure that when Router.get is called, it uses DecisionClient.api3_client
|
|
57
|
+
# In lib/sift/router.rb, we have:
|
|
58
|
+
# wrap_response(client_class.api3_client.get(path, options))
|
|
59
|
+
|
|
60
|
+
expect(DecisionClient.api3_client).to receive(:get).and_call_original
|
|
61
|
+
|
|
62
|
+
# Mock the request to avoid network calls
|
|
63
|
+
stub_request(:get, /api3.siftscience.com/)
|
|
64
|
+
|
|
65
|
+
client.get_user_decisions("user_1")
|
|
66
|
+
end
|
|
67
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sift
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Fred Sadaghiani
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date:
|
|
13
|
+
date: 2026-03-02 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: rspec
|
|
@@ -80,14 +80,14 @@ dependencies:
|
|
|
80
80
|
requirements:
|
|
81
81
|
- - ">="
|
|
82
82
|
- !ruby/object:Gem::Version
|
|
83
|
-
version: 0.
|
|
83
|
+
version: 0.23.3
|
|
84
84
|
type: :runtime
|
|
85
85
|
prerelease: false
|
|
86
86
|
version_requirements: !ruby/object:Gem::Requirement
|
|
87
87
|
requirements:
|
|
88
88
|
- - ">="
|
|
89
89
|
- !ruby/object:Gem::Version
|
|
90
|
-
version: 0.
|
|
90
|
+
version: 0.23.3
|
|
91
91
|
- !ruby/object:Gem::Dependency
|
|
92
92
|
name: multi_json
|
|
93
93
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -116,9 +116,9 @@ dependencies:
|
|
|
116
116
|
- - ">="
|
|
117
117
|
- !ruby/object:Gem::Version
|
|
118
118
|
version: '0'
|
|
119
|
-
description: Sift
|
|
119
|
+
description: Sift Ruby API. Please see http://sift.com for more details.
|
|
120
120
|
email:
|
|
121
|
-
- support@
|
|
121
|
+
- support@sift.com
|
|
122
122
|
executables: []
|
|
123
123
|
extensions: []
|
|
124
124
|
extra_rdoc_files: []
|
|
@@ -157,6 +157,7 @@ files:
|
|
|
157
157
|
- spec/unit/client_psp_merchant_spec.rb
|
|
158
158
|
- spec/unit/client_spec.rb
|
|
159
159
|
- spec/unit/client_validationapi_spec.rb
|
|
160
|
+
- spec/unit/configuration_spec.rb
|
|
160
161
|
- spec/unit/router_spec.rb
|
|
161
162
|
- spec/unit/validate/decision_spec.rb
|
|
162
163
|
- spec/unit/validate/primitive_spec.rb
|
|
@@ -167,7 +168,7 @@ files:
|
|
|
167
168
|
- test_integration_app/psp_merchants_api/test_psp_merchant_api.rb
|
|
168
169
|
- test_integration_app/score_api/test_score_api.rb
|
|
169
170
|
- test_integration_app/verification_api/test_verification_api.rb
|
|
170
|
-
homepage: http://
|
|
171
|
+
homepage: http://sift.com
|
|
171
172
|
licenses: []
|
|
172
173
|
metadata: {}
|
|
173
174
|
post_install_message:
|
|
@@ -178,7 +179,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
178
179
|
requirements:
|
|
179
180
|
- - ">="
|
|
180
181
|
- !ruby/object:Gem::Version
|
|
181
|
-
version:
|
|
182
|
+
version: 2.7.0
|
|
182
183
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
183
184
|
requirements:
|
|
184
185
|
- - ">="
|
|
@@ -188,5 +189,5 @@ requirements: []
|
|
|
188
189
|
rubygems_version: 3.1.6
|
|
189
190
|
signing_key:
|
|
190
191
|
specification_version: 4
|
|
191
|
-
summary: Sift
|
|
192
|
+
summary: Sift Ruby API Gem
|
|
192
193
|
test_files: []
|