cert 0.2.1 → 0.3.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1613b46cf5a0b4f57ac5e90ba9b08551c03bb78c
4
- data.tar.gz: 635914b5ce20080fd08c25d8536d4b471a1c59af
3
+ metadata.gz: 760a074d01502ea87e72833b5d0f2f2c222ee237
4
+ data.tar.gz: e4f2bbc5e8615419ea0b75adaffc6d540a372004
5
5
  SHA512:
6
- metadata.gz: 7d5ccf6591453392d977741fc12ff51e4151f7f4b4a35a7d85f7797a46f053714ef308767e811ebd5bad37ef4e406e41f0ee8f7d4389b9f232a405346db35af4
7
- data.tar.gz: ed9086fc6162cf754b612b0e0019be63ebc5b99836f38f123245e6c4577bbb4ea392d263e2b6d5df621736fb1a6eac7408099ccd2f2f4564aa0e91990890fd03
6
+ metadata.gz: a0ed0694a68b3a3c2e1ee8f0466b2acaac80315ca14f8b6b4c34ddc2f1ab5a99bf32b24030475c6b20a7cbf46afd3d6bc6da238ce8e34f8d1ae9c6fa37629d3e
7
+ data.tar.gz: 11c9f32bc56455b8ef79eb06c304adba30f124c20d3a68761c7e791cb0a88540331d0cb9af583eb0940b318cd9e2747dc6599759ce7efd7de926de2af4ae7c10
data/README.md CHANGED
@@ -120,12 +120,6 @@ end
120
120
  This will result in `sigh` always using the correct signing certificate, which is installed on the local machine.
121
121
 
122
122
 
123
- # How does it work?
124
-
125
- - `cert` accesses the ```iOS Dev Center``` to create or download your certificate. See: [developer_center.rb](https://github.com/KrauseFx/cert/blob/master/lib/cert/developer_center.rb).
126
- - The ```.certSigningRequest``` file will be generated in [signing_request.rb](https://github.com/KrauseFx/cert/blob/master/lib/cert/signing_request.rb)
127
-
128
-
129
123
  ## How is my password stored?
130
124
  ```cert``` uses the [password manager](https://github.com/fastlane/CredentialsManager) from `fastlane`. Take a look the [CredentialsManager README](https://github.com/fastlane/CredentialsManager) for more information.
131
125
 
data/bin/cert CHANGED
@@ -31,7 +31,7 @@ class CertApplication
31
31
 
32
32
  c.action do |args, options|
33
33
  Cert.config = FastlaneCore::Configuration.create(Cert::Options.available_options, options.__hash__)
34
- Cert::CertRunner.run
34
+ Cert::CertRunner.new.launch
35
35
  end
36
36
  end
37
37
 
@@ -1,10 +1,99 @@
1
1
  module Cert
2
2
  class CertRunner
3
- def self.run
4
- Cert::DeveloperCenter.new.run
3
+ def launch
4
+ run
5
5
 
6
- installed = Cert::CertChecker.is_installed?ENV["CER_FILE_PATH"]
6
+ installed = FastlaneCore::CertChecker.is_installed?ENV["CER_FILE_PATH"]
7
7
  raise "Could not find the newly generated certificate installed" unless installed
8
8
  end
9
+
10
+ def run
11
+ Helper.log.info "Starting login"
12
+ Spaceship.login(Cert.config[:username], nil)
13
+ Spaceship.select_team
14
+ Helper.log.info "Successfully logged in"
15
+
16
+ if find_existing_cert
17
+ return # success
18
+ else
19
+ if create_certificate # no certificate here, creating a new one
20
+ return # success
21
+ else
22
+ raise "Something went wrong when trying to create a new certificate..."
23
+ end
24
+ end
25
+ end
26
+
27
+ def find_existing_cert
28
+ certificates.each do |certificate|
29
+ path = store_certificate(certificate)
30
+
31
+ if FastlaneCore::CertChecker.is_installed?path
32
+ # This certificate is installed on the local machine
33
+ ENV["CER_CERTIFICATE_ID"] = certificate.id
34
+ ENV["CER_FILE_PATH"] = path
35
+
36
+ Helper.log.info "Found the certificate #{certificate.id} (#{certificate.name}) which is installed on the local machine. Using this one.".green
37
+
38
+ return path
39
+ end
40
+ end
41
+
42
+ Helper.log.info "Couldn't find an existing certificate... creating a new one"
43
+ return nil
44
+ end
45
+
46
+ # All certificates of this type
47
+ def certificates
48
+ certificate_type.all
49
+ end
50
+
51
+ # The kind of certificate we're interested in
52
+ def certificate_type
53
+ cert_type = Spaceship.certificate.production
54
+ cert_type = Spaceship.certificate.development if Cert.config[:development]
55
+ cert_type = Spaceship.certificate.in_house if Spaceship.client.in_house?
56
+
57
+ cert_type
58
+ end
59
+
60
+ def create_certificate
61
+ # Create a new certificate signing request
62
+ csr, pkey = Spaceship.certificate.create_certificate_signing_request
63
+
64
+ # Use the signing request to create a new distribution certificate
65
+ begin
66
+ certificate = certificate_type.create!(csr: csr)
67
+ rescue => ex
68
+ Helper.log.error "Could not create another certificate, reached the maximum number of available certificates.".red
69
+ raise ex
70
+ end
71
+
72
+ # Store all that onto the filesystem
73
+ request_path = File.join(Cert.config[:output_path], 'CertCertificateSigningRequest.certSigningRequest')
74
+ File.write(request_path, csr.to_pem)
75
+ private_key_path = File.join(Cert.config[:output_path], 'private_key.p12')
76
+ File.write(private_key_path, pkey)
77
+ cert_path = store_certificate(certificate)
78
+
79
+ # Import all the things into the Keychain
80
+ KeychainImporter.import_file(private_key_path)
81
+ KeychainImporter.import_file(cert_path)
82
+
83
+ # Environment variables for the fastlane action
84
+ ENV["CER_CERTIFICATE_ID"] = certificate.id
85
+ ENV["CER_FILE_PATH"] = cert_path
86
+
87
+ Helper.log.info "Successfully generated #{certificate.id} which was imported to the local machine.".green
88
+
89
+ return cert_path
90
+ end
91
+
92
+ def store_certificate(certificate)
93
+ path = File.join(Cert.config[:output_path], "#{certificate.id}.cer")
94
+ raw_data = certificate.download_raw
95
+ File.write(path, raw_data)
96
+ return path
97
+ end
9
98
  end
10
- end
99
+ end
data/lib/cert/options.rb CHANGED
@@ -25,6 +25,10 @@ module Cert
25
25
  verify_block: Proc.new do |value|
26
26
  ENV["FASTLANE_TEAM_ID"] = value
27
27
  end),
28
+ FastlaneCore::ConfigItem.new(key: :output_path,
29
+ env_name: "CERT_OUTPUT_PATH",
30
+ description: "The path to a directory in which all certificates and private keys should be stored",
31
+ default_value: "."),
28
32
  FastlaneCore::ConfigItem.new(key: :keychain_path,
29
33
  short_option: "-k",
30
34
  env_name: "CERT_KEYCHAIN_PATH",
@@ -28,7 +28,7 @@ module Cert
28
28
 
29
29
  # Import the private key into the Keychain
30
30
  puts `chmod 600 '#{private_key_path}'` # otherwise we're not allowed to import the private key
31
- KeychainImporter::import_file(private_key_path)
31
+ KeychainImporter.import_file(private_key_path)
32
32
 
33
33
  Helper.log.info "Successfully generated .certSigningRequest at path '#{path}'".green
34
34
  return path
data/lib/cert/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Cert
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0.beta1"
3
3
  end
data/lib/cert.rb CHANGED
@@ -1,12 +1,11 @@
1
1
  require 'cert/version'
2
2
  require 'cert/dependency_checker'
3
- require 'cert/developer_center'
4
3
  require 'cert/cert_runner'
5
- require 'cert/cert_checker'
6
4
  require 'cert/signing_request'
7
5
  require 'cert/keychain_importer'
8
6
 
9
7
  require 'fastlane_core'
8
+ require 'spaceship'
10
9
 
11
10
  module Cert
12
11
  # Use this to just setup the configuration attribute and set it later somewhere else
metadata CHANGED
@@ -1,127 +1,127 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cert
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix Krause
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-22 00:00:00.000000000 Z
11
+ date: 2015-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fastlane_core
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.7.2
19
+ version: 0.9.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.7.2
26
+ version: 0.9.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: spaceship
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.10
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.0.10
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - '>='
45
+ - - ">="
32
46
  - !ruby/object:Gem::Version
33
47
  version: '0'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - '>='
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - '>='
59
+ - - ">="
46
60
  - !ruby/object:Gem::Version
47
61
  version: '0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - '>='
66
+ - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - ~>
73
+ - - "~>"
60
74
  - !ruby/object:Gem::Version
61
75
  version: 3.1.0
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - ~>
80
+ - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: 3.1.0
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: pry
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - '>='
87
+ - - ">="
74
88
  - !ruby/object:Gem::Version
75
89
  version: '0'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - '>='
94
+ - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: yard
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
- - - ~>
101
+ - - "~>"
88
102
  - !ruby/object:Gem::Version
89
103
  version: 0.8.7.4
90
104
  type: :development
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
- - - ~>
108
+ - - "~>"
95
109
  - !ruby/object:Gem::Version
96
110
  version: 0.8.7.4
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: webmock
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
- - - ~>
115
+ - - "~>"
102
116
  - !ruby/object:Gem::Version
103
117
  version: 1.19.0
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
- - - ~>
122
+ - - "~>"
109
123
  - !ruby/object:Gem::Version
110
124
  version: 1.19.0
111
- - !ruby/object:Gem::Dependency
112
- name: codeclimate-test-reporter
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - '>='
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - '>='
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
125
  description: Create new iOS code signing certificates
126
126
  email:
127
127
  - cert@krausefx.com
@@ -134,10 +134,8 @@ files:
134
134
  - README.md
135
135
  - bin/cert
136
136
  - lib/cert.rb
137
- - lib/cert/cert_checker.rb
138
137
  - lib/cert/cert_runner.rb
139
138
  - lib/cert/dependency_checker.rb
140
- - lib/cert/developer_center.rb
141
139
  - lib/cert/keychain_importer.rb
142
140
  - lib/cert/options.rb
143
141
  - lib/cert/signing_request.rb
@@ -152,17 +150,17 @@ require_paths:
152
150
  - lib
153
151
  required_ruby_version: !ruby/object:Gem::Requirement
154
152
  requirements:
155
- - - '>='
153
+ - - ">="
156
154
  - !ruby/object:Gem::Version
157
155
  version: 2.0.0
158
156
  required_rubygems_version: !ruby/object:Gem::Requirement
159
157
  requirements:
160
- - - '>='
158
+ - - ">"
161
159
  - !ruby/object:Gem::Version
162
- version: '0'
160
+ version: 1.3.1
163
161
  requirements: []
164
162
  rubyforge_project:
165
- rubygems_version: 2.2.2
163
+ rubygems_version: 2.4.6
166
164
  signing_key:
167
165
  specification_version: 4
168
166
  summary: Create new iOS code signing certificates
@@ -1,30 +0,0 @@
1
- module Cert
2
- # This class checks if a specific certificate is installed on the current mac
3
- class CertChecker
4
- def self.is_installed?(path)
5
- raise "Could not find file '#{path}'".red unless File.exists?(path)
6
-
7
- ids = installed_identies
8
- finger_print = sha1_fingerprint(path)
9
-
10
- return ids.include?finger_print
11
- end
12
-
13
- def self.installed_identies
14
- available = `security find-identity -v -p codesigning`
15
- ids = []
16
- available.split("\n").each do |current|
17
- (ids << current.match(/.*\) (.*) \".*/)[1]) rescue nil # the last line does not match
18
- end
19
-
20
- return ids
21
- end
22
-
23
- def self.sha1_fingerprint(path)
24
- result = `openssl x509 -in "#{path}" -inform der -noout -sha1 -fingerprint`
25
- result = result.match(/SHA1 Fingerprint=(.*)/)[1]
26
- result.gsub!(":", "")
27
- return result
28
- end
29
- end
30
- end
@@ -1,194 +0,0 @@
1
- require 'fastlane_core/developer_center/developer_center'
2
-
3
- module Cert
4
- class DeveloperCenter < FastlaneCore::DeveloperCenter
5
- DISTRIBUTION = "Distribution"
6
- DEVELOPMENT = "Development"
7
-
8
- CERTS_URL = "https://developer.apple.com/account/ios/certificate/certificateList.action?type=distribution"
9
- CERTS_URL_DEV = "https://developer.apple.com/account/ios/certificate/certificateList.action?type=development"
10
- CREATE_CERT_URL = "https://developer.apple.com/account/ios/certificate/certificateCreate.action"
11
-
12
- # This will check if there is at least one of the certificates already installed on the local machine
13
- # This will store the resulting file name in ENV 'CER_FILE_PATH' and the Cert ID in 'CER_CERTIFICATE_ID'
14
- def run
15
- @type = (Cert.config[:development] ? DEVELOPMENT : DISTRIBUTION)
16
- file = find_existing_cert
17
- if file
18
- # We don't need to do anything :)
19
- ENV["CER_FILE_PATH"] = file
20
- else
21
- create_certificate
22
- end
23
- rescue => ex
24
- error_occured(ex)
25
- end
26
-
27
- def find_existing_cert
28
- if @type == DEVELOPMENT
29
- visit CERTS_URL_DEV
30
- else
31
- visit CERTS_URL
32
- end
33
-
34
- # Download all available certs to check if they are installed using the SHA1 hash
35
- certs = code_signing_certificate
36
- certs.each do |current|
37
- display_id = current['certificateId']
38
- type_id = current['certificateTypeDisplayId']
39
- url = "/account/ios/certificate/certificateContentDownload.action?displayId=#{display_id}&type=#{type_id}"
40
-
41
- output = File.join(TMP_FOLDER, "#{display_id}-#{type_id}.cer")
42
- download_url(url, output)
43
- if Cert::CertChecker.is_installed?output
44
- # We'll use this one, since it's installed on the local machine
45
- ENV["CER_CERTIFICATE_ID"] = display_id
46
- Helper.log.info "Found the certificate #{display_id}-#{type_id} which is installed on the local machine. Using this one.".green
47
- return output
48
- end
49
- end
50
-
51
- Helper.log.info "Couldn't find an existing certificate... creating a new one"
52
- return false
53
- rescue => ex
54
- error_occured(ex)
55
- end
56
-
57
- # This will actually create a new certificate
58
- def create_certificate
59
- visit CREATE_CERT_URL
60
- wait_for_elements("form[name='certificateSave']")
61
-
62
- Helper.log.info "Creating a new code signing certificate"
63
-
64
- # select certificate type
65
- if @type == DEVELOPMENT
66
- app_store_toggle = first("input#type-development")
67
- else
68
- app_store_toggle = first("input#type-iosNoOCSP") || first("input#type-iosOCSP")
69
- end
70
-
71
- if !!app_store_toggle['disabled']
72
- # Limit of certificates already reached
73
- raise "Could not create another certificate, reached the maximum number of available certificates.".red
74
- end
75
-
76
- app_store_toggle.click
77
-
78
- click_next # submit the certificate type
79
- sleep 2
80
- click_next # information about how to upload the file (no action required on this step)
81
-
82
- cert_signing_request = Cert::SigningRequest.get_path
83
- Helper.log.info "Uploading the cert signing request '#{cert_signing_request}'"
84
-
85
- wait_for_elements("input[name='upload']").first.set cert_signing_request # upload the cert signing request
86
- sleep 1
87
- click_next
88
-
89
- sleep 3
90
-
91
- while all(:css, '.loadingMessage').count > 0
92
- Helper.log.debug "Waiting for iTC to generate the profile"
93
- sleep 2
94
- end
95
-
96
- Helper.log.info "Downloading newly generated certificate"
97
- sleep 2
98
-
99
- # Now download the certificate
100
- download_button = wait_for_elements(".button.small.blue").first
101
- url = download_button['href']
102
-
103
- path = File.join(TMP_FOLDER, "certificate.cer")
104
- download_url(url, path)
105
-
106
- certificate_id = url.match(/.*displayId=(.*)&type.*/)[1]
107
-
108
- ENV["CER_FILE_PATH"] = path
109
- ENV["CER_CERTIFICATE_ID"] = certificate_id
110
- Helper.log.info "Successfully downloaded latest .cer file to '#{path}' (#{certificate_id})".green
111
-
112
- Cert::KeychainImporter::import_file(path)
113
- rescue => ex
114
- error_occured(ex)
115
- end
116
-
117
-
118
- private
119
- def download_url(url, output_path)
120
- host = Capybara.current_session.current_host
121
- url = [host, url].join('')
122
- Helper.log.info "Downloading URL: '#{url}'"
123
-
124
- cookie_string = page.driver.cookies.collect { |key, cookie| "#{cookie.name}=#{cookie.value}" }.join(";")
125
- data = open(url, {'Cookie' => cookie_string}).read
126
-
127
- raise "Something went wrong when downloading the certificate" unless data
128
-
129
- # write data to file
130
- dataWritten = File.open(output_path, "wb") do |f|
131
- f.write(data)
132
- end
133
-
134
- if dataWritten == 0
135
- raise "Can't write to #{output_path}"
136
- end
137
- end
138
-
139
- # Returns a hash, that contains information about the iOS certificate
140
- # @example
141
- # {"certRequestId"=>"B23Q2P396B",
142
- # "name"=>"SunApps GmbH",
143
- # "statusString"=>"Issued",
144
- # "expirationDate"=>"2015-11-25T22:45:50Z",
145
- # "expirationDateString"=>"Nov 25, 2015",
146
- # "ownerType"=>"team",
147
- # "ownerName"=>"SunApps GmbH",
148
- # "ownerId"=>"....",
149
- # "canDownload"=>true,
150
- # "canRevoke"=>true,
151
- # "certificateId"=>"....",
152
- # "certificateStatusCode"=>0,
153
- # "certRequestStatusCode"=>4,
154
- # "certificateTypeDisplayId"=>"...",
155
- # "serialNum"=>"....",
156
- # "typeString"=>"iOS Distribution"},
157
- def code_signing_certificate
158
- if @type == DEVELOPMENT
159
- visit CERTS_URL_DEV
160
- else
161
- visit CERTS_URL
162
- end
163
-
164
- certificateDataURL = wait_for_variable('certificateDataURL')
165
- certificateRequestTypes = wait_for_variable('certificateRequestTypes')
166
- certificateStatuses = wait_for_variable('certificateStatuses')
167
-
168
- url = [certificateDataURL, certificateRequestTypes, certificateStatuses].join('')
169
-
170
- # https://developer.apple.com/services-account/.../account/ios/certificate/listCertRequests.action?content-type=application/x-www-form-urlencoded&accept=application/json&requestId=...&userLocale=en_US&teamId=...&types=...&status=4&certificateStatus=0&type=distribution&pageSize=50&pageNumber=1&sort=name=asc
171
-
172
- available = []
173
-
174
- certTypeName = 'iOS Distribution'
175
- certTypeName = 'iOS Development' if @type == DEVELOPMENT
176
- certs = post_ajax(url, "{pageNumber: 1, pageSize: 500, sort: 'name%3dasc'}")['certRequests']
177
-
178
- raise "Something went wrong with request to #{url}" unless certs
179
- certs.each do |current_cert|
180
- if current_cert['typeString'] == certTypeName and current_cert['canDownload']
181
- # The other profiles are push profiles or ones we are not allowed to download
182
- # We only care about the distribution profile that we can download
183
- available << current_cert # mostly we only care about the 'certificateId'
184
- end
185
- end
186
-
187
- return available
188
- end
189
-
190
- def click_next
191
- wait_for_elements('.button.small.blue.right.submit').last.click
192
- end
193
- end
194
- end