fastlane-plugin-match_keystore 0.1.16 → 0.2.1

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: aaedb3d25e8614b96c43af4e88ddbc46f56e71a7a97a92d2336507afc3afded8
4
- data.tar.gz: 741fc33e956879046126da3fec54cb6f939b34eb8859e22d27244de8a7e6f823
3
+ metadata.gz: 13f57b6db57c10e142d53885360cb1416f676402fd7f234b61a549720501d9c6
4
+ data.tar.gz: 2809854cf748f5ba4931fd4cbe8dfc6292cfea2f4e5d556a887ed422ebfcacc2
5
5
  SHA512:
6
- metadata.gz: e0d3ef8b5d0b9c5a66fcc8bece867e8d230e9f44764b963774cbdfbe110b38f7ef2446bf9592fd913716da8267471ef1cb7d2b6d30a70e494ef8ae75d78c84a9
7
- data.tar.gz: 37849dd986d716d6ce16ab7fe8af4f3d18d7b8c3a1840f6f7d4ccade7121b7ced9ac2085e486c8c4442da6f7bf76435ac7581267a730bb204619f5c41d8b558a
6
+ metadata.gz: 97a47758d5a39ebf414ae7a232e8767cb0dfa6ac7c484f3180b8e3149d3e879fb3ce3b27d363eae444703e9f3a9bad5b4ddc5d66f2987ed5fa0ed29b04bd4c74
7
+ data.tar.gz: 2c27e6a39112bdef3c44c6ed8abd77a31e19c9ce52a002040562d9f4aee229b4cf0e60cbe868196493acc983ca61b39acdfadebd2914e5a9ba15d40dd1024751
data/README.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-match_keystore)
4
4
 
5
+ ## Machine requirements
6
+
7
+ * OpenSSL 1.1.1 min OR LibreSSL 2.9 min installed
8
+ * Git installed
9
+ * Android SDK & Build-tools installed
10
+ * ANDROID_HOME environment variable defined
11
+
5
12
  ## Getting Started
6
13
 
7
14
  This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-match_keystore`, add it to your project by running:
@@ -43,6 +50,8 @@ The keystore properties are encrypted with AES in order to secure sensitive data
43
50
  end
44
51
  ```
45
52
 
53
+ You can build aab files as well by providing an `aab_path` instead of an `apk_path`.
54
+
46
55
  ## Example
47
56
 
48
57
  Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
@@ -2,6 +2,7 @@ require 'fastlane/action'
2
2
  require 'fileutils'
3
3
  require 'os'
4
4
  require 'json'
5
+ require 'pry'
5
6
  require 'digest'
6
7
  require_relative '../helper/match_keystore_helper'
7
8
 
@@ -11,14 +12,13 @@ module Fastlane
11
12
  MATCH_KEYSTORE_PATH = :MATCH_KEYSTORE_PATH
12
13
  MATCH_KEYSTORE_ALIAS_NAME = :MATCH_KEYSTORE_ALIAS_NAME
13
14
  MATCH_KEYSTORE_APK_SIGNED = :MATCH_KEYSTORE_APK_SIGNED
15
+ MATCH_KEYSTORE_AAB_SIGNED = :MATCH_KEYSTORE_AAB_SIGNED
14
16
  end
15
17
 
16
18
  class MatchKeystoreAction < Action
17
19
 
18
- def self.openssl_path
19
- path = "/usr/local/opt/openssl@1.1/bin"
20
- path
21
- end
20
+ KEY_VERSION = "2"
21
+ OPENSSL_BIN_PATH_MAC = "/usr/local/opt/openssl@1.1/bin"
22
22
 
23
23
  def self.to_md5(value)
24
24
  hash_value = Digest::MD5.hexdigest value
@@ -119,8 +119,7 @@ module Fastlane
119
119
 
120
120
  def self.openssl(forceOpenSSL)
121
121
  if forceOpenSSL
122
- path = openssl_path
123
- output = "#{path}/openssl"
122
+ output = "#{self::OPENSSL_BIN_PATH_MAC}/openssl"
124
123
  else
125
124
  output = "openssl"
126
125
  end
@@ -137,10 +136,15 @@ module Fastlane
137
136
  result
138
137
  end
139
138
 
140
- def self.gen_key(key_path, password)
139
+ def self.gen_key(key_path, password, compat_key)
141
140
  `rm -f '#{key_path}'`
142
141
  shaValue = self.sha512(password)
143
- `echo "#{shaValue}" > '#{key_path}'`
142
+ # Backward-compatibility
143
+ if compat_key == "1"
144
+ `echo "#{password}" | openssl dgst -sha512 | awk '{print $2}' | cut -c1-128 > '#{key_path}'`
145
+ else
146
+ `echo "#{shaValue}" > '#{key_path}'`
147
+ end
144
148
  end
145
149
 
146
150
  def self.encrypt_file(clear_file, encrypt_file, key_path, forceOpenSSL)
@@ -190,7 +194,7 @@ module Fastlane
190
194
 
191
195
  # Check SHA-512-File
192
196
  key_path = File.join(Dir.pwd, '/temp/key.txt')
193
- self.gen_key(key_path, fakeValue)
197
+ self.gen_key(key_path, fakeValue, false)
194
198
  shaValue = self.get_file_content(key_path).strip!
195
199
  excepted = "cc6a7b0d89cc61c053f7018a305672bdb82bc07e5015f64bb063d9662be4ec81ec8afa819b009de266482b6bd56b7068def2524c32f5b5d4d9db49ee4578499d"
196
200
  self.assert_equals("SHA-512-File", excepted, shaValue)
@@ -250,49 +254,68 @@ module Fastlane
250
254
  build_tools_path = self.get_build_tools(version_targeted)
251
255
  UI.message("Build-tools path: #{build_tools_path}")
252
256
 
253
- # https://developer.android.com/studio/command-line/zipalign
254
- if zip_align == true
255
- apk_path_aligned = apk_path.gsub(".apk", "-aligned.apk")
256
- `rm -f '#{apk_path_aligned}'`
257
- UI.message("Aligning APK (zipalign): #{apk_path}")
258
- output = `#{build_tools_path}zipalign -v 4 '#{apk_path}' '#{apk_path_aligned}'`
259
- puts ""
260
- puts output
261
-
262
- if !File.file?(apk_path_aligned)
263
- raise "Aligned APK not exists!"
264
- end
265
-
266
- else
267
- UI.message("No zip align!")
268
- apk_path_aligned = apk_path
269
- end
257
+ # https://developer.android.com/studio/command-line/apksigner
270
258
  apk_path_signed = apk_path.gsub(".apk", "-signed.apk")
271
259
  apk_path_signed = apk_path_signed.gsub("unsigned", "")
272
260
  apk_path_signed = apk_path_signed.gsub("--", "-")
273
-
274
- # https://developer.android.com/studio/command-line/apksigner
275
261
  `rm -f '#{apk_path_signed}'`
276
- UI.message("Signing APK: #{apk_path_aligned}")
262
+
263
+ UI.message("Signing APK (input): #{apk_path}")
277
264
  apksigner_opts = ""
278
265
  build_tools_version = self.get_build_tools_version(version_targeted)
279
266
  UI.message("Build-tools version: #{build_tools_version}")
280
267
  if Gem::Version.new(build_tools_version) >= Gem::Version.new('30')
281
268
  apksigner_opts = "--v4-signing-enabled false "
282
269
  end
283
- output = `#{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 #{apksigner_opts}--out '#{apk_path_signed}' '#{apk_path_aligned}'`
270
+ output = `#{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 #{apksigner_opts}--out '#{apk_path_signed}' '#{apk_path}'`
284
271
  puts ""
285
272
  puts output
286
273
 
287
- UI.message("Verifing APK signature: #{apk_path_signed}")
274
+ UI.message("Verifing APK signature (output): #{apk_path_signed}")
288
275
  output = `#{build_tools_path}apksigner verify '#{apk_path_signed}'`
289
276
  puts ""
290
277
  puts output
291
- `rm -f '#{apk_path_aligned}'`
278
+
279
+
280
+ # https://developer.android.com/studio/command-line/zipalign
281
+ if zip_align != false
282
+ apk_path_aligned = apk_path_signed.gsub(".apk", "-aligned.apk")
283
+ `rm -f '#{apk_path_aligned}'`
284
+ UI.message("Aligning APK (zipalign): #{apk_path_signed}")
285
+ output = `#{build_tools_path}zipalign -v 4 '#{apk_path_signed}' '#{apk_path_aligned}'`
286
+ puts ""
287
+ puts output
288
+
289
+ if !File.file?(apk_path_aligned)
290
+ raise "Aligned APK not exists!"
291
+ end
292
+
293
+ `rm -f '#{apk_path_signed}'`
294
+ apk_path_signed = apk_path_aligned
295
+
296
+ else
297
+ UI.message("No zip align - deactivated via parameter!")
298
+ end
292
299
 
293
300
  apk_path_signed
294
301
  end
295
302
 
303
+ def self.sign_aab(aab_path, keystore_path, key_password, alias_name, alias_password)
304
+
305
+ aab_path_signed = aab_path.gsub('.aab', '-signed.aab')
306
+ aab_path_signed = aab_path_signed.gsub('unsigned', '')
307
+ aab_path_signed = aab_path_signed.gsub('--', '-')
308
+ `rm -f '#{aab_path_signed}'`
309
+
310
+ UI.message("Signing AAB (input): #{aab_path}")
311
+ aabsigner_opts = ""
312
+ output = `jarsigner -keystore '#{keystore_path}' -storepass '#{key_password}' -keypass '#{alias_password}' -signedjar '#{aab_path_signed}' '#{aab_path}' '#{alias_name}'`
313
+ puts ""
314
+ puts output
315
+
316
+ aab_path_signed
317
+ end
318
+
296
319
  def self.resolve_dir(path)
297
320
  if !File.directory?(path)
298
321
  path = File.join(Dir.pwd, path)
@@ -316,6 +339,34 @@ module Fastlane
316
339
  data
317
340
  end
318
341
 
342
+ def self.resolve_aab_path(aab_path)
343
+
344
+ # Set default AAB path if not set:
345
+ if aab_path.to_s.strip.empty?
346
+ aab_path = '/app/build/outputs/bundle/release/'
347
+ end
348
+
349
+ if !aab_path.to_s.end_with?('.aab')
350
+
351
+ aab_path = self.resolve_dir(aab_path)
352
+
353
+ pattern = File.join(aab_path, '*.aab')
354
+ files = Dir[pattern]
355
+
356
+ for file in files
357
+ if file.to_s.end_with?('.aab') && !file.to_s.end_with?("-signed.aab")
358
+ apk_path = file
359
+ break
360
+ end
361
+ end
362
+
363
+ else
364
+ aab_path = self.resolve_file(aab_path)
365
+ end
366
+
367
+ aab_path
368
+ end
369
+
319
370
  def self.resolve_apk_path(apk_path)
320
371
 
321
372
  # Set default APK path if not set:
@@ -360,6 +411,7 @@ module Fastlane
360
411
  git_url = params[:git_url]
361
412
  package_name = params[:package_name]
362
413
  apk_path = params[:apk_path]
414
+ aab_path = params[:aab_path]
363
415
  existing_keystore = params[:existing_keystore]
364
416
  match_secret = params[:match_secret]
365
417
  override_keystore = params[:override_keystore]
@@ -367,6 +419,8 @@ module Fastlane
367
419
  clear_keystore = params[:clear_keystore]
368
420
  unit_test = params[:unit_test]
369
421
  build_tools_version = params[:build_tools_version]
422
+ zip_align = params[:zip_align]
423
+ compat_key = params[:compat_key]
370
424
 
371
425
  # Test OpenSSL/LibreSSL
372
426
  if unit_test
@@ -390,6 +444,11 @@ module Fastlane
390
444
  # Check OpenSSL:
391
445
  self.check_ssl_version(false)
392
446
 
447
+ # Check is backward-compatibility is required:
448
+ if !compat_key.to_s.strip.empty?
449
+ UI.message("Compatiblity version: #{compat_key}")
450
+ end
451
+
393
452
  # Init workign local directory:
394
453
  dir_name = ENV['HOME'] + '/.match_keystore'
395
454
  unless File.directory?(dir_name)
@@ -398,7 +457,11 @@ module Fastlane
398
457
  end
399
458
 
400
459
  # Init 'security password' for AES encryption:
401
- key_name = "#{self.to_md5(git_url)}.hex"
460
+ if compat_key == "1"
461
+ key_name = "#{self.to_md5(git_url)}.hex"
462
+ else
463
+ key_name = "#{self.to_md5(git_url)}-#{self::KEY_VERSION}.hex"
464
+ end
402
465
  key_path = File.join(dir_name, key_name)
403
466
  # UI.message(key_path)
404
467
  if !File.file?(key_path)
@@ -407,7 +470,7 @@ module Fastlane
407
470
  raise "Security password is not defined! Please use 'match_secret' parameter for CI."
408
471
  end
409
472
  UI.message "Generating security key '#{key_name}'..."
410
- self.gen_key(key_path, security_password)
473
+ self.gen_key(key_path, security_password, compat_key)
411
474
  end
412
475
 
413
476
  # Check is 'security password' is well initialized:
@@ -446,14 +509,10 @@ module Fastlane
446
509
  gitDir = File.join(repo_dir, '/.git')
447
510
  if !File.directory?(gitDir)
448
511
  UI.message("Cloning remote Keystores repository...")
449
- puts ''
450
512
  `git clone #{git_url} #{repo_dir}`
451
- puts ''
452
513
  else
453
514
  UI.message("Pulling remote Keystores repository...")
454
- puts ''
455
515
  `cd #{repo_dir} && git pull`
456
- puts ''
457
516
  end
458
517
 
459
518
  # Load parameters from JSON for CI or Unit Tests:
@@ -554,6 +613,7 @@ module Fastlane
554
613
  self.decrypt_file(properties_encrypt_path, properties_path, key_path, false)
555
614
 
556
615
  properties = self.load_properties(properties_path)
616
+ # Pry::ColorPrinter.pp(properties)
557
617
  key_password = properties['keyPassword']
558
618
  alias_name = properties['aliasName']
559
619
  alias_password = properties['aliasPassword']
@@ -561,13 +621,13 @@ module Fastlane
561
621
  File.delete(properties_path)
562
622
  end
563
623
 
564
- # Resolve path to the APK to sign:
565
- output_signed_apk = ''
566
- apk_path = self.resolve_apk_path(apk_path)
567
-
568
624
  # Sign APK:
569
- if File.file?(apk_path)
625
+ if apk_path && File.file?(apk_path)
570
626
  UI.message("APK to sign: " + apk_path)
627
+
628
+ # Resolve path to the APK to sign:
629
+ output_signed_apk = ''
630
+ apk_path = self.resolve_apk_path(apk_path)
571
631
 
572
632
  if File.file?(keystore_path)
573
633
 
@@ -579,21 +639,49 @@ module Fastlane
579
639
  key_password,
580
640
  alias_name,
581
641
  alias_password,
582
- true, # Zip align
642
+ zip_align, # Zip align
583
643
  build_tools_version # Buil-tools version
584
644
  )
585
645
  puts ''
586
646
  end
587
- else
588
- UI.message("No APK file found to sign!")
589
- end
590
647
 
591
- # Prepare contect shared values for next lanes:
592
- Actions.lane_context[SharedValues::MATCH_KEYSTORE_PATH] = keystore_path
593
- Actions.lane_context[SharedValues::MATCH_KEYSTORE_ALIAS_NAME] = alias_name
594
- Actions.lane_context[SharedValues::MATCH_KEYSTORE_APK_SIGNED] = output_signed_apk
648
+ # Prepare contect shared values for next lanes:
649
+ Actions.lane_context[SharedValues::MATCH_KEYSTORE_PATH] = keystore_path
650
+ Actions.lane_context[SharedValues::MATCH_KEYSTORE_ALIAS_NAME] = alias_name
651
+ Actions.lane_context[SharedValues::MATCH_KEYSTORE_APK_SIGNED] = output_signed_apk
652
+
653
+ output_signed_apk
654
+ # Sign AAB
655
+ elsif aab_path && File.file?(aab_path)
656
+ UI.message('AAB to sign: '+ aab_path)
657
+
658
+ # Resolve path to the AAB to sign:
659
+ output_signed_aab = ''
660
+ aab_path = self.resolve_aab_path(aab_path)
661
+
662
+ if File.file?(keystore_path)
663
+
664
+ UI.message("Signing the AAB...")
665
+ puts ''
666
+ output_signed_aab = self.sign_aab(
667
+ aab_path,
668
+ keystore_path,
669
+ key_password,
670
+ alias_name,
671
+ alias_password
672
+ )
673
+ puts ''
674
+ end
675
+
676
+ # Prepare contect shared values for next lanes:
677
+ Actions.lane_context[SharedValues::MATCH_KEYSTORE_PATH] = keystore_path
678
+ Actions.lane_context[SharedValues::MATCH_KEYSTORE_ALIAS_NAME] = alias_name
679
+ Actions.lane_context[SharedValues::MATCH_KEYSTORE_AAB_SIGNED] = output_signed_aab
595
680
 
596
- output_signed_apk
681
+ output_signed_aab
682
+ else
683
+ UI.message("No APK or AAB file found")
684
+ end
597
685
  end
598
686
 
599
687
  def self.description
@@ -601,7 +689,7 @@ module Fastlane
601
689
  end
602
690
 
603
691
  def self.authors
604
- ["Christopher NEY"]
692
+ ["Christopher NEY", "Simon Scherzinger"]
605
693
  end
606
694
 
607
695
  def self.return_value
@@ -612,7 +700,8 @@ module Fastlane
612
700
  [
613
701
  ['MATCH_KEYSTORE_PATH', 'File path of the Keystore fot the App.'],
614
702
  ['MATCH_KEYSTORE_ALIAS_NAME', 'Keystore Alias Name.'],
615
- ['MATCH_KEYSTORE_APK_SIGNED', 'Path of the signed APK.']
703
+ ['MATCH_KEYSTORE_APK_SIGNED', 'Path of the signed APK.'],
704
+ ['MATCH_KEYSTORE_AAB_SIGNED', 'Path of the signed AAB.']
616
705
  ]
617
706
  end
618
707
 
@@ -638,6 +727,11 @@ module Fastlane
638
727
  description: "Path of the APK file to sign",
639
728
  optional: true,
640
729
  type: String),
730
+ FastlaneCore::ConfigItem.new(key: :aab_path,
731
+ env_name: "MATCH_KEYSTORE_AAB_PATH",
732
+ description: "Path of the AAB file to sign",
733
+ optional: true,
734
+ type: String),
641
735
  FastlaneCore::ConfigItem.new(key: :match_secret,
642
736
  env_name: "MATCH_KEYSTORE_SECRET",
643
737
  description: "Secret to decrypt keystore.properties file (CI)",
@@ -662,17 +756,27 @@ module Fastlane
662
756
  env_name: "MATCH_KEYSTORE_BUILD_TOOLS_VERSION",
663
757
  description: "Set built-tools version (by default latest available on machine)",
664
758
  optional: true,
665
- type: String),
759
+ type: String),
760
+ FastlaneCore::ConfigItem.new(key: :zip_align,
761
+ env_name: "MATCH_KEYSTORE_ZIPALIGN",
762
+ description: "Define if plugin will run zipalign on APK before sign it (true by default)",
763
+ optional: true,
764
+ type: Boolean),
765
+ FastlaneCore::ConfigItem.new(key: :compat_key,
766
+ env_name: "MATCH_KEYSTORE_COMPAT_KEY",
767
+ description: "Define the compatibility key version used on local machine (nil by default)",
768
+ optional: true,
769
+ type: String),
666
770
  FastlaneCore::ConfigItem.new(key: :clear_keystore,
667
771
  env_name: "MATCH_KEYSTORE_CLEAR",
668
772
  description: "Clear the local keystore (false by default)",
669
773
  optional: true,
670
774
  type: Boolean),
671
775
  FastlaneCore::ConfigItem.new(key: :unit_test,
672
- env_name: "MATCH_KEYSTORE_UNIT_TESTS",
776
+ env_name: "MATCH_KEYSTORE_UNIT_TESTS",
673
777
  description: "launch Unit Tests (false by default)",
674
- optional: true,
675
- type: Boolean)
778
+ optional: true,
779
+ type: Boolean)
676
780
  ]
677
781
  end
678
782
 
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module MatchKeystore
3
- VERSION = "0.1.16"
3
+ VERSION = "0.2.1"
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.16
4
+ version: 0.2.1
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-09-08 00:00:00.000000000 Z
11
+ date: 2021-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -167,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
167
  - !ruby/object:Gem::Version
168
168
  version: '0'
169
169
  requirements: []
170
- rubygems_version: 3.0.3
170
+ rubygems_version: 3.2.17
171
171
  signing_key:
172
172
  specification_version: 4
173
173
  summary: Easily sync your Android keystores across your team