Class: Sigh::Resign

Inherits:
Object
  • Object
show all
Defined in:
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



15
16
17
# File 'lib/sigh/resign.rb', line 15

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



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

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

#create_provisioning_options(provisioning_profiles) ⇒ Object



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

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



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

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

#find_provisioning_profileObject



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

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

#find_resign_pathObject



90
91
92
# File 'lib/sigh/resign.rb', line 90

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

#find_signing_identity(signing_identity) ⇒ Object



102
103
104
105
106
107
108
109
# File 'lib/sigh/resign.rb', line 102

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



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

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



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/sigh/resign.rb', line 169

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



189
190
191
192
193
194
195
196
197
198
199
# File 'lib/sigh/resign.rb', line 189

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


159
160
161
# File 'lib/sigh/resign.rb', line 159

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

#request_valid_identitiesObject



185
186
187
# File 'lib/sigh/resign.rb', line 185

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



19
20
21
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
# File 'lib/sigh/resign.rb', line 19

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 $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,
    ipa.shellescape,
    specific_keychain
  ].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



6
7
8
9
10
11
12
13
# File 'lib/sigh/resign.rb', line 6

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



111
112
113
114
115
# File 'lib/sigh/resign.rb', line 111

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



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

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



139
140
141
142
143
# File 'lib/sigh/resign.rb', line 139

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



153
154
155
156
157
# File 'lib/sigh/resign.rb', line 153

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



145
146
147
# File 'lib/sigh/resign.rb', line 145

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