Class: Spaceship::Portal::Certificate

Inherits:
Spaceship::PortalBase show all
Defined in:
lib/spaceship/portal/certificate.rb

Overview

Represents a certificate from the Apple Developer Portal.

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

Defined Under Namespace

Classes: ApplePay, DeveloperIDApplication, DeveloperIDInstaller, Development, DevelopmentPush, InHouse, MacAppDistribution, MacDevelopment, MacDevelopmentPush, MacInstallerDistribution, MacProductionPush, Passbook, Production, ProductionPush, PushCertificate, VoipPush, WebsitePush

Constant Summary collapse

IOS_CERTIFICATE_TYPE_IDS =
{
  "5QPB9NHCEI" => Development,
  "R58UK2EWSO" => Production,
  "9RQEK7MSXA" => InHouse,
  "LA30L5BJEU" => Certificate,
  "BKLRAVXMGM" => DevelopmentPush,
  "UPV3DW712I" => ProductionPush,
  "Y3B2F3TYSI" => Passbook,
  "3T2ZP62QW8" => WebsitePush,
  "E5D663CMZW" => WebsitePush,
  "4APLUP237T" => ApplePay
}
MAC_CERTIFICATE_TYPE_IDS =
{
  "749Y1QAGU7" => MacDevelopment,
  "HXZEUKP0FP" => MacAppDistribution,
  "2PQI8IDXNH" => MacInstallerDistribution,
  "OYVN2GW35E" => DeveloperIDInstaller,
  "W0EURJRMC5" => DeveloperIDApplication,
  "CDZ7EMXIZ1" => MacProductionPush,
  "HQ4KP3I34R" => MacDevelopmentPush,
  "DIVN2GW3XT" => DeveloperIDApplication
}
CERTIFICATE_TYPE_IDS =
IOS_CERTIFICATE_TYPE_IDS.merge(MAC_CERTIFICATE_TYPE_IDS)

Instance Attribute Summary collapse

Attributes inherited from Base

#client, #raw_data

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Spaceship::PortalBase

client

Methods inherited from Base

attr_accessor, attr_mapping, #attributes, attributes, #initialize, #inspect, mapping_module, method_missing, set_client, #setup, #to_s

Constructor Details

This class inherits a constructor from Spaceship::Base

Instance Attribute Details

#can_downloadBool



70
71
72
# File 'lib/spaceship/portal/certificate.rb', line 70

def can_download
  @can_download
end

#createdDate

Returns The date and time when the certificate was created.

Examples:

2015-04-01 21:24:00 UTC


29
30
31
# File 'lib/spaceship/portal/certificate.rb', line 29

def created
  @created
end

#expiresDate

Returns The date and time when the certificate will expire.

Examples:

2016-04-01 21:24:00 UTC


34
35
36
# File 'lib/spaceship/portal/certificate.rb', line 34

def expires
  @expires
end

#idString

Returns The ID given from the developer portal. You’ll probably not need it.

Examples:

"P577TH3PAA"


12
13
14
# File 'lib/spaceship/portal/certificate.rb', line 12

def id
  @id
end

#nameString

Returns The name of the certificate.

Examples:

Company

"SunApps GmbH"

Push Profile

"com.krausefx.app"


19
20
21
# File 'lib/spaceship/portal/certificate.rb', line 19

def name
  @name
end

#owner_idString

Returns The ID of the owner, that can be used to fetch more information.

Examples:

"75B83SPLAA"


57
58
59
# File 'lib/spaceship/portal/certificate.rb', line 57

def owner_id
  @owner_id
end

#owner_nameString

Returns The name of the owner.

Examples:

Code Signing Identity (usually the company name)

"SunApps Gmbh"

Push Certificate (the name of your App ID)

"Awesome App"


51
52
53
# File 'lib/spaceship/portal/certificate.rb', line 51

def owner_name
  @owner_name
end

#owner_typeString

Returns The owner type that defines if it’s a push profile or a code signing identity.

Examples:

Code Signing Identity

"team"

Push Certificate

"bundle"


43
44
45
# File 'lib/spaceship/portal/certificate.rb', line 43

def owner_type
  @owner_type
end

#statusString

Returns Status of the certificate.

Examples:

"Issued"


24
25
26
# File 'lib/spaceship/portal/certificate.rb', line 24

def status
  @status
end

#type_display_idString

Indicates the type of this certificate which is automatically used to determine the class of the certificate. Available values listed in CERTIFICATE_TYPE_IDS

Examples:

Production Certificate

"R58UK2EWSO"

Development Certificate

"5QPB9NHCEI"


67
68
69
# File 'lib/spaceship/portal/certificate.rb', line 67

def type_display_id
  @type_display_id
end

Class Method Details

.all(mac: false) ⇒ Array



238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/spaceship/portal/certificate.rb', line 238

def all(mac: false)
  if self == Certificate # are we the base-class?
    type_ids = mac ? MAC_CERTIFICATE_TYPE_IDS : IOS_CERTIFICATE_TYPE_IDS
    types = type_ids.keys
  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) ⇒ Device

Generate a new certificate based on a code certificate signing request

Examples:

# 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)


273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/spaceship/portal/certificate.rb', line 273

def create!(csr: nil, bundle_id: nil)
  type = CERTIFICATE_TYPE_IDS.key(self)

  # look up the app_id by the bundle_id
  if bundle_id
    app = Spaceship::App.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)
  # munge the response to make it work for the factory
  response['certificateTypeDisplayId'] = response['certificateType']['certificateTypeDisplayId']
  self.new(response)
end

.create_certificate_signing_requestObject

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

Examples:

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)


181
182
183
184
185
186
187
188
189
190
191
# File 'lib/spaceship/portal/certificate.rb', line 181

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) ⇒ Object

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



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/spaceship/portal/certificate.rb', line 195

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) ⇒ Certificate



254
255
256
257
258
# File 'lib/spaceship/portal/certificate.rb', line 254

def find(certificate_id, mac: false)
  all(mac: mac).find do |c|
    c.id == certificate_id
  end
end

Instance Method Details

#downloadOpenSSL::X509::Certificate



302
303
304
# File 'lib/spaceship/portal/certificate.rb', line 302

def download
  OpenSSL::X509::Certificate.new(download_raw)
end

#download_rawString



297
298
299
# File 'lib/spaceship/portal/certificate.rb', line 297

def download_raw
  client.download_certificate(id, type_display_id, mac: mac?)
end

#is_push?Bool

rubocop:disable Style/PredicateName



313
314
315
# File 'lib/spaceship/portal/certificate.rb', line 313

def is_push?
  self.kind_of? PushCertificate
end

#mac?Bool



319
320
321
# File 'lib/spaceship/portal/certificate.rb', line 319

def mac?
  MAC_CERTIFICATE_TYPE_IDS.include? type_display_id
end

#revoke!Object

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



307
308
309
# File 'lib/spaceship/portal/certificate.rb', line 307

def revoke!
  client.revoke_certificate!(id, type_display_id, mac: mac?)
end