passifier-rails 0.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.
Files changed (43) hide show
  1. data/Gemfile +15 -0
  2. data/LICENSE.md +22 -0
  3. data/README.md +143 -0
  4. data/Rakefile +48 -0
  5. data/examples/assets/background.png +0 -0
  6. data/examples/assets/background@2x.png +0 -0
  7. data/examples/assets/icon.png +0 -0
  8. data/examples/assets/icon@2x.png +0 -0
  9. data/examples/assets/logo.png +0 -0
  10. data/examples/assets/logo@2x.png +0 -0
  11. data/examples/assets/thumbnail.png +0 -0
  12. data/examples/assets/thumbnail@2x.png +0 -0
  13. data/examples/simple.rb +86 -0
  14. data/lib/passifier.rb +27 -0
  15. data/lib/passifier/archive.rb +52 -0
  16. data/lib/passifier/manifest.rb +39 -0
  17. data/lib/passifier/manifest_signature.rb +33 -0
  18. data/lib/passifier/pass.rb +82 -0
  19. data/lib/passifier/signing.rb +39 -0
  20. data/lib/passifier/spec.rb +31 -0
  21. data/lib/passifier/static_file.rb +24 -0
  22. data/lib/passifier/storage.rb +94 -0
  23. data/lib/passifier/url_source.rb +30 -0
  24. data/test/assets/background.png +0 -0
  25. data/test/assets/background@2x.png +0 -0
  26. data/test/assets/icon.png +0 -0
  27. data/test/assets/icon@2x.png +0 -0
  28. data/test/assets/logo.png +0 -0
  29. data/test/assets/logo@2x.png +0 -0
  30. data/test/assets/thumbnail.png +0 -0
  31. data/test/assets/thumbnail@2x.png +0 -0
  32. data/test/helper.rb +159 -0
  33. data/test/passifier/test_archive.rb +44 -0
  34. data/test/passifier/test_manifest.rb +25 -0
  35. data/test/passifier/test_manifest_signature.rb +13 -0
  36. data/test/passifier/test_pass.rb +45 -0
  37. data/test/passifier/test_signing.rb +47 -0
  38. data/test/passifier/test_spec.rb +20 -0
  39. data/test/passifier/test_static_file.rb +25 -0
  40. data/test/passifier/test_storage.rb +157 -0
  41. data/test/passifier/test_url_source.rb +30 -0
  42. data/test/test_passifier.rb +10 -0
  43. metadata +169 -0
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "rdoc", "~> 3.12"
10
+ gem "bundler"
11
+ gem "jeweler", "~> 1.8.4"
12
+ end
13
+
14
+ gem "rake"
15
+ gem "rubyzip"
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License
2
+
3
+ Copyright (c) Paperless Post, http://www.paperlesspost.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # Passifier
2
+
3
+ Generate Apple Passbook passes in Ruby
4
+
5
+ Passifier does most of the hard work and will more easily allow you to automate generating pkpass files. You simply supply
6
+
7
+ * A Hash of metadata and layout (the contents of pass.json for those experienced)
8
+ * Image URLs and paths
9
+ * The location of your key and certificate .pem files
10
+ * Output path where you'd like the generated .pkpass file
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'passifier'
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ### Metadata and Layout
23
+
24
+ First, supply a bunch of pass information and styling. This will become the file pass.json within the pass archive. More information on pass.json and creating a layout can be found at [developers.apple.com](https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Reference/PassKit_Bundle/Chapters/Introduction.html).
25
+
26
+ ```ruby
27
+
28
+ serial_number = "SO_SERIAL"
29
+
30
+ spec = {
31
+ "formatVersion": 1,
32
+ "passTypeIdentifier": "pass.example.example",
33
+ "teamIdentifier": "METS",
34
+ "relevantDate": "2012-07-30T14:19Z",
35
+ "organizationName": "Example Inc.",
36
+ "serialNumber": serial_number,
37
+ "description": "The example pass from README.md",
38
+ "labelColor": "rgb(122, 16, 38)",
39
+ "backgroundColor": "rgb(227, 227, 227)",
40
+ "foregroundColor": "rgb(110,110,110)",
41
+ "generic": {
42
+ "headerFields": [
43
+ {
44
+ "key": "date",
45
+ "label": "Date",
46
+ "value": "October 30th"
47
+ }
48
+ ],
49
+ "primaryFields": [
50
+ {
51
+ "key": "title",
52
+ "label": "",
53
+ "value": "Passifier!"
54
+ }
55
+ ],
56
+ "secondaryFields": [
57
+ {
58
+ "key": "host",
59
+ "label": "Host",
60
+ "value": "paperlesspost.com",
61
+ }
62
+ ]
63
+ }
64
+ }
65
+ ```
66
+
67
+ ### Images
68
+
69
+ Specify a Hash of images. Notice that you can use either paths or urls here.
70
+
71
+ ```ruby
72
+
73
+ assets = {
74
+ "background.png": "assets/background.png",
75
+ "background@2x.png": "assets/background@2x.png",
76
+ "icon.png": "assets/icon.png",
77
+ "icon@2x.png": "assets/icon@2x.png",
78
+ "logo.png": "http://i.imgur.com/WLUf6.png",
79
+ "logo@2x.png": "http://i.imgur.com/mOpQo.png",
80
+ "thumbnail.png": "assets/thumbnail.png",
81
+ "thumbnail@2x.png": "assets/thumbnail@2x.png"
82
+ }
83
+ ```
84
+
85
+ ### Signing
86
+
87
+ Give Passifier some info about your `.pem` files.
88
+
89
+ To get your certificates and keys in order, follow these steps:
90
+
91
+ 1. Sign in to the iOS Provisioning Portal, add a Pass Type ID, download the certificate
92
+ 2. Add the `.cer` file you're given to your keychain
93
+ 3. Right click on the certificate, export it to `Certificates.p12`, create a secure password when prompted
94
+ 4. `openssl pkcs12 -in Certificates.p12 -clcerts -nokeys -out certificate.pem -passin pass:<THAT_SECRET_PASSWORD>`
95
+ 5. `openssl pkcs12 -in Certificates.p12 -nocerts -out key.pem -passin pass:<THAT_SECRET_PASSWORD> -passout pass:<ANOTHER_SECRET_PASSWORD>`
96
+
97
+ Download the [Worldwide Developer Relations](https://www.apple.com/certificateauthority/)
98
+ certificate and export it as a `.pem` file to include in the signature.
99
+
100
+ ```ruby
101
+ key_pem = "path/to/a/key.pem"
102
+ pass_phrase = "<ANOTHER_SECRET_PASSWORD>"
103
+ cert_pem = "path/to/a/certificate.pem"
104
+ wwdr_pem = "path/to/the/wwdr_certificate.pem"
105
+
106
+ # Create a Signing object
107
+ signing = Passifier::Signing.new(key_pem, pass_phrase, cert_pem, wwdr_pem)
108
+ ```
109
+
110
+ ### Generate!
111
+
112
+ Now it's time to create your pass.
113
+
114
+ ```ruby
115
+ Passifier::Pass.generate("readme.pkpass", serial_number, spec, assets, signing)
116
+ ```
117
+
118
+ Passifier will have created the file `readme.pkpass` for you. When opened in Passbook, that pass looks something like:
119
+
120
+ ![image](http://i.imgur.com/fooaB.jpg)
121
+
122
+ ## Further Reading
123
+
124
+ * Find a similar example with some more explanation [here](http://github.com/paperlesspost/passifier/blob/master/examples/simple.rb)
125
+ * Read a blog post about Passifier [here]()
126
+
127
+ ## Documentation
128
+
129
+ * [rubydoc](http://rubydoc.info/github/paperlesspost/passifier)
130
+
131
+ ## Contributing to Passifier
132
+
133
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
134
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
135
+ * Create an issue in the issue tracker
136
+ * Fork the project.
137
+ * Start a feature/bugfix branch; include the issue number in the branch name.
138
+ * Commit and push until you are happy with your contribution.
139
+ * Make sure to add tests for it. This is important so we don't break it in a future version unintentionally.
140
+
141
+ ## Copyright
142
+
143
+ Copyright © 2012 Paperless Post. See LICENSE.md for details.
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ $LOAD_PATH.unshift 'lib'
17
+ require "passifier"
18
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
19
+ gem.version = Passifier::VERSION
20
+ gem.name = "passifier"
21
+ gem.homepage = "http://github.com/paperlesspost/passifier"
22
+ gem.license = "MIT"
23
+ gem.summary = %Q{Generate Apple Passbook passes in Ruby}
24
+ gem.description = %Q{Generate Apple Passbook passes in Ruby}
25
+ gem.email = "ari.russo@gmail.com"
26
+ gem.authors = ["Ari Russo"]
27
+ # dependencies defined in Gemfile
28
+ end
29
+ Jeweler::RubygemsDotOrgTasks.new
30
+
31
+ require 'rake/testtask'
32
+ Rake::TestTask.new(:test) do |test|
33
+ test.libs << 'lib' << 'test'
34
+ test.pattern = 'test/**/test_*.rb'
35
+ test.verbose = true
36
+ end
37
+
38
+ task :default => :test
39
+
40
+ require 'rdoc/task'
41
+ Rake::RDocTask.new do |rdoc|
42
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
43
+
44
+ rdoc.rdoc_dir = 'rdoc'
45
+ rdoc.title = "blah #{version}"
46
+ rdoc.rdoc_files.include('README*')
47
+ rdoc.rdoc_files.include('lib/**/*.rb')
48
+ end
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.join( File.dirname( __FILE__ ), '../lib')
3
+
4
+ require "passifier"
5
+
6
+ # This is an example that will generate a simple pass file
7
+
8
+ # 1. Pass metadata and layout
9
+ # This is used to generate the pass.json file for the archive.
10
+ # See () for more information about pass.json usage
11
+ #
12
+ serial = "SO_SERIAL"
13
+ spec = {
14
+ "formatVersion" => 1,
15
+ "passTypeIdentifier" => "pass.example.example",
16
+ "teamIdentifier" => "ATEAMID",
17
+ "relevantDate" => "2012-07-30T14:19Z",
18
+ "organizationName" => "Example Inc.",
19
+ "serialNumber" => serial,
20
+ "description" => "this is a pass",
21
+ "labelColor" => "rgb(122, 16, 38)",
22
+ "backgroundColor" => "rgb(227, 227, 227)",
23
+ "foregroundColor" => "rgb(110,110,110)",
24
+ "generic" => {
25
+ "headerFields" => [
26
+ {
27
+ "key" => "date",
28
+ "label" => "Date",
29
+ "value" => "October 30th"
30
+ }
31
+ ],
32
+ "primaryFields" => [
33
+ {
34
+ "key" => "title",
35
+ "label" => "",
36
+ "value" => "Passifier!"
37
+ }
38
+ ],
39
+ "secondaryFields" => [
40
+ {
41
+ "key" => "host",
42
+ "label" => "Host",
43
+ "value" => "dev.paperlesspost.com",
44
+ }
45
+ ]
46
+ }
47
+ }
48
+
49
+ #
50
+ # 2. Image assets
51
+ # notice that you can use either paths or urls here
52
+ #
53
+ images = {
54
+ "background.png" => "assets/background.png",
55
+ "background@2x.png" => "assets/background@2x.png",
56
+ "icon.png" => "assets/icon.png",
57
+ "icon@2x.png" => "assets/icon@2x.png",
58
+ "logo.png" => "http://i.imgur.com/WLUf6.png",
59
+ "logo@2x.png" => "http://i.imgur.com/mOpQo.png",
60
+ "thumbnail.png" => "assets/thumbnail.png",
61
+ "thumbnail@2x.png" => "assets/thumbnail@2x.png"
62
+ }
63
+
64
+ #
65
+ # 3. Signing settings
66
+ # Replace with your own paths/password if you plan on running this example
67
+ #
68
+ key_pem = "../test/assets/signing/key/key.pem"
69
+ pass_phrase = File.read("../test/assets/signing/pass_phrase.txt").strip.lstrip # you can just replace this with a string if you want
70
+ cert_pem = "../test/assets/signing/certificate/certificate.pem"
71
+
72
+ # Create a signing object
73
+ signing = Passifier::Signing.new(key_pem, pass_phrase, cert_pem)
74
+
75
+ #
76
+ #
77
+ # Now, generate the pass!
78
+ #
79
+ #
80
+
81
+ # Create the pass archive
82
+ output_file = "./simple.pkpass"
83
+ Passifier::Pass.generate(output_file, serial, spec, images, signing)
84
+
85
+ # Finished!
86
+ puts "Finished generating the pass archive: #{output_file}"
data/lib/passifier.rb ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # libs
4
+ require "forwardable"
5
+ require "json"
6
+ require "net/http"
7
+ require "zip/zip"
8
+ require "digest/sha1"
9
+
10
+ # modules
11
+ require "passifier/signing"
12
+
13
+ # classes
14
+ require "passifier/archive"
15
+ require "passifier/manifest"
16
+ require "passifier/manifest_signature"
17
+ require "passifier/pass"
18
+ require "passifier/spec"
19
+ require "passifier/static_file"
20
+ require "passifier/storage"
21
+ require "passifier/url_source"
22
+
23
+ module Passifier
24
+
25
+ VERSION = "0.0.3"
26
+
27
+ end
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Passifier
4
+
5
+ # Represents the .pkpass archive file for the pass. Despite the extension, a .pkpass file is actually
6
+ # a zip archive.
7
+ class Archive
8
+
9
+ attr_reader :assets,
10
+ :id,
11
+ :path
12
+
13
+ # @param [String] path The archive path
14
+ # @param [String] id An ID to represent the Archive
15
+ def initialize(path, id, assets)
16
+ @assets = assets
17
+ @path = path
18
+ @id = id
19
+ end
20
+
21
+ # The raw data of this archive file
22
+ # @return [String] The raw data of this archive file
23
+ def data
24
+ File.open(@path, 'rb') {|file| file.read } unless @path.nil?
25
+ end
26
+
27
+ def destroy
28
+ unless @storage.nil?
29
+ @storage.cleanup
30
+ @storage.remove_zip(@path)
31
+ end
32
+ end
33
+
34
+ # Write the zip archive to disk
35
+ # @param [Hash] options The options to store an Archive with.
36
+ # @option opts [String] :scratch_directory The directory to use for temp files while creating the archive.
37
+ # (not to be confused with the archive path)
38
+ def store(options = {})
39
+ scratch_dir = options[:scratch_directory] || "/tmp/passkit/#{@id}"
40
+ @storage = Storage.new(scratch_dir, @assets)
41
+ @storage.store
42
+ @storage.zip(@path)
43
+ @storage.cleanup
44
+ end
45
+ alias_method :save, :store
46
+
47
+ end
48
+
49
+ end
50
+
51
+
52
+
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Passifier
4
+
5
+ class Manifest
6
+
7
+ attr_reader :hash
8
+ alias_method :to_hash, :hash
9
+
10
+ # @param [Array<Passifier::StaticFile, Passifier::UrlSource>] asset_files The asset files to populate the manifest with
11
+ # @param [Passifier::Spec] spec The spec generated from the hash used to initialise a pass
12
+ def initialize(asset_files, spec)
13
+ @asset_files = asset_files
14
+ @spec = spec
15
+ populate_content
16
+ end
17
+
18
+ def filename
19
+ "manifest.json"
20
+ end
21
+
22
+ def content
23
+ to_hash.to_json
24
+ end
25
+
26
+ private
27
+
28
+ # Convert the image files into SHA1 digests for use in the manifest file
29
+ # @return [String] The resulting contents of the manifest file (aka Passifier::Manifest#content)
30
+ def populate_content
31
+ @hash = {}
32
+ @asset_files.each { |file| @hash[file.name] = Digest::SHA1.hexdigest file.content }
33
+ @hash["pass.json"] = Digest::SHA1.hexdigest @spec.to_json
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+