fastlane-plugin-match_keystore 0.1.9 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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