convoy.rb 0.1.9 → 0.2.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: f33937f312b1c892facfce7d871bb972fd0f18ccd4fd0480697e91cd7a8b1662
4
- data.tar.gz: 8f8335fc9c3257ad80d68c07fda93fe3066792a0acdb55b1e9c3c9c89da73521
3
+ metadata.gz: 0bb0d6490ecbfd2a8bbef2429e9057ee9861dd7504d182c58e4bb68b9be929f1
4
+ data.tar.gz: e1e2a181c570f0d04af0a07ade86e9fef2839c3528ab1132fdb535fa8d209bb4
5
5
  SHA512:
6
- metadata.gz: 6efa47b6410966a4ee0fd8d254210a5e1e201634544725585739e7b2f80b562b82d5c8ee621bb4890095da43f755f15e410aa2ef77e6e0495e4089c5848e321a
7
- data.tar.gz: 680f6f45ab3fc28ea5ef4236d0b8a26676566ba927d4a9f352c0921af03c4a32735fbce7ce9fc75c37733b4dae65f6c5597c7724ba52afdeee1c3d78ab457d02
6
+ metadata.gz: 2e16c445680e2290940c5d23eb712c26b2b1d893f3e254940fecdb77b0dc1413eb5ed9bfd66b0e52476a14924d86f3b08937d1510ce8c663f6e6105901eb5ef4
7
+ data.tar.gz: 6a0db61a950f75867be10eae911c15812f6b5987957d514f362445b52eb9558f994712283590d01bbf042688a6aa608e9e6f6b87722bf3f754902dbb6e9eef67
data/README.md CHANGED
@@ -1,15 +1,12 @@
1
1
  # Convoy
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/convoy`. 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
2
+ This is the official Convoy Ruby SDK. This SDK contains methods for easily interacting with Convoy's API. Below are examples to get you started. For additional examples, please see our official documentation at (https://convoy.readme.io/reference)
6
3
 
7
4
  ## Installation
8
5
 
9
6
  Add this line to your application's Gemfile:
10
7
 
11
8
  ```ruby
12
- gem 'convoy'
9
+ gem 'convoy.rb'
13
10
  ```
14
11
 
15
12
  And then execute:
@@ -18,11 +15,90 @@ And then execute:
18
15
 
19
16
  Or install it yourself as:
20
17
 
21
- $ gem install convoy
18
+ $ gem install convoy.rb
22
19
 
23
20
  ## Usage
24
21
 
25
- TODO: Write usage instructions here
22
+ ### Setup Client
23
+
24
+ ```ruby
25
+ require 'convoy'
26
+
27
+ Convoy.ssl = true
28
+ Convoy.api_key = "CO.M0aBe..."
29
+ Convoy.path_version = "v1"
30
+ Convoy.base_uri = "https://dashboard.getconvoy.io/api"
31
+
32
+ ```
33
+
34
+ ### Creating an application
35
+ An application represents a user's application trying to receive webhooks. Once you create an application, you'll receive a `uid` as part of the response that you should save and supply in subsequent API calls to perform other requests such as creating an event.
36
+
37
+ ```ruby
38
+ app = Convoy::Application.new(
39
+ params: {
40
+ groupID: "c3637195-53cd-4eba-b9df-e7ba9479fbb2"
41
+ },
42
+ data: {
43
+ name: "Integration One"
44
+ }
45
+ )
46
+
47
+ app_response = app.save
48
+ ```
49
+
50
+ ### Add an Endpoint to Application
51
+ After creating an application, you'll need to add an endpoint to the application you just created. An endpoint represents a target URL to receive events.
52
+
53
+ ```ruby
54
+ endpoint = Convoy::Endpoint.new(
55
+ app_id,
56
+ data: {
57
+ "description": "Endpoint One",
58
+ "http_timeout": "1m",
59
+ "url": "https://webhook.site/73932854-a20e-4d04-a151-d5952e873abd"
60
+ }
61
+ )
62
+
63
+ endpoint_response = endpoint.save
64
+ ```
65
+
66
+ ### Subscribe For Events
67
+ After creating an endpoint, we need to susbcribe the endpoint to events.
68
+
69
+ ```ruby
70
+ subscription = Convoy::Subscription.new(
71
+ data: {
72
+ app_id: app_id,
73
+ endpoint_id: endpoint_id,
74
+ name: 'ruby subscription',
75
+ filter_config: {
76
+ event_types: [ "*" ]
77
+ }
78
+ }
79
+ )
80
+
81
+ subscription_response = subscription.save
82
+ ```
83
+
84
+ ### Publish an Event
85
+ Now let's publish an event.
86
+
87
+ ```ruby
88
+ event = Convoy::Event.new(
89
+ data: {
90
+ app_id: app_id,
91
+ event_type: "wallet.created",
92
+ data: {
93
+ status: "completed",
94
+ event_type: "wallet.created",
95
+ description: "transaction successful"
96
+ }
97
+ }
98
+ )
99
+
100
+ event_response = event.save
101
+ ```
26
102
 
27
103
  ## Development
28
104
 
@@ -35,10 +111,10 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
35
111
  Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/convoy. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/convoy/blob/master/CODE_OF_CONDUCT.md).
36
112
 
37
113
 
38
- ## License
114
+ ## Credits
39
115
 
40
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
116
+ - [Frain](https://github.com/frain-dev)
41
117
 
42
- ## Code of Conduct
118
+ ## License
43
119
 
44
- Everyone interacting in the Convoy project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/convoy/blob/master/CODE_OF_CONDUCT.md).
120
+ The MIT License (MIT). Please see [License File](LICENSE) for more information.
@@ -11,7 +11,7 @@ module Convoy
11
11
  end
12
12
 
13
13
  def delete
14
- send_request(resource_url, :delete, params: @params)
14
+ send_request(resource_uri, :delete, params: @params)
15
15
  end
16
16
 
17
17
  def self.included(base)
@@ -11,7 +11,7 @@ module Convoy
11
11
  end
12
12
 
13
13
  def get
14
- send_request(resource_url, :get, params: @params)
14
+ send_request(resource_uri, :get, params: @params)
15
15
  @data = @response['data']
16
16
  end
17
17
 
@@ -13,7 +13,7 @@ module Convoy
13
13
  end
14
14
 
15
15
  def list
16
- send_request(resource_url, :get, params: @params)
16
+ send_request(resource_uri, :get, params: @params)
17
17
  @data = @response['data']
18
18
  end
19
19
 
@@ -34,8 +34,6 @@ module Convoy
34
34
 
35
35
  if !config.api_key.nil?
36
36
  request['Authorization'] = "Bearer #{config.api_key}"
37
- else
38
- request.basic_auth config.username, config.password
39
37
  end
40
38
 
41
39
  # Build HTTP Client.
@@ -12,12 +12,12 @@ module Convoy
12
12
 
13
13
  def update(data = {})
14
14
  @data = data unless data.empty?
15
- send_request(resource_url, :put, data: @data, params: @params)
15
+ send_request(resource_uri, :put, data: @data, params: @params)
16
16
  end
17
17
 
18
18
  def save
19
19
  method = @id.nil? ? :post : :put
20
- send_request(resource_url, method, data: @data, params: @params)
20
+ send_request(resource_uri, method, data: @data, params: @params)
21
21
  end
22
22
 
23
23
  def self.included(base)
@@ -26,5 +26,19 @@ module Convoy
26
26
  def_delegators :@data, :size, :map, :each
27
27
 
28
28
  attr_reader :response
29
+
30
+ def initialize(**kwargs)
31
+ @params = kwargs[:params].nil? ? {} : kwargs[:params]
32
+ @query = kwargs[:query].nil? ? {} : kwargs[:query]
33
+ @data = kwargs[:data].nil? ? {} : kwargs[:data]
34
+ end
35
+
36
+ def project_base_uri
37
+ if @config.project_id.nil?
38
+ raise ArgumentError, "Project ID not supplied"
39
+ end
40
+
41
+ "#{@config.base_uri}/#{@config.path_version}/projects/#{@config.project_id}"
42
+ end
29
43
  end
30
44
  end
@@ -3,16 +3,15 @@ module Convoy
3
3
 
4
4
  attr_accessor :ssl
5
5
  attr_accessor :debug
6
- attr_accessor :username
7
- attr_accessor :password
8
6
  attr_accessor :api_key
9
7
  attr_accessor :base_uri
10
8
  attr_accessor :path_version
11
9
  attr_accessor :logger
12
10
  attr_accessor :log_level
11
+ attr_accessor :project_id
13
12
 
14
13
  def initialize
15
- @base_uri = "https://dashboard.getconvoy.io"
14
+ @base_uri = "https://dashboard.getconvoy.io/api"
16
15
  @path_version = "/v1"
17
16
  @ssl = true
18
17
  @debug = false
@@ -8,17 +8,17 @@ module Convoy
8
8
 
9
9
  def initialize(id = nil, config = Convoy.config, **kwargs)
10
10
  @id = id
11
- @data = kwargs[:data].nil? ? {} : kwargs[:data]
12
- @params = kwargs[:params].nil? ? {} : kwargs[:params]
13
11
  @config = config
12
+
13
+ super(kwargs)
14
14
  end
15
15
 
16
- def resource_url
16
+ def resource_uri
17
17
  if @id.nil?
18
- return "#{@config.base_uri}/#{@config.path_version}/security/keys"
18
+ return "#{project_base_uri}/security/keys"
19
19
  end
20
20
 
21
- "#{@config.base_uri}/#{@config.path_version}/security/keys" + "/#{@id}"
21
+ "#{project_base_uri}/security/keys/#{@id}"
22
22
  end
23
23
  end
24
24
  end
@@ -4,20 +4,19 @@ module Convoy
4
4
  include ApiOperations::List
5
5
 
6
6
  def initialize(eventId = nil, id = nil, config = Convoy.config, **kwargs)
7
- @eventId = eventId
8
7
  @id = id
9
- @params = kwargs[:params].nil? ? {} : kwargs[:params]
8
+ @eventId = eventId
10
9
  @config = config
10
+
11
+ super(kwargs)
11
12
  end
12
13
 
13
- def resource_url
14
+ def resource_uri
14
15
  if @id.nil?
15
- return "#{@config.base_uri}/#{@config.path_version}/events/#{@eventId}" +
16
- "/deliveryattempts"
16
+ return "#{project_base_uri}/events/#{@eventId}/deliveryattempts"
17
17
  end
18
18
 
19
- "#{@config.base_uri}/#{@config.path_version}/events/#{@eventId}/deliveryattempts" +
20
- "/#{@id}"
19
+ "#{project_base_uri}/events/#{@eventId}/deliveryattempts/#{@id}"
21
20
  end
22
21
  end
23
22
  end
@@ -6,21 +6,19 @@ module Convoy
6
6
  include ApiOperations::List
7
7
  extend ApiOperations::Create
8
8
 
9
- def initialize(app_id = nil, id = nil, config = Convoy.config, **kwargs)
10
- @app_id = app_id
9
+ def initialize(id = nil, config = Convoy.config, **kwargs)
11
10
  @id = id
12
- @data = kwargs[:data].nil? ? {} : kwargs[:data]
13
- @params = kwargs[:params].nil? ? {} : kwargs[:params]
14
- @config = config
11
+ @config = config
12
+
13
+ super(kwargs)
15
14
  end
16
15
 
17
- def resource_url
16
+ def resource_uri
18
17
  if @id.nil?
19
- return "#{@config.base_uri}/#{@config.path_version}/applications/#{@app_id}/endpoints"
18
+ return "#{project_base_uri}/endpoints"
20
19
  end
21
20
 
22
- "#{@config.base_uri}/#{@config.path_version}/applications/#{@app_id}/endpoints" +
23
- "/#{@id}"
21
+ "#{project_base_uri}/endpoints/#{@id}"
24
22
  end
25
23
  end
26
24
  end
@@ -8,17 +8,17 @@ module Convoy
8
8
 
9
9
  def initialize(id = nil , config = Convoy.config, **kwargs)
10
10
  @id = id
11
- @data = kwargs[:data].nil? ? {} : kwargs[:data]
12
- @params = kwargs[:params].nil? ? {} : kwargs[:params]
13
11
  @config = config
12
+
13
+ super(kwargs)
14
14
  end
15
15
 
16
- def resource_url
16
+ def resource_uri
17
17
  if @id.nil?
18
- return "#{@config.base_uri}/#{@config.path_version}/events"
18
+ return "#{project_base_uri}/events"
19
19
  end
20
20
 
21
- "#{@config.base_uri}/#{@config.path_version}/events/#{@id}"
21
+ "#{project_base_uri}/events/#{@id}"
22
22
  end
23
23
  end
24
24
  end
@@ -4,20 +4,19 @@ module Convoy
4
4
  include ApiOperations::List
5
5
 
6
6
  def intialize(eventId = nil, id = nil, config = Convoy.config, **kwargs)
7
- @eventId = eventId
8
- @params = kwargs[:params].nil? ? {} : kwargs[:params]
9
7
  @id = id
8
+ @eventId = eventId
10
9
  @config = config
10
+
11
+ super(kwargs)
11
12
  end
12
13
 
13
- def resource_url
14
+ def resource_uri
14
15
  if @id.nil?
15
- return "#{@config.base_uri}/#{@config.path_version}/events/#{@eventId}" +
16
- "/eventdelivery"
16
+ return "#{project_base_uri}/events/#{@eventId}/eventdelivery"
17
17
  end
18
18
 
19
- "#{@config.base_uri}/#{@config.path_version}/events/#{@eventId}/eventdelivery" +
20
- "/#{@id}"
19
+ "#{project_base_uri}/events/#{@eventId}/eventdelivery/#{@id}"
21
20
  end
22
21
 
23
22
  # TODO: resend event delivery.
@@ -1,5 +1,5 @@
1
1
  module Convoy
2
- class Group < ApiResource
2
+ class Project < ApiResource
3
3
  include ApiOperations::Get
4
4
  include ApiOperations::Save
5
5
  include ApiOperations::Delete
@@ -8,17 +8,17 @@ module Convoy
8
8
 
9
9
  def initialize(id = nil, config = Convoy.config, **kwargs)
10
10
  @id = id
11
- @data = kwargs[:data].nil? ? {} : kwargs[:data]
12
- @params = kwargs[:params].nil? ? {} : kwargs[:params]
13
11
  @config = config
12
+
13
+ super(kwargs)
14
14
  end
15
15
 
16
- def resource_url
16
+ def resource_uri
17
17
  if @id.nil?
18
- return "#{@config.base_uri}/#{@config.path_version}/groups"
18
+ return "#{@config.base_uri}/#{@config.path_version}/projects"
19
19
  end
20
20
 
21
- "#{@config.base_uri}/#{@config.path_version}/groups" + "/#{@id}"
21
+ "#{@config.base_uri}/#{@config.path_version}/projects" + "/#{@id}"
22
22
  end
23
23
 
24
24
  end
@@ -7,17 +7,17 @@ module Convoy
7
7
 
8
8
  def initialize(id = nil, config = Convoy.config, **kwargs)
9
9
  @id = id
10
- @data = kwargs[:data].nil? ? {} : kwargs[:data]
11
- @params = kwargs[:params].nil? ? {} : kwargs[:params]
12
10
  @config = config
11
+
12
+ super(kwargs)
13
13
  end
14
14
 
15
- def resource_url
15
+ def resource_uri
16
16
  if @id.nil?
17
- return "#{@config.base_uri}/#{@config.path_version}/sources"
17
+ return "#{project_base_uri}/sources"
18
18
  end
19
19
 
20
- "#{@config.base_uri}/#{@config.path_version}/sources" + "/#{@id}"
20
+ "#{project_base_uri}/sources/#{@id}"
21
21
  end
22
22
  end
23
23
  end
@@ -7,17 +7,17 @@ module Convoy
7
7
 
8
8
  def initialize(id = nil, config = Convoy.config, **kwargs)
9
9
  @id = id
10
- @data = kwargs[:data].nil? ? {} : kwargs[:data]
11
- @params = kwargs[:params].nil? ? {} : kwargs[:params]
12
10
  @config = config
11
+
12
+ super(kwargs)
13
13
  end
14
14
 
15
- def resource_url
15
+ def resource_uri
16
16
  if @id.nil?
17
- return "#{@config.base_uri}/#{@config.path_version}/subscriptions"
17
+ return "#{project_base_uri}/subscriptions"
18
18
  end
19
19
 
20
- "#{@config.base_uri}/#{@config.path_version}/subscriptions" + "/#{@id}"
20
+ "#{project_base_uri}/subscriptions/#{@id}"
21
21
  end
22
22
  end
23
23
  end
@@ -0,0 +1,15 @@
1
+ module Convoy
2
+ module Util
3
+ # Constant time string comparison to prevent timing attacks
4
+ # Code borrowed from ActiveSupport
5
+ def self.secure_compare(str_a, str_b)
6
+ return false unless str_a.bytesize == str_b.bytesize
7
+
8
+ l = str_a.unpack "C#{str_a.bytesize}"
9
+
10
+ res = 0
11
+ str_b.each_byte { |byte| res |= byte ^ l.shift }
12
+ res.zero?
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module Convoy
2
- VERSION = "0.1.9"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,91 @@
1
+ module Convoy
2
+
3
+ class SignatureVerificationError < StandardError
4
+ end
5
+
6
+ DEFAULT_TOLERANCE = 300
7
+ DEFAULT_ENCODING = "hex"
8
+ DEFAULT_HASH = "SHA256"
9
+
10
+ # webhook := Webhook.new(secret)
11
+ #
12
+ # With Tolerance
13
+ # webhook := Webhook.new(secret, tolerance: 500)
14
+ #
15
+ # with Encoding
16
+ # webhook = Webhook.new(secret, encoding: "base64")
17
+ #
18
+ # With Encoding and Tolerance
19
+ # webhook = Webhook.new(secret, encoding: "base64", tolerance: 900)
20
+ #
21
+ # Verify request
22
+ # webhook.verify(payload, headers)
23
+
24
+ class Webhook
25
+ def initialize(secret, encoding: DEFAULT_ENCODING, tolerance: DEFAULT_TOLERANCE, hash: DEFAULT_HASH)
26
+ @secret = secret
27
+ @encoding = encoding
28
+ @tolerance = tolerance
29
+ @hash = hash
30
+ end
31
+
32
+ def verify(payload, sig_header)
33
+ # 1. Detect Signature Type.
34
+ is_advanced = (sig_header.split(",")).length > 1
35
+
36
+ if is_advanced
37
+ verify_advanced_signature(payload, sig_header)
38
+ return
39
+ end
40
+
41
+ verify_simple_signature(payload, sig_header)
42
+ end
43
+
44
+ private
45
+
46
+ def verify_simple_signature(payload, sig_header)
47
+ return Util.secure_compare(compute_signature(payload), sig_header)
48
+ end
49
+
50
+ def verify_advanced_signature
51
+ timestamp_header, signatures = get_timestamp_and_signatures(sig_header)
52
+
53
+ verify_timestamp(timestamp_header)
54
+
55
+ unless signatures.any? { |s| Util.secure_compare(expected_sig, s) }
56
+ raise SignatureVerificationError.new,
57
+ "No signatures found matching the expected signature for payload"
58
+ end
59
+ end
60
+
61
+ def verify_timestamp(timestamp_header)
62
+ begin
63
+ now = Integer(Time.now)
64
+ timestamp = Integer(timestamp_header)
65
+ rescue
66
+ raise SignatureVerificationError, "Could parse timestamp header"
67
+ end
68
+
69
+ if timestamp < (now - @tolerance)
70
+ raise SignatureVerificationError, "Message timestamp too old"
71
+ end
72
+ end
73
+
74
+ # return encoded string
75
+ def compute_signature(payload)
76
+ case @encoding
77
+ when "hex":
78
+ return OpenSSL::HMAC.hexdigest(@hash, @secret, payload)
79
+ when "base64":
80
+ hmac = OpenSSL::HMAC.digest(@hash, @secret, payload)
81
+ return Base64.encode64(hmac)
82
+ end
83
+ end
84
+
85
+ def get_timestamp_and_signatures(sig_header)
86
+ list_items = sig_header.split(/,\s*/).map { |i| i.split("=", 2) }
87
+ timestamp = Integer(list_items.select { |i| i[0] == "t" }[0][1])
88
+ [Time.at(timestamp), list_items[1]]
89
+ end
90
+ end
91
+ end
data/lib/convoy.rb CHANGED
@@ -23,12 +23,11 @@ module Convoy
23
23
  # Some of them have defaults
24
24
  def_delegators :@config, :ssl, :ssl=
25
25
  def_delegators :@config, :debug, :debug=
26
- def_delegators :@config, :username, :username=
27
- def_delegators :@config, :password, :password=
28
26
  def_delegators :@config, :api_key, :api_key=
29
27
  def_delegators :@config, :base_uri, :base_uri=
30
28
  def_delegators :@config, :logger, :logger=
31
29
  def_delegators :@config, :log_level, :log_level=
32
30
  def_delegators :@config, :path_version, :path_version=
31
+ def_delegators :@config, :project_id, :project_id=
33
32
  end
34
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: convoy.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Subomi Oluwalana
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-25 00:00:00.000000000 Z
11
+ date: 2022-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -54,15 +54,16 @@ files:
54
54
  - lib/convoy/errors.rb
55
55
  - lib/convoy/instrumentation.rb
56
56
  - lib/convoy/resources/api_key.rb
57
- - lib/convoy/resources/application.rb
58
57
  - lib/convoy/resources/delivery_attempt.rb
59
58
  - lib/convoy/resources/endpoint.rb
60
59
  - lib/convoy/resources/event.rb
61
60
  - lib/convoy/resources/event_delivery.rb
62
- - lib/convoy/resources/group.rb
61
+ - lib/convoy/resources/project.rb
63
62
  - lib/convoy/resources/source.rb
64
63
  - lib/convoy/resources/subscription.rb
64
+ - lib/convoy/util.rb
65
65
  - lib/convoy/version.rb
66
+ - lib/convoy/webhook.rb
66
67
  homepage: https://getconvoy.io
67
68
  licenses:
68
69
  - MIT
@@ -1,23 +0,0 @@
1
- module Convoy
2
- class Application < ApiResource
3
- include ApiOperations::Save
4
- include ApiOperations::Delete
5
- include ApiOperations::List
6
- extend ApiOperations::Create
7
-
8
- def initialize(id = nil, config = Convoy.config, **kwargs)
9
- @id = id
10
- @data = kwargs[:data].nil? ? {} : kwargs[:data]
11
- @params = kwargs[:params].nil? ? {} : kwargs[:params]
12
- @config = config
13
- end
14
-
15
- def resource_url
16
- if @id.nil?
17
- return "#{@config.base_uri}/#{@config.path_version}/applications"
18
- end
19
-
20
- "#{@config.base_uri}/#{@config.path_version}/applications" + "/#{@id}"
21
- end
22
- end
23
- end