From 6daa50e9598de7035db123c7a84790082766ef52 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 19 Sep 2013 08:15:58 -0500 Subject: [PATCH 1/8] pem can be a path to a certificate file or an object that responds to read. --- lib/pushmeup/apns/core.rb | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/pushmeup/apns/core.rb b/lib/pushmeup/apns/core.rb index 5d74778..2478bd5 100644 --- a/lib/pushmeup/apns/core.rb +++ b/lib/pushmeup/apns/core.rb @@ -46,16 +46,23 @@ def self.feedback return apns_feedback end - + protected + def self.pem_data + raise "Your pem file is not set. (APNS.pem = /path/to/cert.pem or object that responds to read)" unless pem + if pem.respond_to? :read + self.pem.read + else + raise "The path to your pem file does not exist!" unless File.exist?(@pem) + File.read(self.pem) + end + end + def self.open_connection - raise "The path to your pem file is not set. (APNS.pem = /path/to/cert.pem)" unless self.pem - raise "The path to your pem file does not exist!" unless File.exist?(self.pem) - context = OpenSSL::SSL::SSLContext.new - context.cert = OpenSSL::X509::Certificate.new(File.read(self.pem)) - context.key = OpenSSL::PKey::RSA.new(File.read(self.pem), self.pass) + context.cert = OpenSSL::X509::Certificate.new(self.pem_data) + context.key = OpenSSL::PKey::RSA.new(self.pem_data, self.pass) sock = TCPSocket.new(self.host, self.port) ssl = OpenSSL::SSL::SSLSocket.new(sock,context) @@ -65,12 +72,9 @@ def self.open_connection end def self.feedback_connection - raise "The path to your pem file is not set. (APNS.pem = /path/to/cert.pem)" unless self.pem - raise "The path to your pem file does not exist!" unless File.exist?(self.pem) - context = OpenSSL::SSL::SSLContext.new - context.cert = OpenSSL::X509::Certificate.new(File.read(self.pem)) - context.key = OpenSSL::PKey::RSA.new(File.read(self.pem), self.pass) + context.cert = OpenSSL::X509::Certificate.new(self.pem_data) + context.key = OpenSSL::PKey::RSA.new(self.pem_data, self.pass) fhost = self.host.gsub('gateway','feedback') puts fhost From 9edd54ebd64456c2eddd2593e38c6079c9f3c6e3 Mon Sep 17 00:00:00 2001 From: Yujing Zheng Date: Mon, 23 Sep 2013 12:09:21 -0500 Subject: [PATCH 2/8] Change pem to pem_data, which require the cert-pem content directly. This change is made to suit the actual store situation happend in database, where all certs are stored as string. --- lib/pushmeup/apns/core.rb | 55 +++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/lib/pushmeup/apns/core.rb b/lib/pushmeup/apns/core.rb index 2478bd5..0eeb849 100644 --- a/lib/pushmeup/apns/core.rb +++ b/lib/pushmeup/apns/core.rb @@ -7,29 +7,31 @@ module APNS @host = 'gateway.sandbox.push.apple.com' @port = 2195 # openssl pkcs12 -in mycert.p12 -out client-cert.pem -nodes -clcerts - @pem = nil # this should be the path of the pem file not the contentes + @pem_data = nil + # this should the content of the pem-cert(String format) + # changed this because all certs are stored in database @pass = nil - + class << self - attr_accessor :host, :pem, :port, :pass + attr_accessor :host, :pem_data, :port, :pass end - + def self.send_notification(device_token, message) n = APNS::Notification.new(device_token, message) self.send_notifications([n]) end - + def self.send_notifications(notifications) sock, ssl = self.open_connection - + notifications.each do |n| - ssl.write(n.packaged_notification) - end + ssl.write(n.packaged_notification) + end ssl.close sock.close end - + def self.feedback sock, ssl = self.feedback_connection @@ -47,43 +49,34 @@ def self.feedback return apns_feedback end - protected - - def self.pem_data - raise "Your pem file is not set. (APNS.pem = /path/to/cert.pem or object that responds to read)" unless pem - if pem.respond_to? :read - self.pem.read - else - raise "The path to your pem file does not exist!" unless File.exist?(@pem) - File.read(self.pem) - end - end - - def self.open_connection +protected + def self.build_connection_context + raise "Your don't have valid pem data. (APNS.pem = Certificate.development_pem)" unless pem_data context = OpenSSL::SSL::SSLContext.new context.cert = OpenSSL::X509::Certificate.new(self.pem_data) context.key = OpenSSL::PKey::RSA.new(self.pem_data, self.pass) + context + end - sock = TCPSocket.new(self.host, self.port) - ssl = OpenSSL::SSL::SSLSocket.new(sock,context) + def self.open_connection + context = self.build_connection_context + sock = TCPSocket.new(self.host, self.port) + ssl = OpenSSL::SSL::SSLSocket.new(sock,context) ssl.connect return sock, ssl end - + def self.feedback_connection - context = OpenSSL::SSL::SSLContext.new - context.cert = OpenSSL::X509::Certificate.new(self.pem_data) - context.key = OpenSSL::PKey::RSA.new(self.pem_data, self.pass) - + context = self.build_connection_context fhost = self.host.gsub('gateway','feedback') puts fhost - + sock = TCPSocket.new(fhost, 2196) ssl = OpenSSL::SSL::SSLSocket.new(sock, context) ssl.connect return sock, ssl end - + end From 429e5f91fe626e36c88307e3aa525d6a58af1f9c Mon Sep 17 00:00:00 2001 From: Yujing Zheng Date: Mon, 23 Sep 2013 12:11:53 -0500 Subject: [PATCH 3/8] update readme --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index c48cd3c..fedfa75 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,11 @@ Currently we have only support for ``iOS`` and ``Android`` but we are planning c ## Installation $ gem install pushmeup - + or add to your ``Gemfile`` gem 'pushmeup' - + and install it with $ bundle install @@ -40,13 +40,13 @@ and install it with 3. After you have created your ``pem`` file. Set the host, port and certificate file location on the APNS class. You just need to set this once: - APNS.host = 'gateway.push.apple.com' + APNS.host = 'gateway.push.apple.com' # gateway.sandbox.push.apple.com is default - - APNS.port = 2195 + + APNS.port = 2195 # this is also the default. Shouldn't ever have to set this, but just in case Apple goes crazy, you can. - APNS.pem = '/path/to/pem/file' + APNS.pem_data = "your cert-pem content string" # this is the file you just created APNS.pass = '' @@ -69,9 +69,9 @@ and install it with #### Sending more information along - APNS.send_notification(device_token, :alert => 'Hello iPhone!', :badge => 1, :sound => 'default', + APNS.send_notification(device_token, :alert => 'Hello iPhone!', :badge => 1, :sound => 'default', :other => {:sent => 'with apns gem', :custom_param => "value"}) - + this will result in a payload like this: {"aps":{"alert":"Hello iPhone!","badge":1,"sound":"default"},"sent":"with apns gem", "custom_param":"value"} @@ -81,13 +81,13 @@ this will result in a payload like this: - (void)applicationDidFinishLaunching:(UIApplication *)application { // Register with apple that this app will use push notification ... - + [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)]; - + ... - + } - + - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // Show the device token obtained from apple to the log NSLog("deviceToken: %", deviceToken); @@ -105,7 +105,7 @@ this will result in a payload like this: GCM.key = "123abc456def" # this is the apiKey obtained from here https://code.google.com/apis/console/ - + ### Usage #### Sending a single notification: @@ -136,17 +136,17 @@ for more information on parameters check documentation: [GCM | Android Developer data1 = {:key => "value", :key2 => ["array", "value"]} # must be an hash with all values you want inside you notification - + options1 = {:collapse_key => "placar_score_global", :time_to_live => 3600, :delay_while_idle => false} # options for the notification - + n1 = GCM::Notification.new(destination1, data1, options1) n2 = GCM::Notification.new(destination2, data2) n3 = GCM::Notification.new(destination3, data3, options2) GCM.send_notifications( [n1, n2, n3] ) # In this case, every notification has his own parameters - + for more information on parameters check documentation: [GCM | Android Developers](http://developer.android.com/guide/google/gcm/gcm.html#request) #### Getting your Android device token (regId) @@ -155,7 +155,7 @@ Check this link [GCM: Getting Started](http://developer.android.com/guide/google ### (Optional) You can add multiple keys for GCM -You can use multiple keys to send notifications, to do it just do this changes in the code +You can use multiple keys to send notifications, to do it just do this changes in the code #### Configure From d4a11124a8b1cd504a2985929f1b978317c86414 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 9 Oct 2013 13:19:35 -0500 Subject: [PATCH 4/8] Revert "Change pem to pem_data, which require the cert-pem content directly." This reverts commit 9edd54ebd64456c2eddd2593e38c6079c9f3c6e3. --- lib/pushmeup/apns/core.rb | 55 ++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/lib/pushmeup/apns/core.rb b/lib/pushmeup/apns/core.rb index 0eeb849..2478bd5 100644 --- a/lib/pushmeup/apns/core.rb +++ b/lib/pushmeup/apns/core.rb @@ -7,31 +7,29 @@ module APNS @host = 'gateway.sandbox.push.apple.com' @port = 2195 # openssl pkcs12 -in mycert.p12 -out client-cert.pem -nodes -clcerts - @pem_data = nil - # this should the content of the pem-cert(String format) - # changed this because all certs are stored in database + @pem = nil # this should be the path of the pem file not the contentes @pass = nil - + class << self - attr_accessor :host, :pem_data, :port, :pass + attr_accessor :host, :pem, :port, :pass end - + def self.send_notification(device_token, message) n = APNS::Notification.new(device_token, message) self.send_notifications([n]) end - + def self.send_notifications(notifications) sock, ssl = self.open_connection - + notifications.each do |n| - ssl.write(n.packaged_notification) - end + ssl.write(n.packaged_notification) + end ssl.close sock.close end - + def self.feedback sock, ssl = self.feedback_connection @@ -49,34 +47,43 @@ def self.feedback return apns_feedback end -protected - def self.build_connection_context - raise "Your don't have valid pem data. (APNS.pem = Certificate.development_pem)" unless pem_data + protected + + def self.pem_data + raise "Your pem file is not set. (APNS.pem = /path/to/cert.pem or object that responds to read)" unless pem + if pem.respond_to? :read + self.pem.read + else + raise "The path to your pem file does not exist!" unless File.exist?(@pem) + File.read(self.pem) + end + end + + def self.open_connection context = OpenSSL::SSL::SSLContext.new context.cert = OpenSSL::X509::Certificate.new(self.pem_data) context.key = OpenSSL::PKey::RSA.new(self.pem_data, self.pass) - context - end - def self.open_connection - context = self.build_connection_context - sock = TCPSocket.new(self.host, self.port) - ssl = OpenSSL::SSL::SSLSocket.new(sock,context) + sock = TCPSocket.new(self.host, self.port) + ssl = OpenSSL::SSL::SSLSocket.new(sock,context) ssl.connect return sock, ssl end - + def self.feedback_connection - context = self.build_connection_context + context = OpenSSL::SSL::SSLContext.new + context.cert = OpenSSL::X509::Certificate.new(self.pem_data) + context.key = OpenSSL::PKey::RSA.new(self.pem_data, self.pass) + fhost = self.host.gsub('gateway','feedback') puts fhost - + sock = TCPSocket.new(fhost, 2196) ssl = OpenSSL::SSL::SSLSocket.new(sock, context) ssl.connect return sock, ssl end - + end From bfc689e24186796040c6cff33278bd39ece2315d Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 9 Oct 2013 13:20:06 -0500 Subject: [PATCH 5/8] Revert "update readme" This reverts commit 429e5f91fe626e36c88307e3aa525d6a58af1f9c. --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index fedfa75..c48cd3c 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,11 @@ Currently we have only support for ``iOS`` and ``Android`` but we are planning c ## Installation $ gem install pushmeup - + or add to your ``Gemfile`` gem 'pushmeup' - + and install it with $ bundle install @@ -40,13 +40,13 @@ and install it with 3. After you have created your ``pem`` file. Set the host, port and certificate file location on the APNS class. You just need to set this once: - APNS.host = 'gateway.push.apple.com' + APNS.host = 'gateway.push.apple.com' # gateway.sandbox.push.apple.com is default - - APNS.port = 2195 + + APNS.port = 2195 # this is also the default. Shouldn't ever have to set this, but just in case Apple goes crazy, you can. - APNS.pem_data = "your cert-pem content string" + APNS.pem = '/path/to/pem/file' # this is the file you just created APNS.pass = '' @@ -69,9 +69,9 @@ and install it with #### Sending more information along - APNS.send_notification(device_token, :alert => 'Hello iPhone!', :badge => 1, :sound => 'default', + APNS.send_notification(device_token, :alert => 'Hello iPhone!', :badge => 1, :sound => 'default', :other => {:sent => 'with apns gem', :custom_param => "value"}) - + this will result in a payload like this: {"aps":{"alert":"Hello iPhone!","badge":1,"sound":"default"},"sent":"with apns gem", "custom_param":"value"} @@ -81,13 +81,13 @@ this will result in a payload like this: - (void)applicationDidFinishLaunching:(UIApplication *)application { // Register with apple that this app will use push notification ... - + [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)]; - + ... - + } - + - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // Show the device token obtained from apple to the log NSLog("deviceToken: %", deviceToken); @@ -105,7 +105,7 @@ this will result in a payload like this: GCM.key = "123abc456def" # this is the apiKey obtained from here https://code.google.com/apis/console/ - + ### Usage #### Sending a single notification: @@ -136,17 +136,17 @@ for more information on parameters check documentation: [GCM | Android Developer data1 = {:key => "value", :key2 => ["array", "value"]} # must be an hash with all values you want inside you notification - + options1 = {:collapse_key => "placar_score_global", :time_to_live => 3600, :delay_while_idle => false} # options for the notification - + n1 = GCM::Notification.new(destination1, data1, options1) n2 = GCM::Notification.new(destination2, data2) n3 = GCM::Notification.new(destination3, data3, options2) GCM.send_notifications( [n1, n2, n3] ) # In this case, every notification has his own parameters - + for more information on parameters check documentation: [GCM | Android Developers](http://developer.android.com/guide/google/gcm/gcm.html#request) #### Getting your Android device token (regId) @@ -155,7 +155,7 @@ Check this link [GCM: Getting Started](http://developer.android.com/guide/google ### (Optional) You can add multiple keys for GCM -You can use multiple keys to send notifications, to do it just do this changes in the code +You can use multiple keys to send notifications, to do it just do this changes in the code #### Configure From ea0edca54414c2bad99b97e2f1768e129ed2e416 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 9 Oct 2013 14:56:39 -0500 Subject: [PATCH 6/8] rewind stream after reading --- lib/pushmeup/apns/core.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pushmeup/apns/core.rb b/lib/pushmeup/apns/core.rb index 2478bd5..d6dbbff 100644 --- a/lib/pushmeup/apns/core.rb +++ b/lib/pushmeup/apns/core.rb @@ -52,11 +52,13 @@ def self.feedback def self.pem_data raise "Your pem file is not set. (APNS.pem = /path/to/cert.pem or object that responds to read)" unless pem if pem.respond_to? :read - self.pem.read + data = pem.read + pem.rewind if pem.respond_to(:rewind) else - raise "The path to your pem file does not exist!" unless File.exist?(@pem) - File.read(self.pem) + raise "The path to your pem file does not exist!" unless File.exist?(pem) + data = File.read(pem) end + data end def self.open_connection From 91cf14bbcadc9d132c811624e176e19ebbc65722 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 9 Oct 2013 14:58:45 -0500 Subject: [PATCH 7/8] Document alternative certificate configuration. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c48cd3c..c84ec3c 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,10 @@ and install it with APNS.pass = '' # Just in case your pem need a password + Alternatively, If you don't have the certificate stored in a file, you can pass any object that responds to ``read``. + + APNS.pem = StringIO.new(pem_string) + ### Usage #### Sending a single notification: From 5a4b12301a271b68b6526e7499bd4c7b1b5f7d86 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Fri, 11 Oct 2013 10:50:31 -0500 Subject: [PATCH 8/8] fixed typo --- lib/pushmeup/apns/core.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pushmeup/apns/core.rb b/lib/pushmeup/apns/core.rb index d6dbbff..57016b6 100644 --- a/lib/pushmeup/apns/core.rb +++ b/lib/pushmeup/apns/core.rb @@ -53,7 +53,7 @@ def self.pem_data raise "Your pem file is not set. (APNS.pem = /path/to/cert.pem or object that responds to read)" unless pem if pem.respond_to? :read data = pem.read - pem.rewind if pem.respond_to(:rewind) + pem.rewind if pem.respond_to?(:rewind) else raise "The path to your pem file does not exist!" unless File.exist?(pem) data = File.read(pem)