diff --git a/lib/passkit.rb b/lib/passkit.rb index 0358c44..08abc40 100644 --- a/lib/passkit.rb +++ b/lib/passkit.rb @@ -18,36 +18,70 @@ class << self def self.configure self.configuration ||= Configuration.new yield(configuration) if block_given? + configuration.validate! end class Configuration attr_accessor :available_passes, :web_service_host, - :certificate_key, - :private_p12_certificate, - :apple_intermediate_certificate, + :p12_password, + :p12_certificate, + :p12_key, + :wwdc_cert, :apple_team_identifier, - :pass_type_identifier + :pass_type_identifier, + :format_version, + :dashboard_username, + :dashboard_password - DEFAULT_AUTHENTICATION = proc do - authenticate_or_request_with_http_basic("Passkit Dashboard. Login required") do |username, password| - username == ENV["PASSKIT_DASHBOARD_USERNAME"] && password == ENV["PASSKIT_DASHBOARD_PASSWORD"] - end - end def authenticate_dashboard_with(&block) @authenticate = block if block - @authenticate || DEFAULT_AUTHENTICATION + @authenticate || proc do + authenticate_or_request_with_http_basic("Passkit Dashboard. Login required") do |username, password| + username == dashboard_username && password == dashboard_password + end + end end def initialize @available_passes = {"Passkit::ExampleStoreCard" => -> {}} - @web_service_host = ENV["PASSKIT_WEB_SERVICE_HOST"] || (raise "Please set PASSKIT_WEB_SERVICE_HOST") - raise("PASSKIT_WEB_SERVICE_HOST must start with https://") unless @web_service_host.start_with?("https://") - @certificate_key = ENV["PASSKIT_CERTIFICATE_KEY"] || (raise "Please set PASSKIT_CERTIFICATE_KEY") - @private_p12_certificate = ENV["PASSKIT_PRIVATE_P12_CERTIFICATE"] || (raise "Please set PASSKIT_PRIVATE_P12_CERTIFICATE") - @apple_intermediate_certificate = ENV["PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE"] || (raise "Please set PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE") - @apple_team_identifier = ENV["PASSKIT_APPLE_TEAM_IDENTIFIER"] || (raise "Please set PASSKIT_APPLE_TEAM_IDENTIFIER") - @pass_type_identifier = ENV["PASSKIT_PASS_TYPE_IDENTIFIER"] || (raise "Please set PASSKIT_PASS_TYPE_IDENTIFIER") + @web_service_host = ENV["PASSKIT_WEB_SERVICE_HOST"] + @p12_password = ENV["PASSKIT_P12_PASSWORD"] || ENV["PASSKIT_CERTIFICATE_KEY"] + @p12_certificate = ENV["PASSKIT_P12_CERTIFICATE"] || ENV["PASSKIT_PRIVATE_P12_CERTIFICATE"] + @p12_key = ENV["PASSKIT_P12_KEY"] + @wwdc_cert = ENV["PASSKIT_WWDC_CERT"] || ENV["PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE"] + @apple_team_identifier = ENV["PASSKIT_APPLE_TEAM_IDENTIFIER"] + @pass_type_identifier = ENV["PASSKIT_PASS_TYPE_IDENTIFIER"] + @format_version = ENV["PASSKIT_FORMAT_VERSION"] || 1 + end + + def validate! + raise "Please set PASSKIT_WEB_SERVICE_HOST" unless web_service_host + raise("PASSKIT_WEB_SERVICE_HOST must start with https://") unless web_service_host.start_with?("https://") + + if wwdc_cert + intermediate_certificate = OpenSSL::X509::Certificate.new(File.read(Rails.root.join(wwdc_cert))) + else + raise "Please set PASSKIT_WWDC_CERT" + end + + raise "Please set PASSKIT_P12_CERTIFICATE" unless p12_certificate + raise "Please set PASSKIT_P12_PASSWORD" unless p12_password + + if p12_key + key = OpenSSL::PKey::RSA.new(File.read(Rails.root.join(p12_key)), p12_password) + cert = OpenSSL::X509::Certificate.new(File.read(Rails.root.join(p12_certificate))) + else + p12_certificate = OpenSSL::PKCS12.new(File.read(Rails.root.join(p12_certificate)), p12_password) + key = p12_certificate.key + cert = p12_certificate.certificate + end + + flag = OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY + OpenSSL::PKCS7.sign(cert, key, 'test', [intermediate_certificate], flag) # If this runs, all good + + raise "Please set PASSKIT_APPLE_TEAM_IDENTIFIER" unless apple_team_identifier + raise "Please set PASSKIT_PASS_TYPE_IDENTIFIER" unless pass_type_identifier end end end diff --git a/lib/passkit/base_pass.rb b/lib/passkit/base_pass.rb index 49789fc..953dbb9 100644 --- a/lib/passkit/base_pass.rb +++ b/lib/passkit/base_pass.rb @@ -5,15 +5,15 @@ def initialize(generator = nil) end def format_version - ENV["PASSKIT_FORMAT_VERSION"] || 1 + Passkit.configuration.format_version end def apple_team_identifier - ENV["PASSKIT_APPLE_TEAM_IDENTIFIER"] || raise(Error.new("Missing environment variable: PASSKIT_APPLE_TEAM_IDENTIFIER")) + Passkit.configuration.apple_team_identifier end def pass_type_identifier - ENV["PASSKIT_PASS_TYPE_IDENTIFIER"] || raise(Error.new("Missing environment variable: PASSKIT_PASS_TYPE_IDENTIFIER")) + Passkit.configuration.pass_type_identifier end def language @@ -40,8 +40,7 @@ def pass_type end def web_service_url - raise Error.new("Missing environment variable: PASSKIT_WEB_SERVICE_HOST") unless ENV["PASSKIT_WEB_SERVICE_HOST"] - "#{ENV["PASSKIT_WEB_SERVICE_HOST"]}/passkit/api" + "#{Passkit.configuration.web_service_host}/passkit/api" end def foreground_color diff --git a/lib/passkit/generator.rb b/lib/passkit/generator.rb index 43efc8c..dd74fe5 100644 --- a/lib/passkit/generator.rb +++ b/lib/passkit/generator.rb @@ -87,19 +87,21 @@ def generate_json_manifest File.write(@manifest_url, manifest.to_json) end - CERTIFICATE = Rails.root.join(ENV["PASSKIT_PRIVATE_P12_CERTIFICATE"]) - INTERMEDIATE_CERTIFICATE = Rails.root.join(ENV["PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE"]) - CERTIFICATE_PASSWORD = ENV["PASSKIT_CERTIFICATE_KEY"] - # :nocov: def sign_manifest - p12_certificate = OpenSSL::PKCS12.new(File.read(CERTIFICATE), CERTIFICATE_PASSWORD) - intermediate_certificate = OpenSSL::X509::Certificate.new(File.read(INTERMEDIATE_CERTIFICATE)) + intermediate_certificate = OpenSSL::X509::Certificate.new(File.read(Rails.root.join(Passkit.configuration.wwdc_cert))) + + if Passkit.configuration.p12_key + key = OpenSSL::PKey::RSA.new(File.read(Rails.root.join(Passkit.configuration.p12_key)), Passkit.configuration.p12_password) + cert = OpenSSL::X509::Certificate.new(File.read(Rails.root.join(Passkit.configuration.p12_certificate))) + else + p12_certificate = OpenSSL::PKCS12.new(File.read(Rails.root.join(Passkit.configuration.p12_certificate)), Passkit.configuration.p12_password) + key = p12_certificate.key + cert = p12_certificate.certificate + end flag = OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY - signed = OpenSSL::PKCS7.sign(p12_certificate.certificate, - p12_certificate.key, File.read(@manifest_url), - [intermediate_certificate], flag) + signed = OpenSSL::PKCS7.sign(cert, key, File.read(@manifest_url), [intermediate_certificate], flag) @signature_url = @temporary_path.join("signature") File.open(@signature_url, "w") { |f| f.syswrite signed.to_der } diff --git a/lib/passkit/url_generator.rb b/lib/passkit/url_generator.rb index 8781160..9c01d21 100644 --- a/lib/passkit/url_generator.rb +++ b/lib/passkit/url_generator.rb @@ -3,7 +3,7 @@ class UrlGenerator include Passkit::Engine.routes.url_helpers def initialize(pass_class, generator = nil) - @url = passes_api_url(host: ENV["PASSKIT_WEB_SERVICE_HOST"], + @url = passes_api_url(host: Passkit.configuration.web_service_host, payload: PayloadGenerator.encrypted(pass_class, generator)) end diff --git a/test/api/v1/test_passes_controller.rb b/test/api/v1/test_passes_controller.rb index 58e835e..36c0913 100644 --- a/test/api/v1/test_passes_controller.rb +++ b/test/api/v1/test_passes_controller.rb @@ -21,15 +21,15 @@ def test_show _pkpass = Passkit::Factory.create_pass(Passkit::ExampleStoreCard) assert_equal 1, Passkit::Pass.count pass = Passkit::Pass.last - get pass_path(pass_type_id: ENV["PASSKIT_PASS_TYPE_IDENTIFIER"], serial_number: pass.serial_number) + get pass_path(pass_type_id: Passkit.configuration.pass_type_identifier, serial_number: pass.serial_number) assert_response :unauthorized - get pass_path(pass_type_id: ENV["PASSKIT_PASS_TYPE_IDENTIFIER"], serial_number: pass.serial_number), + get pass_path(pass_type_id: Passkit.configuration.pass_type_identifier, serial_number: pass.serial_number), headers: {"Authorization" => "ApplePass #{pass.authentication_token}"} assert_response :success - get pass_path(pass_type_id: ENV["PASSKIT_PASS_TYPE_IDENTIFIER"], serial_number: pass.serial_number), + get pass_path(pass_type_id: Passkit.configuration.pass_type_identifier, serial_number: pass.serial_number), headers: {"Authorization" => "ApplePass #{pass.authentication_token}", "If-Modified-Since" => Time.zone.now.httpdate} assert_equal "", response.body diff --git a/test/system/logs_dashboard_test.rb b/test/system/logs_dashboard_test.rb index a4ec0e9..4e08ee5 100644 --- a/test/system/logs_dashboard_test.rb +++ b/test/system/logs_dashboard_test.rb @@ -8,7 +8,7 @@ class LogsDashboardTest < ActionDispatch::SystemTestCase end def authorize - visit "http://#{ENV["PASSKIT_DASHBOARD_USERNAME"]}:#{ENV["PASSKIT_DASHBOARD_PASSWORD"]}@#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}/passkit/dashboard/logs" + visit "http://#{Passkit.configuration.dashboard_username}:#{Passkit.configuration.dashboard_password}@#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}/passkit/dashboard/logs" end test "visiting the logs dashboard" do