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.
Files changed (114) hide show
  1. checksums.yaml +13 -5
  2. data/.gitignore +1 -1
  3. data/.travis.yml +20 -9
  4. data/AUTHORS.md +32 -25
  5. data/CHANGES.md +203 -0
  6. data/Gemfile +8 -1
  7. data/{LICENSE → LICENSE.md} +4 -2
  8. data/Makefile +1 -2
  9. data/README.md +70 -39
  10. data/Rakefile +8 -10
  11. data/docs/faq.rst +3 -3
  12. data/docs/getting-started.rst +17 -12
  13. data/docs/index.rst +15 -0
  14. data/docs/usage/accounts.rst +6 -6
  15. data/docs/usage/addresses.rst +101 -0
  16. data/docs/usage/applications.rst +10 -10
  17. data/docs/usage/basics.rst +17 -4
  18. data/docs/usage/caller-ids.rst +4 -2
  19. data/docs/usage/conferences.rst +11 -11
  20. data/docs/usage/errors.rst +7 -7
  21. data/docs/usage/messages.rst +48 -20
  22. data/docs/usage/notifications.rst +6 -4
  23. data/docs/usage/phone-calls.rst +33 -14
  24. data/docs/usage/phone-numbers.rst +45 -31
  25. data/docs/usage/queues.rst +8 -8
  26. data/docs/usage/recordings.rst +12 -10
  27. data/docs/usage/sip.rst +15 -14
  28. data/docs/usage/taskrouter-tokens.rst +98 -0
  29. data/docs/usage/taskrouter.rst +226 -0
  30. data/docs/usage/token-generation.rst +19 -4
  31. data/docs/usage/transcriptions.rst +3 -2
  32. data/docs/usage/twiml.rst +7 -7
  33. data/docs/usage/validation.rst +39 -3
  34. data/examples/examples.rb +44 -20
  35. data/examples/print-call-log.rb +1 -1
  36. data/lib/rack/twilio_webhook_authentication.rb +47 -0
  37. data/lib/twilio-ruby/rest/accounts.rb +2 -1
  38. data/lib/twilio-ruby/rest/addresses/dependent_phone_numbers.rb +6 -0
  39. data/lib/twilio-ruby/rest/addresses.rb +12 -0
  40. data/lib/twilio-ruby/rest/base_client.rb +127 -0
  41. data/lib/twilio-ruby/rest/call_feedback.rb +28 -0
  42. data/lib/twilio-ruby/rest/call_feedback_summary.rb +13 -0
  43. data/lib/twilio-ruby/rest/calls.rb +10 -5
  44. data/lib/twilio-ruby/rest/client.rb +44 -109
  45. data/lib/twilio-ruby/rest/conferences/participants.rb +2 -2
  46. data/lib/twilio-ruby/rest/incoming_phone_numbers.rb +1 -1
  47. data/lib/twilio-ruby/rest/instance_resource.rb +2 -16
  48. data/lib/twilio-ruby/rest/list_resource.rb +20 -30
  49. data/lib/twilio-ruby/rest/lookups/phone_numbers.rb +17 -0
  50. data/lib/twilio-ruby/rest/lookups_client.rb +99 -0
  51. data/lib/twilio-ruby/rest/messages.rb +5 -0
  52. data/lib/twilio-ruby/rest/next_gen_list_resource.rb +36 -0
  53. data/lib/twilio-ruby/rest/outgoing_caller_ids.rb +1 -1
  54. data/lib/twilio-ruby/rest/queues/members.rb +1 -1
  55. data/lib/twilio-ruby/rest/sip.rb +1 -3
  56. data/lib/twilio-ruby/rest/sms/messages.rb +23 -0
  57. data/lib/twilio-ruby/rest/task_router/activities.rb +8 -0
  58. data/lib/twilio-ruby/rest/task_router/events.rb +8 -0
  59. data/lib/twilio-ruby/rest/task_router/reservations.rb +8 -0
  60. data/lib/twilio-ruby/rest/task_router/statistics.rb +26 -0
  61. data/lib/twilio-ruby/rest/task_router/task_queues.rb +17 -0
  62. data/lib/twilio-ruby/rest/task_router/task_queues_statistics.rb +15 -0
  63. data/lib/twilio-ruby/rest/task_router/tasks.rb +15 -0
  64. data/lib/twilio-ruby/rest/task_router/workers.rb +13 -0
  65. data/lib/twilio-ruby/rest/task_router/workers_statistics.rb +8 -0
  66. data/lib/twilio-ruby/rest/task_router/workflow_statistics.rb +7 -0
  67. data/lib/twilio-ruby/rest/task_router/workflows.rb +11 -0
  68. data/lib/twilio-ruby/rest/task_router/workspace_statistics.rb +7 -0
  69. data/lib/twilio-ruby/rest/task_router/workspaces.rb +17 -0
  70. data/lib/twilio-ruby/rest/task_router_client.rb +176 -0
  71. data/lib/twilio-ruby/rest/tokens.rb +7 -0
  72. data/lib/twilio-ruby/rest/usage/records.rb +2 -2
  73. data/lib/twilio-ruby/rest/utils.rb +35 -11
  74. data/lib/twilio-ruby/task_router/capability.rb +87 -0
  75. data/lib/twilio-ruby/task_router.rb +0 -0
  76. data/lib/twilio-ruby/twiml/response.rb +1 -0
  77. data/lib/twilio-ruby/util/capability.rb +10 -7
  78. data/lib/twilio-ruby/util/client_config.rb +29 -0
  79. data/lib/twilio-ruby/util/configuration.rb +7 -0
  80. data/lib/twilio-ruby/util/request_validator.rb +18 -3
  81. data/lib/twilio-ruby/version.rb +1 -1
  82. data/lib/twilio-ruby.rb +48 -0
  83. data/spec/rack/twilio_webhook_authentication_spec.rb +110 -0
  84. data/spec/rest/account_spec.rb +51 -20
  85. data/spec/rest/address_spec.rb +11 -0
  86. data/spec/rest/call_feedback_spec.rb +12 -0
  87. data/spec/rest/call_feedback_summary_spec.rb +9 -0
  88. data/spec/rest/call_spec.rb +8 -4
  89. data/spec/rest/client_spec.rb +209 -51
  90. data/spec/rest/conference_spec.rb +4 -2
  91. data/spec/rest/instance_resource_spec.rb +4 -4
  92. data/spec/rest/lookups/phone_number_spec.rb +8 -0
  93. data/spec/rest/message_spec.rb +2 -2
  94. data/spec/rest/numbers_spec.rb +25 -13
  95. data/spec/rest/queue_spec.rb +4 -2
  96. data/spec/rest/recording_spec.rb +4 -2
  97. data/spec/rest/sms/message_spec.rb +37 -0
  98. data/spec/rest/sms/messages_spec.rb +31 -0
  99. data/spec/rest/task_router/reservation_spec.rb +9 -0
  100. data/spec/rest/task_router/task_queue_spec.rb +9 -0
  101. data/spec/rest/token_spec.rb +7 -0
  102. data/spec/rest/utils_spec.rb +45 -0
  103. data/spec/spec_helper.rb +12 -3
  104. data/spec/support/fakeweb.rb +2 -0
  105. data/spec/task_router_spec.rb +114 -0
  106. data/spec/twilio_spec.rb +15 -0
  107. data/spec/util/capability_spec.rb +167 -118
  108. data/spec/util/client_config_spec.rb +21 -0
  109. data/spec/util/configuration_spec.rb +15 -0
  110. data/spec/util/request_validator_spec.rb +31 -3
  111. data/spec/util/url_encode_spec.rb +2 -2
  112. data/twilio-ruby.gemspec +28 -27
  113. metadata +93 -71
  114. 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,8 @@
1
+ module Twilio
2
+ module REST
3
+ module TaskRouter
4
+ class WorkersStatistics < Twilio::REST::InstanceResource; end
5
+ class WorkerStatistics < InstanceResource; end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module Twilio
2
+ module REST
3
+ module TaskRouter
4
+ class WorkflowStatistics < InstanceResource; end
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module Twilio
2
+ module REST
3
+ module TaskRouter
4
+ class Workflows < Twilio::REST::NextGenListResource; end
5
+
6
+ class Workflow < InstanceResource
7
+ include Twilio::REST::TaskRouter::Statistics
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ module Twilio
2
+ module REST
3
+ module TaskRouter
4
+ class WorkspaceStatistics < InstanceResource; end
5
+ end
6
+ end
7
+ 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
@@ -0,0 +1,7 @@
1
+ module Twilio
2
+ module REST
3
+ class Tokens < ListResource; end
4
+
5
+ class Token < InstanceResource; end
6
+ end
7
+ 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, :yesterday,
6
- :this_month, :last_month]
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
- Hash[*something.to_a.map! {|a| [twilify(a[0]).to_sym, a[1]]}.flatten(1)]
8
- else
9
- something.to_s.split('_').map! do |s|
10
- [s[0,1].capitalize, s[1..-1]].join
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
- Hash[*something.to_a.map! {|pair| [detwilify(pair[0]).to_sym, pair[1]]}.flatten]
18
- else
19
- something.to_s.gsub(/[A-Z][a-z]*/) {|s| "_#{s.downcase}"}.gsub(/^_/, '')
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
@@ -3,6 +3,7 @@ module Twilio
3
3
  class Response
4
4
 
5
5
  attr_reader :text
6
+ alias_method :to_xml , :text
6
7
 
7
8
  def initialize(&block)
8
9
  xml = Builder::XmlMarkup.new
@@ -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!({'clientName' => @client_name}) if @client_name
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
@@ -0,0 +1,7 @@
1
+ module Twilio
2
+ module Util
3
+ class Configuration
4
+ attr_accessor :account_sid, :auth_token
5
+ end
6
+ end
7
+ 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 == signature
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
@@ -1,3 +1,3 @@
1
1
  module Twilio
2
- VERSION = '3.11.5'
2
+ VERSION = '4.0.0'
3
3
  end