resignios 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'commander/import'
3
+
4
+ require 'colored2'
5
+ require 'version'
6
+ require_relative 'resign'
7
+
8
+ module Sigh
9
+ class CommandsGenerator
10
+
11
+ def self.start
12
+ self.new.run
13
+ end
14
+
15
+ def run
16
+ program :name, 'resignios'
17
+ program :version, Resignios::VERSION
18
+ program :description, 'ios resign tool.'
19
+
20
+ command :ipa do |c|
21
+ c.syntax = 'resignios ipa'
22
+ c.description = 'Resigns an existing ipa file with the given provisioning profile'
23
+ c.option '-i', '--signing_identity STRING', String, 'The signing identity to use. Must match the one defined in the provisioning profile.'
24
+ c.option '-x', '--version_number STRING', String, 'Version number to force binary and all nested binaries to use. Changes both CFBundleShortVersionString and CFBundleIdentifier.'
25
+ c.option '-p', '--provisioning_profile PATH', String, '(or BUNDLE_ID=PATH) The path to the provisioning profile which should be used. '\
26
+ 'Can be provided multiple times if the application contains nested applications and app extensions, which need their own provisioning profile. '\
27
+ 'The path may be prefixed with a identifier in order to determine which provisioning profile should be used on which app.',
28
+ &multiple_values_option_proc(c, "provisioning_profile", &proc { |value| value.split('=', 2) })
29
+ c.option '-d', '--display_name STRING', String, 'Display name to use'
30
+ c.option '-e', '--entitlements PATH', String, 'The path to the entitlements file to use.'
31
+ c.option '--short_version STRING', String, 'Short version string to force binary and all nested binaries to use (CFBundleShortVersionString).'
32
+ c.option '--bundle_version STRING', String, 'Bundle version to force binary and all nested binaries to use (CFBundleVersion).'
33
+ c.option '--use_app_entitlements', 'Extract app bundle codesigning entitlements and combine with entitlements from new provisionin profile.'
34
+ c.option '-g', '--new_bundle_id STRING', String, 'New application bundle ID (CFBundleIdentifier)'
35
+ c.option '--remove_plugins', 'Remove new Application plugins'
36
+ c.option '--keychain_path STRING', String, 'Path to the keychain that /usr/bin/codesign should use'
37
+ c.option '-o', '--output_path STRING', String, 'Output IPA Path.'
38
+ c.action do |args, options|
39
+ Sigh::Resign.new.run(options, args)
40
+ end
41
+ end
42
+
43
+ default_command :ipa
44
+ end
45
+
46
+ def multiple_values_option_proc(command, name)
47
+ proc do |value|
48
+ value = yield(value) if block_given?
49
+ option = command.proxy_options.find { |opt| opt[0] == name } || []
50
+ values = option[1] || []
51
+ values << value
52
+
53
+ command.proxy_options.delete option
54
+ command.proxy_options << [name, values]
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,194 @@
1
+ require 'shellwords'
2
+
3
+ module Sigh
4
+ class Resign
5
+ def run(options, args)
6
+ # get the command line inputs and parse those into the vars we need...
7
+ ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, remove_plugins, keychain_path, output_path = get_inputs(options, args)
8
+ # ... then invoke our programmatic interface with these vars
9
+ unless resign(ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, remove_plugins, keychain_path, output_path)
10
+ puts "Failed to re-sign .ipa".red
11
+ end
12
+ end
13
+
14
+ def find_resign_path
15
+ File.expand_path('../../assets/resign.sh', __FILE__)
16
+ end
17
+
18
+ def resign(ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, remove_plugins, keychain_path, output_path)
19
+ resign_path = find_resign_path
20
+ signing_identity = find_signing_identity(signing_identity)
21
+
22
+ unless provisioning_profiles.kind_of?(Enumerable)
23
+ provisioning_profiles = [provisioning_profiles]
24
+ end
25
+
26
+ # validate that we have valid values for all these params, we don't need to check signing_identity because `find_signing_identity` will only ever return a valid value
27
+ validate_params(resign_path, ipa, provisioning_profiles)
28
+ entitlements = "-e #{entitlements.shellescape}" if entitlements
29
+
30
+ provisioning_options = create_provisioning_options(provisioning_profiles)
31
+ version = "-n #{version}" if version
32
+ display_name = "-d #{display_name.shellescape}" if display_name
33
+ short_version = "--short-version #{short_version}" if short_version
34
+ bundle_version = "--bundle-version #{bundle_version}" if bundle_version
35
+ verbose = "-v" if $verbose
36
+ bundle_id = "-b '#{new_bundle_id}'" if new_bundle_id
37
+ use_app_entitlements_flag = "--use-app-entitlements" if use_app_entitlements
38
+ remove_plugins_flag = "--remove-plugins" if remove_plugins
39
+ specific_keychain = "--keychain-path #{keychain_path.shellescape}" if keychain_path
40
+
41
+ command = [
42
+ resign_path.shellescape,
43
+ ipa.shellescape,
44
+ signing_identity.shellescape,
45
+ provisioning_options, # we are aleady shellescaping this above, when we create the provisioning_options from the provisioning_profiles
46
+ entitlements,
47
+ version,
48
+ display_name,
49
+ short_version,
50
+ bundle_version,
51
+ use_app_entitlements_flag,
52
+ remove_plugins_flag,
53
+ verbose,
54
+ bundle_id,
55
+ output_path || ipa.shellescape,
56
+ specific_keychain
57
+ ].join(' ')
58
+
59
+ puts command.magenta
60
+ puts `#{command}`
61
+
62
+ if $?.to_i == 0
63
+ puts "Successfully signed #{ipa}!"
64
+ true
65
+ else
66
+ puts "Something went wrong while code signing #{ipa}".red
67
+ false
68
+ end
69
+ end
70
+
71
+ def find_signing_identity(signing_identity)
72
+ until (signing_identity = sha1_for_signing_identity(signing_identity))
73
+ puts "Couldn't find signing identity '#{signing_identity}'.".red
74
+ signing_identity = ask_for_signing_identity
75
+ end
76
+
77
+ signing_identity
78
+ end
79
+
80
+ def sha1_for_signing_identity(signing_identity)
81
+ identities = installed_identities
82
+ return signing_identity if identities.keys.include?(signing_identity)
83
+ identities.key(signing_identity)
84
+ end
85
+
86
+ def create_provisioning_options(provisioning_profiles)
87
+ # provisioning_profiles is passed either a hash (to be able to resign extensions/nested apps):
88
+ # (in that case the underlying resign.sh expects values given as "-p at.fastlane=/folder/mobile.mobileprovision -p at.fastlane.today=/folder/mobile.mobileprovision")
89
+ # {
90
+ # "at.fastlane" => "/folder/mobile.mobileprovision",
91
+ # "at.fastlane.today" => "/folder/mobile.mobileprovision"
92
+ # }
93
+ # or an array
94
+ # (resign.sh also takes "-p /folder/mobile.mobileprovision" as a param)
95
+ # [
96
+ # "/folder/mobile.mobileprovision"
97
+ # ]
98
+ provisioning_profiles.map do |app_id, app_id_prov|
99
+ if app_id_prov
100
+ app_id_prov = File.expand_path(app_id_prov)
101
+ else
102
+ app_id = File.expand_path(app_id)
103
+ end
104
+ "-p #{[app_id, app_id_prov].compact.map(&:shellescape).join('=')}"
105
+ end.join(' ')
106
+ end
107
+
108
+ def validate_params(resign_path, ipa, provisioning_profiles)
109
+ validate_resign_path(resign_path)
110
+ validate_ipa_file(ipa)
111
+ provisioning_profiles.each { |fst, snd| validate_provisioning_file(snd || fst) }
112
+ end
113
+
114
+ def validate_resign_path(resign_path)
115
+ puts 'Could not find resign.sh file. Please try re-installing the gem'.red unless File.exist?(resign_path)
116
+ end
117
+
118
+ def validate_ipa_file(ipa)
119
+ puts "ipa file could not be found or is not an ipa file (#{ipa})".red unless File.exist?(ipa) && ipa.end_with?('.ipa')
120
+ end
121
+
122
+ def validate_provisioning_file(provisioning_profile)
123
+ unless File.exist?(provisioning_profile) && provisioning_profile.end_with?('.mobileprovision')
124
+ puts "Provisioning profile file could not be found or is not a .mobileprovision file (#{provisioning_profile})".red
125
+ end
126
+ end
127
+
128
+ def get_inputs(options, args)
129
+ ipa = args.first || self.input('Path to ipa file: ')
130
+ signing_identity = options.signing_identity || ask_for_signing_identity
131
+ provisioning_profiles = options.provisioning_profile || self.input('Path to provisioning file: ')
132
+ entitlements = options.entitlements || nil
133
+ version = options.version_number || nil
134
+ display_name = options.display_name || nil
135
+ short_version = options.short_version || nil
136
+ bundle_version = options.bundle_version || nil
137
+ new_bundle_id = options.new_bundle_id || nil
138
+ use_app_entitlements = options.use_app_entitlements || nil
139
+ remove_plugins = options.remove_plugins || (options.provisioning_profile.nil? ? true : false)
140
+ keychain_path = options.keychain_path || nil
141
+ output_path = options.output_path || ask_for_output_ipa_path
142
+
143
+ if options.provisioning_name
144
+ puts "The provisioning_name (-n) option is not applicable to resign. You should use provisioning_profile (-p) instead".yellow
145
+ end
146
+
147
+ return ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, remove_plugins, keychain_path, output_path
148
+ end
149
+
150
+ def ask_for_signing_identity
151
+ descriptions = []
152
+ installed_identities.group_by { |sha1, name| name }.each do |name, identities|
153
+ descriptions << name
154
+ # Show SHA-1 for homonymous identities
155
+ descriptions += identities.map do |sha1, _|
156
+ "\t#{sha1}"
157
+ end
158
+ end
159
+ puts "Available identities: \n\t#{descriptions.join("\n\t")}\n"
160
+ self.input('Signing Identity: ')
161
+ end
162
+
163
+ # Hash of available signing identities
164
+ def installed_identities
165
+ available = `security find-identity -v -p codesigning`
166
+ ids = {}
167
+ available.split("\n").each do |current|
168
+ begin
169
+ sha1 = current.match(/[a-zA-Z0-9]{40}/).to_s
170
+ name = current.match(/.*\"(.*)\"/)[1]
171
+ ids[sha1] = name
172
+ rescue
173
+ nil
174
+ end # the last line does not match
175
+ end
176
+
177
+ ids
178
+ end
179
+
180
+ def ask_for_output_ipa_path
181
+ output_path = self.input('Output path to ipa file: ')
182
+ unless output_path.end_with?('.ipa')
183
+ puts "Output path to ipa file error.".yellow
184
+ return nil
185
+ end
186
+ output_path
187
+ end
188
+
189
+ def input(message)
190
+ print "#{message}".red
191
+ STDIN.gets.chomp.strip
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,31 @@
1
+
2
+ module ResignTool
3
+ class Command
4
+ class Cert < Command
5
+ self.summary = "列出本机安装的所有证书信息"
6
+ self.description = '列出本机安装的所有证书信息'
7
+ self.command = "cert"
8
+ self.abstract_command = false
9
+ self.arguments = [
10
+ ]
11
+ def self.options
12
+ [
13
+ ["--valid", "输出有效证书"],
14
+ ["--codesigning", "只输出用于iOS签名的证书信息"]
15
+ ]
16
+ end
17
+ def initialize(argv)
18
+ @valid = argv.flag?("valid", true)
19
+ @codesigning = argv.flag?("codesigning", false)
20
+ super
21
+ end
22
+ def validate!
23
+ super
24
+ end
25
+ def run
26
+ command = 'security find-identity' << (@valid ? ' -v' : '') << (@codesigning ? ' -p codesigning' : '')
27
+ exec "#{command}"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,80 @@
1
+ module ResignTool
2
+ class Command
3
+ class Provisioning < Command
4
+ self.summary = '展示和清除本机安装的描述文件'
5
+ self.description = '展示和清除本机安装的描述文件'
6
+ self.command = 'provisioning'
7
+ self.arguments = [
8
+ CLAide::Argument.new('Provisioning Profiles Path', false)
9
+ ]
10
+ def self.options
11
+ [
12
+ ["--list", "列出本机安装的所有描述文件"],
13
+ ["--clean", "清除本机已安装的所有描述文件"]
14
+ ]
15
+ end
16
+
17
+ def initialize(argv)
18
+ @list = argv.flag?("list", true)
19
+ @clean = argv.flag?("clean", false)
20
+
21
+ @profile_path = argv.shift_argument || "~/Library/MobileDevice/Provisioning\ Profiles/"
22
+ super
23
+ end
24
+
25
+ def validate!
26
+ super
27
+ end
28
+
29
+ def run
30
+ @profile_path = File.expand_path(@profile_path)
31
+ if !File.exist?(@profile_path)
32
+ puts "没有找到`mobile provision`的安装路径, #{@profile_path}"
33
+ return
34
+ end
35
+
36
+ if @clean
37
+ clean_pp
38
+ else
39
+ find_pp
40
+ end
41
+ end
42
+
43
+ private
44
+ def clean_pp
45
+ FileUtils.chdir(@profile_path)
46
+
47
+ Dir.glob("*.mobileprovision").each do |file|
48
+ FileUtils.rm_rf(file)
49
+ end
50
+ puts "mobileprovision files clean success"
51
+ end
52
+
53
+ def find_pp
54
+ FileUtils.chdir(@profile_path)
55
+
56
+ index = 0
57
+ Dir.glob("*.mobileprovision").each do |file|
58
+ name = print_pp_info("Name", file)
59
+ identifier = print_pp_info("Entitlements:application-identifier", file)
60
+ uuid = print_pp_info("UUID", file) || ''
61
+ team_name = print_pp_info("TeamName", file) || ''
62
+ create_date = print_pp_info("CreationDate", file) || ''
63
+ expiration_date = print_pp_info("ExpirationDate", file) || ''
64
+
65
+ puts "#{index += 1})".red " #{name}".green
66
+ puts " application-identifier: ".yellow "#{identifier}".green
67
+ puts " UUID: ".yellow "#{uuid}".green
68
+ puts " TeamName: ".yellow "#{team_name}".green
69
+ puts " CreationDate: ".yellow "#{create_date}".green
70
+ puts " ExpirationDate: ".yellow "#{expiration_date}".green
71
+ end
72
+ end
73
+
74
+ def print_pp_info(name, file)
75
+ command = "/usr/libexec/PlistBuddy -c 'Print :#{name}' /dev/stdin <<< $(security cms -D -u 11 -i #{file})"
76
+ `#{command}`.lines.to_a.first.strip! || ''
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,33 @@
1
+ require 'claide'
2
+ require 'colored2'
3
+ require 'version'
4
+
5
+ module ResignTool
6
+ class Command < CLAide::Command
7
+ self.summary = "iOS重签名"
8
+ self.description = 'ipa包重签名信息查看,证书、描述文件等'
9
+ self.command = "resigntool"
10
+ self.abstract_command = true
11
+ def self.options
12
+ [
13
+ ["--version", "Show sign tool version"]
14
+ ]
15
+ end
16
+ def initialize(argv)
17
+ @version = argv.flag?("version", false)
18
+ super
19
+ end
20
+ def validate!
21
+ if @version
22
+ puts "#{Resignios::VERSION}"
23
+ return
24
+ end
25
+ super
26
+ end
27
+ def run
28
+ end
29
+ end
30
+ end
31
+
32
+ require_relative 'command/cert'
33
+ require_relative 'command/provisioning'
data/lib/version.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resignios
4
+ VERSION = "0.1.1"
5
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resignios
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Cary
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-09-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: claide
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.2
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '2.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 1.0.2
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: colored2
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.1'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.1'
47
+ - !ruby/object:Gem::Dependency
48
+ name: commander
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: shellwords
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ description: iOS重签名工具,基于fastlane sigh命令做了些许修改
76
+ email:
77
+ - guojiashuang@live.com
78
+ executables:
79
+ - resigntool
80
+ - resign
81
+ - resignios
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - CHANGELOG.md
86
+ - LICENSE.txt
87
+ - README.md
88
+ - bin/resign
89
+ - bin/resignios
90
+ - bin/resigntool
91
+ - lib/assets/resign.sh
92
+ - lib/resign/commands_generator.rb
93
+ - lib/resign/resign.rb
94
+ - lib/tool/command/cert.rb
95
+ - lib/tool/command/provisioning.rb
96
+ - lib/tool/resigntool.rb
97
+ - lib/version.rb
98
+ homepage: https://github.com/CaryGo/resignios
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 2.6.0
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubygems_version: 3.1.2
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: iOS重签名工具,基于fastlane sigh命令做了些许修改
121
+ test_files: []