class Spaceship::Portal::Certificate

Represents a certificate from the Apple Developer Portal.

This can either be a code signing identity or a push profile

Constants

APPLE_CERTIFICATE_TYPE_IDS
CERTIFICATE_TYPE_IDS
IOS_CERTIFICATE_TYPE_IDS
MAC_CERTIFICATE_TYPE_IDS
OLDER_IOS_CERTIFICATE_TYPES

Attributes

can_download[RW]

@return (Bool) Whether or not the certificate can be downloaded

created[RW]

@return (Date) The date and time when the certificate was created @example

2015-04-01 21:24:00 UTC
expires[RW]

@return (Date) The date and time when the certificate will expire @example

2016-04-01 21:24:00 UTC
id[RW]

@return (String) The ID given from the developer portal. You'll probably not need it. @example

"P577TH3PAA"
name[RW]

@return (String) The name of the certificate @example Company

"SunApps GmbH"

@example Push Profile

"Apple Push Services"
owner_id[RW]

@return (String) The ID of the owner, that can be used to

fetch more information

@example

"75B83SPLAA"
owner_name[RW]

@return (String) The name of the owner

@example Code Signing Identity (usually the company name)

"SunApps Gmbh"

@example Push Certificate (the bundle identifier)

"tools.fastlane.app"
owner_type[RW]

@return (String) The owner type that defines if it's a push profile

or a code signing identity

@example Code Signing Identity

"team"

@example Push Certificate

"bundle"
status[RW]

@return (String) Status of the certificate @example

"Issued"
type_display_id[RW]

Indicates the type of this certificate which is automatically used to determine the class of the certificate. Available values listed in CERTIFICATE_TYPE_IDS @return (String) The type of the certificate @example Production Certificate

"R58UK2EWSO"

@example Development Certificate

"5QPB9NHCEI"

Private Class Methods

all(mac: false) click to toggle source

@param mac [Bool] Fetches Mac certificates if true. (Ignored if called from a subclass) @return (Array) Returns all certificates of this account.

If this is called from a subclass of Certificate, this will
only include certificates matching the current type.
# File spaceship/lib/spaceship/portal/certificate.rb, line 272
def all(mac: false)
  if self == Certificate # are we the base-class?
    type_ids = mac ? MAC_CERTIFICATE_TYPE_IDS : IOS_CERTIFICATE_TYPE_IDS
    type_ids = APPLE_CERTIFICATE_TYPE_IDS.merge(type_ids)
    types = type_ids.keys
    types += OLDER_IOS_CERTIFICATE_TYPES unless mac
  else
    types = [CERTIFICATE_TYPE_IDS.key(self)]
    mac = MAC_CERTIFICATE_TYPE_IDS.values.include?(self)
  end

  client.certificates(types, mac: mac).map do |cert|
    factory(cert)
  end
end
create!(csr: nil, bundle_id: nil) click to toggle source

Generate a new certificate based on a code certificate signing request @param csr (OpenSSL::X509::Request) (required): The certificate signing request to use. Get one using

`create_certificate_signing_request`

@param bundle_id (String) (optional): The app identifier this certificate is for.

This value is only needed if you create a push profile. For normal code signing
certificates, you must only pass a certificate signing request.

@example

# Create a new certificate signing request
csr, pkey = Spaceship::Certificate.create_certificate_signing_request

# Use the signing request to create a new distribution certificate
Spaceship::Certificate::Production.create!(csr: csr)

@return (Certificate): The newly created certificate

# File spaceship/lib/spaceship/portal/certificate.rb, line 309
def create!(csr: nil, bundle_id: nil)
  type = CERTIFICATE_TYPE_IDS.key(self)
  mac = MAC_CERTIFICATE_TYPE_IDS.include?(type)

  # look up the app_id by the bundle_id
  if bundle_id
    app = portal_type.set_client(client).find(bundle_id)
    raise "Could not find app with bundle id '#{bundle_id}'" unless app
    app_id = app.app_id
  end

  # ensure csr is a OpenSSL::X509::Request
  csr = OpenSSL::X509::Request.new(csr) if csr.kind_of?(String)

  # if this succeeds, we need to save the .cer and the private key in keychain access or wherever they go in linux
  response = client.create_certificate!(type, csr.to_pem, app_id, mac)
  # munge the response to make it work for the factory
  response['certificateTypeDisplayId'] = response['certificateType']['certificateTypeDisplayId']
  self.new(response)
end
create_certificate_signing_request() click to toggle source

Create a new code signing request that can be used to generate a new certificate @example

Create a new certificate signing request
csr, pkey = Spaceship.certificate.create_certificate_signing_request

# Use the signing request to create a new distribution certificate
Spaceship.certificate.production.create!(csr: csr)
# File spaceship/lib/spaceship/portal/certificate.rb, line 215
def create_certificate_signing_request
  key = OpenSSL::PKey::RSA.new(2048)
  csr = OpenSSL::X509::Request.new
  csr.version = 0
  csr.subject = OpenSSL::X509::Name.new([
                                          ['CN', 'PEM', OpenSSL::ASN1::UTF8STRING]
                                        ])
  csr.public_key = key.public_key
  csr.sign(key, OpenSSL::Digest::SHA1.new)
  return [csr, key]
end
factory(attrs) click to toggle source

Create a new object based on a hash. This is used to create a new object based on the server response.

# File spaceship/lib/spaceship/portal/certificate.rb, line 229
def factory(attrs)
  # Example:
  # => {"name"=>"iOS Distribution: SunApps GmbH",
  #  "certificateId"=>"XC5PH8DAAA",
  #  "serialNumber"=>"797E732CCE8B7AAA",
  #  "status"=>"Issued",
  #  "statusCode"=>0,
  #  "expirationDate"=>#<DateTime: 2015-11-25T22:45:50+00:00 ((2457352j,81950s,0n),+0s,2299161j)>,
  #  "certificatePlatform"=>"ios",
  #  "certificateType"=>
  #   {"certificateTypeDisplayId"=>"R58UK2EAAA",
  #    "name"=>"iOS Distribution",
  #    "platform"=>"ios",
  #    "permissionType"=>"distribution",
  #    "distributionType"=>"store",
  #    "distributionMethod"=>"app",
  #    "ownerType"=>"team",
  #    "daysOverlap"=>364,
  #    "maxActive"=>2}}

  if attrs['certificateType']
    # On some accounts this is nested, so we need to flatten it
    attrs.merge!(attrs['certificateType'])
    attrs.delete('certificateType')
  end

  # Parse the dates
  # rubocop:disable Style/RescueModifier
  attrs['expirationDate'] = (Time.parse(attrs['expirationDate']) rescue attrs['expirationDate'])
  attrs['dateCreated'] = (Time.parse(attrs['dateCreated']) rescue attrs['dateCreated'])
  # rubocop:enable Style/RescueModifier

  # Here we go
  klass = CERTIFICATE_TYPE_IDS[attrs['certificateTypeDisplayId']]
  klass ||= Certificate
  klass.client = @client
  klass.new(attrs)
end
find(certificate_id, mac: false) click to toggle source

@param mac [Bool] Searches Mac certificates if true @return (Certificate) Find a certificate based on the ID of the certificate.

# File spaceship/lib/spaceship/portal/certificate.rb, line 290
def find(certificate_id, mac: false)
  all(mac: mac).find do |c|
    c.id == certificate_id
  end
end
portal_type() click to toggle source

Default portal class to use when finding by bundle_id @return (Class): The class this type of certificate belongs to

# File spaceship/lib/spaceship/portal/certificate.rb, line 332
def portal_type
  Spaceship::Portal::App
end

Private Instance Methods

download() click to toggle source

@return (OpenSSL::X509::Certificate) Downloads and parses the certificate

# File spaceship/lib/spaceship/portal/certificate.rb, line 345
def download
  OpenSSL::X509::Certificate.new(download_raw)
end
download_raw() click to toggle source

@return (String) Download the raw data of the certificate without parsing

# File spaceship/lib/spaceship/portal/certificate.rb, line 340
def download_raw
  client.download_certificate(id, type_display_id, mac: mac?)
end
is_push?() click to toggle source

@return (Bool): Is this certificate a push profile for apps?

# File spaceship/lib/spaceship/portal/certificate.rb, line 355
def is_push?
  self.kind_of?(PushCertificate)
end
mac?() click to toggle source

@return (Bool) Is this a Mac profile?

# File spaceship/lib/spaceship/portal/certificate.rb, line 360
def mac?
  MAC_CERTIFICATE_TYPE_IDS.include?(type_display_id)
end
revoke!() click to toggle source

Revoke the certificate. You shouldn't use this method probably.

# File spaceship/lib/spaceship/portal/certificate.rb, line 350
def revoke!
  client.revoke_certificate!(id, type_display_id, mac: mac?)
end