apple-push 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+
2
+ *0.1*
3
+
4
+ * First public release
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010, 2011 Niklas Holmgren, Sutajio
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,45 @@
1
+ ApplePush
2
+ =========
3
+
4
+ ApplePush is a very simple implementation of the APNS (Apple Push Notification
5
+ Service) protocol. It differs from the
6
+ [APNS gem](https://github.com/jpoz/APNS) by being able to push to different
7
+ iOS apps from the same Ruby application.
8
+
9
+ Setup
10
+ -----
11
+
12
+ $ gem install apple-push
13
+
14
+ require 'apple-push'
15
+ ApplePush.host = 'gateway.push.apple.com'
16
+ ApplePush.port = 2195
17
+
18
+ Creating a PEM certificate
19
+ --------------------------
20
+
21
+ In Keychain access export your certificate as a p12. Then run the following command to convert it to a .pem
22
+
23
+ openssl pkcs12 -in cert.p12 -out cert.pem -nodes -clcerts
24
+
25
+ The store the PEM data in your database or in a file.
26
+
27
+ Example usage
28
+ -------------
29
+
30
+ ApplePush.send_notification(pem, device_token, 'Hello, world!')
31
+ ApplePush.send_notification(pem, device_token, :alert => 'Hello, world!', :badge => 1, :sound => 'default')
32
+ ApplePush.send_notification(pem, device_token, :alert => 'Hello, world!', :badge => 1, :sound => 'default', :other => { :foo => 'bar' })
33
+
34
+ The `pem` parameter can either be the path to a .pem file or the PEM data it
35
+ self, retrieved from a database for example. If the PEM certificate is
36
+ encrypted with a password you should pass an array with the pem and the
37
+ password instead of just the pem.
38
+
39
+ The `device_token` can either be binary data, or Base64 encoded.
40
+
41
+ Author
42
+ ------
43
+
44
+ Created by Niklas Holmgren (niklas@sutajio.se) and released under
45
+ the MIT license.
@@ -0,0 +1,11 @@
1
+ require 'rake/testtask'
2
+
3
+ $LOAD_PATH.unshift 'lib'
4
+
5
+ task :default => [:test]
6
+
7
+ task :test do
8
+ Dir.glob('test/**/*_test.rb').each do |file|
9
+ require File.expand_path(file)
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
3
+ VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
4
+ ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
5
+ KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
6
+ ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
7
+ MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
8
+ ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
9
+ b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
10
+ bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
11
+ U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
12
+ A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
13
+ I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
14
+ wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
15
+ AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
16
+ oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
17
+ BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
18
+ dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
19
+ MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
20
+ b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
21
+ dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
22
+ MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
23
+ E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
24
+ MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
25
+ hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
26
+ 95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
27
+ 2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
28
+ -----END CERTIFICATE-----
@@ -0,0 +1,63 @@
1
+ require 'base64'
2
+ require 'openssl'
3
+ require 'socket'
4
+ require 'json'
5
+
6
+ require 'apple-push/version'
7
+ require 'apple-push/notification'
8
+
9
+ module ApplePush
10
+
11
+ @host = 'gateway.sandbox.push.apple.com'
12
+ @port = 2195
13
+
14
+ class<<self
15
+ attr_accessor :host
16
+ attr_accessor :port
17
+ end
18
+
19
+ def self.send_notification(apns_pem, apns_token, message = {})
20
+ connection(apns_pem) do |ssl|
21
+ notification = ApplePush::Notification.new(apns_token, message)
22
+ puts "#{Time.now} [#{host}:#{port}] Device: #{notification.device_token.unpack('H*')} sending #{message.inspect}"
23
+ ssl.write(notification.to_s)
24
+ end
25
+ end
26
+
27
+ protected
28
+
29
+ def self.connection(apns_pem, &block)
30
+ sock = TCPSocket.new(host.to_s, port.to_i)
31
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, security_context(apns_pem))
32
+ ssl.connect
33
+
34
+ yield(ssl)
35
+
36
+ ssl.close
37
+ sock.close
38
+
39
+ return true
40
+ end
41
+
42
+ def self.security_context(apns_pem)
43
+ pem, password = self.pem_and_password(apns_pem)
44
+ context = OpenSSL::SSL::SSLContext.new
45
+ context.cert = OpenSSL::X509::Certificate.new(pem)
46
+ context.key = OpenSSL::PKey::RSA.new(pem, password)
47
+ context.ca_file = File.expand_path(File.join(File.dirname(__FILE__),'../certs/entrust_ssl_ca.cer'))
48
+ context
49
+ end
50
+
51
+ def self.pem_and_password(apns_pem)
52
+ if apns_pem.is_a?(Array)
53
+ return self.read_pem(apns_pem.first), apns_pem.last
54
+ else
55
+ return self.read_pem(apns_pem), nil
56
+ end
57
+ end
58
+
59
+ def self.read_pem(file_or_string)
60
+ File.exist?(file_or_string) ? File.read(file_or_string) : file_or_string
61
+ end
62
+
63
+ end
@@ -0,0 +1,49 @@
1
+ module ApplePush
2
+ class Notification
3
+ attr_accessor :device_token, :alert, :badge, :sound, :other
4
+
5
+ def initialize(device_token, message)
6
+ if device_token
7
+ self.device_token = device_token
8
+ else
9
+ raise "Invalid device token"
10
+ end
11
+ if message.is_a?(Hash)
12
+ self.alert = message[:alert]
13
+ self.badge = message[:badge]
14
+ self.sound = message[:sound]
15
+ self.other = message[:other]
16
+ elsif message.is_a?(String)
17
+ self.alert = message
18
+ else
19
+ raise "Notification message needs to be either a hash or a string"
20
+ end
21
+ end
22
+
23
+ def device_token
24
+ if @device_token =~ /=$/
25
+ Base64.decode64(@device_token)
26
+ else
27
+ @device_token
28
+ end
29
+ end
30
+
31
+ def to_s
32
+ dt = self.device_token
33
+ pl = self.payload
34
+ [0, 0, dt.size, dt, 0, pl.size, pl].pack("ccca*cca*")
35
+ end
36
+
37
+ protected
38
+
39
+ def payload
40
+ aps = {'aps'=> {} }
41
+ aps['aps']['alert'] = self.alert if self.alert
42
+ aps['aps']['badge'] = self.badge if self.badge
43
+ aps['aps']['sound'] = self.sound if self.sound
44
+ aps.merge!(self.other) if self.other
45
+ aps.to_json
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ module ApplePush
2
+ Version = VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path('test/test_helper')
2
+
3
+ class ApplePushTest < Test::Unit::TestCase
4
+
5
+ def test_can_push_notification
6
+ pem = File.read('test/cert.pem')
7
+ device_token = 'gM/RJodgEmAI////WGWMs/QjbFq05pyQ8hCVsTTDeiI='
8
+ assert ApplePush.send_notification(pem, device_token, 'Hello, world!')
9
+ assert ApplePush.send_notification(pem, device_token, :alert => 'Hello, world!', :badge => 1)
10
+ end
11
+
12
+ def test_can_create_security_context_from_file
13
+ assert ApplePush.security_context('test/cert.pem')
14
+ end
15
+
16
+ def test_can_create_security_context_from_string
17
+ assert ApplePush.security_context(File.read('test/cert.pem'))
18
+ end
19
+
20
+ def test_can_create_security_context_from_file_with_password
21
+ assert ApplePush.security_context(['test/cert_secure.pem', '123456'])
22
+ end
23
+
24
+ def test_can_create_security_context_from_string_with_password
25
+ assert ApplePush.security_context([File.read('test/cert_secure.pem'), '123456'])
26
+ end
27
+
28
+ end
Binary file
@@ -0,0 +1,69 @@
1
+ Bag Attributes
2
+ friendlyName: Apple Development IOS Push Services: 9YGP3C6FRF:9YGP3C6FRF
3
+ localKeyID: 72 FA 95 A0 3B AD A0 B7 B8 FF 25 FF 6E 15 4E 06 7C 57 C3 A6
4
+ subject=/UID=com.sutajio.Friend/CN=Apple Development IOS Push Services: 9YGP3C6FRF:9YGP3C6FRF/C=SE
5
+ issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
6
+ -----BEGIN CERTIFICATE-----
7
+ MIIFdjCCBF6gAwIBAgIIYdy07VBp8fIwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV
8
+ BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
9
+ ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
10
+ aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
11
+ HhcNMTEwODE0MTg1NjMwWhcNMTExMTEyMTg1NjMwWjB2MSIwIAYKCZImiZPyLGQB
12
+ AQwSY29tLnN1dGFqaW8uRnJpZW5kMUMwQQYDVQQDDDpBcHBsZSBEZXZlbG9wbWVu
13
+ dCBJT1MgUHVzaCBTZXJ2aWNlczogOVlHUDNDNkZSRjo5WUdQM0M2RlJGMQswCQYD
14
+ VQQGEwJTRTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKB9nU1aCeC4
15
+ SJAX2/WC6bl2VrINAaOmHJt15Z47cbeppSJ9sirnZYP420fUlDCT1LQMR5hw0yT2
16
+ MCRH6cC76jFKMSlt80eQ5ahiVwDACmIc3CuGafcfiNh/F3oJ6Z7esUqU8y2wIQGn
17
+ W4BfSMVlxtUEnW5z3r9GugsFOovBB39GckgvQO9GOrZRuIVQc+8chWvqBxBrKpds
18
+ //vqwAYvTsnIbpSBh80G9Z9z/Ni6KFldaa+uz3ylG86Vh/r4QmCzlHHivC8H1Qmk
19
+ 3OygKx0M9sUVUsu2OuwngCP2S9cN6JcMSiIlp3clk1jOK4aUh4hwc5TOoQAlZXey
20
+ 5/vQ/9I6wxkCAwEAAaOCAeUwggHhMB0GA1UdDgQWBBRy+pWgO62gt7j/Jf9uFU4G
21
+ fFfDpjAJBgNVHRMEAjAAMB8GA1UdIwQYMBaAFIgnFwmpthhgi+zruvZHWcVSVKO3
22
+ MIIBDwYDVR0gBIIBBjCCAQIwgf8GCSqGSIb3Y2QFATCB8TCBwwYIKwYBBQUHAgIw
23
+ gbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh
24
+ c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy
25
+ ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGlj
26
+ eSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjApBggrBgEF
27
+ BQcCARYdaHR0cDovL3d3dy5hcHBsZS5jb20vYXBwbGVjYS8wTQYDVR0fBEYwRDBC
28
+ oECgPoY8aHR0cDovL2RldmVsb3Blci5hcHBsZS5jb20vY2VydGlmaWNhdGlvbmF1
29
+ dGhvcml0eS93d2RyY2EuY3JsMAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEF
30
+ BQcDAjAQBgoqhkiG92NkBgMBBAIFADANBgkqhkiG9w0BAQUFAAOCAQEAsPFrmajA
31
+ pd4c9h63Z4j0BjS9aFdlTvuP1rrZUwQG2vCGfbg9BAv1YQfPGmHqOFDuCbr2Br9y
32
+ K6apMwgzfhO2C94H0uw+CmppUwo4h2zyweZC2BNT13a28Lg8QRnqDG4JdByTCyvp
33
+ Sa4pLwSG4dhZqp6tKB5e9k80x/73oXLQOLWIfhgg0jxxeLP/ZJQbjrO4re8PNOxi
34
+ pFohKnjVB6cxc/GWTkWUkjaZhRzMAcPGCKm7zDzsoHF7si55sc4l5QPLFxMT/BF5
35
+ Ble5Yv70jcJ9uBiQBu6gVO2+SC/8EouCORcKEsE90MNFQWuH0zafiwdw57Eq1SG5
36
+ RyzYEuwYfe5xAA==
37
+ -----END CERTIFICATE-----
38
+ Bag Attributes
39
+ friendlyName: Niklas Holmgren
40
+ localKeyID: 72 FA 95 A0 3B AD A0 B7 B8 FF 25 FF 6E 15 4E 06 7C 57 C3 A6
41
+ Key Attributes: <No Attributes>
42
+ -----BEGIN PRIVATE KEY-----
43
+ MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCgfZ1NWgnguEiQ
44
+ F9v1gum5dlayDQGjphybdeWeO3G3qaUifbIq52WD+NtH1JQwk9S0DEeYcNMk9jAk
45
+ R+nAu+oxSjEpbfNHkOWoYlcAwApiHNwrhmn3H4jYfxd6Ceme3rFKlPMtsCEBp1uA
46
+ X0jFZcbVBJ1uc96/RroLBTqLwQd/RnJIL0DvRjq2UbiFUHPvHIVr6gcQayqXbP/7
47
+ 6sAGL07JyG6UgYfNBvWfc/zYuihZXWmvrs98pRvOlYf6+EJgs5Rx4rwvB9UJpNzs
48
+ oCsdDPbFFVLLtjrsJ4Aj9kvXDeiXDEoiJad3JZNYziuGlIeIcHOUzqEAJWV3suf7
49
+ 0P/SOsMZAgMBAAECggEAeyrsJgkLu6KyTaOB85FcvjDLqCnDMEyzd7urVRxZ0ZIo
50
+ YagFrFeZ2QaLgzzp3b4WZ3dlGuC7qooluDJYesm8mcdOo3T2V94j4m5WRwUa8uEj
51
+ N2QYvsc8xqoC4m3pFTvi5FIbrtyU+CfwWTzHJHdPePvptnLGaBVngj2pCMhDcLDw
52
+ bmcpe6NtE62tYj12ToVKZZ6L85sTZ+cZ3u4nrIghWz0YivJJyXoLncozxfRKq77p
53
+ e9tYcJcidW2FurrfTRRsGB4U1YPULv7c4IKe7i+6T90YBc4230dl61VFQ/mAb2Or
54
+ 26TkSpMjcT74lIJ8Pdte9HgNsAmA5maTPpczx99BgQKBgQDTatn3bxJkIpPbYTug
55
+ RlatQeHigaxuwUIJxz3LIfcaa5QllgTPbM5LP090ocqn8S7U24b3U5FC/CbCgjyV
56
+ SdgZg/rCYhALcOYtJJPZAZuF/G9ZN2fdcsn7yd5RYwcz2/RRZEVH9QIlrQDIvim+
57
+ CTLhndwp8PL2esM1hRuOypuyLQKBgQDCVYmcjZ1gyCIG60ORwXiOH1FjYD+8g37f
58
+ 3HAB6GojAStZMzQs+csv5NDtmp19jnMgHTi4iuL3/U9R/cyvsg8bGDO6gU8KHy7t
59
+ 1x3fmfa2DH03QPah+eISSMWZ0iJKfZZOVh7q7seJLL801Y3CxtON5MA0+NivKV0E
60
+ 5K2chbZkHQKBgQCNr5FuKukHZMj0gEBmlF0odfu9QixeeXQZe4alKRkigrBhVB3b
61
+ KU9DzKUiQ/+993vsOUdFX6L9YmFTf9a8MiX6S6H1PaUFFd+cp2PSTip9bATvpJse
62
+ JPzKmqo8nwJHtgQRvAJWTBPpTf01i4QMELwhyhqvnQQnPXSv3Inwc0ZO7QKBgCLj
63
+ pH8c1aJoi+NeHZVvfKtXaA9FWmwH16FtPBa7mUKLlTLAhJ+GgToqBHCED75Y8sZT
64
+ OLm5BaKsMa9wt2zbtOaSY8caLAyPKKe+tThNtgNdHqXq3dyatkG+GuvQ1CM3hOKv
65
+ h4F6OQyhofpkVL0hYR3acb+Q5aYc8PxN6fVt9B7pAoGAcgWYHNs0LpTlpvQCDOuE
66
+ hEZEU5NdAO1HXB+DYSs31gWVSs1d2j6lkaeyIqaGDSDS06NsS8D5715GXMsqzkGd
67
+ a5q92h76eW9keosF2VtG2llHevghWe73yB2qpoxK8myR2XkMPTRa+L4yS/8BrcWJ
68
+ oSXfBq9svsqxpGadVIkxeng=
69
+ -----END PRIVATE KEY-----
Binary file
@@ -0,0 +1,69 @@
1
+ Bag Attributes
2
+ friendlyName: Apple Development IOS Push Services: 9YGP3C6FRF:9YGP3C6FRF
3
+ localKeyID: 72 FA 95 A0 3B AD A0 B7 B8 FF 25 FF 6E 15 4E 06 7C 57 C3 A6
4
+ subject=/UID=com.sutajio.Friend/CN=Apple Development IOS Push Services: 9YGP3C6FRF:9YGP3C6FRF/C=SE
5
+ issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
6
+ -----BEGIN CERTIFICATE-----
7
+ MIIFdjCCBF6gAwIBAgIIYdy07VBp8fIwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV
8
+ BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
9
+ ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
10
+ aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
11
+ HhcNMTEwODE0MTg1NjMwWhcNMTExMTEyMTg1NjMwWjB2MSIwIAYKCZImiZPyLGQB
12
+ AQwSY29tLnN1dGFqaW8uRnJpZW5kMUMwQQYDVQQDDDpBcHBsZSBEZXZlbG9wbWVu
13
+ dCBJT1MgUHVzaCBTZXJ2aWNlczogOVlHUDNDNkZSRjo5WUdQM0M2RlJGMQswCQYD
14
+ VQQGEwJTRTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKB9nU1aCeC4
15
+ SJAX2/WC6bl2VrINAaOmHJt15Z47cbeppSJ9sirnZYP420fUlDCT1LQMR5hw0yT2
16
+ MCRH6cC76jFKMSlt80eQ5ahiVwDACmIc3CuGafcfiNh/F3oJ6Z7esUqU8y2wIQGn
17
+ W4BfSMVlxtUEnW5z3r9GugsFOovBB39GckgvQO9GOrZRuIVQc+8chWvqBxBrKpds
18
+ //vqwAYvTsnIbpSBh80G9Z9z/Ni6KFldaa+uz3ylG86Vh/r4QmCzlHHivC8H1Qmk
19
+ 3OygKx0M9sUVUsu2OuwngCP2S9cN6JcMSiIlp3clk1jOK4aUh4hwc5TOoQAlZXey
20
+ 5/vQ/9I6wxkCAwEAAaOCAeUwggHhMB0GA1UdDgQWBBRy+pWgO62gt7j/Jf9uFU4G
21
+ fFfDpjAJBgNVHRMEAjAAMB8GA1UdIwQYMBaAFIgnFwmpthhgi+zruvZHWcVSVKO3
22
+ MIIBDwYDVR0gBIIBBjCCAQIwgf8GCSqGSIb3Y2QFATCB8TCBwwYIKwYBBQUHAgIw
23
+ gbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh
24
+ c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy
25
+ ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGlj
26
+ eSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjApBggrBgEF
27
+ BQcCARYdaHR0cDovL3d3dy5hcHBsZS5jb20vYXBwbGVjYS8wTQYDVR0fBEYwRDBC
28
+ oECgPoY8aHR0cDovL2RldmVsb3Blci5hcHBsZS5jb20vY2VydGlmaWNhdGlvbmF1
29
+ dGhvcml0eS93d2RyY2EuY3JsMAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEF
30
+ BQcDAjAQBgoqhkiG92NkBgMBBAIFADANBgkqhkiG9w0BAQUFAAOCAQEAsPFrmajA
31
+ pd4c9h63Z4j0BjS9aFdlTvuP1rrZUwQG2vCGfbg9BAv1YQfPGmHqOFDuCbr2Br9y
32
+ K6apMwgzfhO2C94H0uw+CmppUwo4h2zyweZC2BNT13a28Lg8QRnqDG4JdByTCyvp
33
+ Sa4pLwSG4dhZqp6tKB5e9k80x/73oXLQOLWIfhgg0jxxeLP/ZJQbjrO4re8PNOxi
34
+ pFohKnjVB6cxc/GWTkWUkjaZhRzMAcPGCKm7zDzsoHF7si55sc4l5QPLFxMT/BF5
35
+ Ble5Yv70jcJ9uBiQBu6gVO2+SC/8EouCORcKEsE90MNFQWuH0zafiwdw57Eq1SG5
36
+ RyzYEuwYfe5xAA==
37
+ -----END CERTIFICATE-----
38
+ Bag Attributes
39
+ friendlyName: Niklas Holmgren
40
+ localKeyID: 72 FA 95 A0 3B AD A0 B7 B8 FF 25 FF 6E 15 4E 06 7C 57 C3 A6
41
+ Key Attributes: <No Attributes>
42
+ -----BEGIN PRIVATE KEY-----
43
+ MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCgfZ1NWgnguEiQ
44
+ F9v1gum5dlayDQGjphybdeWeO3G3qaUifbIq52WD+NtH1JQwk9S0DEeYcNMk9jAk
45
+ R+nAu+oxSjEpbfNHkOWoYlcAwApiHNwrhmn3H4jYfxd6Ceme3rFKlPMtsCEBp1uA
46
+ X0jFZcbVBJ1uc96/RroLBTqLwQd/RnJIL0DvRjq2UbiFUHPvHIVr6gcQayqXbP/7
47
+ 6sAGL07JyG6UgYfNBvWfc/zYuihZXWmvrs98pRvOlYf6+EJgs5Rx4rwvB9UJpNzs
48
+ oCsdDPbFFVLLtjrsJ4Aj9kvXDeiXDEoiJad3JZNYziuGlIeIcHOUzqEAJWV3suf7
49
+ 0P/SOsMZAgMBAAECggEAeyrsJgkLu6KyTaOB85FcvjDLqCnDMEyzd7urVRxZ0ZIo
50
+ YagFrFeZ2QaLgzzp3b4WZ3dlGuC7qooluDJYesm8mcdOo3T2V94j4m5WRwUa8uEj
51
+ N2QYvsc8xqoC4m3pFTvi5FIbrtyU+CfwWTzHJHdPePvptnLGaBVngj2pCMhDcLDw
52
+ bmcpe6NtE62tYj12ToVKZZ6L85sTZ+cZ3u4nrIghWz0YivJJyXoLncozxfRKq77p
53
+ e9tYcJcidW2FurrfTRRsGB4U1YPULv7c4IKe7i+6T90YBc4230dl61VFQ/mAb2Or
54
+ 26TkSpMjcT74lIJ8Pdte9HgNsAmA5maTPpczx99BgQKBgQDTatn3bxJkIpPbYTug
55
+ RlatQeHigaxuwUIJxz3LIfcaa5QllgTPbM5LP090ocqn8S7U24b3U5FC/CbCgjyV
56
+ SdgZg/rCYhALcOYtJJPZAZuF/G9ZN2fdcsn7yd5RYwcz2/RRZEVH9QIlrQDIvim+
57
+ CTLhndwp8PL2esM1hRuOypuyLQKBgQDCVYmcjZ1gyCIG60ORwXiOH1FjYD+8g37f
58
+ 3HAB6GojAStZMzQs+csv5NDtmp19jnMgHTi4iuL3/U9R/cyvsg8bGDO6gU8KHy7t
59
+ 1x3fmfa2DH03QPah+eISSMWZ0iJKfZZOVh7q7seJLL801Y3CxtON5MA0+NivKV0E
60
+ 5K2chbZkHQKBgQCNr5FuKukHZMj0gEBmlF0odfu9QixeeXQZe4alKRkigrBhVB3b
61
+ KU9DzKUiQ/+993vsOUdFX6L9YmFTf9a8MiX6S6H1PaUFFd+cp2PSTip9bATvpJse
62
+ JPzKmqo8nwJHtgQRvAJWTBPpTf01i4QMELwhyhqvnQQnPXSv3Inwc0ZO7QKBgCLj
63
+ pH8c1aJoi+NeHZVvfKtXaA9FWmwH16FtPBa7mUKLlTLAhJ+GgToqBHCED75Y8sZT
64
+ OLm5BaKsMa9wt2zbtOaSY8caLAyPKKe+tThNtgNdHqXq3dyatkG+GuvQ1CM3hOKv
65
+ h4F6OQyhofpkVL0hYR3acb+Q5aYc8PxN6fVt9B7pAoGAcgWYHNs0LpTlpvQCDOuE
66
+ hEZEU5NdAO1HXB+DYSs31gWVSs1d2j6lkaeyIqaGDSDS06NsS8D5715GXMsqzkGd
67
+ a5q92h76eW9keosF2VtG2llHevghWe73yB2qpoxK8myR2XkMPTRa+L4yS/8BrcWJ
68
+ oSXfBq9svsqxpGadVIkxeng=
69
+ -----END PRIVATE KEY-----
@@ -0,0 +1,45 @@
1
+ require File.expand_path('test/test_helper')
2
+
3
+ class NotificationTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @notification = ApplePush::Notification.new('FkjWc8HztEiEblJ7g1n8AKw8kvyCtkQKc10tmoo2Tak=',
7
+ :alert => 'Hello, world!', :badge => 1, :sound => 'default', :other => { :foo => 'bar' })
8
+ end
9
+
10
+ def test_raises_errors
11
+ assert_raises RuntimeError do
12
+ ApplePush::Notification.new(nil, 'Hello, world!')
13
+ end
14
+ assert_raises RuntimeError do
15
+ ApplePush::Notification.new('...', nil)
16
+ end
17
+ end
18
+
19
+ def test_can_create_notification_with_only_an_alert_string
20
+ assert_equal 'Hello, world!', ApplePush::Notification.new('...', 'Hello, world!').alert
21
+ end
22
+
23
+ def test_can_handle_base64_encoded_device_token
24
+ @notification.device_token = 'FkjWc8HztEiEblJ7g1n8AKw8kvyCtkQKc10tmoo2Tak='
25
+ assert_equal Base64.decode64('FkjWc8HztEiEblJ7g1n8AKw8kvyCtkQKc10tmoo2Tak='), @notification.device_token
26
+ end
27
+
28
+ def test_can_handle_binary_device_token
29
+ @notification.device_token = Base64.decode64('FkjWc8HztEiEblJ7g1n8AKw8kvyCtkQKc10tmoo2Tak=')
30
+ assert_equal Base64.decode64('FkjWc8HztEiEblJ7g1n8AKw8kvyCtkQKc10tmoo2Tak='), @notification.device_token
31
+ end
32
+
33
+ def test_payload
34
+ payload = JSON.parse(@notification.send(:payload))
35
+ assert_equal 'Hello, world!', payload['aps']['alert']
36
+ assert_equal 1, payload['aps']['badge']
37
+ assert_equal 'default', payload['aps']['sound']
38
+ assert_equal 'bar', payload['foo']
39
+ end
40
+
41
+ def test_packaged_notification
42
+ assert_equal "\x00\x00 \x16H\xD6s\xC1\xF3\xB4H\x84nR{\x83Y\xFC\x00\xAC<\x92\xFC\x82\xB6D\ns]-\x9A\x8A6M\xA9\x00I{\"aps\":{\"alert\":\"Hello, world!\",\"badge\":1,\"sound\":\"default\"},\"foo\":\"bar\"}", @notification.to_s
43
+ end
44
+
45
+ end
@@ -0,0 +1,6 @@
1
+
2
+ dir = File.dirname(File.expand_path(__FILE__))
3
+ $LOAD_PATH.unshift dir + '/../lib'
4
+
5
+ require 'test/unit'
6
+ require 'apple-push'
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: apple-push
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Niklas Holmgren
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-09-27 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: json
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">"
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 1
30
+ - 0
31
+ - 0
32
+ version: 1.0.0
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: ApplePush is a very simple implementation of the APNS (Apple Push Notification Service) protocol. It differs from the APNS gem by being able to push to different iOS apps from the same Ruby application.
36
+ email: niklas@sutajio.se
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.md
44
+ files:
45
+ - README.md
46
+ - Rakefile
47
+ - LICENSE
48
+ - CHANGELOG
49
+ - lib/apple-push/notification.rb
50
+ - lib/apple-push/version.rb
51
+ - lib/apple-push.rb
52
+ - test/apple_push_test.rb
53
+ - test/cert.p12
54
+ - test/cert.pem
55
+ - test/cert_secure.p12
56
+ - test/cert_secure.pem
57
+ - test/notification_test.rb
58
+ - test/test_helper.rb
59
+ - certs/entrust_ssl_ca.cer
60
+ has_rdoc: true
61
+ homepage: http://github.com/sutajio/apple-push/
62
+ licenses: []
63
+
64
+ post_install_message:
65
+ rdoc_options:
66
+ - --charset=UTF-8
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project:
88
+ rubygems_version: 1.3.7
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: ApplePush is a very simple implementation of the APNS (Apple Push Notification Service) protocol
92
+ test_files: []
93
+