import fs = require ( 'fs' ) ; import tl = require ( 'azure-pipelines-task-lib/task' ) ; import { ToolRunner } from 'azure-pipelines-task-lib/toolrunner' ; let userProvisioningProfilesPath = tl . resolve ( tl . getVariable ( 'HOME' ) , 'Library' , 'MobileDevice' , 'Provisioning Profiles' ) ; param keychainPath param keychainPwd param p12CertPath param p12Pwd export async function installCertInTemporaryKeychain ( keychainPath , keychainPwd , p12CertPath , p12Pwd ) { await deleteKeychain ( keychainPath ) ; let createKeychainCommand = tl . tool ( tl . which ( 'security' , true ) ) ; createKeychainCommand . arg ( [ 'create-keychain' , '-p' , keychainPwd , keychainPath ] ) ; await createKeychainCommand . exec ( ) ; let keychainSettingsCommand = tl . tool ( tl . which ( 'security' , true ) ) ; keychainSettingsCommand . arg ( [ 'set-keychain-settings' , '-lut' , '7200' , keychainPath ] ) ; await keychainSettingsCommand . exec ( ) ; await unlockKeychain ( keychainPath , keychainPwd ) ; let importP12Command = tl . tool ( tl . which ( 'security' , true ) ) ; importP12Command . arg ( [ 'import' , p12CertPath , '-P' , p12Pwd , '-A' , '-t' , 'cert' , '-f' , 'pkcs12' , '-k' , keychainPath ] ) ; await importP12Command . exec ( ) ; let listAllOutput ; let listAllCommand = tl . tool ( tl . which ( 'security' , true ) ) ; listAllCommand . arg ( [ 'list-keychain' , '-d' , 'user' ] ) ; listAllCommand . on ( 'stdout' , function ( data ) { if ( data ) { if ( listAllOutput ) { listAllOutput = listAllOutput . concat ( data . toString ( ) . trim ( ) ) ; } else { listAllOutput = data . toString ( ) . trim ( ) ; } } } ) ; await listAllCommand . exec ( ) ; let allKeychainsArr = [ ] ; tl . debug ( 'listAllOutput = ' + listAllOutput ) ; if ( listAllOutput ) { allKeychainsArr = listAllOutput . split ( /[\n\r\f\v]/gm ) ; } if ( ! listAllOutput || listAllOutput . indexOf ( 'login.keychain' ) < 0 ) { allKeychainsArr . push ( tl . resolve ( tl . getVariable ( 'HOME' ) , 'Library' , 'Keychains' , 'login.keychain' ) ) ; } let listAddCommand = tl . tool ( tl . which ( 'security' , true ) ) ; listAddCommand . arg ( [ 'list-keychain' , '-d' , 'user' , '-s' , keychainPath ] ) ; for ( let i = 0 ; i < allKeychainsArr . length ; i ++ ) { listAddCommand . arg ( allKeychainsArr [ i ] . trim ( ) . replace ( /"/gm , '' ) ) ; } await listAddCommand . exec ( ) ; let listVerifyOutput ; let listVerifyCommand = tl . tool ( tl . which ( 'security' , true ) ) ; listVerifyCommand . arg ( [ 'list-keychain' , '-d' , 'user' ] ) ; listVerifyCommand . on ( 'stdout' , function ( data ) { if ( data ) { if ( listVerifyOutput ) { listVerifyOutput = listVerifyOutput . concat ( data . toString ( ) . trim ( ) ) ; } else { listVerifyOutput = data . toString ( ) . trim ( ) ; } } } ) ; await listVerifyCommand . exec ( ) ; if ( listVerifyOutput . indexOf ( keychainPath ) < 0 ) { throw tl . loc ( 'TempKeychainSetupFailed' ) ; } } param keychainPath returns { string } export async function findSigningIdentity ( keychainPath ) { let signIdentity ; let findIdentityCmd = tl . tool ( tl . which ( 'security' , true ) ) ; findIdentityCmd . arg ( [ 'find-identity' , '-v' , '-p' , 'codesigning' , keychainPath ] ) ; findIdentityCmd . on ( 'stdout' , function ( data ) { if ( data ) { let matches = data . toString ( ) . trim ( ) . match ( /"(.+)"/g ) ; tl . debug ( 'signing identity data = ' + matches ) ; if ( matches && matches [ 0 ] ) { signIdentity = matches [ 0 ] . replace ( /"/gm , '' ) ; tl . debug ( 'signing identity data trimmed = ' + signIdentity ) ; } } } ) ; await findIdentityCmd . exec ( ) ; if ( signIdentity ) { tl . debug ( 'findSigningIdentity = ' + signIdentity ) ; return signIdentity ; } else { throw tl . loc ( 'SignIdNotFound' ) ; } } param provProfilePath returns { string } export async function getProvisioningProfileUUID ( provProfilePath ) { let provProfileDetails ; let getProvProfileDetailsCmd = tl . tool ( tl . which ( 'security' , true ) ) ; getProvProfileDetailsCmd . arg ( [ 'cms' , '-D' , '-i' , provProfilePath ] ) ; getProvProfileDetailsCmd . on ( 'stdout' , function ( data ) { if ( data ) { if ( provProfileDetails ) { provProfileDetails = provProfileDetails . concat ( data . toString ( ) . trim ( ) . replace ( /[,\n\r\f\v]/gm , '' ) ) ; } else { provProfileDetails = data . toString ( ) . trim ( ) . replace ( /[,\n\r\f\v]/gm , '' ) ; } } } ) ; await getProvProfileDetailsCmd . exec ( ) ; let tmpPlist ; if ( provProfileDetails ) { tmpPlist = '_xcodetasktmp.plist' ; fs . writeFileSync ( tmpPlist , provProfileDetails ) ; } else { throw tl . loc ( 'ProvProfileDetailsNotFound' , provProfilePath ) ; } let provProfileUUID ; let plist = tl . which ( '/usr/libexec/PlistBuddy' , true ) ; let plistTool = tl . tool ( plist ) ; plistTool . arg ( [ '-c' , 'Print UUID' , tmpPlist ] ) ; plistTool . on ( 'stdout' , function ( data ) { if ( data ) { provProfileUUID = data . toString ( ) ; } } ) ; await plistTool . exec ( ) ; let deletePlistCommand = tl . tool ( tl . which ( 'rm' , true ) ) ; deletePlistCommand . arg ( [ '-f' , tmpPlist ] ) ; await deletePlistCommand . exec ( ) ; if ( provProfileUUID ) { tl . mkdirP ( userProvisioningProfilesPath ) ; let pathToProvProfile = getProvisioningProfilePath ( provProfileUUID ) ; let copyProvProfileCmd = tl . tool ( tl . which ( 'cp' , true ) ) ; copyProvProfileCmd . arg ( [ '-f' , provProfilePath , pathToProvProfile ] ) ; await copyProvProfileCmd . exec ( ) ; return provProfileUUID ; } else { throw tl . loc ( 'ProvProfileUUIDNotFound' , provProfilePath ) ; } } param provProfilePath returns { string } export async function getProvisioningProfileType ( provProfilePath ) { let provProfileType ; try { let provProfileDetails ; let getProvProfileDetailsCmd = tl . tool ( tl . which ( 'security' , true ) ) ; getProvProfileDetailsCmd . arg ( [ 'cms' , '-D' , '-i' , provProfilePath ] ) ; getProvProfileDetailsCmd . on ( 'stdout' , function ( data ) { if ( data ) { if ( provProfileDetails ) { provProfileDetails = provProfileDetails . concat ( data . toString ( ) . trim ( ) . replace ( /[,\n\r\f\v]/gm , '' ) ) ; } else { provProfileDetails = data . toString ( ) . trim ( ) . replace ( /[,\n\r\f\v]/gm , '' ) ; } } } ) ; await getProvProfileDetailsCmd . exec ( ) ; let tmpPlist ; if ( provProfileDetails ) { tmpPlist = '_xcodetasktmp.plist' ; fs . writeFileSync ( tmpPlist , provProfileDetails ) ; } else { throw tl . loc ( 'ProvProfileDetailsNotFound' , provProfilePath ) ; } let provisionsAllDevices = await printFromPlist ( 'ProvisionsAllDevices' , tmpPlist ) ; tl . debug ( 'provisionsAllDevices = ' + provisionsAllDevices ) ; if ( provisionsAllDevices && provisionsAllDevices . toLowerCase ( ) === 'true' ) { provProfileType = 'enterprise' ; } else { let getTaskAllow = await printFromPlist ( 'Entitlements:get-task-allow' , tmpPlist ) ; tl . debug ( 'getTaskAllow = ' + getTaskAllow ) ; if ( getTaskAllow && getTaskAllow . trim ( ) . toLowerCase ( ) === 'true' ) { provProfileType = 'development' ; } else { let provisionedDevices = await printFromPlist ( 'ProvisionedDevices' , tmpPlist ) ; if ( ! provisionedDevices ) { provProfileType = 'app-store' ; } else { provProfileType = 'ad-hoc' ; } } } let deletePlistCommand = tl . tool ( tl . which ( 'rm' , true ) ) ; deletePlistCommand . arg ( [ '-f' , tmpPlist ] ) ; await deletePlistCommand . exec ( ) ; } catch ( err ) { tl . debug ( err ) ; } return provProfileType ; } async function printFromPlist ( itemToPrint , plistPath ) { let plist = tl . which ( '/usr/libexec/PlistBuddy' , true ) ; let plistTool = tl . tool ( plist ) ; plistTool . arg ( [ '-c' , 'Print ' + itemToPrint , plistPath ] ) ; let printedValue ; plistTool . on ( 'stdout' , function ( data ) { if ( data ) { printedValue = data . toString ( ) ; } } ) ; try { await plistTool . exec ( ) ; } catch ( err ) { tl . debug ( 'Exception when looking for ' + itemToPrint + ' in plist.' ) ; printedValue = null ; } return printedValue ; } param keychainPath export async function deleteKeychain ( keychainPath ) { if ( fs . existsSync ( keychainPath ) ) { let deleteKeychainCommand = tl . tool ( tl . which ( 'security' , true ) ) ; deleteKeychainCommand . arg ( [ 'delete-keychain' , keychainPath ] ) ; await deleteKeychainCommand . exec ( ) ; } } param keychainPath param keychainPwd export async function unlockKeychain ( keychainPath , keychainPwd ) { let unlockCommand = tl . tool ( tl . which ( 'security' , true ) ) ; unlockCommand . arg ( [ 'unlock-keychain' , '-p' , keychainPwd , keychainPath ] ) ; await unlockCommand . exec ( ) ; } param uuid export async function deleteProvisioningProfile ( uuid ) { let provProfilePath = getProvisioningProfilePath ( uuid ) ; tl . warning ( 'Deleting provisioning profile: ' + provProfilePath ) ; if ( fs . existsSync ( provProfilePath ) ) { tl . warning ( 'Deleting provisioning profile: ' + provProfilePath ) ; let deleteProfileCommand = tl . tool ( tl . which ( 'rm' , true ) ) ; deleteProfileCommand . arg ( [ '-f' , provProfilePath ] ) ; await deleteProfileCommand . exec ( ) ; } } export function getProvisioningProfilePath ( uuid ) { return tl . resolve ( userProvisioningProfilesPath , uuid . trim ( ) . concat ( '.mobileprovision' ) ) ; } /**
 * Gets the path to the iOS default keychain
 */ export async function getDefaultKeychainPath ( ) { let defaultKeychainPath ; let getKeychainCmd = tl . tool ( tl . which ( 'security' , true ) ) ; getKeychainCmd . arg ( 'default-keychain' ) ; getKeychainCmd . on ( 'stdout' , function ( data ) { if ( data ) { defaultKeychainPath = data . toString ( ) . trim ( ) . replace ( /[",\n\r\f\v]/gm , '' ) ; } } ) ; await getKeychainCmd . exec ( ) ; return defaultKeychainPath ; }