require 'digest' require 'time' module Pushlet class APNSGateway def initialize(o={}) @mode = o[:mode] @pass = o[:p12_pass] @pem = o[:pem] || self.class.p12_to_pem_text(o[:p12], o[:p12_pass]) create_pusher end def feedback feedback = Grocer.feedback( certificate: StringIO.new(@pem), passphrase: @pass, gateway: (@mode == "development" ? gateway_sandbox : gateway_production), port: feedback_port, retries: retries ) failed_delivery_attempts = [] feedback.each do |fda| failed_delivery_attempts << fda end failed_delivery_attempts end def create_pusher @pusher = Grocer.pusher( certificate: StringIO.new(@pem), passphrase: @pass, gateway: (@mode == "development" ? gateway_sandbox : gateway_production), port: port, retries: retries ) end def gateway_sandbox; 'gateway.sandbox.push.apple.com' end def gateway_production; 'gateway.push.apple.com' end def port; 2195 end def feedback_port; 2196 end def retries; 3 end def push(args={}) if args[:identifier] identifier = args[:identifier] else # Seriously Apple, a 4 byte identifier? Really guys? identifier = SecureRandom.random_bytes(4) end payload = {} [:device_token, :alert, :badge, :sound, :expiry, :identifier].each do |a| if a == :expiry payload[a] = args[a] || Time.now + 60*10 else payload[a] = args[a] if args[a] end end notification = Grocer::Notification.new payload @pusher.push(notification) end def self.p12_to_pem_text(p12, p12_pass='') p12_pass = '' if p12_pass.nil? if Running.jruby? tf_p12 = Tempfile.new 'tf_p12' tf_p12.write p12 tf_p12.rewind tf_p12.close tf_pem = Tempfile.new 'tf_pem' tf_pem.close cmd = Escape.shell_command(['openssl', 'pkcs12', '-in', tf_p12.path, '-out', tf_pem.path, '-nodes', '-clcerts', '-password', 'pass:'+p12_pass]).to_s + ' &> /dev/null' begin result = system cmd raise CommandFailError if result.nil? || result == false pem = File.read tf_pem.path ensure tf_pem.unlink tf_p12.unlink end pem else pkcs12 = OpenSSL::PKCS12.new p12, p12_pass pkcs12.certificate.to_s + pkcs12.key.to_s end end end end