class Cert::Runner
Public Instance Methods
Source
# File cert/lib/cert/runner.rb, line 151 def certificate_type return certificate_types.first end
The kind of certificate weโre interested in (for creating)
Source
# File cert/lib/cert/runner.rb, line 156 def certificate_types if Cert.config[:type] case Cert.config[:type].to_sym when :mac_installer_distribution return [Spaceship::ConnectAPI::Certificate::CertificateType::MAC_INSTALLER_DISTRIBUTION] when :developer_id_application return [ Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_APPLICATION_G2, Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_APPLICATION ] when :developer_id_kext return [Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_KEXT] when :developer_id_installer if !Spaceship::ConnectAPI.token.nil? raise "As of 2021-11-09, the App Store Connect API does not allow accessing DEVELOPER_ID_INSTALLER with the API Key. Please file an issue on GitHub if this has changed and needs to be updated" else return [Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_INSTALLER] end else UI.user_error("Unaccepted value for :type - #{Cert.config[:type]}") end end # Check if apple certs (Xcode 11 and later) should be used if Cert.config[:generate_apple_certs] cert_type = Spaceship::ConnectAPI::Certificate::CertificateType::DISTRIBUTION cert_type = Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DISTRIBUTION if Spaceship::ConnectAPI.client.in_house? # Enterprise doesn't use Apple Distribution cert_type = Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPMENT if Cert.config[:development] else case Cert.config[:platform].to_s when 'ios', 'tvos' cert_type = Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DISTRIBUTION cert_type = Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DISTRIBUTION if Spaceship::ConnectAPI.client.in_house? cert_type = Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DEVELOPMENT if Cert.config[:development] when 'macos' cert_type = Spaceship::ConnectAPI::Certificate::CertificateType::MAC_APP_DISTRIBUTION cert_type = Spaceship::ConnectAPI::Certificate::CertificateType::MAC_APP_DEVELOPMENT if Cert.config[:development] end end return [cert_type] end
The kind of certificates weโre interested in (for listing)
Source
# File cert/lib/cert/runner.rb, line 143 def certificates filter = { certificateType: certificate_types.join(",") } return Spaceship::ConnectAPI::Certificate.all(filter: filter) end
All certificates of this type
Source
# File cert/lib/cert/runner.rb, line 200 def create_certificate # Create a new certificate signing request csr, pkey = Spaceship::ConnectAPI::Certificate.create_certificate_signing_request # Use the signing request to create a new (development|distribution) certificate begin certificate = Spaceship::ConnectAPI::Certificate.create( certificate_type: certificate_type, csr_content: csr.to_pem ) rescue => ex type_name = (Cert.config[:development] ? "Development" : "Distribution") if ex.to_s.include?("You already have a current") UI.user_error!("Could not create another #{type_name} certificate, reached the maximum number of available #{type_name} certificates.", show_github_issues: true) elsif ex.to_s.include?("You are not allowed to perform this operation.") && type_name == "Distribution" UI.user_error!("You do not have permission to create this certificate. Only Team Admins can create Distribution certificates\n ๐ See https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/ManagingYourTeam/ManagingYourTeam.html for more information.") end raise ex end # Store all that onto the filesystem request_path = File.expand_path(File.join(Cert.config[:output_path], "#{certificate.id}.certSigningRequest")) File.write(request_path, csr.to_pem) private_key_path = File.expand_path(File.join(Cert.config[:output_path], "#{certificate.id}.p12")) File.write(private_key_path, pkey) cert_path = store_certificate(certificate, Cert.config[:filename]) if Helper.mac? # Import all the things into the Keychain keychain = File.expand_path(Cert.config[:keychain_path]) password = Cert.config[:keychain_password] FastlaneCore::KeychainImporter.import_file(private_key_path, keychain, keychain_password: password, skip_set_partition_list: Cert.config[:skip_set_partition_list]) FastlaneCore::KeychainImporter.import_file(cert_path, keychain, keychain_password: password, skip_set_partition_list: Cert.config[:skip_set_partition_list]) else UI.message("Skipping importing certificates as it would not work on this operating system.") end # Environment variables for the fastlane action ENV["CER_CERTIFICATE_ID"] = certificate.id ENV["CER_FILE_PATH"] = cert_path if Helper.mac? UI.success("Successfully generated #{certificate.id} which was imported to the local machine.") else UI.success("Successfully generated #{certificate.id}") end return cert_path end
Source
# File cert/lib/cert/runner.rb, line 94 def expired_certs certificates.reject(&:valid?) end
Source
# File cert/lib/cert/runner.rb, line 98 def find_existing_cert certificates.each do |certificate| unless certificate.certificate_content next end path = store_certificate(certificate, Cert.config[:filename]) private_key_path = File.expand_path(File.join(Cert.config[:output_path], "#{certificate.id}.p12")) # As keychain is specific to macOS, this will likely fail on non macOS systems. # See also: https://github.com/fastlane/fastlane/pull/14462 keychain = File.expand_path(Cert.config[:keychain_path]) unless Cert.config[:keychain_path].nil? if FastlaneCore::CertChecker.installed?(path, in_keychain: keychain) # This certificate is installed on the local machine ENV["CER_CERTIFICATE_ID"] = certificate.id ENV["CER_FILE_PATH"] = path ENV["CER_KEYCHAIN_PATH"] = keychain UI.success("Found the certificate #{certificate.id} (#{certificate.display_name}) which is installed on the local machine. Using this one.") return path elsif File.exist?(private_key_path) password = Cert.config[:keychain_password] FastlaneCore::KeychainImporter.import_file(private_key_path, keychain, keychain_password: password, skip_set_partition_list: Cert.config[:skip_set_partition_list]) FastlaneCore::KeychainImporter.import_file(path, keychain, keychain_password: password, skip_set_partition_list: Cert.config[:skip_set_partition_list]) ENV["CER_CERTIFICATE_ID"] = certificate.id ENV["CER_FILE_PATH"] = path ENV["CER_KEYCHAIN_PATH"] = keychain UI.success("Found the cached certificate #{certificate.id} (#{certificate.display_name}). Using this one.") return path else UI.error("Certificate #{certificate.id} (#{certificate.display_name}) can't be found on your local computer") end File.delete(path) # as apparently this certificate is pretty useless without a private key end UI.important("Couldn't find an existing certificate... creating a new one") return nil end
Source
# File cert/lib/cert/runner.rb, line 12 def launch run if Helper.mac? UI.message("Verifying the certificate is properly installed locally...") installed = FastlaneCore::CertChecker.installed?(ENV["CER_FILE_PATH"], in_keychain: ENV["CER_KEYCHAIN_PATH"]) UI.user_error!("Could not find the newly generated certificate installed", show_github_issues: true) unless installed UI.success("Successfully installed certificate #{ENV['CER_CERTIFICATE_ID']}") else UI.message("Skipping verifying certificates as it would not work on this operating system.") end return ENV["CER_FILE_PATH"] end
Source
# File cert/lib/cert/runner.rb, line 26 def login if (api_token = Spaceship::ConnectAPI::Token.from(hash: Cert.config[:api_key], filepath: Cert.config[:api_key_path])) UI.message("Creating authorization token for App Store Connect API") Spaceship::ConnectAPI.token = api_token elsif !Spaceship::ConnectAPI.token.nil? UI.message("Using existing authorization token for App Store Connect API") else # Username is now optional since addition of App Store Connect API Key # Force asking for username to prompt user if not already set Cert.config.fetch(:username, force_ask: true) UI.message("Starting login with user '#{Cert.config[:username]}'") Spaceship::ConnectAPI.login(Cert.config[:username], nil, use_portal: true, use_tunes: false) UI.message("Successfully logged in") end end
Source
# File cert/lib/cert/runner.rb, line 66 def revoke_expired_certs! FastlaneCore::PrintTable.print_values(config: Cert.config, hide_keys: [:output_path], title: "Summary for cert #{Fastlane::VERSION}") login to_revoke = expired_certs if to_revoke.empty? UI.success("No expired certificates were found to revoke! ๐") return end revoke_count = 0 to_revoke.each do |certificate| begin UI.message("#{certificate.id} #{certificate.display_name} has expired, revoking...") certificate.delete! revoke_count += 1 rescue => e UI.error("An error occurred while revoking #{certificate.id} #{certificate.display_name}") UI.error("#{e.message}\n#{e.backtrace.join("\n")}") if FastlaneCore::Globals.verbose? end end UI.success("#{revoke_count} expired certificate#{'s' if revoke_count != 1} #{revoke_count == 1 ? 'has' : 'have'} been revoked! ๐") end
Command method for the :revoke_expired sub-command
Source
# File cert/lib/cert/runner.rb, line 43 def run FileUtils.mkdir_p(Cert.config[:output_path]) FastlaneCore::PrintTable.print_values(config: Cert.config, hide_keys: [:output_path], title: "Summary for cert #{Fastlane::VERSION}") login should_create = Cert.config[:force] unless should_create cert_path = find_existing_cert if Helper.mac? should_create = cert_path.nil? end return unless should_create if create_certificate # no certificate here, creating a new one return # success else UI.user_error!("Something went wrong when trying to create a new certificate...") end end
Source
# File cert/lib/cert/runner.rb, line 253 def store_certificate(certificate, filename = nil) cert_name = filename ? filename : certificate.id cert_name = "#{cert_name}.cer" unless File.extname(cert_name) == ".cer" path = File.expand_path(File.join(Cert.config[:output_path], cert_name)) raw_data = Base64.decode64(certificate.certificate_content) File.write(path, raw_data.force_encoding("UTF-8")) return path end