pusher 1.3.1 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/pusher/client.rb CHANGED
@@ -1,57 +1,63 @@
1
+ require 'base64'
1
2
  require 'pusher-signature'
2
3
 
3
4
  module Pusher
4
5
  class Client
5
- attr_accessor :scheme, :host, :port, :app_id, :key, :secret, :notification_host, :notification_scheme
6
+ attr_accessor :scheme, :host, :port, :app_id, :key, :secret, :encryption_master_key
6
7
  attr_reader :http_proxy, :proxy
7
8
  attr_writer :connect_timeout, :send_timeout, :receive_timeout,
8
9
  :keep_alive_timeout
9
10
 
10
11
  ## CONFIGURATION ##
12
+ DEFAULT_CONNECT_TIMEOUT = 5
13
+ DEFAULT_SEND_TIMEOUT = 5
14
+ DEFAULT_RECEIVE_TIMEOUT = 5
15
+ DEFAULT_KEEP_ALIVE_TIMEOUT = 30
16
+ DEFAULT_CLUSTER = "mt1"
11
17
 
12
18
  # Loads the configuration from an url in the environment
13
19
  def self.from_env(key = 'PUSHER_URL')
14
20
  url = ENV[key] || raise(ConfigurationError, key)
21
+ from_url(url)
22
+ end
23
+
24
+ # Loads the configuration from a url
25
+ def self.from_url(url)
15
26
  client = new
16
27
  client.url = url
17
28
  client
18
29
  end
19
30
 
20
31
  def initialize(options = {})
21
- default_options = {
22
- :scheme => 'http',
23
- :port => 80,
24
- }
25
- merged_options = default_options.merge(options)
32
+ @scheme = "https"
33
+ @port = options[:port] || 443
26
34
 
27
- if options.has_key?(:host)
28
- merged_options[:host] = options[:host]
29
- elsif options.has_key?(:cluster)
30
- merged_options[:host] = "api-#{options[:cluster]}.pusher.com"
31
- else
32
- merged_options[:host] = "api.pusherapp.com"
35
+ if options.key?(:encrypted)
36
+ warn "[DEPRECATION] `encrypted` is deprecated and will be removed in the next major version. Use `use_tls` instead."
33
37
  end
34
38
 
35
- # TODO: Change host name when finalized
36
- merged_options[:notification_host] =
37
- options.fetch(:notification_host, "nativepush-cluster1.pusher.com")
39
+ if options[:use_tls] == false || options[:encrypted] == false
40
+ @scheme = "http"
41
+ @port = options[:port] || 80
42
+ end
38
43
 
39
- merged_options[:notification_scheme] =
40
- options.fetch(:notification_scheme, "https")
44
+ @app_id = options[:app_id]
45
+ @key = options[:key]
46
+ @secret = options[:secret]
41
47
 
42
- @scheme, @host, @port, @app_id, @key, @secret, @notification_host, @notification_scheme =
43
- merged_options.values_at(
44
- :scheme, :host, :port, :app_id, :key, :secret, :notification_host, :notification_scheme
45
- )
48
+ @host = options[:host]
49
+ @host ||= "api-#{options[:cluster]}.pusher.com" unless options[:cluster].nil? || options[:cluster].empty?
50
+ @host ||= "api-#{DEFAULT_CLUSTER}.pusher.com"
51
+
52
+ @encryption_master_key = Base64.strict_decode64(options[:encryption_master_key_base64]) if options[:encryption_master_key_base64]
46
53
 
47
- @http_proxy = nil
48
- self.http_proxy = options[:http_proxy] if options[:http_proxy]
54
+ @http_proxy = options[:http_proxy]
49
55
 
50
56
  # Default timeouts
51
- @connect_timeout = 5
52
- @send_timeout = 5
53
- @receive_timeout = 5
54
- @keep_alive_timeout = 30
57
+ @connect_timeout = DEFAULT_CONNECT_TIMEOUT
58
+ @send_timeout = DEFAULT_SEND_TIMEOUT
59
+ @receive_timeout = DEFAULT_RECEIVE_TIMEOUT
60
+ @keep_alive_timeout = DEFAULT_KEEP_ALIVE_TIMEOUT
55
61
  end
56
62
 
57
63
  # @private Returns the authentication token for the client
@@ -65,10 +71,10 @@ module Pusher
65
71
  def url(path = nil)
66
72
  raise ConfigurationError, :app_id unless @app_id
67
73
  URI::Generic.build({
68
- :scheme => @scheme,
69
- :host => @host,
70
- :port => @port,
71
- :path => "/apps/#{@app_id}#{path}"
74
+ scheme: @scheme,
75
+ host: @host,
76
+ port: @port,
77
+ path: "/apps/#{@app_id}#{path}"
72
78
  })
73
79
  end
74
80
 
@@ -92,13 +98,12 @@ module Pusher
92
98
  @http_proxy = http_proxy
93
99
  uri = URI.parse(http_proxy)
94
100
  @proxy = {
95
- :scheme => uri.scheme,
96
- :host => uri.host,
97
- :port => uri.port,
98
- :user => uri.user,
99
- :password => uri.password
101
+ scheme: uri.scheme,
102
+ host: uri.host,
103
+ port: uri.port,
104
+ user: uri.user,
105
+ password: uri.password
100
106
  }
101
- @http_proxy
102
107
  end
103
108
 
104
109
  # Configure whether Pusher API calls should be made over SSL
@@ -118,6 +123,8 @@ module Pusher
118
123
  end
119
124
 
120
125
  def cluster=(cluster)
126
+ cluster = DEFAULT_CLUSTER if cluster.nil? || cluster.empty?
127
+
121
128
  @host = "api-#{cluster}.pusher.com"
122
129
  end
123
130
 
@@ -127,7 +134,13 @@ module Pusher
127
134
  @connect_timeout, @send_timeout, @receive_timeout = value, value, value
128
135
  end
129
136
 
130
- ## INTERACE WITH THE API ##
137
+ # Set an encryption_master_key to use with private-encrypted channels from
138
+ # a base64 encoded string.
139
+ def encryption_master_key_base64=(s)
140
+ @encryption_master_key = s ? Base64.strict_decode64(s) : nil
141
+ end
142
+
143
+ ## INTERACT WITH THE API ##
131
144
 
132
145
  def resource(path)
133
146
  Resource.new(self, path)
@@ -306,24 +319,6 @@ module Pusher
306
319
  post_async('/batch_events', trigger_batch_params(events.flatten))
307
320
  end
308
321
 
309
- def notification_client
310
- @notification_client ||=
311
- NativeNotification::Client.new(@app_id, @notification_host, @notification_scheme, self)
312
- end
313
-
314
-
315
- # Send a push notification
316
- #
317
- # POST /apps/[app_id]/notifications
318
- #
319
- # @param interests [Array] An array of interests
320
- # @param message [String] Message to send
321
- # @param options [Hash] Additional platform specific options
322
- #
323
- # @return [Hash]
324
- def notify(interests, data = {})
325
- notification_client.notify(interests, data)
326
- end
327
322
 
328
323
  # Generate the expected response for an authentication endpoint.
329
324
  # See http://pusher.com/docs/authenticating_users for details.
@@ -351,14 +346,20 @@ module Pusher
351
346
  #
352
347
  def authenticate(channel_name, socket_id, custom_data = nil)
353
348
  channel_instance = channel(channel_name)
354
- channel_instance.authenticate(socket_id, custom_data)
349
+ r = channel_instance.authenticate(socket_id, custom_data)
350
+ if channel_name.match(/^private-encrypted-/)
351
+ r[:shared_secret] = Base64.strict_encode64(
352
+ channel_instance.shared_secret(encryption_master_key)
353
+ )
354
+ end
355
+ r
355
356
  end
356
357
 
357
358
  # @private Construct a net/http http client
358
359
  def sync_http_client
359
- @client ||= begin
360
- require 'httpclient'
360
+ require 'httpclient'
361
361
 
362
+ @client ||= begin
362
363
  HTTPClient.new(@http_proxy).tap do |c|
363
364
  c.connect_timeout = @connect_timeout
364
365
  c.send_timeout = @send_timeout
@@ -377,14 +378,14 @@ module Pusher
377
378
  require 'em-http' unless defined?(EventMachine::HttpRequest)
378
379
 
379
380
  connection_opts = {
380
- :connect_timeout => @connect_timeout,
381
- :inactivity_timeout => @receive_timeout,
381
+ connect_timeout: @connect_timeout,
382
+ inactivity_timeout: @receive_timeout,
382
383
  }
383
384
 
384
385
  if defined?(@proxy)
385
386
  proxy_opts = {
386
- :host => @proxy[:host],
387
- :port => @proxy[:port]
387
+ host: @proxy[:host],
388
+ port: @proxy[:port]
388
389
  }
389
390
  if @proxy[:user]
390
391
  proxy_opts[:authorization] = [@proxy[:user], @proxy[:password]]
@@ -400,12 +401,19 @@ module Pusher
400
401
 
401
402
  def trigger_params(channels, event_name, data, params)
402
403
  channels = Array(channels).map(&:to_s)
403
- raise Pusher::Error, "Too many channels (#{channels.length}), max 10" if channels.length > 10
404
+ raise Pusher::Error, "Too many channels (#{channels.length}), max 100" if channels.length > 100
405
+
406
+ encoded_data = if channels.any?{ |c| c.match(/^private-encrypted-/) } then
407
+ raise Pusher::Error, "Cannot trigger to multiple channels if any are encrypted" if channels.length > 1
408
+ encrypt(channels[0], encode_data(data))
409
+ else
410
+ encode_data(data)
411
+ end
404
412
 
405
413
  params.merge({
406
414
  name: event_name,
407
415
  channels: channels,
408
- data: encode_data(data),
416
+ data: encoded_data,
409
417
  })
410
418
  end
411
419
 
@@ -413,7 +421,11 @@ module Pusher
413
421
  {
414
422
  batch: events.map do |event|
415
423
  event.dup.tap do |e|
416
- e[:data] = encode_data(e[:data])
424
+ e[:data] = if e[:channel].match(/^private-encrypted-/) then
425
+ encrypt(e[:channel], encode_data(e[:data]))
426
+ else
427
+ encode_data(e[:data])
428
+ end
417
429
  end
418
430
  end
419
431
  }
@@ -425,8 +437,37 @@ module Pusher
425
437
  MultiJson.encode(data)
426
438
  end
427
439
 
440
+ # Encrypts a message with a key derived from the master key and channel
441
+ # name
442
+ def encrypt(channel_name, encoded_data)
443
+ raise ConfigurationError, :encryption_master_key unless @encryption_master_key
444
+
445
+ # Only now load rbnacl, so that people that aren't using it don't need to
446
+ # install libsodium
447
+ require_rbnacl
448
+
449
+ secret_box = RbNaCl::SecretBox.new(
450
+ channel(channel_name).shared_secret(@encryption_master_key)
451
+ )
452
+
453
+ nonce = RbNaCl::Random.random_bytes(secret_box.nonce_bytes)
454
+ ciphertext = secret_box.encrypt(nonce, encoded_data)
455
+
456
+ MultiJson.encode({
457
+ "nonce" => Base64::strict_encode64(nonce),
458
+ "ciphertext" => Base64::strict_encode64(ciphertext),
459
+ })
460
+ end
461
+
428
462
  def configured?
429
463
  host && scheme && key && secret && app_id
430
464
  end
465
+
466
+ def require_rbnacl
467
+ require 'rbnacl'
468
+ rescue LoadError => e
469
+ $stderr.puts "You don't have rbnacl installed in your application. Please add it to your Gemfile and run bundle install"
470
+ raise e
471
+ end
431
472
  end
432
473
  end
@@ -94,6 +94,8 @@ module Pusher
94
94
  raise Error, "404 Not found (#{@uri.path})"
95
95
  when 407
96
96
  raise Error, "Proxy Authentication Required"
97
+ when 413
98
+ raise Error, "Payload Too Large > 10KB"
97
99
  else
98
100
  raise Error, "Unknown error (status code #{status_code}): #{body}"
99
101
  end
@@ -1,3 +1,3 @@
1
1
  module Pusher
2
- VERSION = '1.3.1'
2
+ VERSION = '2.0.3'
3
3
  end
data/lib/pusher.rb CHANGED
@@ -27,12 +27,12 @@ module Pusher
27
27
  class << self
28
28
  extend Forwardable
29
29
 
30
- def_delegators :default_client, :scheme, :host, :port, :app_id, :key, :secret, :http_proxy
31
- def_delegators :default_client, :notification_host, :notification_scheme
32
- def_delegators :default_client, :scheme=, :host=, :port=, :app_id=, :key=, :secret=, :http_proxy=
33
- def_delegators :default_client, :notification_host=, :notification_scheme=
30
+ def_delegators :default_client, :scheme, :host, :port, :app_id, :key,
31
+ :secret, :http_proxy, :encryption_master_key_base64
32
+ def_delegators :default_client, :scheme=, :host=, :port=, :app_id=, :key=,
33
+ :secret=, :http_proxy=, :encryption_master_key_base64=
34
34
 
35
- def_delegators :default_client, :authentication_token, :url
35
+ def_delegators :default_client, :authentication_token, :url, :cluster
36
36
  def_delegators :default_client, :encrypted=, :url=, :cluster=
37
37
  def_delegators :default_client, :timeout=, :connect_timeout=, :send_timeout=, :receive_timeout=, :keep_alive_timeout=
38
38
 
@@ -66,4 +66,3 @@ require 'pusher/channel'
66
66
  require 'pusher/request'
67
67
  require 'pusher/resource'
68
68
  require 'pusher/webhook'
69
- require 'pusher/native_notification/client'
metadata CHANGED
@@ -1,185 +1,186 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pusher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pusher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-15 00:00:00.000000000 Z
11
+ date: 2022-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '1.15'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '1.15'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pusher-signature
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: 0.1.8
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.1.8
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: httpclient
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '2.7'
47
+ version: '2.8'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '2.7'
54
+ version: '2.8'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.0'
61
+ version: '3.9'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.0'
68
+ version: '3.9'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: webmock
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ! '>='
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '3.9'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ! '>='
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '3.9'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: em-http-request
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 1.1.0
89
+ version: '1.1'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ~>
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 1.1.0
96
+ version: '1.1'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: addressable
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '='
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 2.4.0
103
+ version: '2.7'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '='
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 2.4.0
110
+ version: '2.7'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rake
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - ~>
115
+ - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 10.4.2
117
+ version: '13.0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - ~>
122
+ - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 10.4.2
124
+ version: '13.0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rack
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ~>
129
+ - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 1.6.4
131
+ version: '2.2'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ~>
136
+ - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 1.6.4
138
+ version: '2.2'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: json
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - ~>
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '2.3'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '2.3'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rbnacl
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
144
158
  - !ruby/object:Gem::Version
145
- version: 1.8.3
159
+ version: '7.1'
146
160
  type: :development
147
161
  prerelease: false
148
162
  version_requirements: !ruby/object:Gem::Requirement
149
163
  requirements:
150
- - - ~>
164
+ - - "~>"
151
165
  - !ruby/object:Gem::Version
152
- version: 1.8.3
153
- description: Wrapper for pusher.com REST api
166
+ version: '7.1'
167
+ description: 'Wrapper for Pusher Channels REST api: : https://pusher.com/channels'
154
168
  email:
155
169
  - support@pusher.com
156
170
  executables: []
157
171
  extensions: []
158
172
  extra_rdoc_files: []
159
173
  files:
160
- - .document
161
- - .gemtest
162
- - .gitignore
163
- - .travis.yml
164
174
  - CHANGELOG.md
165
- - Gemfile
166
175
  - LICENSE
167
176
  - README.md
168
- - Rakefile
169
- - examples/async_message.rb
170
177
  - lib/pusher.rb
171
178
  - lib/pusher/channel.rb
172
179
  - lib/pusher/client.rb
173
- - lib/pusher/native_notification/client.rb
174
180
  - lib/pusher/request.rb
175
181
  - lib/pusher/resource.rb
176
182
  - lib/pusher/version.rb
177
183
  - lib/pusher/webhook.rb
178
- - pusher.gemspec
179
- - spec/channel_spec.rb
180
- - spec/client_spec.rb
181
- - spec/spec_helper.rb
182
- - spec/web_hook_spec.rb
183
184
  homepage: http://github.com/pusher/pusher-http-ruby
184
185
  licenses:
185
186
  - MIT
@@ -190,22 +191,17 @@ require_paths:
190
191
  - lib
191
192
  required_ruby_version: !ruby/object:Gem::Requirement
192
193
  requirements:
193
- - - ! '>='
194
+ - - ">="
194
195
  - !ruby/object:Gem::Version
195
- version: '0'
196
+ version: '2.6'
196
197
  required_rubygems_version: !ruby/object:Gem::Requirement
197
198
  requirements:
198
- - - ! '>='
199
+ - - ">="
199
200
  - !ruby/object:Gem::Version
200
201
  version: '0'
201
202
  requirements: []
202
- rubyforge_project:
203
- rubygems_version: 2.6.10
203
+ rubygems_version: 3.1.2
204
204
  signing_key:
205
205
  specification_version: 4
206
- summary: Pusher API client
207
- test_files:
208
- - spec/channel_spec.rb
209
- - spec/client_spec.rb
210
- - spec/spec_helper.rb
211
- - spec/web_hook_spec.rb
206
+ summary: Pusher Channels API client
207
+ test_files: []
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
data/.gemtest DELETED
File without changes
data/.gitignore DELETED
@@ -1,24 +0,0 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
- .yardoc
21
- Gemfile.lock
22
-
23
- ## PROJECT::SPECIFIC
24
- .bundle
data/.travis.yml DELETED
@@ -1,15 +0,0 @@
1
- language: ruby
2
- sudo: false
3
- rvm:
4
- - 1.9.3
5
- - 2.0
6
- - 2.1
7
- - 2.2
8
- - 2.3.0
9
- - jruby
10
- - rbx-2
11
-
12
- matrix:
13
- allow_failures:
14
- - rvm: jruby
15
- - rvm: rbx-2
data/Gemfile DELETED
@@ -1,2 +0,0 @@
1
- source "https://rubygems.org"
2
- gemspec
data/Rakefile DELETED
@@ -1,11 +0,0 @@
1
- require 'bundler'
2
- Bundler::GemHelper.install_tasks
3
-
4
- require "rspec/core/rake_task"
5
-
6
- RSpec::Core::RakeTask.new(:spec) do |s|
7
- s.pattern = 'spec/**/*.rb'
8
- end
9
-
10
- task :default => :spec
11
- task :test => :spec