messagebird-rest 2.0.0 → 3.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: dd213489a7f5a7e70a7418ab2e3be5c4aa8cedfa61042121edb1c03dddd6d56a
4
- data.tar.gz: 9eca63a90298b50cc4d07fb0b7ff6abc7d1ae292155e7f456df18256ae7f64e3
3
+ metadata.gz: f31ec7bbc1d49554a915dde71c24245246453df62bfd7ab7a4b912727990de5b
4
+ data.tar.gz: 9dcdd828d54250134e2d4cd95a3ccd418d799e7f1e387324885faa8b2d23e385
5
5
  SHA512:
6
- metadata.gz: 373dae967d6e226cccb6f775666369b1cdc07491593cc1f5ed4fb6e7950c887723475360d4b3d04e50f00b609542190980a99ac3c09bbca5974f636791b86755
7
- data.tar.gz: 8bc8ca63f00b5b77731ca3082497ea9cf9f8ae4738878e15d49361438adf5aa03baa2a35bc3bebec4e46a5b7c30e42cbc17be109fefee47543e0f3c3ac7410c0
6
+ metadata.gz: e6c773c63307706d30dd415dae6860714575a0ed4ce217abec279acc1030120899b38871c4e62d7b7cd6d207ac16049c519d2c81a05d6a9cbdae60b69436a5c1
7
+ data.tar.gz: 1595298d447d97acfb71ee8dfd3cef0e9facab22935bb30abe7d000fed73919c34b548340b93d087cea98393ec4ebafe2d3d2c7f529fb72f01b0b62d2e498663
data/README.md CHANGED
@@ -2,7 +2,7 @@ MessageBird's REST API for Ruby
2
2
  ===============================
3
3
  This repository contains the open source Ruby client for MessageBird's REST API. Documentation can be found at: https://developers.messagebird.com/
4
4
 
5
- [![Build Status](https://travis-ci.org/messagebird/ruby-rest-api.svg?branch=master)](https://travis-ci.org/messagebird/ruby-rest-api)
5
+ [![Build Status](https://github.com/messagebird/ruby-rest-api/actions/workflows/ruby_ci.yml/badge.svg)](https://github.com/messagebird/ruby-rest-api/actions)
6
6
 
7
7
  Requirements
8
8
  ------------
@@ -20,6 +20,7 @@ require 'messagebird/message'
20
20
  require 'messagebird/number'
21
21
  require 'messagebird/number_client'
22
22
  require 'messagebird/verify'
23
+ require 'messagebird/verify_email_message'
23
24
  require 'messagebird/voice/client'
24
25
  require 'messagebird/voice/list'
25
26
  require 'messagebird/voice/webhook'
@@ -77,7 +78,7 @@ module MessageBird
77
78
 
78
79
  def request(method, path, params = {})
79
80
  response_body = @http_client.request(method, path, params)
80
- return if response_body.empty?
81
+ return if response_body.nil? || response_body.empty?
81
82
 
82
83
  parse_body(response_body)
83
84
  end
@@ -207,6 +208,11 @@ module MessageBird
207
208
  Verify.new(request(:get, "verify/#{id}"))
208
209
  end
209
210
 
211
+ # Retrieve the information of specific Verify email message
212
+ def verify_email_message(id)
213
+ VerifyEmailMessage.new(request(:get, "verify/messages/email/#{id}"))
214
+ end
215
+
210
216
  # Generate a new One-Time-Password message.
211
217
  def verify_create(recipient, params = {})
212
218
  Verify.new(request(
@@ -221,9 +227,9 @@ module MessageBird
221
227
  Verify.new(request(:get, "verify/#{id}?token=#{token}"))
222
228
  end
223
229
 
224
- # Delete a Verify
230
+ # Delete a Verify, response is empty
225
231
  def verify_delete(id)
226
- Verify.new(request(:delete, "verify/#{id}"))
232
+ request(:delete, "verify/#{id}")
227
233
  end
228
234
 
229
235
  # Retrieve the information of specific message.
@@ -232,16 +238,10 @@ module MessageBird
232
238
  end
233
239
 
234
240
  # Retrieve messages with optional paging and status filter.
235
- def message_list(filter = {})
236
- limit = filter[:limit] || 10
237
- offset = filter[:offset] || 0
238
- status = filter[:status] || ''
239
-
240
- params = { limit: limit, offset: offset }
241
- if status != ''
242
- params['status'] = status
243
- end
244
- query = 'messages?' + URI.encode_www_form(params)
241
+ def message_list(filters = {})
242
+ params = { limit: 10, offset: 0 }.merge(filters).compact
243
+ query = "messages?#{URI.encode_www_form(params)}"
244
+
245
245
  List.new(Message, request(:get, query))
246
246
  end
247
247
 
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'digest'
5
+ require 'time'
6
+ require 'jwt'
7
+
8
+ module MessageBird
9
+ class ValidationError < StandardError
10
+ end
11
+
12
+ ##
13
+ # RequestValidator validates request signature signed by MessageBird services.
14
+ #
15
+ # @see https://developers.messagebird.com/docs/verify-http-requests
16
+ class RequestValidator
17
+ ALLOWED_ALGOS = %w[HS256 HS384 HS512].freeze
18
+
19
+ ##
20
+ #
21
+ # @param [string] signature_key customer signature key. Can be retrieved through <a href="https://dashboard.messagebird.com/developers/settings">Developer Settings</a>. This is NOT your API key.
22
+ # @param [bool] skip_url_validation whether url_hash claim validation should be skipped. Note that when true, no query parameters should be trusted.
23
+ def initialize(signature_key, skip_url_validation = false)
24
+ @signature_key = signature_key
25
+ @skip_url_validation = skip_url_validation
26
+ end
27
+
28
+ ##
29
+ # This method validates provided request signature, which is a JWT token.
30
+ # This JWT is signed with a MessageBird account unique secret key, ensuring the request is from MessageBird and a specific account.
31
+ # The JWT contains the following claims:
32
+ # * "url_hash" - the raw URL hashed with SHA256 ensuring the URL wasn't altered.
33
+ # * "payload_hash" - the raw payload hashed with SHA256 ensuring the payload wasn't altered.
34
+ # * "jti" - a unique token ID to implement an optional non-replay check (NOT validated by default).
35
+ # * "nbf" - the not before timestamp.
36
+ # * "exp" - the expiration timestamp is ensuring that a request isn't captured and used at a later time.
37
+ # * "iss" - the issuer name, always MessageBird.
38
+ # @param [String] signature the actual signature taken from request header "MessageBird-Signature-JWT".
39
+ # @param [String] url the raw url including the protocol, hostname and query string, e.g. "https://example.com/?example=42".
40
+ # @param [Array] request_body the raw request body.
41
+ # @return [Array] raw signature payload
42
+ # @raise [ValidationError] if signature is invalid
43
+ # @see https://developers.messagebird.com/docs/verify-http-requests
44
+ def validate_signature(signature, url, request_body)
45
+ raise ValidationError, 'Signature can not be empty' if signature.to_s.empty?
46
+ raise ValidationError, 'URL can not be empty' if !@skip_url_validation && url.to_s.empty?
47
+
48
+ claims = decode_signature signature
49
+ validate_url(url, claims['url_hash']) unless @skip_url_validation
50
+ validate_payload(request_body, claims['payload_hash'])
51
+
52
+ claims
53
+ end
54
+
55
+ private # Applies to every method below this line
56
+
57
+ def decode_signature(signature)
58
+ begin
59
+ claims, * = JWT.decode signature, @signature_key, true,
60
+ algorithm: ALLOWED_ALGOS,
61
+ iss: 'MessageBird',
62
+ required_claims: %w[iss nbf exp],
63
+ verify_iss: true,
64
+ leeway: 1
65
+ rescue JWT::DecodeError => e
66
+ raise ValidationError, e
67
+ end
68
+
69
+ claims
70
+ end
71
+
72
+ def validate_url(url, url_hash)
73
+ expected_url_hash = Digest::SHA256.hexdigest url
74
+ unless JWT::SecurityUtils.secure_compare(expected_url_hash, url_hash)
75
+ raise ValidationError, 'invalid jwt: claim url_hash is invalid'
76
+ end
77
+ end
78
+
79
+ def validate_payload(body, payload_hash)
80
+ if !body.to_s.empty? && !payload_hash.to_s.empty?
81
+ unless JWT::SecurityUtils.secure_compare(Digest::SHA256.hexdigest(body), payload_hash)
82
+ raise ValidationError, 'invalid jwt: claim payload_hash is invalid'
83
+ end
84
+ elsif !body.to_s.empty?
85
+ raise ValidationError, 'invalid jwt: claim payload_hash is not set but payload is present'
86
+ elsif !payload_hash.to_s.empty?
87
+ raise ValidationError, 'invalid jwt: claim payload_hash is set but actual payload is missing'
88
+ end
89
+ end
90
+ end
91
+ end
@@ -5,10 +5,16 @@ require 'digest'
5
5
  require 'time'
6
6
 
7
7
  module MessageBird
8
+ ##
9
+ # @deprecated Use {MessageBird::RequestValidator::ValidationError} instead.
8
10
  class ValidationException < TypeError
9
11
  end
10
12
 
13
+ ##
14
+ # @deprecated Use {MessageBird::RequestValidator} instead.
11
15
  class SignedRequest
16
+ ##
17
+ # @deprecated Use {MessageBird::RequestValidator} instead.
12
18
  def initialize(query_parameters, signature, request_timestamp, body)
13
19
  unless query_parameters.is_a? Hash
14
20
  raise ValidationException, 'The "query_parameters" value is invalid.'
@@ -29,12 +35,16 @@ module MessageBird
29
35
  @body = body
30
36
  end
31
37
 
38
+ ##
39
+ # @deprecated Use {MessageBird::RequestValidator::validateSignature} instead.
32
40
  def verify(signing_key)
33
41
  calculated_signature = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), signing_key, build_payload)
34
42
  expected_signature = Base64.decode64(@signature)
35
43
  calculated_signature.bytes == expected_signature.bytes
36
44
  end
37
45
 
46
+ ##
47
+ # @deprecated Use {MessageBird::RequestValidator} instead.
38
48
  def build_payload
39
49
  parts = []
40
50
  parts.push(@request_timestamp)
@@ -43,6 +53,8 @@ module MessageBird
43
53
  parts.join("\n")
44
54
  end
45
55
 
56
+ ##
57
+ # @deprecated Use {MessageBird::RequestValidator} instead.
46
58
  def recent?(offset = 10)
47
59
  (Time.now.getutc.to_i - @request_timestamp) < offset
48
60
  end
@@ -1,20 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'time'
4
-
5
4
  require 'messagebird/base'
6
5
 
7
6
  module MessageBird
8
7
  class Verify < MessageBird::Base
9
- attr_accessor :id, :recipient, :reference, :status, :href
10
- attr_reader :created_datetime, :valid_until_date_time
8
+ attr_accessor :id,
9
+ :href,
10
+ :recipient,
11
+ :reference,
12
+ :messages,
13
+ :status
14
+ attr_reader :created_datetime,
15
+ :valid_until_datetime
11
16
 
12
17
  def created_datetime=(value)
13
18
  @created_datetime = value_to_time(value)
14
19
  end
15
20
 
16
- def valid_until_date_time=(value)
17
- @valid_until_date_time = value_to_time(value)
21
+ def valid_until_datetime=(value)
22
+ @valid_until_datetime = value_to_time(value)
18
23
  end
19
24
  end
20
25
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'messagebird/base'
4
+
5
+ module MessageBird
6
+ class VerifyEmailMessage < MessageBird::Base
7
+ attr_accessor :id, :status
8
+ end
9
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module MessageBird
4
4
  module Version
5
- STRING = '2.0.0'
5
+ STRING = '3.1.0'
6
6
  end
7
7
  end
data/lib/messagebird.rb CHANGED
@@ -12,7 +12,8 @@ require 'messagebird/group_reference'
12
12
  require 'messagebird/hlr'
13
13
  require 'messagebird/http_client'
14
14
  require 'messagebird/message_reference'
15
- require 'messagebird/signed_request'
15
+ require 'messagebird/signed_request' # @deprecated
16
+ require 'messagebird/request_validator'
16
17
  require 'messagebird/verify'
17
18
  require 'messagebird/message'
18
19
  require 'messagebird/voicemessage'
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: messagebird-rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maurice Nonnekes
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-14 00:00:00.000000000 Z
11
+ date: 2022-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jwt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.2.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.2.3
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rspec
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -87,8 +101,10 @@ files:
87
101
  - lib/messagebird/number.rb
88
102
  - lib/messagebird/number_client.rb
89
103
  - lib/messagebird/recipient.rb
104
+ - lib/messagebird/request_validator.rb
90
105
  - lib/messagebird/signed_request.rb
91
106
  - lib/messagebird/verify.rb
107
+ - lib/messagebird/verify_email_message.rb
92
108
  - lib/messagebird/version.rb
93
109
  - lib/messagebird/voice/base.rb
94
110
  - lib/messagebird/voice/call.rb
@@ -104,7 +120,7 @@ homepage: https://github.com/messagebird/ruby-rest-api
104
120
  licenses:
105
121
  - BSD-2-Clause
106
122
  metadata: {}
107
- post_install_message:
123
+ post_install_message:
108
124
  rdoc_options: []
109
125
  require_paths:
110
126
  - lib
@@ -112,15 +128,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
112
128
  requirements:
113
129
  - - ">="
114
130
  - !ruby/object:Gem::Version
115
- version: 1.9.3
131
+ version: '2.0'
116
132
  required_rubygems_version: !ruby/object:Gem::Requirement
117
133
  requirements:
118
134
  - - ">="
119
135
  - !ruby/object:Gem::Version
120
136
  version: '0'
121
137
  requirements: []
122
- rubygems_version: 3.2.15
123
- signing_key:
138
+ rubygems_version: 3.1.2
139
+ signing_key:
124
140
  specification_version: 4
125
141
  summary: MessageBird's REST API
126
142
  test_files: []