fastlane-plugin-match_keystore 0.1.9 → 0.1.10

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
  SHA256:
3
- metadata.gz: 42c7915b7d46b87470d41acfd251257c04ce89460ac60a08318404530a1fbd24
4
- data.tar.gz: 07f280f892d41adee35f025218da2a1eeb345f17c9cf27d2d027246f4b248940
3
+ metadata.gz: 1e26b0b531512693d08eedc46159379bded6984aa802a32f6d6296d94a0116c3
4
+ data.tar.gz: ae4ba30e68e58c3c85bfa15a6a57ec0ab93fd98fc90bf23c597124e57235d4c5
5
5
  SHA512:
6
- metadata.gz: 85ff5b2dda6f5a38714a09aea05fb279ec87015e970860ac3238f10280d233195936b84ef617d6bfafca36ee9d164f4a1c6267d8ea76e75305a40f4d44b55627
7
- data.tar.gz: f8e3fba2336ef34b35300d38535d2f5fbb5798af9efc50f268fa33a7a05282157f1a46755953eac2d99b362642560b8dc9e7b6255377a13e0fae9b5ebcfcd60d
6
+ metadata.gz: 8c5983fd39c9d8d92b9981d153e59e21121eb992bb52f04d882b99918e199d1a6edf96588a8a905d3f17b26856a3aa66da7f8f63a587be4d969c29370fbbc3a5
7
+ data.tar.gz: 961c71d337aed1417bf10cbe1b682974fb2c262a830ff04efa99f9a063f32c7ad15345b5a8344a170cded7bdd53eb1ae56839a43e3f571b59a273f385feeec18
@@ -1,6 +1,8 @@
1
1
  require 'fastlane/action'
2
2
  require 'fileutils'
3
3
  require 'os'
4
+ require 'json'
5
+ require 'digest'
4
6
  require_relative '../helper/match_keystore_helper'
5
7
 
6
8
  module Fastlane
@@ -13,6 +15,17 @@ module Fastlane
13
15
 
14
16
  class MatchKeystoreAction < Action
15
17
 
18
+ def self.to_md5(value)
19
+ hash_value = Digest::MD5.hexdigest value
20
+ hash_value
21
+ end
22
+
23
+ def self.load_json(json_path)
24
+ file = File.read(json_path)
25
+ data_hash = JSON.parse(file)
26
+ data_hash
27
+ end
28
+
16
29
  def self.load_properties(properties_filename)
17
30
  properties = {}
18
31
  File.open(properties_filename, 'r') do |properties_file|
@@ -88,12 +101,14 @@ module Fastlane
88
101
  else
89
102
  apk_path_aligned = apk_path
90
103
  end
104
+ apk_path_signed = apk_path.gsub(".apk", "-signed.apk")
105
+ apk_path_signed = apk_path_signed.gsub("unsigned", "")
106
+ apk_path_signed = apk_path_signed.gsub("--", "-")
91
107
 
92
108
  # https://developer.android.com/studio/command-line/apksigner
93
- apk_path_signed = apk_path.gsub(".apk", "-signed.apk")
94
109
  `rm -f #{apk_path_signed}`
95
- `#{build_tools_path}apksigner sign --ks #{keystore_path} --ks-key-alias '#{alias_name}' --ks-pass pass:'#{alias_password}' --key-pass pass:'#{key_password}' --v1-signing-enabled true --v2-signing-enabled true --out #{apk_path_signed} #{apk_path_aligned}`
96
-
110
+ `#{build_tools_path}apksigner sign --ks #{keystore_path} --ks-key-alias '#{alias_name}' --ks-pass pass:'#{key_password}' --key-pass pass:'#{alias_password}' --v1-signing-enabled true --v2-signing-enabled true --out #{apk_path_signed} #{apk_path_aligned}`
111
+
97
112
  `#{build_tools_path}apksigner verify #{apk_path_signed}`
98
113
  `rm -f #{apk_path_aligned}`
99
114
 
@@ -107,6 +122,11 @@ module Fastlane
107
122
 
108
123
  def self.resolve_apk_path(apk_path)
109
124
 
125
+ # Set default APK path if not set:
126
+ if apk_path.to_s.strip.empty?
127
+ apk_path = '/app/build/outputs/apk/'
128
+ end
129
+
110
130
  if !apk_path.to_s.end_with?(".apk")
111
131
 
112
132
  if !File.directory?(apk_path)
@@ -134,15 +154,28 @@ module Fastlane
134
154
  apk_path
135
155
  end
136
156
 
157
+ def self.prompt2(params)
158
+ # UI.message("prompt2: #{params[:value]}")
159
+ if params[:value].to_s.empty?
160
+ return_value = other_action.prompt(text: params[:text], secure_text: params[:secure_text], ci_input: params[:ci_input])
161
+ else
162
+ return_value = params[:value]
163
+ end
164
+ return_value
165
+ end
166
+
137
167
  def self.run(params)
138
168
 
169
+ # Get input parameters:
139
170
  git_url = params[:git_url]
140
171
  package_name = params[:package_name]
141
172
  apk_path = params[:apk_path]
142
173
  existing_keystore = params[:existing_keystore]
143
- ci_password = params[:ci_password]
174
+ match_secret = params[:match_secret]
144
175
  override_keystore = params[:override_keystore]
176
+ keystore_data = params[:keystore_data]
145
177
 
178
+ # Init constants:
146
179
  keystore_name = 'keystore.jks'
147
180
  properties_name = 'keystore.properties'
148
181
  keystore_info_name = 'keystore.txt'
@@ -158,35 +191,43 @@ module Fastlane
158
191
  # Check OpenSSL:
159
192
  self.check_openssl_version
160
193
 
194
+ # Init workign local directory:
161
195
  dir_name = ENV['HOME'] + '/.match_keystore'
162
196
  unless File.directory?(dir_name)
163
197
  UI.message("Creating '.match_keystore' working directory...")
164
198
  FileUtils.mkdir_p(dir_name)
165
199
  end
166
200
 
167
- key_path = dir_name + '/key.hex'
201
+ # Init 'security password' for AES encryption:
202
+ key_name = "#{self.to_md5(git_url)}.hex"
203
+ key_path = File.join(dir_name, key_name)
204
+ # UI.message(key_path)
168
205
  if !File.file?(key_path)
169
- security_password = other_action.prompt(text: "Security password: ", secure_text: true, ci_input: ci_password)
206
+ security_password = self.prompt2(text: "Security password: ", secure_text: true, value: match_secret)
170
207
  if security_password.to_s.strip.empty?
171
- raise "Security password is not defined! Please use 'ci_password' parameter for CI."
208
+ raise "Security password is not defined! Please use 'match_secret' parameter for CI."
172
209
  end
173
- UI.message "Generating security key..."
210
+ UI.message "Generating security key '#{key_name}'..."
174
211
  self.gen_key(key_path, security_password)
175
212
  end
176
213
 
214
+ # Check is 'security password' is well initialized:
177
215
  tmpkey = self.get_file_content(key_path).strip
178
216
  if tmpkey.length == 128
179
- UI.message "Security key initialized"
217
+ UI.message "Security key '#{key_name}' initialized"
180
218
  else
181
- raise "The security key format is invalid, or not initialized!"
219
+ raise "The security key '#{key_name}' is malformed, or not initialized!"
182
220
  end
183
221
 
184
- repo_dir = dir_name + '/repo'
222
+ # Create repo directory to sync remote Keystores repository:
223
+ repo_dir = File.join(dir_name, self.to_md5(git_url))
224
+ # UI.message(repo_dir)
185
225
  unless File.directory?(repo_dir)
186
226
  UI.message("Creating 'repo' directory...")
187
227
  FileUtils.mkdir_p(repo_dir)
188
228
  end
189
229
 
230
+ # Cloning GIT remote repository:
190
231
  gitDir = repo_dir + '/.git'
191
232
  unless File.directory?(gitDir)
192
233
  UI.message("Cloning remote Keystores repository...")
@@ -195,6 +236,10 @@ module Fastlane
195
236
  puts ''
196
237
  end
197
238
 
239
+ # Create sub-directory for Android app:
240
+ if package_name.to_s.strip.empty?
241
+ raise "Package name is not defined!"
242
+ end
198
243
  keystoreAppDir = repo_dir + '/' + package_name
199
244
  unless File.directory?(keystoreAppDir)
200
245
  UI.message("Creating '#{package_name}' keystore directory...")
@@ -205,6 +250,20 @@ module Fastlane
205
250
  properties_path = keystoreAppDir + '/' + properties_name
206
251
  properties_encrypt_path = keystoreAppDir + '/' + properties_encrypt_name
207
252
 
253
+ # Load parameters from JSON for CI or Unit Tests:
254
+ if keystore_data != nil && File.file?(keystore_data)
255
+ data_json = self.load_json(keystore_data)
256
+ data_key_password = data_json['key_password']
257
+ data_alias_name = data_json['alias_name']
258
+ data_alias_password = data_json['alias_password']
259
+ data_full_name = data_json['full_name']
260
+ data_org_unit = data_json['org_unit']
261
+ data_org = data_json['org']
262
+ data_city_locality = data_json['city_locality']
263
+ data_state_province = data_json['state_province']
264
+ data_country = data_json['country']
265
+ end
266
+
208
267
  # Create keystore with command
209
268
  override_keystore = !existing_keystore.to_s.strip.empty? && File.file?(existing_keystore)
210
269
  if !File.file?(keystore_path) || override_keystore
@@ -213,15 +272,15 @@ module Fastlane
213
272
  FileUtils.remove_dir(keystore_path)
214
273
  end
215
274
 
216
- key_password = other_action.prompt(text: "Keystore Password: ")
275
+ key_password = self.prompt2(text: "Keystore Password: ", value: data_key_password)
217
276
  if key_password.to_s.strip.empty?
218
277
  raise "Keystore Password is not definined!"
219
278
  end
220
- alias_name = other_action.prompt(text: "Keystore Alias name: ")
279
+ alias_name = self.prompt2(text: "Keystore Alias name: ", value: data_alias_name)
221
280
  if alias_name.to_s.strip.empty?
222
281
  raise "Keystore Alias name is not definined!"
223
282
  end
224
- alias_password = other_action.prompt(text: "Keystore Alias password: ")
283
+ alias_password = self.prompt2(text: "Keystore Alias password: ", value: data_alias_password)
225
284
  if alias_password.to_s.strip.empty?
226
285
  raise "Keystore Alias password is not definined!"
227
286
  end
@@ -230,12 +289,12 @@ module Fastlane
230
289
  if !File.file?(existing_keystore)
231
290
  UI.message("Generating Android Keystore...")
232
291
 
233
- full_name = other_action.prompt(text: "Certificate First and Last Name: ")
234
- org_unit = other_action.prompt(text: "Certificate Organisation Unit: ")
235
- org = other_action.prompt(text: "Certificate Organisation: ")
236
- city_locality = other_action.prompt(text: "Certificate City or Locality: ")
237
- state_province = other_action.prompt(text: "Certificate State or Province: ")
238
- country = other_action.prompt(text: "Certificate Country Code (XX): ")
292
+ full_name = self.prompt2(text: "Certificate First and Last Name: ", value: data_full_name)
293
+ org_unit = self.prompt2(text: "Certificate Organisation Unit: ", value: data_org_unit)
294
+ org = self.prompt2(text: "Certificate Organisation: ", value: data_org)
295
+ city_locality = self.prompt2(text: "Certificate City or Locality: ", value: data_city_locality)
296
+ state_province = self.prompt2(text: "Certificate State or Province: ", value: data_state_province)
297
+ country = self.prompt2(text: "Certificate Country Code (XX): ", value: data_country)
239
298
 
240
299
  keytool_parts = [
241
300
  "keytool -genkey -v",
@@ -272,14 +331,16 @@ module Fastlane
272
331
 
273
332
  # Print Keystore data in repo:
274
333
  keystore_info_path = keystoreAppDir + '/' + keystore_info_name
275
- `yes "" | keytool -list -v -keystore #{keystore_path} > #{keystore_info_path}`
334
+ `yes "" | keytool -list -v -keystore #{keystore_path} -storepass #{key_password} > #{keystore_info_path}`
276
335
 
277
336
  UI.message("Upload new Keystore to remote repository...")
337
+ puts ''
278
338
  `cd #{repo_dir} && git add .`
279
339
  `cd #{repo_dir} && git commit -m "[ADD] Keystore for app '#{package_name}'."`
280
340
  `cd #{repo_dir} && git push`
341
+ puts ''
281
342
 
282
- else
343
+ else
283
344
  UI.message "Keystore file already exists, continue..."
284
345
 
285
346
  self.decrypt_file(properties_encrypt_path, properties_path, key_path)
@@ -290,37 +351,40 @@ module Fastlane
290
351
  alias_password = properties['aliasPassword']
291
352
 
292
353
  File.delete(properties_path)
293
-
294
354
  end
295
355
 
356
+ # Resolve path to the APK to sign:
296
357
  output_signed_apk = ''
297
358
  apk_path = self.resolve_apk_path(apk_path)
298
359
 
360
+ # Sign APK:
299
361
  if File.file?(apk_path)
300
362
  UI.message("APK to sign: " + apk_path)
301
363
 
302
364
  if File.file?(keystore_path)
303
365
 
304
366
  UI.message("Signing the APK...")
367
+ puts ''
305
368
  output_signed_apk = self.sign_apk(
306
369
  apk_path,
307
370
  keystore_path,
308
371
  key_password,
309
372
  alias_name,
310
373
  alias_password,
311
- true
374
+ true # Zip align
312
375
  )
376
+ puts ''
313
377
  end
314
378
  else
315
379
  UI.message("No APK file found to sign!")
316
380
  end
317
381
 
382
+ # Prepare contect shared values for next lanes:
318
383
  Actions.lane_context[SharedValues::MATCH_KEYSTORE_PATH] = keystore_path
319
384
  Actions.lane_context[SharedValues::MATCH_KEYSTORE_ALIAS_NAME] = alias_name
320
385
  Actions.lane_context[SharedValues::MATCH_KEYSTORE_APK_SIGNED] = output_signed_apk
321
386
 
322
387
  output_signed_apk
323
-
324
388
  end
325
389
 
326
390
  def self.description
@@ -363,11 +427,11 @@ module Fastlane
363
427
  FastlaneCore::ConfigItem.new(key: :apk_path,
364
428
  env_name: "MATCH_KEYSTORE_APK_PATH",
365
429
  description: "Path of the APK file to sign",
366
- optional: false,
430
+ optional: true,
367
431
  type: String),
368
- FastlaneCore::ConfigItem.new(key: :ci_password,
369
- env_name: "MATCH_KEYSTORE_CI_PASSWORD",
370
- description: "Password to decrypt keystore.properties file (CI)",
432
+ FastlaneCore::ConfigItem.new(key: :match_secret,
433
+ env_name: "MATCH_KEYSTORE_SECRET",
434
+ description: "Secret to decrypt keystore.properties file (CI)",
371
435
  optional: true,
372
436
  type: String),
373
437
  FastlaneCore::ConfigItem.new(key: :existing_keystore,
@@ -379,7 +443,12 @@ module Fastlane
379
443
  env_name: "MATCH_KEYSTORE_OVERRIDE",
380
444
  description: "Override an existing Keystore (false by default)",
381
445
  optional: true,
382
- type: Boolean)
446
+ type: Boolean),
447
+ FastlaneCore::ConfigItem.new(key: :keystore_data,
448
+ env_name: "MATCH_KEYSTORE_JSON_PATH",
449
+ description: "Required data to import an existing keystore, or create a new one",
450
+ optional: true,
451
+ type: String)
383
452
  ]
384
453
  end
385
454
 
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module MatchKeystore
3
- VERSION = "0.1.9"
3
+ VERSION = "0.1.10"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-match_keystore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher NEY
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-11 00:00:00.000000000 Z
11
+ date: 2020-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry