1# Copyright 2015 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5 6import argparse 7import os 8import subprocess 9import sys 10import re 11 12 13def Redact(value, from_nth_char=5): 14 """Redact value past the N-th character.""" 15 return value[:from_nth_char] + '*' * (len(value) - from_nth_char) 16 17 18class Identity(object): 19 """Represents a valid identity.""" 20 21 def __init__(self, identifier, name, team): 22 self.identifier = identifier 23 self.name = name 24 self.team = team 25 26 def redacted(self): 27 return Identity(Redact(self.identifier), self.name, Redact(self.team)) 28 29 def format(self): 30 return '%s: "%s (%s)"' % (self.identifier, self.name, self.team) 31 32 33def ListIdentities(): 34 return subprocess.check_output([ 35 'xcrun', 36 'security', 37 'find-identity', 38 '-v', 39 '-p', 40 'codesigning', 41 ]).decode('utf8') 42 43 44def FindValidIdentity(pattern): 45 """Find all identities matching the pattern.""" 46 lines = list(l.strip() for l in ListIdentities().splitlines()) 47 # Look for something like 48 # 1) 123ABC123ABC123ABC****** "iPhone Developer: DeveloperName (Team)" 49 regex = re.compile('[0-9]+\) ([A-F0-9]+) "([^"(]*) \(([^)"]*)\)"') 50 51 result = [] 52 for line in lines: 53 res = regex.match(line) 54 if res is None: 55 continue 56 identifier, developer_name, team = res.groups() 57 if pattern is None or pattern in '%s (%s)' % (developer_name, team): 58 result.append(Identity(identifier, developer_name, team)) 59 return result 60 61 62def Main(args): 63 parser = argparse.ArgumentParser('codesign iOS bundles') 64 parser.add_argument('--matching-pattern', 65 dest='pattern', 66 help='Pattern used to select the code signing identity.') 67 parsed = parser.parse_args(args) 68 69 identities = FindValidIdentity(parsed.pattern) 70 if len(identities) == 1: 71 print(identities[0].identifier, end='') 72 return 0 73 74 all_identities = FindValidIdentity(None) 75 76 print('Automatic code signing identity selection was enabled but could not') 77 print('find exactly one codesigning identity matching "%s".' % parsed.pattern) 78 print('') 79 print('Check that the keychain is accessible and that there is exactly one') 80 print('valid codesigning identity matching the pattern. Here is the parsed') 81 print('output of `xcrun security find-identity -v -p codesigning`:') 82 print() 83 for i, identity in enumerate(all_identities): 84 print(' %d) %s' % (i + 1, identity.redacted().format())) 85 print(' %d valid identities found' % (len(all_identities))) 86 return 1 87 88 89if __name__ == '__main__': 90 sys.exit(Main(sys.argv[1:])) 91