pusher 1.3.2 → 2.0.3

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.
data/lib/pusher/client.rb CHANGED
@@ -1,13 +1,19 @@
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')
@@ -23,46 +29,35 @@ module Pusher
23
29
  end
24
30
 
25
31
  def initialize(options = {})
26
- default_options = {
27
- :scheme => 'http',
28
- :port => 80,
29
- }
32
+ @scheme = "https"
33
+ @port = options[:port] || 443
30
34
 
31
- if options[:use_tls] || options[:encrypted]
32
- default_options[:scheme] = "https"
33
- default_options[:port] = 443
35
+ if options.key?(:encrypted)
36
+ warn "[DEPRECATION] `encrypted` is deprecated and will be removed in the next major version. Use `use_tls` instead."
34
37
  end
35
38
 
36
- merged_options = default_options.merge(options)
37
-
38
- if options.has_key?(:host)
39
- merged_options[:host] = options[:host]
40
- elsif options.has_key?(:cluster)
41
- merged_options[:host] = "api-#{options[:cluster]}.pusher.com"
42
- else
43
- merged_options[:host] = "api.pusherapp.com"
39
+ if options[:use_tls] == false || options[:encrypted] == false
40
+ @scheme = "http"
41
+ @port = options[:port] || 80
44
42
  end
45
43
 
46
- # TODO: Change host name when finalized
47
- merged_options[:notification_host] =
48
- options.fetch(:notification_host, "nativepush-cluster1.pusher.com")
44
+ @app_id = options[:app_id]
45
+ @key = options[:key]
46
+ @secret = options[:secret]
49
47
 
50
- merged_options[:notification_scheme] =
51
- options.fetch(:notification_scheme, "https")
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"
52
51
 
53
- @scheme, @host, @port, @app_id, @key, @secret, @notification_host, @notification_scheme =
54
- merged_options.values_at(
55
- :scheme, :host, :port, :app_id, :key, :secret, :notification_host, :notification_scheme
56
- )
52
+ @encryption_master_key = Base64.strict_decode64(options[:encryption_master_key_base64]) if options[:encryption_master_key_base64]
57
53
 
58
- @http_proxy = nil
59
- self.http_proxy = options[:http_proxy] if options[:http_proxy]
54
+ @http_proxy = options[:http_proxy]
60
55
 
61
56
  # Default timeouts
62
- @connect_timeout = 5
63
- @send_timeout = 5
64
- @receive_timeout = 5
65
- @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
66
61
  end
67
62
 
68
63
  # @private Returns the authentication token for the client
@@ -76,10 +71,10 @@ module Pusher
76
71
  def url(path = nil)
77
72
  raise ConfigurationError, :app_id unless @app_id
78
73
  URI::Generic.build({
79
- :scheme => @scheme,
80
- :host => @host,
81
- :port => @port,
82
- :path => "/apps/#{@app_id}#{path}"
74
+ scheme: @scheme,
75
+ host: @host,
76
+ port: @port,
77
+ path: "/apps/#{@app_id}#{path}"
83
78
  })
84
79
  end
85
80
 
@@ -103,13 +98,12 @@ module Pusher
103
98
  @http_proxy = http_proxy
104
99
  uri = URI.parse(http_proxy)
105
100
  @proxy = {
106
- :scheme => uri.scheme,
107
- :host => uri.host,
108
- :port => uri.port,
109
- :user => uri.user,
110
- :password => uri.password
101
+ scheme: uri.scheme,
102
+ host: uri.host,
103
+ port: uri.port,
104
+ user: uri.user,
105
+ password: uri.password
111
106
  }
112
- @http_proxy
113
107
  end
114
108
 
115
109
  # Configure whether Pusher API calls should be made over SSL
@@ -129,6 +123,8 @@ module Pusher
129
123
  end
130
124
 
131
125
  def cluster=(cluster)
126
+ cluster = DEFAULT_CLUSTER if cluster.nil? || cluster.empty?
127
+
132
128
  @host = "api-#{cluster}.pusher.com"
133
129
  end
134
130
 
@@ -138,6 +134,12 @@ module Pusher
138
134
  @connect_timeout, @send_timeout, @receive_timeout = value, value, value
139
135
  end
140
136
 
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
+
141
143
  ## INTERACT WITH THE API ##
142
144
 
143
145
  def resource(path)
@@ -317,24 +319,6 @@ module Pusher
317
319
  post_async('/batch_events', trigger_batch_params(events.flatten))
318
320
  end
319
321
 
320
- def notification_client
321
- @notification_client ||=
322
- NativeNotification::Client.new(@app_id, @notification_host, @notification_scheme, self)
323
- end
324
-
325
-
326
- # Send a push notification
327
- #
328
- # POST /apps/[app_id]/notifications
329
- #
330
- # @param interests [Array] An array of interests
331
- # @param message [String] Message to send
332
- # @param options [Hash] Additional platform specific options
333
- #
334
- # @return [Hash]
335
- def notify(interests, data = {})
336
- notification_client.notify(interests, data)
337
- end
338
322
 
339
323
  # Generate the expected response for an authentication endpoint.
340
324
  # See http://pusher.com/docs/authenticating_users for details.
@@ -362,14 +346,20 @@ module Pusher
362
346
  #
363
347
  def authenticate(channel_name, socket_id, custom_data = nil)
364
348
  channel_instance = channel(channel_name)
365
- 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
366
356
  end
367
357
 
368
358
  # @private Construct a net/http http client
369
359
  def sync_http_client
370
- @client ||= begin
371
- require 'httpclient'
360
+ require 'httpclient'
372
361
 
362
+ @client ||= begin
373
363
  HTTPClient.new(@http_proxy).tap do |c|
374
364
  c.connect_timeout = @connect_timeout
375
365
  c.send_timeout = @send_timeout
@@ -388,14 +378,14 @@ module Pusher
388
378
  require 'em-http' unless defined?(EventMachine::HttpRequest)
389
379
 
390
380
  connection_opts = {
391
- :connect_timeout => @connect_timeout,
392
- :inactivity_timeout => @receive_timeout,
381
+ connect_timeout: @connect_timeout,
382
+ inactivity_timeout: @receive_timeout,
393
383
  }
394
384
 
395
385
  if defined?(@proxy)
396
386
  proxy_opts = {
397
- :host => @proxy[:host],
398
- :port => @proxy[:port]
387
+ host: @proxy[:host],
388
+ port: @proxy[:port]
399
389
  }
400
390
  if @proxy[:user]
401
391
  proxy_opts[:authorization] = [@proxy[:user], @proxy[:password]]
@@ -411,12 +401,19 @@ module Pusher
411
401
 
412
402
  def trigger_params(channels, event_name, data, params)
413
403
  channels = Array(channels).map(&:to_s)
414
- 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
415
412
 
416
413
  params.merge({
417
414
  name: event_name,
418
415
  channels: channels,
419
- data: encode_data(data),
416
+ data: encoded_data,
420
417
  })
421
418
  end
422
419
 
@@ -424,7 +421,11 @@ module Pusher
424
421
  {
425
422
  batch: events.map do |event|
426
423
  event.dup.tap do |e|
427
- 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
428
429
  end
429
430
  end
430
431
  }
@@ -436,8 +437,37 @@ module Pusher
436
437
  MultiJson.encode(data)
437
438
  end
438
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
+
439
462
  def configured?
440
463
  host && scheme && key && secret && app_id
441
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
442
472
  end
443
473
  end
@@ -1,3 +1,3 @@
1
1
  module Pusher
2
- VERSION = '1.3.2'
2
+ VERSION = '2.0.3'
3
3
  end
data/lib/pusher.rb CHANGED
@@ -27,10 +27,10 @@ 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
35
  def_delegators :default_client, :authentication_token, :url, :cluster
36
36
  def_delegators :default_client, :encrypted=, :url=, :cluster=
@@ -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,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pusher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
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: 2018-10-17 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
@@ -16,14 +16,14 @@ dependencies:
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
@@ -44,142 +44,143 @@ dependencies:
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
144
  - !ruby/object:Gem::Version
145
- version: 1.8.3
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
+ - - "~>"
158
+ - !ruby/object:Gem::Version
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
@@ -192,20 +193,15 @@ 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.11
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,16 +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
- - 2.4.1
10
- - jruby
11
- - rbx-2
12
-
13
- matrix:
14
- allow_failures:
15
- - rvm: jruby
16
- - 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
@@ -1,28 +0,0 @@
1
- require 'rubygems'
2
- require 'pusher'
3
- require 'eventmachine'
4
- require 'em-http-request'
5
-
6
- # To get these values:
7
- # - Go to https://app.pusherapp.com/
8
- # - Click on Choose App.
9
- # - Click on one of your apps
10
- # - Click API Access
11
- Pusher.app_id = 'your_app_id'
12
- Pusher.key = 'your_key'
13
- Pusher.secret = 'your_secret'
14
-
15
-
16
- EM.run {
17
- deferrable = Pusher['test_channel'].trigger_async('my_event', 'hi')
18
-
19
- deferrable.callback { # called on success
20
- puts "Message sent successfully."
21
- EM.stop
22
- }
23
- deferrable.errback { |error| # called on error
24
- puts "Message could not be sent."
25
- puts error
26
- EM.stop
27
- }
28
- }