Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add quarantine attribute to downloads #22388

Closed
2 tasks
vitorgalvao opened this issue Jun 25, 2016 · 18 comments · Fixed by Homebrew/brew#4656
Closed
2 tasks

Add quarantine attribute to downloads #22388

vitorgalvao opened this issue Jun 25, 2016 · 18 comments · Fixed by Homebrew/brew#4656
Labels
core Issue with Homebrew itself rather than with a specific cask. discussion in progress

Comments

@vitorgalvao
Copy link
Member

vitorgalvao commented Jun 25, 2016

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:

  • Add the com.apple.quarantine attribute automatically to all downloaded files.
  • Add a --no-quarantine flag that won’t add the attribute.

Problems / things that need to checked:

  • It seems you can’t just make the com.apple.quarantine true, and it needs to have actual values that we need to understand how to set.
  • It makes sense for HBC to have this, but not necessarily HB. Since we use their download strategy, it makes more sense to add this as something exterior to the download strategy that simply checks for the flag and sets the attribute.
  • Since we unpack dmgs and the like on the CLI, quarantine shouldn’t have any effect there and only when opening apps (which is what we want). If, however, we verify that isn’t the case, we need only add the setting of quarantine to the artifact stanzas themselves or to do it in one swoop to all files when first unpacking.

@reitermarkus is doing great research on this.

@vitorgalvao vitorgalvao added discussion core Issue with Homebrew itself rather than with a specific cask. labels Jun 25, 2016
@mwean
Copy link
Contributor

mwean commented Jun 27, 2016

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.

@vitorgalvao
Copy link
Member Author

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).

@vitorgalvao vitorgalvao changed the title Add quarantine attribute on downloads Add quarantine attribute to downloads Jun 27, 2016
@joshka
Copy link
Contributor

joshka commented Jun 27, 2016

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.xattr

You can then apply those attributes to another file like this:

xattr -w com.apple.quarantine "`cat file.xattr`" file

@Eitot
Copy link
Contributor

Eitot commented Jun 27, 2016

@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.

@vitorgalvao
Copy link
Member Author

@joshka Yes, I found that method as well, but I’d 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.

@joshka
Copy link
Contributor

joshka commented Jun 28, 2016

yep - fair call :)

@reitermarkus
Copy link
Member

reitermarkus commented Jul 5, 2016

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}'"

@Eitot
Copy link
Contributor

Eitot commented Jul 5, 2016

@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?

@vitorgalvao
Copy link
Member Author

Great work, @reitermarkus! Thank you.

I’ll defer to your opinion regarding if com.apple.metadata:kMDItemWhereFroms and com.apple.metadata:kMDItemDownloadedDate should be set or not. I’m 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’t), the --no-quarantine flag I also suggested is so the users who like the system as it aren’t forced to have the quarantine.

@reitermarkus
Copy link
Member

For us, only 0002 is relevant:

  • 0002 means that the Application was never opened.
  • 0022 means that the GUI dialog was shown, but cancelled.
  • 0042 means that the GUI dialog was accepted.

One thing I haven't tested yet is if unpacking an archive via Terminal preserves/sets the attribute on the extracted Application.

@reitermarkus
Copy link
Member

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.

@reitermarkus
Copy link
Member

Ok, I found that an entry in the database has these fields:

  • LSQuarantineEventIdentifier
  • LSQuarantineTimeStamp
  • LSQuarantineAgentBundleIdentifier
  • LSQuarantineAgentName
  • LSQuarantineDataURLString
  • LSQuarantineSenderName
  • LSQuarantineSenderAddress
  • LSQuarantineTypeNumber
  • LSQuarantineOriginTitle
  • LSQuarantineOriginURLString
  • LSQuarantineOriginAlias

@reitermarkus
Copy link
Member

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.

@vitorgalvao
Copy link
Member Author

@reitermarkus You’re 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).

@reitermarkus
Copy link
Member

@vitorgalvao, I started something here: https://github.com/reitermarkus/quarantine

@vitorgalvao
Copy link
Member Author

@reitermarkus Really interesting read. Added it to the top post.

@amyspark
Copy link
Contributor

amyspark commented Nov 6, 2017

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.

@commitay
Copy link
Contributor

commitay commented Dec 4, 2017

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:
quip1

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

quip3


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

github

@lock lock bot locked and limited conversation to collaborators Sep 30, 2018
@amyspark amyspark removed their assignment Mar 29, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
core Issue with Homebrew itself rather than with a specific cask. discussion in progress
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants