Last active
June 16, 2017 14:33
-
-
Save trevordevore/3e91724c4573690b691510d2e2dcd2a7 to your computer and use it in GitHub Desktop.
LiveCode script-only stack that will code sign LIveCode applications on OS X
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
script "SignApplicationForOSX" | |
on preOpenCard | |
set the visible of this stack to true | |
put the rect of this stack into tRect | |
put item 1 of tRect + 400 into item 3 of tRect | |
put item 2 of tRect + 400 into item 4 of tRect | |
set the rect of this stack to tRect | |
create button "Sign Application" | |
set the width of it to 150 | |
set the loc of it to 200, 50 | |
create field "Log" | |
set the rect of it to 16,90,384,384 | |
set the dontWrap of it to true | |
set the vscrollbar of it to true | |
set the hscrollbar of it to true | |
end preOpenCard | |
on mouseUp | |
if the short name of the target is "Sign Application" then | |
answer file "Select bundle to sign" | |
put it into tBundlePath | |
if tBundlePath is not empty then | |
ask "Enter certificate name:" | |
put it into tCertName | |
end if | |
if tBundlePath is not empty and tCertName is not empty then | |
SignApplication tBundlePath, tCertName, false | |
put the result into tError | |
if tError is not empty then | |
answer "Error signing application:" && tError | |
end if | |
beep | |
end if | |
end if | |
end mouseUp | |
# Sign applications on OS X. lipo if preparing for MAS. | |
command SignApplication pBundlePath, pCertificateName, pIsMas | |
local theError | |
if pIsMas then | |
put "3rd Party Mac Developer Application: " & pCertificateName into pCertificateName | |
else | |
put "Developer ID Application: " & pCertificateName into pCertificateName | |
end if | |
# Sierra on up needs extended attributes stripped out | |
if theError is empty AND the platform is "macos" then | |
put format("chmod -R u+rw \"%s\"", pBundlePath) into theCmd | |
_log theCmd | |
get shell(theCmd) | |
if the result > 0 then | |
put the result into theError | |
end if | |
end if | |
if theError is empty AND the platform is "macos" then | |
put format("xattr -rc \"%s\"", pBundlePath) into theCmd | |
_log theCmd | |
get shell(theCmd) | |
if the result > 0 then | |
put the result into theError | |
end if | |
end if | |
# With Mavericks we have to sign everything. Just start in the MacOS folder | |
# and everything will end up signed. | |
if theError is empty then | |
signAndStrip pBundlePath, pCertificateName, pIsMas | |
put the result into theError | |
end if | |
if theError is empty then | |
put format("codesign -dvvv \"%s\"", pBundlePath) into theCmd | |
_log theCmd | |
get shell(theCmd) | |
if the result > 0 then | |
put the result into theError | |
end if | |
end if | |
if theError is empty then | |
put format("spctl --verbose --assess --type execute -v \"%s\"", pBundlePath) into theCmd | |
_log theCmd | |
get shell(theCmd) | |
if the result > 0 then | |
put the result into theError | |
end if | |
end if | |
if theError is not empty then | |
_log theError | |
end if | |
return theError | |
end SignApplication | |
## Monte Goulding with modifications by Trevor DeVore | |
command signAndStrip pBundle, pCertificate, pMas, pSignFile | |
local theError | |
# recursively parse any frameworks | |
if theError is empty then | |
put pBundle & "/Contents/Frameworks" into theRootFolder | |
if there is a folder theRootFolder then | |
_findBundlesAndStripExecutables theRootFolder, pCertificate, pMAS, pSignFiles | |
put the result into theError | |
end if | |
end if | |
# recursively parse the MacOS folder | |
if theError is empty then | |
put pBundle & "/Contents/MacOS" into theRootFolder | |
if there is a folder theRootFolder then | |
_findBundlesAndStripExecutables theRootFolder, pCertificate, pMAS, pSignFiles | |
put the result into theError | |
end if | |
end if | |
if theError is empty then | |
_signFile pBundle, pCertificate, pMas | |
put the result into theError | |
end if | |
return theError | |
end signAndStrip | |
# Signs a file or folder | |
private command _signFile pFilename, pCertificate, pMas | |
local theEntitlementsFile, theCmd, theError | |
if theError is empty then | |
put _BundleEntitlementFile(pFilename) into theEntitlementsFile | |
if theEntitlementsFile is not empty then | |
put format("codesign --verbose --force -s \"%s\" --entitlements \"%s\" \"%s\"", pCertificate, theEntitlementsFile, pFilename) into theCmd | |
else | |
put format("codesign --verbose --force -s \"%s\" \"%s\"", pCertificate, pFilename) into theCmd | |
end if | |
_log theCmd | |
get shell(theCmd) | |
put the result into theError | |
if theError is 1 then | |
put "codesign process failed:" && it into theError | |
else if theError is 2 then | |
put "invalid arguments passed to codesign:" && it into theError | |
else if theError is 3 then | |
put "requirements not met for -R flag in codesign:" && it into theError | |
end if | |
end if | |
# troubleshooting | |
if theError is not empty then | |
put theCmd & cr & cr & the executioncontexts | |
end if | |
return theError | |
end _signFile | |
private function _BundleEntitlementFile pBundle | |
local theFiles, theBundleName | |
# Look for an entitlement file that matches the bundle name | |
set the itemDelimiter to "/" | |
put the last item of pBundle into theBundleName | |
set the itemDelimiter to "." | |
put item 1 to -2 of theBundleName into theBundleName | |
put sys_fileListing(pBundle & "/Contents/Resources", true) into theFiles | |
filter theFiles with "*/" & theBundleName & ".entitlements" | |
if theFiles is empty then | |
put sys_fileListing(pBundle & "/Contents", true) into theFiles | |
filter theFiles with "*/" & theBundleName & ".entitlements" | |
end if | |
return theFiles | |
end _BundleEntitlementFile | |
private command _log pMsg | |
if there is a field "Log" then | |
put pMsg & cr after field "Log" | |
if the number of lines of field "Log" mod 2 is 0 then | |
set the backgroundcolor of the last line of field "Log" to 230,230,230 | |
end if | |
end if | |
end _log | |
private function _IsMacOSExecutable pFilepath | |
return pFilepath ends with ".bundle" \ | |
OR pFilepath ends with ".dylib" \ | |
OR pFilepath ends with ".framework" \ | |
OR pFilepath ends with ".app" | |
end _IsMacOSExecutable | |
## Monte Goulding with modifications by Trevor DeVore | |
private command _findBundlesAndStripExecutables pFolder, pCertificate, pMAS, pSignFiles | |
local theError | |
put pSignFiles is not false into pSignFiles | |
# Get list of folders and reset. Can't wait until end as it messes up recursive calls. | |
put the defaultFolder into theOldDefaultFolder | |
set the defaultFolder to pFolder | |
put the folders into theFolders | |
put the detailed files into theFilesInfo | |
put the files into theFiles | |
set the defaultFolder to theOldDefaultFolder | |
repeat for each line theFolder in line 2 to -1 of theFolders | |
if _IsMacOSExecutable(theFolder) then | |
signAndStrip pFolder&"/"&theFolder, pCertificate, pMAS, false # don't sign any files within bundle | |
put the result into theError | |
else if theFolder ends with ".app" OR theFolder ends with ".framework" then | |
signAndStrip pFolder&"/"&theFolder, pCertificate, pMAS, true # sign files within the app | |
put the result into theError | |
else | |
_findBundlesAndStripExecutables pFolder&"/"&theFolder, pCertificate, pMAS, pSignFiles # inherit behavior | |
put the result into theError | |
end if | |
if theError is not empty then exit repeat | |
end repeat | |
# On Mavericks and above additional signing is required. Anything that can contain code (or that OS X thinks can contain code) | |
if theError is empty then | |
if pSignFiles then # don't sign if part of a bundle | |
set the itemdelimiter to "." | |
# sign things like .dylib before others. Otherwise codesign will try to sign app and complain that .dylib isn't signed. | |
put theFiles into theFilesWOExt | |
filter theFilesWOExt without "*.*" | |
filter theFiles with "*.*" | |
if theFilesWOExt is not empty then | |
put theFilesWOExt into line (the number of lines of theFiles + 1) of theFiles | |
end if | |
repeat for each line theFile in theFiles | |
if the platform is "macos" AND \ | |
(item 1 of the itemDelimiter > 10 OR item 1 of the systemVersion = 10 AND item 2 of the systemVersion >= 9) then | |
_signFile pFolder & "/" & theFile, pCertificate, pMAS | |
put the result into theError | |
end if | |
if theError is not empty then exit repeat | |
end repeat | |
end if | |
end if | |
# strip | |
if theError is empty then | |
if pMAS then | |
set the itemDelimiter to "," | |
repeat for each line theFile in theFilesInfo | |
# If executable bit is set then lipo it. | |
# Prior to 2014-05-27 we assumed 755. Now we just check for a 7 in the first char. | |
# TODO: error reporting | |
if char 1 of item 10 of theFile = "7" then | |
get shell(format("lipo -remove ppc \"%s\" -output \"%s\"", pFolder & "/" & URLDecode(item 1 of theFile), pFolder & "/" & URLDecode(item 1 of theFile))) | |
put the result into theResult | |
_log "lipo ppc" && pFolder & "/" & URLDecode(item 1 of theFile) && theResult | |
if theResult is not empty then | |
get shell(format("lipo -remove ppc7400 \"%s\" -output \"%s\"", pFolder & "/" & URLDecode(item 1 of theFile), pFolder & "/" & URLDecode(item 1 of theFile))) | |
_log "lipo ppc7400" && pFolder & "/" & URLDecode(item 1 of theFile) && theResult | |
end if | |
end if | |
end repeat | |
end if | |
end if | |
return theError | |
end _findBundlesAndStripExecutables | |
function sys_fileListing pFolder, pFullPath | |
local tDefault,tFiles,tFullFiles,tFile | |
if there is not a folder pFolder then return empty | |
if last char of pFolder is not slash then put slash after pFolder | |
put the defaultfolder into tDefault | |
set the defaultfolder to pFolder | |
put files() into tFiles | |
set the defaultfolder to tDefault | |
filter tFiles without ".*" | |
if pFullPath then | |
repeat for each line tFile in tFiles | |
put pFolder & tFile &cr after tFullFiles | |
end REPEAT | |
delete last char of tFullFiles | |
return tFullFiles | |
else | |
return tFiles | |
end if | |
end sys_fileListing |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment