twilio-ruby 3.11.5 → 4.0.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 +13 -5
- data/.gitignore +1 -1
- data/.travis.yml +20 -9
- data/AUTHORS.md +32 -25
- data/CHANGES.md +203 -0
- data/Gemfile +8 -1
- data/{LICENSE → LICENSE.md} +4 -2
- data/Makefile +1 -2
- data/README.md +70 -39
- data/Rakefile +8 -10
- data/docs/faq.rst +3 -3
- data/docs/getting-started.rst +17 -12
- data/docs/index.rst +15 -0
- data/docs/usage/accounts.rst +6 -6
- data/docs/usage/addresses.rst +101 -0
- data/docs/usage/applications.rst +10 -10
- data/docs/usage/basics.rst +17 -4
- data/docs/usage/caller-ids.rst +4 -2
- data/docs/usage/conferences.rst +11 -11
- data/docs/usage/errors.rst +7 -7
- data/docs/usage/messages.rst +48 -20
- data/docs/usage/notifications.rst +6 -4
- data/docs/usage/phone-calls.rst +33 -14
- data/docs/usage/phone-numbers.rst +45 -31
- data/docs/usage/queues.rst +8 -8
- data/docs/usage/recordings.rst +12 -10
- data/docs/usage/sip.rst +15 -14
- data/docs/usage/taskrouter-tokens.rst +98 -0
- data/docs/usage/taskrouter.rst +226 -0
- data/docs/usage/token-generation.rst +19 -4
- data/docs/usage/transcriptions.rst +3 -2
- data/docs/usage/twiml.rst +7 -7
- data/docs/usage/validation.rst +39 -3
- data/examples/examples.rb +44 -20
- data/examples/print-call-log.rb +1 -1
- data/lib/rack/twilio_webhook_authentication.rb +47 -0
- data/lib/twilio-ruby/rest/accounts.rb +2 -1
- data/lib/twilio-ruby/rest/addresses/dependent_phone_numbers.rb +6 -0
- data/lib/twilio-ruby/rest/addresses.rb +12 -0
- data/lib/twilio-ruby/rest/base_client.rb +127 -0
- data/lib/twilio-ruby/rest/call_feedback.rb +28 -0
- data/lib/twilio-ruby/rest/call_feedback_summary.rb +13 -0
- data/lib/twilio-ruby/rest/calls.rb +10 -5
- data/lib/twilio-ruby/rest/client.rb +44 -109
- data/lib/twilio-ruby/rest/conferences/participants.rb +2 -2
- data/lib/twilio-ruby/rest/incoming_phone_numbers.rb +1 -1
- data/lib/twilio-ruby/rest/instance_resource.rb +2 -16
- data/lib/twilio-ruby/rest/list_resource.rb +20 -30
- data/lib/twilio-ruby/rest/lookups/phone_numbers.rb +17 -0
- data/lib/twilio-ruby/rest/lookups_client.rb +99 -0
- data/lib/twilio-ruby/rest/messages.rb +5 -0
- data/lib/twilio-ruby/rest/next_gen_list_resource.rb +36 -0
- data/lib/twilio-ruby/rest/outgoing_caller_ids.rb +1 -1
- data/lib/twilio-ruby/rest/queues/members.rb +1 -1
- data/lib/twilio-ruby/rest/sip.rb +1 -3
- data/lib/twilio-ruby/rest/sms/messages.rb +23 -0
- data/lib/twilio-ruby/rest/task_router/activities.rb +8 -0
- data/lib/twilio-ruby/rest/task_router/events.rb +8 -0
- data/lib/twilio-ruby/rest/task_router/reservations.rb +8 -0
- data/lib/twilio-ruby/rest/task_router/statistics.rb +26 -0
- data/lib/twilio-ruby/rest/task_router/task_queues.rb +17 -0
- data/lib/twilio-ruby/rest/task_router/task_queues_statistics.rb +15 -0
- data/lib/twilio-ruby/rest/task_router/tasks.rb +15 -0
- data/lib/twilio-ruby/rest/task_router/workers.rb +13 -0
- data/lib/twilio-ruby/rest/task_router/workers_statistics.rb +8 -0
- data/lib/twilio-ruby/rest/task_router/workflow_statistics.rb +7 -0
- data/lib/twilio-ruby/rest/task_router/workflows.rb +11 -0
- data/lib/twilio-ruby/rest/task_router/workspace_statistics.rb +7 -0
- data/lib/twilio-ruby/rest/task_router/workspaces.rb +17 -0
- data/lib/twilio-ruby/rest/task_router_client.rb +176 -0
- data/lib/twilio-ruby/rest/tokens.rb +7 -0
- data/lib/twilio-ruby/rest/usage/records.rb +2 -2
- data/lib/twilio-ruby/rest/utils.rb +35 -11
- data/lib/twilio-ruby/task_router/capability.rb +87 -0
- data/lib/twilio-ruby/task_router.rb +0 -0
- data/lib/twilio-ruby/twiml/response.rb +1 -0
- data/lib/twilio-ruby/util/capability.rb +10 -7
- data/lib/twilio-ruby/util/client_config.rb +29 -0
- data/lib/twilio-ruby/util/configuration.rb +7 -0
- data/lib/twilio-ruby/util/request_validator.rb +18 -3
- data/lib/twilio-ruby/version.rb +1 -1
- data/lib/twilio-ruby.rb +48 -0
- data/spec/rack/twilio_webhook_authentication_spec.rb +110 -0
- data/spec/rest/account_spec.rb +51 -20
- data/spec/rest/address_spec.rb +11 -0
- data/spec/rest/call_feedback_spec.rb +12 -0
- data/spec/rest/call_feedback_summary_spec.rb +9 -0
- data/spec/rest/call_spec.rb +8 -4
- data/spec/rest/client_spec.rb +209 -51
- data/spec/rest/conference_spec.rb +4 -2
- data/spec/rest/instance_resource_spec.rb +4 -4
- data/spec/rest/lookups/phone_number_spec.rb +8 -0
- data/spec/rest/message_spec.rb +2 -2
- data/spec/rest/numbers_spec.rb +25 -13
- data/spec/rest/queue_spec.rb +4 -2
- data/spec/rest/recording_spec.rb +4 -2
- data/spec/rest/sms/message_spec.rb +37 -0
- data/spec/rest/sms/messages_spec.rb +31 -0
- data/spec/rest/task_router/reservation_spec.rb +9 -0
- data/spec/rest/task_router/task_queue_spec.rb +9 -0
- data/spec/rest/token_spec.rb +7 -0
- data/spec/rest/utils_spec.rb +45 -0
- data/spec/spec_helper.rb +12 -3
- data/spec/support/fakeweb.rb +2 -0
- data/spec/task_router_spec.rb +114 -0
- data/spec/twilio_spec.rb +15 -0
- data/spec/util/capability_spec.rb +167 -118
- data/spec/util/client_config_spec.rb +21 -0
- data/spec/util/configuration_spec.rb +15 -0
- data/spec/util/request_validator_spec.rb +31 -3
- data/spec/util/url_encode_spec.rb +2 -2
- data/twilio-ruby.gemspec +28 -27
- metadata +93 -71
- data/CHANGES +0 -47
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Twilio
|
|
2
|
+
module REST
|
|
3
|
+
module TaskRouter
|
|
4
|
+
module Statistics
|
|
5
|
+
def statistics(args={})
|
|
6
|
+
path = "#{@path}/Statistics"
|
|
7
|
+
response = @client.get(path, args, true)
|
|
8
|
+
statistics_class.new(path, @client, response)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# Gets the class for the statistics of the current class.
|
|
15
|
+
# Should just be Object.const_get("#{self.class.to_s}Statistics") but
|
|
16
|
+
# Ruby 1.9.3 did not agree. Can be updated if support is dropped.
|
|
17
|
+
def statistics_class
|
|
18
|
+
current_class = self.class.to_s.split('::').last
|
|
19
|
+
statistics_class = Twilio::REST::TaskRouter.const_get(
|
|
20
|
+
"#{current_class}Statistics"
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Twilio
|
|
2
|
+
module REST
|
|
3
|
+
module TaskRouter
|
|
4
|
+
class TaskQueues < Twilio::REST::NextGenListResource
|
|
5
|
+
def statistics(args={})
|
|
6
|
+
path = "#{@path}/Statistics"
|
|
7
|
+
stats = Twilio::REST::TaskRouter::TaskQueuesStatistics.new path, @client
|
|
8
|
+
stats.list args, true
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class TaskQueue < InstanceResource
|
|
13
|
+
include Statistics
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Twilio
|
|
2
|
+
module REST
|
|
3
|
+
module TaskRouter
|
|
4
|
+
class TaskQueuesStatistics < Twilio::REST::NextGenListResource
|
|
5
|
+
def initialize(path, client)
|
|
6
|
+
@path, @client = path, client
|
|
7
|
+
@instance_class = Twilio::REST::TaskRouter::TaskQueueStatistics
|
|
8
|
+
@list_key, @instance_id_key = 'task_queues_statistics', 'task_queue_sid'
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class TaskQueueStatistics < InstanceResource; end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Twilio
|
|
2
|
+
module REST
|
|
3
|
+
module TaskRouter
|
|
4
|
+
class Tasks < Twilio::REST::NextGenListResource; end
|
|
5
|
+
|
|
6
|
+
class Task < InstanceResource
|
|
7
|
+
def initialize(path, client, params={})
|
|
8
|
+
super path, client, params
|
|
9
|
+
@submodule = :TaskRouter
|
|
10
|
+
resource :reservations
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Twilio
|
|
2
|
+
module REST
|
|
3
|
+
module TaskRouter
|
|
4
|
+
class Workers < Twilio::REST::NextGenListResource
|
|
5
|
+
include Twilio::REST::TaskRouter::Statistics
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class Worker < InstanceResource
|
|
9
|
+
include Twilio::REST::TaskRouter::Statistics
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Twilio
|
|
2
|
+
module REST
|
|
3
|
+
module TaskRouter
|
|
4
|
+
class Workspaces < Twilio::REST::NextGenListResource; end
|
|
5
|
+
|
|
6
|
+
class Workspace < InstanceResource
|
|
7
|
+
include Twilio::REST::TaskRouter::Statistics
|
|
8
|
+
|
|
9
|
+
def initialize(path, client, params={})
|
|
10
|
+
super path, client, params
|
|
11
|
+
@submodule = :TaskRouter
|
|
12
|
+
resource :activities, :events, :task_queues, :tasks, :workers, :workflows
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
require 'twilio-ruby/rest/base_client'
|
|
2
|
+
module Twilio
|
|
3
|
+
module REST
|
|
4
|
+
class TaskRouterClient < BaseClient
|
|
5
|
+
API_VERSION = 'v1'
|
|
6
|
+
|
|
7
|
+
attr_reader :workspace, :workspace_sid, :workspaces
|
|
8
|
+
|
|
9
|
+
host 'taskrouter.twilio.com'
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Instantiate a new HTTP TaskRouter client to talk to Twilio. The parameters
|
|
13
|
+
# +account_sid+, +auth_token+ and +workspace_sid are required, unless you
|
|
14
|
+
# have configured them already using the block configure syntax, and used
|
|
15
|
+
# to generate the HTTP basic auth header in each request. The +options+
|
|
16
|
+
# parameter is a hash of connection configuration options. the following
|
|
17
|
+
# keys are supported:
|
|
18
|
+
#
|
|
19
|
+
# === <tt>host: 'taskrouter.twilio.com'</tt>
|
|
20
|
+
#
|
|
21
|
+
# The domain to which you'd like the client to make HTTP requests. Useful
|
|
22
|
+
# for testing. Defaults to 'api.twilio.com'.
|
|
23
|
+
#
|
|
24
|
+
# === <tt>port: 443</tt>
|
|
25
|
+
#
|
|
26
|
+
# The port on which to connect to the above domain. Defaults to 443 and
|
|
27
|
+
# should be left that way except in testing environments.
|
|
28
|
+
#
|
|
29
|
+
# === <tt>use_ssl: true</tt>
|
|
30
|
+
#
|
|
31
|
+
# Declare whether ssl should be used for connections to the above domain.
|
|
32
|
+
# Defaults to true and should be left alone except when testing.
|
|
33
|
+
#
|
|
34
|
+
# === <tt>ssl_verify_peer: true</tt>
|
|
35
|
+
#
|
|
36
|
+
# Declare whether to verify the host's ssl cert when setting up the
|
|
37
|
+
# connection to the above domain. Defaults to true, but can be turned off
|
|
38
|
+
# to avoid ssl certificate verification failures in environments without
|
|
39
|
+
# the necessary ca certificates.
|
|
40
|
+
#
|
|
41
|
+
# === <tt>ssl_ca_file: '/path/to/ca/file'</tt>
|
|
42
|
+
#
|
|
43
|
+
# Specify the path to the certificate authority bundle you'd like to use
|
|
44
|
+
# to verify Twilio's SSL certificate on each request. If not specified, a
|
|
45
|
+
# certificate bundle extraced from Firefox is packaged with the gem and
|
|
46
|
+
# used by default.
|
|
47
|
+
#
|
|
48
|
+
# === <tt>timeout: 30</tt>
|
|
49
|
+
#
|
|
50
|
+
# Set the time in seconds to wait before timing out the HTTP request.
|
|
51
|
+
# Defaults to 30 seconds. If you aren't fetching giant pages of call or
|
|
52
|
+
# SMS logs you can safely decrease this to something like 3 seconds or
|
|
53
|
+
# lower. In paricular if you are sending SMS you can set this to 1 second
|
|
54
|
+
# or less and swallow the exception if you don't care about the response.
|
|
55
|
+
#
|
|
56
|
+
# === <tt>proxy_addr: 'proxy.host.domain'</tt>
|
|
57
|
+
#
|
|
58
|
+
# The domain of a proxy through which you'd like the client to make HTTP
|
|
59
|
+
# requests. Defaults to nil.
|
|
60
|
+
#
|
|
61
|
+
# === <tt>proxy_port: 3128</tt>
|
|
62
|
+
#
|
|
63
|
+
# The port on which to connect to the above proxy. Defaults to nil.
|
|
64
|
+
#
|
|
65
|
+
# === <tt>proxy_user: 'username'</tt>
|
|
66
|
+
#
|
|
67
|
+
# The user name to use for authentication with the proxy. Defaults to nil.
|
|
68
|
+
#
|
|
69
|
+
# === <tt>proxy_pass: 'password'</tt>
|
|
70
|
+
#
|
|
71
|
+
# The password to use for authentication with the proxy. Defaults to nil.
|
|
72
|
+
#
|
|
73
|
+
# === <tt>retry_limit: 1</tt>
|
|
74
|
+
#
|
|
75
|
+
# The number of times to retry a request that has failed before throwing
|
|
76
|
+
# an exception. Defaults to one.
|
|
77
|
+
def initialize(*args)
|
|
78
|
+
@workspace_sid = args[2]
|
|
79
|
+
if @workspace_sid.nil?
|
|
80
|
+
raise ArgumentError, 'Workspace SID is required'
|
|
81
|
+
end
|
|
82
|
+
super(*args)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def inspect # :nodoc:
|
|
86
|
+
"<Twilio::REST::TaskRouterClient @account_sid=#{@account_sid}>"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
##
|
|
90
|
+
# Delegate workspace methods from the client. This saves having to call
|
|
91
|
+
# <tt>client.workspace</tt> every time for resources on the default
|
|
92
|
+
# workspace.
|
|
93
|
+
def method_missing(method_name, *args, &block)
|
|
94
|
+
if workspace.respond_to?(method_name)
|
|
95
|
+
workspace.send(method_name, *args, &block)
|
|
96
|
+
else
|
|
97
|
+
super
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def respond_to?(method_name, include_private=false)
|
|
102
|
+
if workspace.respond_to?(method_name, include_private)
|
|
103
|
+
true
|
|
104
|
+
else
|
|
105
|
+
super
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
##
|
|
110
|
+
# Get statistics of a task queue.
|
|
111
|
+
def task_queue_statistics(task_queue_sid, *args) # :doc:
|
|
112
|
+
warn "[DEPRECATED] task_queue_statistics is deprecated. " \
|
|
113
|
+
"Please call client.task_queue.get(sid).statistics."
|
|
114
|
+
task_queues.get(task_queue_sid).statistics
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
##
|
|
118
|
+
# Get statistics of task queues.
|
|
119
|
+
def task_queues_statistics(*args) # :doc:
|
|
120
|
+
warn "[DEPRECATED] task_queues_statistics is deprecated. " \
|
|
121
|
+
"Please call client.task_queues.statistics."
|
|
122
|
+
task_queues.statistics
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
##
|
|
126
|
+
# Get statistics of a worker.
|
|
127
|
+
def worker_statistics(worker_sid, *args) # :doc:
|
|
128
|
+
warn "[DEPRECATED] worker_statistics is deprecated. " \
|
|
129
|
+
"Please call client.worker.get(sid).statistics."
|
|
130
|
+
workers.get(worker_sid).statistics
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
##
|
|
134
|
+
# Get statistics of workers.
|
|
135
|
+
def workers_statistics(*args) # :doc:
|
|
136
|
+
warn "[DEPRECATED] workers_statistics is deprecated. " \
|
|
137
|
+
"Please call client.workers.statistics."
|
|
138
|
+
workers.statistics
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
##
|
|
142
|
+
# Get statistics of a workflow.
|
|
143
|
+
def workflow_statistics(workflow_sid, *args) # :doc:
|
|
144
|
+
warn "[DEPRECATED] workflow_statistics is deprecated. " \
|
|
145
|
+
"Please call client.workflow.get(sid).statistics."
|
|
146
|
+
workflows.get(workflow_sid).statistics
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
##
|
|
150
|
+
# Get statistics of a workspace.
|
|
151
|
+
def workspace_statistics(*args) # :doc:
|
|
152
|
+
warn "[DEPRECATED] worker_statistics is deprecated. " \
|
|
153
|
+
"Please call client.workspace.statistics."
|
|
154
|
+
workspace.statistics
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
protected
|
|
158
|
+
|
|
159
|
+
##
|
|
160
|
+
# Set up +workspace+ and +workspaces+ attributes.
|
|
161
|
+
def set_up_subresources # :doc:
|
|
162
|
+
@workspaces = Twilio::REST::TaskRouter::Workspaces.new "/#{API_VERSION}/Workspaces", self
|
|
163
|
+
@workspace = @workspaces.get @workspace_sid
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
##
|
|
167
|
+
# Builds up full request path
|
|
168
|
+
def build_full_path(path, params, method)
|
|
169
|
+
path = path.dup
|
|
170
|
+
path << "?#{url_encode(params)}" if method == :get && !params.empty?
|
|
171
|
+
path
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -2,8 +2,8 @@ module Twilio
|
|
|
2
2
|
module REST
|
|
3
3
|
class Records < ListResource
|
|
4
4
|
|
|
5
|
-
SUBRESOURCES = [:daily, :monthly, :yearly, :all_time, :today,
|
|
6
|
-
|
|
5
|
+
SUBRESOURCES = [:daily, :monthly, :yearly, :all_time, :today,
|
|
6
|
+
:yesterday, :this_month, :last_month]
|
|
7
7
|
|
|
8
8
|
def initialize(path, client)
|
|
9
9
|
super
|
|
@@ -3,23 +3,47 @@ module Twilio
|
|
|
3
3
|
module Utils
|
|
4
4
|
|
|
5
5
|
def twilify(something)
|
|
6
|
-
if something.is_a? Hash
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
end.join
|
|
12
|
-
end
|
|
6
|
+
return key_map(something, :twilify) if something.is_a? Hash
|
|
7
|
+
string = something.to_s
|
|
8
|
+
string.split('_').map do |string_part|
|
|
9
|
+
string_part[0,1].capitalize + string_part[1..-1]
|
|
10
|
+
end.join
|
|
13
11
|
end
|
|
14
12
|
|
|
15
13
|
def detwilify(something)
|
|
16
|
-
if something.is_a? Hash
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
return key_map(something, :detwilify) if something.is_a? Hash
|
|
15
|
+
string = something.to_s
|
|
16
|
+
string = string[0,1].downcase + string[1..-1]
|
|
17
|
+
string.gsub(/[A-Z][a-z]*/) { |s| "_#{s.downcase}" }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
protected
|
|
21
|
+
|
|
22
|
+
def resource(*resources)
|
|
23
|
+
custom_resource_names = { sms: 'SMS', sip: 'SIP' }
|
|
24
|
+
resources.each do |r|
|
|
25
|
+
resource = twilify r
|
|
26
|
+
relative_path = custom_resource_names.fetch(r, resource)
|
|
27
|
+
path = "#{@path}/#{relative_path}"
|
|
28
|
+
enclosing_module = if @submodule == nil
|
|
29
|
+
Twilio::REST
|
|
30
|
+
else
|
|
31
|
+
Twilio::REST.const_get(@submodule)
|
|
32
|
+
end
|
|
33
|
+
resource_class = enclosing_module.const_get resource
|
|
34
|
+
instance_variable_set("@#{r}", resource_class.new(path, @client))
|
|
20
35
|
end
|
|
36
|
+
self.class.instance_eval { attr_reader *resources }
|
|
21
37
|
end
|
|
22
38
|
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def key_map(something, method)
|
|
42
|
+
something = something.to_a.flat_map do |pair|
|
|
43
|
+
[send(method, pair[0]).to_sym, pair[1]]
|
|
44
|
+
end
|
|
45
|
+
Hash[*something]
|
|
46
|
+
end
|
|
23
47
|
end
|
|
24
48
|
end
|
|
25
49
|
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module Twilio
|
|
2
|
+
module TaskRouter
|
|
3
|
+
class Capability
|
|
4
|
+
|
|
5
|
+
TASK_ROUTER_BASE_URL = 'https://taskrouter.twilio.com'
|
|
6
|
+
TASK_ROUTER_VERSION = 'v1'
|
|
7
|
+
TASK_ROUTER_WEBSOCKET_BASE_URL = 'https://event-bridge.twilio.com/v1/wschannels'
|
|
8
|
+
|
|
9
|
+
REQUIRED = {required: true}
|
|
10
|
+
OPTIONAL = {required: false}
|
|
11
|
+
|
|
12
|
+
def initialize(account_sid, auth_token, workspace_sid, worker_sid)
|
|
13
|
+
@account_sid = account_sid
|
|
14
|
+
@auth_token = auth_token
|
|
15
|
+
@workspace_sid = workspace_sid
|
|
16
|
+
@worker_sid = worker_sid
|
|
17
|
+
@policies = []
|
|
18
|
+
allow_websocket_requests
|
|
19
|
+
allow_activity_list_fetch
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def workspace_url
|
|
23
|
+
"#{TASK_ROUTER_BASE_URL}/#{TASK_ROUTER_VERSION}/Workspaces/#{@workspace_sid}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def worker_url
|
|
27
|
+
"#{workspace_url}/Workers/#{@worker_sid}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def allow_worker_activity_updates
|
|
31
|
+
add_policy(worker_url, "POST", nil, {ActivitySid: REQUIRED})
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def allow_worker_fetch_attributes
|
|
35
|
+
add_policy(worker_url, "GET")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def allow_task_reservation_updates
|
|
39
|
+
task_url = "#{workspace_url}/Tasks/**"
|
|
40
|
+
add_policy(task_url, "POST", nil, {ReservationStatus: REQUIRED})
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def add_policy(url, method, query_filters = nil, post_filters = nil, allowed = true)
|
|
44
|
+
policy = {
|
|
45
|
+
url: url,
|
|
46
|
+
method: method,
|
|
47
|
+
query_filter: query_filters || {},
|
|
48
|
+
post_filter: post_filters || {},
|
|
49
|
+
allow: allowed
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@policies.push(policy)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def generate_token(ttl = 3600)
|
|
56
|
+
payload = {
|
|
57
|
+
iss: @account_sid,
|
|
58
|
+
exp: (Time.now.to_i + ttl),
|
|
59
|
+
version: @version,
|
|
60
|
+
friendly_name: @worker_sid,
|
|
61
|
+
policies: @policies,
|
|
62
|
+
account_sid: @account_sid,
|
|
63
|
+
worker_sid: @worker_sid,
|
|
64
|
+
channel: @worker_sid,
|
|
65
|
+
workspace_sid: @workspace_sid
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
JWT.encode payload, @auth_token
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
protected
|
|
72
|
+
|
|
73
|
+
def allow_websocket_requests
|
|
74
|
+
worker_url = "#{TASK_ROUTER_WEBSOCKET_BASE_URL}/#{@account_sid}/#{@worker_sid}"
|
|
75
|
+
['GET', 'POST'].each do |meth|
|
|
76
|
+
add_policy(worker_url, meth)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def allow_activity_list_fetch
|
|
81
|
+
url = "#{workspace_url}/Activities"
|
|
82
|
+
add_policy(url, 'GET')
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
File without changes
|
|
@@ -4,28 +4,31 @@ module Twilio
|
|
|
4
4
|
|
|
5
5
|
include Twilio::Util
|
|
6
6
|
|
|
7
|
-
def initialize(account_sid, auth_token)
|
|
8
|
-
@account_sid = account_sid
|
|
9
|
-
@auth_token = auth_token
|
|
7
|
+
def initialize(account_sid = nil, auth_token = nil)
|
|
8
|
+
@account_sid = account_sid || Twilio.account_sid
|
|
9
|
+
@auth_token = auth_token || Twilio.auth_token
|
|
10
|
+
if @account_sid.nil? || @auth_token.nil?
|
|
11
|
+
raise ArgumentError, 'Account SID and auth token are required'
|
|
12
|
+
end
|
|
10
13
|
@capabilities = []
|
|
11
14
|
end
|
|
12
15
|
|
|
13
16
|
def allow_client_incoming(client_name)
|
|
14
17
|
@client_name = client_name # stash for use in outgoing
|
|
15
|
-
scope_params = {'clientName' => client_name}
|
|
18
|
+
scope_params = { 'clientName' => client_name }
|
|
16
19
|
@capabilities << scope_uri_for('client', 'incoming', scope_params)
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
def allow_client_outgoing(app_sid, params = {})
|
|
20
23
|
@allow_client_outgoing = true
|
|
21
|
-
@outgoing_scope_params = {'appSid' => app_sid}
|
|
24
|
+
@outgoing_scope_params = { 'appSid' => app_sid }
|
|
22
25
|
unless params.empty?
|
|
23
26
|
@outgoing_scope_params['appParams'] = url_encode params
|
|
24
27
|
end
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
def allow_event_stream(filters = {})
|
|
28
|
-
scope_params = {'path' => '/2010-04-01/Events'}
|
|
31
|
+
scope_params = { 'path' => '/2010-04-01/Events' }
|
|
29
32
|
scope_params['params'] = filters unless filters.empty?
|
|
30
33
|
@capabilities << scope_uri_for('stream', 'subscribe', scope_params)
|
|
31
34
|
end
|
|
@@ -42,7 +45,7 @@ module Twilio
|
|
|
42
45
|
# build the outgoing scope lazily so that we can use @client_name
|
|
43
46
|
if @allow_client_outgoing
|
|
44
47
|
params = @outgoing_scope_params
|
|
45
|
-
params.merge!(
|
|
48
|
+
params.merge!('clientName' => @client_name) if @client_name
|
|
46
49
|
capabilities << scope_uri_for('client', 'outgoing', params)
|
|
47
50
|
end
|
|
48
51
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Twilio
|
|
2
|
+
module Util
|
|
3
|
+
class ClientConfig
|
|
4
|
+
DEFAULTS = {
|
|
5
|
+
host: 'api.twilio.com',
|
|
6
|
+
port: 443,
|
|
7
|
+
use_ssl: true,
|
|
8
|
+
ssl_verify_peer: true,
|
|
9
|
+
ssl_ca_file: File.dirname(__FILE__) + '/../../../conf/cacert.pem',
|
|
10
|
+
timeout: 30,
|
|
11
|
+
proxy_addr: nil,
|
|
12
|
+
proxy_port: nil,
|
|
13
|
+
proxy_user: nil,
|
|
14
|
+
proxy_pass: nil,
|
|
15
|
+
retry_limit: 1
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
DEFAULTS.each_key do |attribute|
|
|
19
|
+
attr_accessor attribute
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def initialize(opts={})
|
|
23
|
+
DEFAULTS.each do |attribute, value|
|
|
24
|
+
send("#{attribute}=".to_sym, opts.fetch(attribute, value))
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -2,13 +2,14 @@ module Twilio
|
|
|
2
2
|
module Util
|
|
3
3
|
class RequestValidator
|
|
4
4
|
|
|
5
|
-
def initialize(auth_token)
|
|
6
|
-
@auth_token = auth_token
|
|
5
|
+
def initialize(auth_token = nil)
|
|
6
|
+
@auth_token = auth_token || Twilio.auth_token
|
|
7
|
+
raise ArgumentError, 'Auth token is required' if @auth_token.nil?
|
|
7
8
|
end
|
|
8
9
|
|
|
9
10
|
def validate(url, params, signature)
|
|
10
11
|
expected = build_signature_for url, params
|
|
11
|
-
expected
|
|
12
|
+
secure_compare(expected, signature)
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def build_signature_for(url, params)
|
|
@@ -17,6 +18,20 @@ module Twilio
|
|
|
17
18
|
Base64.encode64(OpenSSL::HMAC.digest(digest, @auth_token, data)).strip
|
|
18
19
|
end
|
|
19
20
|
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# Compares two strings in constant time to avoid timing attacks.
|
|
24
|
+
# Borrowed from ActiveSupport::MessageVerifier.
|
|
25
|
+
# https://github.com/rails/rails/blob/master/activesupport/lib/active_support/message_verifier.rb
|
|
26
|
+
def secure_compare(a, b)
|
|
27
|
+
return false unless a.bytesize == b.bytesize
|
|
28
|
+
|
|
29
|
+
l = a.unpack("C#{a.bytesize}")
|
|
30
|
+
|
|
31
|
+
res = 0
|
|
32
|
+
b.each_byte { |byte| res |= byte ^ l.shift }
|
|
33
|
+
res == 0
|
|
34
|
+
end
|
|
20
35
|
end
|
|
21
36
|
end
|
|
22
37
|
end
|
data/lib/twilio-ruby/version.rb
CHANGED