Skip to content

Commit

Permalink
Merge pull request #268 from Vonage/dev
Browse files Browse the repository at this point in the history
Release 7.10.0
  • Loading branch information
superchilled authored May 31, 2023
2 parents 8d2f2b4 + fd06932 commit 8f87c6f
Show file tree
Hide file tree
Showing 27 changed files with 1,241 additions and 4 deletions.
7 changes: 6 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# 7.10.0

* Adds Verify2. [#261](https://github.com/Vonage/vonage-ruby-sdk/pull/261)
* Fixes link in README. [#266](https://github.com/Vonage/vonage-ruby-sdk/pull/266)

# 7.9.0

* Updates the Messages API implementation to ass support for `video` and `file` messages types to the Viber channel, and `sticker` messages in the WhatsApp channel. [#260](https://github.com/Vonage/vonage-ruby-sdk/pull/260)
* Updates the Messages API implementation to add support for `video` and `file` messages types to the Viber channel, and `sticker` messages in the WhatsApp channel. [#260](https://github.com/Vonage/vonage-ruby-sdk/pull/260)
* Updates the Numbers API implementation to use Basic authentication. [#262](https://github.com/Vonage/vonage-ruby-sdk/pull/262)

# 7.8.2
Expand Down
130 changes: 129 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ need a Vonage account. Sign up [for free at vonage.com][signup].
* [Webhook signatures](#webhook-signatures)
* [Pagination](#pagination)
* [NCCO Builder](#ncco-builder)
* [Messages API](#messages-api)
* [Verify API v2](#verify-api-v2)
* [Documentation](#documentation)
* [Frequently Asked Questions](#frequently-asked-questions)
* [Supported APIs](#supported-apis)
Expand Down Expand Up @@ -220,11 +222,136 @@ Once the message data is created, you can then send the message.
response = client.messaging.send(to: "447700900000", from: "447700900001", **message)
```

## Verify API v2

The [Vonage Verify API v2](https://developer.vonage.com/en/verify/verify-v2/overview) allows you to manage 2FA verification workflows over a number of different channels such as SMS, WhatsApp, WhatsApp Interactive, Voice, Email, and Silent Authentication, either individually or in combination with each other. See the Vonage Developer Documentation for a [complete API reference](https://developer.vonage.com/en/api/verify.v2) listing all the channels, verification options, and callback types.

The Ruby SDK provides two methods for interacting with the Verify v2 API:

- `Verify2#start_verification`: starts a new verification request. Here you can specify options for the request and the workflow to be used.
- `Verify2#check_code`: for channels where the end-user is sent a one-time code, this method is used to verify the code against the `request_id` of the verification request created by the `start_verification` method.

### Creating a Verify2 Object

```ruby
verify = client.verify2
```

### Making a verification request

For simple requests, you may prefer to manually set the value for `workflow` (an array of one or more hashes containing the settings for a particular channel) and any optional params.

Example with the required `:brand` and `:workflow` arguments:

```ruby
verification_request = verify.start_verification(
brand: 'Acme',
workflow: [{channel: 'sms', to: '447000000000'}]
)
```

Example with the required `:brand` and `:workflow` arguments, and an optional `code_length`:

```ruby
verification_request = verify.start_verification(
brand: 'Acme',
workflow: [{channel: 'sms', to: '447000000000'}],
code_length: 6
)
```

For more complex requests (e.g. with mutliple workflow channels or addtional options), or to take advantage of built-in input validation, you can use the `StartVerificationOptions` object and the `Workflow` and various channel objects or the `WorkflowBuilder`:

#### Create options using StartVerificationOptions object

```ruby
opts = verify.start_verification_options(
locale: 'fr-fr',
code_length: 6,
client_ref: 'abc-123'
).to_h
verification_request = verify.start_verification(
brand: 'Acme',
workflow: [{channel: 'email', to: 'alice.example.com'}],
**opts
)
```

#### Create workflow using Workflow and Channel objects

```ruby
# Instantiate a Workflow object
workflow = verify.workflow
# Add channels to the workflow
workflow << workflow.sms(to: '447000000000')
workflow << workflow.email(to: 'alice.example.com')
# Channel data is encpsulated in channel objects stored in the Workflow list array
workflow.list
# => [ #<Vonage::Verify2::Channels::SMS:0x0000561474a74778 @channel="sms", @to="447000000000">,
#<Vonage::Verify2::Channels::Email:0x0000561474c51a28 @channel="email", @to="alice.example.com">]
# To use the list as the value for `:workflow` in a `start_verification` request call,
# the objects must be hashified
workflow_list = workflow.hashified_list
# => [{:channel=>"sms", :to=>"447000000000"}, {:channel=>"email", :to=>"alice.example.com"}]
verification_request = verify.start_verification(brand: 'Acme', workflow: workflow_list)
```

#### Create a workflow using the WorkflowBuilder

```ruby
workflow = verify.workflow_builder.build do |builder|
builder.add_voice(to: '447000000001')
builder.add_whatsapp(to: '447000000000')
end
workflow_list = workflow.hashified_list
# => [{:channel=>"voice", :to=>"447000000001"}, {:channel=>"whatsapp", :to=>"447000000000"}]
verification_request = verify.start_verification(brand: 'Acme', workflow: workflow_list)
```

### Cancelling a request

You can cancel in in-progress verification request

```ruby
# Get the `request_id` from the Vonage#Response object returned by the `start_verification` method call
request_id = verification_request.request_id
verify.cancel_verification_request(request_id: request_id)
```

### Checking a code

```ruby
# Get the `request_id` from the Vonage#Response object returned by the `start_verification` method call
request_id = verification_request.request_id
# Get the one-time code via user input
# e.g. from params in a route handler or controller action for a form input
code = params[:code]
begin
code_check = verify.check_code(request_id: request_id, code: code)
rescue => error
# an invalid code will raise an exception of type Vonage::ClientError
end
if code_check.http_response.code == '200'
# code is valid
end
```

## Documentation

Vonage Ruby documentation: https://www.rubydoc.info/github/Vonage/vonage-ruby-sdk

Vonage Ruby code examples: https://github.com/Nexmo/nexmo-ruby-code-snippets
Vonage Ruby code examples: https://github.com/Vonage/vonage-ruby-code-snippets

Vonage APIs API reference: https://developer.nexmo.com/api

Expand Down Expand Up @@ -252,6 +379,7 @@ The following is a list of Vonage APIs and whether the Ruby SDK provides support
| Reports API | Beta ||
| SMS API | General Availability ||
| Verify API | General Availability ||
| Verify API v2 | General Availability ||
| Voice API | General Availability ||

## License
Expand Down
7 changes: 7 additions & 0 deletions lib/vonage/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ def verify
@verify ||= T.let(Verify.new(config), T.nilable(Vonage::Verify))
end

# @return [Verify2]
#
sig { returns(T.nilable(Vonage::Verify2)) }
def verify2
@verify2 ||= T.let(Verify2.new(config), T.nilable(Vonage::Verify2))
end

# @return [Voice]
#
sig { returns(T.nilable(Vonage::Voice)) }
Expand Down
2 changes: 1 addition & 1 deletion lib/vonage/namespace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def parse(response, response_class)
when Net::HTTPNoContent
response_class.new(nil, response)
when Net::HTTPSuccess
if response['Content-Type'].split(';').first == 'application/json'
if response['Content-Type'] && response['Content-Type'].split(';').first == 'application/json'
entity = ::JSON.parse(response.body, object_class: Vonage::Entity)

response_class.new(entity, response)
Expand Down
93 changes: 93 additions & 0 deletions lib/vonage/verify2.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# typed: true
# frozen_string_literal: true

module Vonage
class Verify2 < Namespace
self.authentication = BearerToken

self.request_body = JSON

# Request a verification be sent to a user.
#
# @example
# verification_request = verify.start_verification(
# brand: 'Acme',
# workflow: [{channel: 'sms', to: '447000000000'}],
# code_length: 6
# )
#
# @param [required, String] :brand The brand that is sending the verification request
#
# @param [required, Array<Hash>] :workflow An array of hashes for channels in the workflow
#
# @param [optional, Hash] opts the options for the verification request.
# @option opts [Integer] :code_length The length of the one-time code provided to the end-user
# @option opts [String] :code An optional alphanumeric custom code to use instead of an auto-generated code
# @option opts [String] :locale The language to use for the verification message (where applicable)
# @option opts [Integer] :channel_timeout Wait time in seconds before trying the next channel in the workflow
# @option opts [String] :client_ref Reference to be included in callbacks
# @option opts [Boolean] If used, must be set to `false`. Will bypass a network block for a single Verify V2 request
#
# @return Vomage::Response
# @see https://developer.vonage.com/en/api/verify.v2#newRequest
#
def start_verification(brand:, workflow:, **opts)
raise ArgumentError, ':workflow must be an Array' unless workflow.is_a?(Array)
raise ArgumentError, ':workflow must not be empty' if workflow.empty?

request('/v2/verify/', params: opts.merge(brand: brand, workflow: workflow), type: Post)
end

# Check a supplied code against a request to see if it is valid.
#
# @example
# code_check = verify.check_code(request_id: '7e8c5965-0a3f-44df-8a14-f1486209d8a2', code: '1234')
#
# @param [required, String] :request_id The request_id of the verification request being checked
#
# @param [required, String] :code The code supplied to the end-user by the verification request
#
# @see https://developer.vonage.com/en/api/verify.v2#checkCode
#
def check_code(request_id:, code:)
request('/v2/verify/' + request_id, params: {code: code}, type: Post)
end

# Cancel a verifiction. If a verification request is still active, calling this method aborts the workflow.
#
# @example
# verify.cancel_verification_request(request_id: '7e8c5965-0a3f-44df-8a14-f1486209d8a2')
#
# @param [required, String] :request_id The request_id of the verification request to be cancelled
#
# @see https://developer.vonage.com/en/api/verify.v2#cancelRequest
#
def cancel_verification_request(request_id:)
request('/v2/verify/' + request_id, type: Delete)
end

# Instantiate a new Vonage::Verify2::StartVerificationOptions object
#
# @param [optional, Hash] opts the options for the verification request.
# @option opts [Integer] :code_length The length of the one-time code provided to the end-user
# @option opts [String] :code An optional alphanumeric custom code to use instead of an auto-generated code
# @option opts [String] :locale The language to use for the verification message (where applicable)
# @option opts [Integer] :channel_timeout Wait time in seconds before trying the next channel in the workflow
# @option opts [String] :client_ref Reference to be included in callbacks
# @option opts [Boolean] If used, must be set to `false`. Will bypass a network block for a single Verify V2 request
#
def start_verification_options(**opts)
StartVerificationOptions.new(**opts)
end

# Instantiate a new Vonage::Verify2::Workflow object
def workflow
Workflow.new
end

# Return the Vonage::Verify2::WorkflowBuilder class
def workflow_builder
WorkflowBuilder.itself
end
end
end
38 changes: 38 additions & 0 deletions lib/vonage/verify2/channels/email.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# typed: true
# frozen_string_literal: true
require 'phonelib'

module Vonage
class Verify2::Channels::Email

attr_reader :channel, :to, :from

def initialize(to:, from: nil)
self.channel = 'email'
self.to = to
self.from = from if from
end

def to=(to)
# TODO: add validation
@to = to
end

def from=(from)
# TODO: add validation
@from = from
end

def to_h
hash = Hash.new
self.instance_variables.each do |ivar|
hash[ivar.to_s.delete("@").to_sym] = self.instance_variable_get(ivar)
end
hash
end

private

attr_writer :channel
end
end
32 changes: 32 additions & 0 deletions lib/vonage/verify2/channels/silent_auth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# typed: true
# frozen_string_literal: true
require 'phonelib'

module Vonage
class Verify2::Channels::SilentAuth

attr_reader :channel, :to

def initialize(to:)
self.channel = 'silent_auth'
self.to = to
end

def to=(to)
raise ArgumentError, "Invalid 'to' value #{to}. Expected to be in E.164 format" unless Phonelib.parse(to.to_i).valid?
@to = to
end

def to_h
hash = Hash.new
self.instance_variables.each do |ivar|
hash[ivar.to_s.delete("@").to_sym] = self.instance_variable_get(ivar)
end
hash
end

private

attr_writer :channel
end
end
39 changes: 39 additions & 0 deletions lib/vonage/verify2/channels/sms.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# typed: true
# frozen_string_literal: true
require 'phonelib'

module Vonage
class Verify2::Channels::SMS
APP_HASH_LENGTH = 11

attr_reader :channel, :to, :app_hash

def initialize(to:, app_hash: nil)
self.channel = 'sms'
self.to = to
self.app_hash = app_hash if app_hash
end

def to=(to)
raise ArgumentError, "Invalid 'to' value #{to}. Expected to be in E.164 format" unless Phonelib.parse(to).valid?
@to = to
end

def app_hash=(app_hash)
raise ArgumentError, "Invalid 'app_hash' value #{app_hash}. Length must be #{APP_HASH_LENGTH}" unless app_hash.length == APP_HASH_LENGTH
@app_hash = app_hash
end

def to_h
hash = Hash.new
self.instance_variables.each do |ivar|
hash[ivar.to_s.delete("@").to_sym] = self.instance_variable_get(ivar)
end
hash
end

private

attr_writer :channel
end
end
Loading

0 comments on commit 8f87c6f

Please sign in to comment.