reattract 0.4.1 → 0.4.3

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: d788029cfabbe3aa6a894388ea0dac86ccba0891deb9b5eecd8366d3e931c412
4
- data.tar.gz: b83d5843485a28165e9e1c5d5cb1eb3d97018861ab8dd8463854229d6962060e
3
+ metadata.gz: bf5cfc801f5c995cff77779a49585f2777dec7034be5cb25d42cc972fa42ac9e
4
+ data.tar.gz: e5aa74ecdeeda05a7d2c98b0f6d83497efcb6b37f16f52736ea18db4ce849dcf
5
5
  SHA512:
6
- metadata.gz: f4f36d5e427823a146c68f43b9f5b7c0b356f142ae4b9ce08c293138a0acc6654d1c7cc92805773e075426e845850d958ca971608a6c6c1cf2bfb96b02d01637
7
- data.tar.gz: 5298603faf71b6c7dd81fe9d347dfc06cedcdf56d7c4108e8e3dd17e0eda69b9cc5faced3ebceb0df255c9bbce885d1534f960c8ca19edb64a53521a030ff724
6
+ metadata.gz: aec4a441a83025aad75c7b94d12b2e56dc75b8b552fb65661eb4be7d8b0591524269f37440110626f7e40b64c083e64c25e6f9ca8218bef187a51ea8342ac046
7
+ data.tar.gz: 326847fc5d71033e425802520d9a81e23bfa5dcf154af97b9bddc42bcd86cc710dd8b00225808500e64286c6adee2bbdc204e408a2ca61fa9f706efeb31b3a45
data/.rubocop.yml CHANGED
@@ -10,6 +10,9 @@ AllCops:
10
10
  - 'Guardfile'
11
11
  - 'reattract.gemspec'
12
12
  - 'bin/**/*'
13
+ - 'spec/reattract/webhoook_spec.rb' # rebranded
14
+ - 'lib/reattract/webhook.rb' # rebranded
15
+ - 'lib/reattract/active_support_include.rb' # rebranded
13
16
 
14
17
  Layout/LineLength:
15
18
  Max: 120
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- reattract (0.4.1)
4
+ reattract (0.4.3)
5
5
  jwt (~> 2.7.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,18 +1,16 @@
1
- # Reattract
1
+ # Reattract Ruby SDK
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/reattract/api`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ Reattract's ruby API
6
4
 
7
5
  ## Installation
8
6
 
9
7
  Install the gem and add to the application's Gemfile by executing:
10
8
 
11
- $ bundle add reattract_api
9
+ $ bundle add reattract
12
10
 
13
11
  If bundler is not being used to manage dependencies, install the gem by executing:
14
12
 
15
- $ gem install reattract_api
13
+ $ gem install reattract
16
14
 
17
15
  ## Usage
18
16
 
@@ -26,7 +24,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
26
24
 
27
25
  ## Contributing
28
26
 
29
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/reattract.
27
+ Bug reports and pull requests are welcome on GitHub at https://github.com/reattract/sdk-platform.
30
28
 
31
29
  ## License
32
30
 
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Constant time string comparison, for fixed length strings.
4
+ # Code borrowed from ActiveSupport
5
+ # https://github.com/rails/rails/blob/75ac626c4e21129d8296d4206a1960563cc3d4aa/activesupport/lib/active_support/security_utils.rb#L33
6
+ #
7
+ # The values compared should be of fixed length, such as strings
8
+ # that have already been processed by HMAC. Raises in case of length mismatch.
9
+ module Reattract
10
+ if defined?(OpenSSL.fixed_length_secure_compare)
11
+ def fixed_length_secure_compare(a, b)
12
+ OpenSSL.fixed_length_secure_compare(a, b)
13
+ end
14
+ else
15
+ def fixed_length_secure_compare(a, b)
16
+ raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
17
+
18
+ l = a.unpack "C#{a.bytesize}"
19
+
20
+ res = 0
21
+ b.each_byte { |byte| res |= byte ^ l.shift }
22
+ res == 0
23
+ end
24
+ end
25
+ module_function :fixed_length_secure_compare
26
+
27
+ # Secure string comparison for strings of variable length.
28
+ #
29
+ # While a timing attack would not be able to discern the content of
30
+ # a secret compared via secure_compare, it is possible to determine
31
+ # the secret length. This should be considered when using secure_compare
32
+ # to compare weak, short secrets to user input.
33
+ def secure_compare(a, b)
34
+ a.length == b.length && fixed_length_secure_compare(a, b)
35
+ end
36
+ module_function :secure_compare
37
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Reattract
4
+ # Standard error message
5
+ class ReattractError < StandardError
6
+ attr_reader :message
7
+
8
+ def initialize(message = nil)
9
+ @message = message
10
+ super
11
+ end
12
+ end
13
+
14
+ class WebhookVerificationError < ReattractError
15
+ end
16
+
17
+ class WebhookSigningError < ReattractError
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Reattract
4
- VERSION = '0.4.1'
4
+ VERSION = '0.4.3'
5
5
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Reattract
4
+ # Reattract's webhook verification class
5
+ class Webhook
6
+
7
+ def self.new_using_raw_bytes(secret)
8
+ self.new(secret.pack("C*").force_encoding("UTF-8"))
9
+ end
10
+
11
+ def initialize(secret)
12
+ if secret.start_with?(SECRET_PREFIX)
13
+ secret = secret[SECRET_PREFIX.length..-1]
14
+ end
15
+
16
+ @secret = Base64.decode64(secret)
17
+ end
18
+
19
+ def verify(payload, headers)
20
+ msgId = headers["svix-id"]
21
+ msgSignature = headers["svix-signature"]
22
+ msgTimestamp = headers["svix-timestamp"]
23
+ if !msgSignature || !msgId || !msgTimestamp
24
+ msgId = headers["webhook-id"]
25
+ msgSignature = headers["webhook-signature"]
26
+ msgTimestamp = headers["webhook-timestamp"]
27
+ if !msgSignature || !msgId || !msgTimestamp
28
+ raise WebhookVerificationError, "Missing required headers"
29
+ end
30
+ end
31
+
32
+ verify_timestamp(msgTimestamp)
33
+
34
+ _, signature = sign(msgId, msgTimestamp, payload).split(",", 2)
35
+
36
+ passedSignatures = msgSignature.split(" ")
37
+ passedSignatures.each do |versionedSignature|
38
+ version, expectedSignature = versionedSignature.split(",", 2)
39
+ if version != "v1"
40
+ next
41
+ end
42
+ if ::Reattract::secure_compare(signature, expectedSignature)
43
+ return JSON.parse(payload, symbolize_names: true)
44
+ end
45
+ end
46
+ raise WebhookVerificationError, "No matching signature found"
47
+ end
48
+
49
+ def sign(msgId, timestamp, payload)
50
+ begin
51
+ now = Integer(timestamp)
52
+ rescue
53
+ raise WebhookSigningError, "Invalid timestamp"
54
+ end
55
+ toSign = "#{msgId}.#{timestamp}.#{payload}"
56
+ signature = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new("sha256"), @secret, toSign)).strip
57
+ return "v1,#{signature}"
58
+ end
59
+
60
+ private
61
+ SECRET_PREFIX = "whsec_"
62
+ TOLERANCE = 5 * 60
63
+
64
+ def verify_timestamp(timestampHeader)
65
+ begin
66
+ now = Integer(Time.now)
67
+ timestamp = Integer(timestampHeader)
68
+ rescue
69
+ raise WebhookVerificationError, "Invalid Signature Headers"
70
+ end
71
+
72
+ if timestamp < (now - TOLERANCE)
73
+ raise WebhookVerificationError, "Message timestamp too old"
74
+ end
75
+ if timestamp > (now + TOLERANCE)
76
+ raise WebhookVerificationError, "Message timestamp too new"
77
+ end
78
+ end
79
+ end
80
+ end
data/lib/reattract.rb CHANGED
@@ -2,11 +2,16 @@
2
2
 
3
3
  require 'forwardable'
4
4
 
5
+ require_relative 'reattract/active_support_include'
6
+ require_relative 'reattract/reattract_error'
5
7
  require_relative 'reattract/version'
6
8
  require_relative 'reattract/configuration'
7
9
  require_relative 'reattract/jwt_generator'
8
10
  require_relative 'reattract/connection'
9
11
  require_relative 'reattract/request'
12
+ require_relative 'reattract/webhook'
13
+
14
+ # resources
10
15
  require_relative 'reattract/resources/app_event'
11
16
  require_relative 'reattract/resources/campaign'
12
17
  require_relative 'reattract/resources/customer'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reattract
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Burris
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-15 00:00:00.000000000 Z
11
+ date: 2023-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jwt
@@ -41,9 +41,11 @@ files:
41
41
  - README.md
42
42
  - Rakefile
43
43
  - lib/reattract.rb
44
+ - lib/reattract/active_support_include.rb
44
45
  - lib/reattract/configuration.rb
45
46
  - lib/reattract/connection.rb
46
47
  - lib/reattract/jwt_generator.rb
48
+ - lib/reattract/reattract_error.rb
47
49
  - lib/reattract/request.rb
48
50
  - lib/reattract/resources/app_event.rb
49
51
  - lib/reattract/resources/campaign.rb
@@ -52,6 +54,7 @@ files:
52
54
  - lib/reattract/resources/invite_conversion.rb
53
55
  - lib/reattract/resources/invite_session.rb
54
56
  - lib/reattract/version.rb
57
+ - lib/reattract/webhook.rb
55
58
  - sig/reattract/api.rbs
56
59
  homepage: https://docs.reattract.io
57
60
  licenses: