Class: Sigh::Resign

Inherits:
Object
  • Object
show all
Defined in:
sigh/lib/sigh/resign.rb

Overview

Resigns an existing ipa file

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.resign(ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, keychain_path) ⇒ Object


18
19
20
# File 'sigh/lib/sigh/resign.rb', line 18

def self.resign(ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, keychain_path)
  self.new.resign(ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, keychain_path)
end

Instance Method Details

#ask_for_signing_identityObject


166
167
168
169
# File 'sigh/lib/sigh/resign.rb', line 166

def ask_for_signing_identity
  print_available_identities
  UI.input('Signing Identity: ')
end

#create_provisioning_options(provisioning_profiles) ⇒ Object


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'sigh/lib/sigh/resign.rb', line 120

def create_provisioning_options(provisioning_profiles)
  # provisioning_profiles is passed either a hash (to be able to resign extensions/nested apps):
  # (in that case the underlying resign.sh expects values given as "-p at.fastlane=/folder/mobile.mobileprovision -p at.fastlane.today=/folder/mobile.mobileprovision")
  #   {
  #     "at.fastlane" => "/folder/mobile.mobileprovision",
  #     "at.fastlane.today" => "/folder/mobile.mobileprovision"
  #   }
  # or an array
  # (resign.sh also takes "-p /folder/mobile.mobileprovision" as a param)
  #   [
  #        "/folder/mobile.mobileprovision"
  #   ]
  provisioning_profiles.map do |app_id, app_id_prov|
    if app_id_prov
      app_id_prov = File.expand_path(app_id_prov)
    else
      app_id = File.expand_path(app_id)
    end
    "-p #{[app_id, app_id_prov].compact.map(&:shellescape).join('=')}"
  end.join(' ')
end

#find_ipaObject


97
98
99
# File 'sigh/lib/sigh/resign.rb', line 97

def find_ipa
  Dir[File.join(Dir.pwd, '*.ipa')].sort { |a, b| File.mtime(a) <=> File.mtime(b) }.first
end

#find_provisioning_profileObject


101
102
103
# File 'sigh/lib/sigh/resign.rb', line 101

def find_provisioning_profile
  Dir[File.join(Dir.pwd, '*.mobileprovision')].sort { |a, b| File.mtime(a) <=> File.mtime(b) }.first
end

#find_resign_pathObject


93
94
95
# File 'sigh/lib/sigh/resign.rb', line 93

def find_resign_path
  File.join(Sigh::ROOT, 'lib', 'assets', 'resign.sh')
end

#find_signing_identity(signing_identity) ⇒ Object


105
106
107
108
109
110
111
112
# File 'sigh/lib/sigh/resign.rb', line 105

def find_signing_identity(signing_identity)
  until (signing_identity = sha1_for_signing_identity(signing_identity))
    UI.error("Couldn't find signing identity '#{signing_identity}'.")
    signing_identity = ask_for_signing_identity
  end

  signing_identity
end

#get_inputs(options, args) ⇒ Object


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'sigh/lib/sigh/resign.rb', line 73

def get_inputs(options, args)
  ipa = args.first || find_ipa || UI.input('Path to ipa file: ')
  signing_identity = options.signing_identity || ask_for_signing_identity
  provisioning_profiles = options.provisioning_profile || find_provisioning_profile || UI.input('Path to provisioning file: ')
  entitlements = options.entitlements || nil
  version = options.version_number || nil
  display_name = options.display_name || nil
  short_version = options.short_version || nil
  bundle_version = options.bundle_version || nil
  new_bundle_id = options.new_bundle_id || nil
  use_app_entitlements = options.use_app_entitlements || nil
  keychain_path = options.keychain_path || nil

  if options.provisioning_name
    UI.important("The provisioning_name (-n) option is not applicable to resign. You should use provisioning_profile (-p) instead")
  end

  return ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, keychain_path
end

#installed_identitiesObject

Hash of available signing identities


172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'sigh/lib/sigh/resign.rb', line 172

def installed_identities
  available = request_valid_identities
  ids = {}
  available.split("\n").each do |current|
    begin
      sha1 = current.match(/[a-zA-Z0-9]{40}/).to_s
      name = current.match(/.*\"(.*)\"/)[1]
      ids[sha1] = name
    rescue
      nil
    end # the last line does not match
  end

  ids
end

#installed_identity_descriptionsObject


192
193
194
195
196
197
198
199
200
201
202
# File 'sigh/lib/sigh/resign.rb', line 192

def installed_identity_descriptions
  descriptions = []
  installed_identities.group_by { |sha1, name| name }.each do |name, identities|
    descriptions << name
    # Show SHA-1 for homonymous identities
    descriptions += identities.map do |sha1, _|
      "\t#{sha1}"
    end
  end
  descriptions
end

162
163
164
# File 'sigh/lib/sigh/resign.rb', line 162

def print_available_identities
  UI.message("Available identities: \n\t#{installed_identity_descriptions.join("\n\t")}\n")
end

#request_valid_identitiesObject


188
189
190
# File 'sigh/lib/sigh/resign.rb', line 188

def request_valid_identities
  `security find-identity -v -p codesigning`
end

#resign(ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, keychain_path) ⇒ Object


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'sigh/lib/sigh/resign.rb', line 22

def resign(ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, keychain_path)
  resign_path = find_resign_path
  signing_identity = find_signing_identity(signing_identity)

  unless provisioning_profiles.kind_of?(Enumerable)
    provisioning_profiles = [provisioning_profiles]
  end

  # 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
  validate_params(resign_path, ipa, provisioning_profiles)
  entitlements = "-e #{entitlements.shellescape}" if entitlements

  provisioning_options = create_provisioning_options(provisioning_profiles)
  version = "-n #{version}" if version
  display_name = "-d #{display_name.shellescape}" if display_name
  short_version = "--short-version #{short_version}" if short_version
  bundle_version = "--bundle-version #{bundle_version}" if bundle_version
  verbose = "-v" if FastlaneCore::Globals.verbose?
  bundle_id = "-b '#{new_bundle_id}'" if new_bundle_id
  use_app_entitlements_flag = "--use-app-entitlements" if use_app_entitlements
  specific_keychain = "--keychain-path #{keychain_path.shellescape}" if keychain_path

  command = [
    resign_path.shellescape,
    ipa.shellescape,
    signing_identity.shellescape,
    provisioning_options, # we are aleady shellescaping this above, when we create the provisioning_options from the provisioning_profiles
    entitlements,
    version,
    display_name,
    short_version,
    bundle_version,
    use_app_entitlements_flag,
    verbose,
    bundle_id,
    specific_keychain,
    ipa.shellescape # Output path must always be last argument
  ].join(' ')

  puts(command.magenta)
  puts(`#{command}`)

  if $?.to_i == 0
    UI.success("Successfully signed #{ipa}!")
    true
  else
    UI.error("Something went wrong while code signing #{ipa}")
    false
  end
end

#run(options, args) ⇒ Object


9
10
11
12
13
14
15
16
# File 'sigh/lib/sigh/resign.rb', line 9

def run(options, args)
  # get the command line inputs and parse those into the vars we need...
  ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, keychain_path = get_inputs(options, args)
  # ... then invoke our programmatic interface with these vars
  unless resign(ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, keychain_path)
    UI.user_error!("Failed to re-sign .ipa")
  end
end

#sha1_for_signing_identity(signing_identity) ⇒ Object


114
115
116
117
118
# File 'sigh/lib/sigh/resign.rb', line 114

def sha1_for_signing_identity(signing_identity)
  identities = installed_identities
  return signing_identity if identities.keys.include?(signing_identity)
  identities.key(signing_identity)
end

#validate_ipa_file(ipa) ⇒ Object


152
153
154
# File 'sigh/lib/sigh/resign.rb', line 152

def validate_ipa_file(ipa)
  UI.user_error!("ipa file could not be found or is not an ipa file (#{ipa})") unless File.exist?(ipa) && ipa.end_with?('.ipa')
end

#validate_params(resign_path, ipa, provisioning_profiles) ⇒ Object


142
143
144
145
146
# File 'sigh/lib/sigh/resign.rb', line 142

def validate_params(resign_path, ipa, provisioning_profiles)
  validate_resign_path(resign_path)
  validate_ipa_file(ipa)
  provisioning_profiles.each { |fst, snd| validate_provisioning_file(snd || fst) }
end

#validate_provisioning_file(provisioning_profile) ⇒ Object


156
157
158
159
160
# File 'sigh/lib/sigh/resign.rb', line 156

def validate_provisioning_file(provisioning_profile)
  unless File.exist?(provisioning_profile) && provisioning_profile.end_with?('.mobileprovision')
    UI.user_error!("Provisioning profile file could not be found or is not a .mobileprovision file (#{provisioning_profile})")
  end
end

#validate_resign_path(resign_path) ⇒ Object


148
149
150
# File 'sigh/lib/sigh/resign.rb', line 148

def validate_resign_path(resign_path)
  UI.user_error!('Could not find resign.sh file. Please try re-installing the gem') unless File.exist?(resign_path)
end