Class: FruityBuilder::IOS::Signing

Inherits:
Execution
  • Object
show all
Defined in:
lib/fruity_builder/signing.rb

Overview

Namespace for all methods encapsulating idevice calls

Constant Summary

Constants inherited from Execution

Execution::COMMAND_RETRIES, Execution::COMMAND_TIMEOUT

Class Method Summary collapse

Methods inherited from Execution

execute, execute_with_timeout_and_retry

Class Method Details

.enable_get_tasks(app_path) ⇒ Object



106
107
108
109
110
111
112
# File 'lib/fruity_builder/signing.rb', line 106

def self.enable_get_tasks(app_path)
  entitlements = get_entitlements(app_path, raw: true)

  return entitlements if entitlements.scan(/<key>get-task-allow<\/key>\\n.*<true\/>/).count > 0

  entitlements.gsub('<false/>', '<true/>') if entitlements.scan(/<key>get-task-allow<\/key>\\n.*<false\/>/)
end

.get_entitlements(app_path, raw = false) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/fruity_builder/signing.rb', line 89

def self.get_entitlements(app_path, raw = false)
  app_path = unpack_ipa(app_path) if is_ipa?(app_path)
  result = execute("codesign -d --entitlements - #{app_path}")

  if result.exit != 0
    raise SigningCommandError.new(result.stderr)
  end

  # Clean up the result as it occasionally contains invalid UTF-8 characters
  xml = result.stdout.to_s.encode('UTF-8', 'UTF-8', invalid: :replace)
  xml = xml[xml.index('<')..xml.length]

  return xml if raw
  entitlements = Plistutil.parse_xml(xml)
  return entitlements
end

.get_signing_certsObject



75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/fruity_builder/signing.rb', line 75

def self.get_signing_certs
  result = execute('security find-identity -p codesigning -v')

  raise SigningCommandError.new(result.stderr) if result.exit != 0

  certs = []
  result.stdout.split("\n").each do |line|
    if /\)\s*(\S*)\s*"(.*)"/.match(line)
      certs << { id: Regexp.last_match[1], name: Regexp.last_match[2] }
    end
  end
  certs
end

.is_app_signed?(app_path) ⇒ Boolean

Returns:

  • (Boolean)


28
29
30
31
32
33
34
35
36
37
38
# File 'lib/fruity_builder/signing.rb', line 28

def self.is_app_signed?(app_path)
  app_path = unpack_ipa(app_path) if is_ipa?(app_path)
  result = execute("codesign -d -vvvv '#{app_path}'")

  if result.exit != 0
    return false if /is not signed/.match(result.stderr)
    raise SigningCommandError.new(result.stderr)
  end

  true
end

.is_ipa?(path) ⇒ Boolean

Check to see if the path is an IPA

Returns:

  • (Boolean)


10
11
12
13
# File 'lib/fruity_builder/signing.rb', line 10

def self.is_ipa?(path)
  return true if (File.extname path).downcase == '.ipa'
  false
end

.sign_app(options = {}) ⇒ Object



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
# File 'lib/fruity_builder/signing.rb', line 40

def self.sign_app(options = {})
  cert          = options[:cert]
  entitlements  = options[:entitlements]
  app           = options[:app]
  original_app  = nil

  if is_ipa?(app)
    original_app = app
    app = unpack_ipa(app)
  end

  command = "codesign --force --sign '#{cert}'"
  # Check to see if the entitlements passed in is a file or the XML
  unless File.exists?(entitlements)
    file = Tempfile.new('entitlements')
    file.write(entitlements)
    file.close
    entitlements = file.path
    command = command + " --entitlements #{entitlements}"
  end

  result = execute(command + " '#{app}'")

  raise SigningCommandError.new(result.stderr) if result.exit != 0

  zip_app(app, original_app) if original_app
end

.unpack_ipa(path) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/fruity_builder/signing.rb', line 15

def self.unpack_ipa(path)
  folder = File.dirname(path)
  target = (File.basename path, (File.extname path))

  # Check to see if the target has already been unzipped
  return Dir["#{folder}/#{target}/Payload/*.app"].first if File.exists? ("#{folder}/#{target}/Payload/")

  result = execute("unzip '#{path}' -d '#{folder}/#{target}'")
  raise SigningCommandError.new(result.stderr) if result.exit != 0

  Dir["#{folder}/#{target}/Payload/*.app"].first
end

.zip_app(payload_path, ipa_path) ⇒ Object



68
69
70
71
72
73
# File 'lib/fruity_builder/signing.rb', line 68

def self.zip_app(payload_path, ipa_path)
  result = execute("cd #{File.dirname(payload_path)}; zip -r #{ipa_path} ../Payload ")
  raise SigningCommandError.new(result.stderr) if result.exit != 0

  true
end