From 010637125b556223fbb70f5c8ab49cea07220fe7 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Sun, 20 Sep 2015 01:11:22 -0700 Subject: Add support for entitlements to the code signing process. Change-Id: I14111b46f0b0a864a27b86618ad716b35c074d64 Reviewed-by: Christian Kandeler --- share/qbs/modules/bundle/BundleModule.qbs | 34 +++++++----- share/qbs/modules/cpp/gcc.js | 12 +++-- share/qbs/modules/xcode/xcode.qbs | 89 +++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 17 deletions(-) (limited to 'share/qbs') diff --git a/share/qbs/modules/bundle/BundleModule.qbs b/share/qbs/modules/bundle/BundleModule.qbs index e5b6c414c..414a55222 100644 --- a/share/qbs/modules/bundle/BundleModule.qbs +++ b/share/qbs/modules/bundle/BundleModule.qbs @@ -400,8 +400,9 @@ Module { condition: qbs.targetOS.contains("darwin") multiplex: true inputs: ["infoplist", "pkginfo", "hpp", - "icns", "resourcerules", - "compiled_ibdoc", "compiled_assetcatalog"] + "icns", "resourcerules", "xcent", + "compiled_ibdoc", "compiled_assetcatalog", + "xcode.provisioningprofile"] outputFileTags: ["bundle", "bundle.symlink.headers", "bundle.symlink.private-headers", @@ -416,14 +417,13 @@ Module { fileTags: ["bundle"] }); - var provisioningProfilePath = product.moduleProperty("xcode", - "provisioningProfilePath"); - if (provisioningProfilePath) { - var ext = product.moduleProperty("qbs", "targetOS").contains("osx") - ? "provisionprofile" - : "mobileprovision"; + for (i in inputs["xcode.provisioningprofile"]) { + var ext = inputs["xcode.provisioningprofile"][i].fileName.split('.')[1]; artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, ModUtils.moduleProperty(product, "contentsFolderPath"), "embedded." + ext), + filePath: FileInfo.joinPaths(product.destinationDirectory, + ModUtils.moduleProperty(product, + "contentsFolderPath"), + "embedded." + ext), fileTags: ["bundle.provisioningprofile"] }); } @@ -560,7 +560,7 @@ Module { cmd = new JavaScriptCommand(); cmd.description = "copying provisioning profile"; cmd.highlight = "filegen"; - cmd.source = product.moduleProperty("xcode", "provisioningProfilePath"); + cmd.source = inputs["xcode.provisioningprofile"][i].filePath; cmd.destination = provisioningProfiles[i].filePath; cmd.sourceCode = function() { File.copy(source, destination); @@ -623,10 +623,16 @@ Module { subpath = subpath.substring(subpath.indexOf(ModUtils.moduleProperty("qbs", "pathSeparator"))); } - cmd = new Command(product.moduleProperty("xcode", "codesignPath"), - (product.moduleProperty("xcode", "codesignFlags") || []) - .concat(["--force", "--sign", actualSigningIdentity, - bundles[i].filePath + subpath])); + var args = product.moduleProperty("xcode", "codesignFlags") || []; + args.push("--force"); + args.push("--sign", actualSigningIdentity); + for (var j in inputs.xcent) { + args.push("--entitlements", inputs.xcent[j].filePath); + break; // there should only be one + } + args.push(bundles[i].filePath + subpath); + + cmd = new Command(product.moduleProperty("xcode", "codesignPath"), args); cmd.description = "codesign " + ModUtils.moduleProperty(product, "bundleName") + " using " + codesignDisplayName diff --git a/share/qbs/modules/cpp/gcc.js b/share/qbs/modules/cpp/gcc.js index 626bb588c..3f48c4dd1 100644 --- a/share/qbs/modules/cpp/gcc.js +++ b/share/qbs/modules/cpp/gcc.js @@ -762,9 +762,15 @@ function prepareLinker(project, product, inputs, outputs, input, output) { var actualSigningIdentity = product.moduleProperty("xcode", "actualSigningIdentity"); var codesignDisplayName = product.moduleProperty("xcode", "actualSigningIdentityDisplayName"); if (actualSigningIdentity && !product.moduleProperty("bundle", "isBundle")) { - cmd = new Command(product.moduleProperty("xcode", "codesignPath"), - ["--force", "--sign", actualSigningIdentity, - primaryOutput.filePath]); + var args = product.moduleProperty("xcode", "codesignFlags") || []; + args.push("--force"); + args.push("--sign", actualSigningIdentity); + for (var j in inputs.xcent) { + args.push("--entitlements", inputs.xcent[j].filePath); + break; // there should only be one + } + args.push(primaryOutput.filePath); + cmd = new Command(product.moduleProperty("xcode", "codesignPath"), args); cmd.description = "codesign " + primaryOutput.fileName + " using " + codesignDisplayName diff --git a/share/qbs/modules/xcode/xcode.qbs b/share/qbs/modules/xcode/xcode.qbs index 06e11c354..d1324bf3b 100644 --- a/share/qbs/modules/xcode/xcode.qbs +++ b/share/qbs/modules/xcode/xcode.qbs @@ -1,8 +1,10 @@ import qbs +import qbs.BundleTools import qbs.File import qbs.FileInfo import qbs.DarwinTools import qbs.ModUtils +import qbs.PropertyList import 'xcode.js' as Utils Module { @@ -60,6 +62,8 @@ Module { return _actualSigningIdentity[0][1]; } + property path signingEntitlements + property string provisioningProfile property path provisioningProfilePath: { var files = _availableProvisioningProfiles; @@ -205,4 +209,89 @@ Module { v.set(); } } + + Group { + name: "Provisioning Profile" + files: xcode.provisioningProfilePath + ? [xcode.provisioningProfilePath] + : [] + } + + FileTagger { + fileTags: ["xcode.provisioningprofile"] + patterns: ["*.mobileprovision", "*.provisionprofile"] + } + + Rule { + multiplex: true + inputs: ["xcode.provisioningprofile"] + + Artifact { + filePath: FileInfo.joinPaths(product.destinationDirectory, + product.targetName + ".xcent") + fileTags: ["xcent"] + } + + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "generating entitlements"; + cmd.highlight = "codegen"; + cmd.bundleIdentifier = product.moduleProperty("bundle", "identifier"); + cmd.signingEntitlements = ModUtils.moduleProperty(product, "signingEntitlements"); + cmd.platformPath = ModUtils.moduleProperty(product, "platformPath"); + cmd.sdkPath = ModUtils.moduleProperty(product, "sdkPath"); + cmd.sourceCode = function() { + var provData = Utils.readProvisioningProfileData( + inputs["xcode.provisioningprofile"][0].filePath); + + var aggregateEntitlements = {}; + + // Start building up an aggregate entitlements plist from the files in the SDKs, + // which contain placeholders in the same manner as Info.plist + function entitlementsFileContents(path) { + return File.exists(path) ? BundleTools.infoPlistContents(path) : undefined; + } + var entitlementsSources = [ + entitlementsFileContents(FileInfo.joinPaths(platformPath, "Entitlements.plist")), + entitlementsFileContents(FileInfo.joinPaths(sdkPath, "Entitlements.plist")), + entitlementsFileContents(signingEntitlements) + ]; + + for (var i = 0; i < entitlementsSources.length; ++i) { + var contents = entitlementsSources[i]; + for (var key in contents) { + if (contents.hasOwnProperty(key)) + aggregateEntitlements[key] = contents[key]; + } + } + + contents = provData["Entitlements"]; + for (key in contents) { + if (contents.hasOwnProperty(key) && !aggregateEntitlements.hasOwnProperty(key)) + aggregateEntitlements[key] = contents[key]; + } + + // Expand entitlements variables with data from the provisioning profile + var env = { + "AppIdentifierPrefix": provData["ApplicationIdentifierPrefix"] + ".", + "CFBundleIdentifier": bundleIdentifier + }; + DarwinTools.expandPlistEnvironmentVariables(aggregateEntitlements, env, true); + + // Anything with an undefined or otherwise empty value should be removed + // Only JSON-formatted plists can have null values, other formats error out + // This also follows Xcode behavior + DarwinTools.cleanPropertyList(aggregateEntitlements); + + var plist = new PropertyList(); + try { + plist.readFromObject(aggregateEntitlements); + plist.writeToFile(outputs.xcent[0].filePath, "xml1"); + } finally { + plist.clear(); + } + }; + return [cmd]; + } + } } -- cgit v1.2.3