Gatekeeper only works when the com.apple.quarantine is set, which is quite frankly ridiculous and makes the feature incredibly less useful. It also means no HBC user is covered by it, since curl does not set the attribute.
My suggestion:
com.apple.quarantine attribute automatically to all downloaded files.--no-quarantine flag that won鈥檛 add the attribute.Problems / things that need to checked:
com.apple.quarantine true, and it needs to have actual values that we need to understand how to set.@reitermarkus is doing great research on this.
I mentioned this in the linked malware PR, but we might be able to use the spctl command to manually check the app? It returns a non-zero exit code if there's something wrong with an app.
> spctl -a /Applications/Amazon\ Music.app
/Applications/Amazon Music.app: a sealed resource is missing or invalid
Might be something worth looking into.
Issue with that approach is what to do after checking the app. Simply outputting a message is insufficient. That also puts the responsibility on us.
What we want is to defer the responsibility to Apple (they have much better resources and the solution is theirs, after all).
http://stackoverflow.com/questions/21591485/using-xattr-to-set-the-mac-osx-quarantine-property
Another approach is to just copy the quarantine information from one file to another. You can serialize xattr information like this:
xattr -p com.apple.quarantine file > file.xattrYou can then apply those attributes to another file like this:
xattr -w com.apple.quarantine "`cat file.xattr`" file
@joshka: The quarantine flag is composed of a UUID, however, which the system keeps a record of, even when the flag is removed afterwards. Duplicating this _en masse_ could lead to problems at some point, but who knows.
The quarantine flag is set automatically by applications that adopt the LSFileQuarantineEnabled property in the info.plist file, which applications like Safari seem to be doing. The functionality can also be provided through the Core Services framework, by adding the attributes.
There is some background information about the content of the flag in this, albeit old, blog post: http://ilostmynotes.blogspot.co.uk/2012/06/gatekeeper-xprotect-and-quarantine.html.
@joshka Yes, I found that method as well, but I鈥檇 like for this to be correct. When you try to open a quarantined file, the GUI dialog tells you where and when it came from. Breaking that is not desirable.
yep - fair call :)
Ok, I got it working. I think you don't actually need to set com.apple.metadata:kMDItemWhereFroms and com.apple.metadata:kMDItemDownloadedDate.
Read com.apple.metadata:kMDItemWhereFroms
/usr/bin/xattr -p com.apple.metadata:kMDItemWhereFroms "${file}" | /usr/bin/xxd -r -p | /usr/bin/plutil -convert xml1 -o - -
Set com.apple.metadata:kMDItemWhereFroms
url="http://example.com"
hexdump=$(echo "<plist><array><string>${url}</string></array></plist>" | /usr/bin/plutil -convert binary1 -o - - | /usr/bin/xxd -p | /usr/bin/tr -d "\n")
/usr/bin/xattr -w com.apple.metadata:kMDItemWhereFroms "${hexdump}" "${file}"
Read com.apple.metadata:kMDItemDownloadedDate
/usr/bin/xattr -p com.apple.metadata:kMDItemDownloadedDate "${file}" | /usr/bin/xxd -r -p | /usr/bin/plutil -convert xml1 -o - -
Set com.apple.metadata:kMDItemDownloadedDate
date=$(date +%Y-%m-%dT%H:%M:%SZ)
hexdump=$(echo "<plist><array><date>${date}</date></array></plist>" | /usr/bin/plutil -convert binary1 -o - - | /usr/bin/xxd -p | /usr/bin/tr -d "\n")
/usr/bin/xattr -w com.apple.metadata:kMDItemDownloadedDate "${hexdump}" "${file}"
Read com.apple.quarantine
/usr/bin/xattr -p com.apple.quarantine "${file}"
Set com.apple.quarantine
application="cURL"
date=$(printf %x $(date +%s))
uuid=$(/usr/bin/uuidgen)
/usr/bin/xattr -w com.apple.quarantine "0002;${date};${application};${uuid}" "${file}"
Insert UUID into Database
download_url="http://example.com/file.zip"
date=$(($(date +%s) - 978307200))
/usr/bin/sqlite3 ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2 \
"INSERT INTO \"LSQuarantineEvent\" VALUES('${uuid}',${date},NULL,'${application}','${download_url}',NULL,NULL,0,NULL,'${url}',NULL);"
Check if UUID exists in Database
/usr/bin/sqlite3 ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2 \
"SELECT * FROM LSQuarantineEvent WHERE LSQuarantineEventIdentifier == '${uuid}'"
@reitermarkus: I think you are correct about com.apple.metadata:kMDItemWhereFroms and com.apple.metadata:kMDItemDownloadedDate. This is just metadata that Finder uses to show more information about the origin, e.g. in the Get Info window. The quarantine attribute is the one that contains all the necessary information for File Quarantine and Gatekeeper.
Do you think that the UUID has to be checked for uniqueness in the database?
Great work, @reitermarkus! Thank you.
I鈥檒l defer to your opinion regarding if com.apple.metadata:kMDItemWhereFroms and com.apple.metadata:kMDItemDownloadedDate should be set or not. I鈥檓 fine either way (just glad we can quarantine files).
Do you have any idea what the 0002; means, or is that just something you noticed to be consistent with all quarantine attributes?
Could we in theory have application="cURL via Homebrew-Cask" instead of just application="cURL"?
On another note, just to clarify (realised now I hadn鈥檛), the --no-quarantine flag I also suggested is so the users who like the system as it aren鈥檛 forced to have the quarantine.
For us, only 0002 is relevant:
One thing I haven't tested yet is if unpacking an archive via Terminal preserves/sets the attribute on the extracted Application.
And yes, application can be set to anything.
Although, I tried this with a file downloaded with Safari, and the database field before application included the bundle ID. I don't think this is used for anything, though. We could simply set it to /usr/bin/curl, as TCC.db also uses the path to allow accessibility access.
Ok, I found that an entry in the database has these fields:
Do you think that the UUID has to be checked for uniqueness in the database?
Yes, good catch. Added a check to my post above.
@reitermarkus You鈥檙e really on to something. Instead of adding this logic to HBC directly, would it be sensible to perhaps abstract this to a filequarantiner binary? Something other people could benefit from as well, if desired (though setting quarantine seems to not be a popular request).
@vitorgalvao, I started something here: https://github.com/reitermarkus/quarantine
@reitermarkus Really interesting read. Added it to the top post.
Are there any news on this? I've checked @reitermarkus's work and can confirm it quarantines apps successfully.
If you want, I can pick this up and finalize the implementation.
Thanks for picking this up @amyspark!
Something I'm not sure about is the url being displayed in the prompt.
While it is accurate and matches the output of brew cask install {cask} (Downloading ...), using a url that will in some cases have no apparent relation to the Cask might lead to some confusion.
Also in some cases the "Show Web Page" won't open a website (or if it does it won't be relevant to the Cask).
It might be better to use the homepage to conform with user expectations?
Installed with Cask:

Downloaded from the homepage which redirects to the same cloudfront download url :


Edit: Is it possible to use the full homepage URL?

Most helpful comment
Ok, I got it working. I think you don't actually need to set
com.apple.metadata:kMDItemWhereFromsandcom.apple.metadata:kMDItemDownloadedDate.Read
com.apple.metadata:kMDItemWhereFromsSet
com.apple.metadata:kMDItemWhereFromsRead
com.apple.metadata:kMDItemDownloadedDateSet
com.apple.metadata:kMDItemDownloadedDateRead
com.apple.quarantineSet
com.apple.quarantineInsert UUID into Database
Check if UUID exists in Database