[CodeSign] Improve cert finding by only checking codesign identities.

Also move the logic out into a separate util module.

Fixes http://hipbyte.myjetbrains.com/youtrack/issue/RM-399.
This commit is contained in:
Eloy Durán
2014-02-27 13:56:58 +01:00
parent 9183b059fc
commit 0b2a392f98
12 changed files with 218 additions and 10 deletions

View File

@@ -21,9 +21,11 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'motion/project/app'
module Motion; module Project
class Config
include Rake::DSL if Rake.const_defined?(:DSL)
include Rake::DSL if defined?(Rake) && Rake.const_defined?(:DSL)
VARS = []

View File

@@ -21,6 +21,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'motion/project/config'
require 'motion/util/code_sign'
module Motion; module Project;
class XcodeConfig < Config
variable :xcode_dir, :sdk_version, :deployment_target, :frameworks,
@@ -47,7 +50,7 @@ module Motion; module Project;
xcode_dot_app_path = '/Applications/Xcode.app/Contents/Developer'
# First, honor /usr/bin/xcode-select
xcodeselect = '/usr/bin/xcode-select'
xcodeselect = '/usr/bin/xcode-select'
if File.exist?(xcodeselect)
path = `#{xcodeselect} -print-path`.strip
if path.match(/^\/Developer\//) and File.exist?(xcode_dot_app_path)
@@ -331,14 +334,15 @@ EOS
def codesign_certificate(platform)
@codesign_certificate ||= begin
cert_type = (distribution_mode ? 'Distribution' : 'Developer')
certs = `/usr/bin/security -q find-certificate -a`.scan(/"#{platform} #{cert_type}: [^"]+"/).uniq
certs = Util::CodeSign.identity_names(release?).grep(/#{platform} #{cert_type}/)
if certs.size == 0
App.fail "Cannot find any #{platform} #{cert_type} certificate in the keychain"
elsif certs.size > 1
App.warn "Found #{certs.size} #{platform} #{cert_type} certificates in the keychain. Set the `codesign_certificate' project setting. Will use the first certificate: `#{certs[0]}'"
# TODO list all the values for the user's convenience.
App.warn "Found #{certs.size} #{platform} #{cert_type} certificates in the keychain. Set the `codesign_certificate' project setting to explicitely use one of (defaults to the first): #{certs.join(', ')}"
end
certs[0][1..-2] # trim trailing `"` characters
end
certs.first
end
end
def gen_bridge_metadata(platform, headers, bs_file, c_flags, exceptions=[])

View File

@@ -0,0 +1,33 @@
module Motion; module Util
module CodeSign
class << self
# @param Boolean valid_only Whether or not to include only valid code
# sign identities.
#
# @returns String The raw output from querying the `security` DB.
#
def query_security_db_for_identities(valid_only)
`/usr/bin/security -q find-identity -p codesigning#{' -v' if valid_only}`.strip
end
# @param Boolean valid_only Whether or not to include only valid code
# sign identities.
#
# @returns Hash{String => String} The UUIDs and names of the identities.
#
def identities(valid_only)
output = query_security_db_for_identities(valid_only)
Hash[*output.scan(/([0-9A-F]{40})\s"(.+?)"/).flatten]
end
# @param Boolean valid_only Whether or not to include only valid code
# sign identities.
#
# @returns Array<String> The names of the identities.
#
def identity_names(valid_only)
identities(valid_only).values
end
end
end
end; end

5
test/external/Gemfile vendored Normal file
View File

@@ -0,0 +1,5 @@
source 'https://rubygems.org'
gem 'bacon'
gem 'mocha'
gem 'mocha-on-bacon'

17
test/external/Gemfile.lock vendored Normal file
View File

@@ -0,0 +1,17 @@
GEM
remote: https://rubygems.org/
specs:
bacon (1.2.0)
metaclass (0.0.4)
mocha (1.0.0)
metaclass (~> 0.0.1)
mocha-on-bacon (0.2.2)
mocha (>= 0.13.0)
PLATFORMS
ruby
DEPENDENCIES
bacon
mocha
mocha-on-bacon

View File

@@ -1,6 +1,6 @@
desc "Run all tests"
task :spec do
sh "bacon **/*_spec.rb"
sh "bundle exec bacon #{FileList['**/*_spec.rb'].join(' ')}"
end
task :default => :spec

7
test/external/spec_helper.rb vendored Normal file
View File

@@ -0,0 +1,7 @@
require 'bacon'
require 'mocha'
require 'mocha-on-bacon'
$:.unshift File.expand_path('../../../lib', __FILE__)
Mocha::Configuration.prevent(:stubbing_non_existent_method)

View File

@@ -0,0 +1,49 @@
require File.expand_path('../../../spec_helper', __FILE__)
require 'motion/project/xcode_config'
require 'tempfile'
module Motion; module Project
describe XcodeConfig do
describe "concerning codesign certificates" do
before do
Util::CodeSign.stubs(:identity_names).with(false).returns([
'iPhone Developer: Eloy Duran (K5B8YH2WD5)',
'Mac Developer Self-Signed for Eloy Durán',
'Mac Developer: Eloy Duran (K5B8YH2WD5)',
])
App.stubs(:warn)
@config = XcodeConfig.new(Dir.tmpdir, :development)
end
it "selects an identity meant for codesigning iPhone apps" do
@config.codesign_certificate('iPhone').should == 'iPhone Developer: Eloy Duran (K5B8YH2WD5)'
end
it "selects an identity meant for codesigning Mac apps" do
@config.codesign_certificate('Mac').should == 'Mac Developer Self-Signed for Eloy Durán'
end
it "warns when there are multiple matching identities" do
App.expects(:warn)
@config.codesign_certificate('Mac')
end
it "fails when there no identities could be found" do
App.expects(:fail)
@config.codesign_certificate('Android')
end
it "limits identities to valid ones in release mode" do
Util::CodeSign.stubs(:identity_names).with(true).returns([
'iPhone Developer: Eloy Duran (K5B8YH2WD5)',
'Mac Developer: Eloy Duran (K5B8YH2WD5)',
])
@config.instance_variable_set(:@build_mode, :release)
@config.codesign_certificate('Mac').should == 'Mac Developer: Eloy Duran (K5B8YH2WD5)'
end
end
end
end; end

View File

@@ -0,0 +1,91 @@
require File.expand_path('../../../spec_helper', __FILE__)
require 'motion/util/code_sign'
module SpecHelper
module Fixtures
NO_CODESIGN_IDENTITIES = <<-EOS
Policy: Code Signing
Matching identities
0 identities found
EOS
ALL_CODESIGN_IDENTITIES = <<-EOS
Policy: Code Signing
Matching identities
1) 5DD1D0DB197456F156D58D0F176200FB18840923 "Developer ID Application: Fingertips B.V."
2) 689D97626D58D0F11F26AE048CBAD0FFB53545C9 "iPhone Developer: Eloy Duran (K5B8YH2WD5)"
3) 01D976265D06F156D585560DB19740AD053C1162 "Mac Developer Self-Signed for Eloy Durán" (CSSMERR_TP_INVALID_ANCHOR_CERT)
3 identities found
Valid identities only
1) 5DD1D0DB197456F156D58D0F176200FB18840923 "Developer ID Application: Fingertips B.V."
2) 689D97626D58D0F11F26AE048CBAD0FFB53545C9 "iPhone Developer: Eloy Duran (K5B8YH2WD5)"
2 valid identities found
EOS
VALID_CODESIGN_IDENTITIES = <<-EOS
1) 5DD1D0DB197456F156D58D0F176200FB18840923 "Developer ID Application: Fingertips B.V."
2) 689D97626D58D0F11F26AE048CBAD0FFB53545C9 "iPhone Developer: Eloy Duran (K5B8YH2WD5)"
2 valid identities found
EOS
end
end
module Motion; module Util
describe CodeSign do
it "queries the security database for all codesigning identities" do
CodeSign.expects(:`).with('/usr/bin/security -q find-identity -p codesigning').returns(' ALL ')
CodeSign.query_security_db_for_identities(false).should == 'ALL'
end
it "queries the security database for valid codesigning identities" do
CodeSign.expects(:`).with('/usr/bin/security -q find-identity -p codesigning -v').returns(' VALID ')
CodeSign.query_security_db_for_identities(true).should == 'VALID'
end
it "returns an empty list if there are no codesigning identities" do
CodeSign.stubs(:query_security_db_for_identities).returns(SpecHelper::Fixtures::NO_CODESIGN_IDENTITIES)
CodeSign.identities(false).should == {}
end
before do
CodeSign.stubs(:query_security_db_for_identities).with(false).returns(SpecHelper::Fixtures::ALL_CODESIGN_IDENTITIES)
CodeSign.stubs(:query_security_db_for_identities).with(true).returns(SpecHelper::Fixtures::VALID_CODESIGN_IDENTITIES)
end
it "returns all codesign identities" do
CodeSign.identities(false).should == {
'5DD1D0DB197456F156D58D0F176200FB18840923' => 'Developer ID Application: Fingertips B.V.',
'689D97626D58D0F11F26AE048CBAD0FFB53545C9' => 'iPhone Developer: Eloy Duran (K5B8YH2WD5)',
'01D976265D06F156D585560DB19740AD053C1162' => 'Mac Developer Self-Signed for Eloy Durán',
}
end
it "returns only valid identities" do
CodeSign.identities(true).should == {
'5DD1D0DB197456F156D58D0F176200FB18840923' => 'Developer ID Application: Fingertips B.V.',
'689D97626D58D0F11F26AE048CBAD0FFB53545C9' => 'iPhone Developer: Eloy Duran (K5B8YH2WD5)',
}
end
it "returns all codesign identity names" do
CodeSign.identity_names(false).should == [
'Developer ID Application: Fingertips B.V.',
'iPhone Developer: Eloy Duran (K5B8YH2WD5)',
'Mac Developer Self-Signed for Eloy Durán',
]
end
it "returns only valid identity names" do
CodeSign.identity_names(true).should == [
'Developer ID Application: Fingertips B.V.',
'iPhone Developer: Eloy Duran (K5B8YH2WD5)',
]
end
end
end; end

View File

@@ -1,6 +1,4 @@
require 'bacon'
$:.unshift File.expand_path('../../../../lib', __FILE__)
require File.expand_path('../../../spec_helper', __FILE__)
require 'motion/util/version'
module Motion; module Util

View File

@@ -107,3 +107,4 @@ ReturnsIntBlock KreateGlobalBlock();
- (BOOL)isEqualTo:(id)other;
@end
#endif

View File

@@ -209,3 +209,4 @@ void _objc_insert_tagged_isa(unsigned char slotNumber, Class isa);
@end
#endif