| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  | require "development_tools" | 
					
						
							| 
									
										
										
										
											2018-09-06 08:29:14 +02:00
										 |  |  | module Cask | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  |   module Quarantine | 
					
						
							|  |  |  |     module_function | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QUARANTINE_ATTRIBUTE = "com.apple.quarantine".freeze | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-03 19:39:07 +01:00
										 |  |  |     QUARANTINE_SCRIPT = (HOMEBREW_LIBRARY_PATH/"cask/utils/quarantine.swift").freeze | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # @private | 
					
						
							|  |  |  |     def swift | 
					
						
							|  |  |  |       @swift ||= DevelopmentTools.locate("swift") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 21:11:29 +00:00
										 |  |  |     def check_quarantine_support | 
					
						
							|  |  |  |       odebug "Checking quarantine support" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if swift.nil? | 
					
						
							|  |  |  |         odebug "Swift is not available on this system." | 
					
						
							| 
									
										
										
										
											2018-09-14 15:48:16 +00:00
										 |  |  |         :no_swift | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         api_check = system_command(swift, | 
					
						
							|  |  |  |                                    args: [QUARANTINE_SCRIPT], | 
					
						
							|  |  |  |                                    print_stderr: false) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case api_check.exit_status | 
					
						
							|  |  |  |         when 5
 | 
					
						
							|  |  |  |           odebug "This feature requires the macOS 10.10 SDK or higher." | 
					
						
							|  |  |  |           :no_quarantine | 
					
						
							|  |  |  |         when 2
 | 
					
						
							|  |  |  |           odebug "Quarantine is available." | 
					
						
							|  |  |  |           :quarantine_available | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           odebug "Unknown support status" | 
					
						
							|  |  |  |           :unknown | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2018-09-04 21:11:29 +00:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  |     def available? | 
					
						
							| 
									
										
										
										
											2018-09-04 21:11:29 +00:00
										 |  |  |       @status ||= check_quarantine_support | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @status == :quarantine_available | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def detect(file) | 
					
						
							|  |  |  |       return if file.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       odebug "Verifying Gatekeeper status of #{file}" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       quarantine_status = !status(file).empty? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       odebug "#{file} is #{quarantine_status ? "quarantined" : "not quarantined"}" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       quarantine_status | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 21:11:29 +00:00
										 |  |  |     def status(file) | 
					
						
							|  |  |  |       system_command("/usr/bin/xattr", | 
					
						
							|  |  |  |                      args:         ["-p", QUARANTINE_ATTRIBUTE, file], | 
					
						
							|  |  |  |                      print_stderr: false).stdout.rstrip | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 20:20:25 +00:00
										 |  |  |     def toggle_no_translocation_bit(xattr) | 
					
						
							| 
									
										
										
										
											2018-09-07 15:37:31 +00:00
										 |  |  |       fields = xattr.split(";") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Fields: status, epoch, download agent, event ID | 
					
						
							|  |  |  |       # Let's toggle the app translocation bit, bit 8 | 
					
						
							|  |  |  |       # http://openradar.me/radar?id=5022734169931776 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fields[0] = (fields[0].to_i(16) | 0x0100).to_s(16).rjust(4, "0") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fields.join(";") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 14:00:44 +00:00
										 |  |  |     def release!(download_path: nil) | 
					
						
							|  |  |  |       return unless detect(download_path) | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 14:00:44 +00:00
										 |  |  |       odebug "Releasing #{download_path} from quarantine" | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 14:00:44 +00:00
										 |  |  |       quarantiner = system_command("/usr/bin/xattr", | 
					
						
							| 
									
										
										
										
											2018-09-14 15:48:16 +00:00
										 |  |  |                                    args: [ | 
					
						
							|  |  |  |                                      "-d", | 
					
						
							|  |  |  |                                      QUARANTINE_ATTRIBUTE, | 
					
						
							|  |  |  |                                      download_path, | 
					
						
							|  |  |  |                                    ], | 
					
						
							|  |  |  |                                    print_stderr: false) | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 14:00:44 +00:00
										 |  |  |       return if quarantiner.success? | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 14:00:44 +00:00
										 |  |  |       raise CaskQuarantineReleaseError.new(download_path, quarantiner.stderr) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2018-09-07 15:37:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 14:00:44 +00:00
										 |  |  |     def cask!(cask: nil, download_path: nil, action: true) | 
					
						
							|  |  |  |       return if cask.nil? || download_path.nil? | 
					
						
							| 
									
										
										
										
											2018-09-07 15:37:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 14:00:44 +00:00
										 |  |  |       return if detect(download_path) | 
					
						
							| 
									
										
										
										
											2018-09-07 15:37:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 14:00:44 +00:00
										 |  |  |       odebug "Quarantining #{download_path}" | 
					
						
							| 
									
										
										
										
											2018-09-07 15:37:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 14:00:44 +00:00
										 |  |  |       quarantiner = system_command(swift, | 
					
						
							| 
									
										
										
										
											2018-09-14 15:48:16 +00:00
										 |  |  |                                    args: [ | 
					
						
							|  |  |  |                                      QUARANTINE_SCRIPT, | 
					
						
							|  |  |  |                                      download_path, | 
					
						
							|  |  |  |                                      cask.url.to_s, | 
					
						
							|  |  |  |                                      cask.homepage.to_s, | 
					
						
							|  |  |  |                                    ], | 
					
						
							|  |  |  |                                    print_stderr: false) | 
					
						
							| 
									
										
										
										
											2018-09-07 15:37:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 14:00:44 +00:00
										 |  |  |       return if quarantiner.success? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       case quarantiner.exit_status | 
					
						
							|  |  |  |       when 2
 | 
					
						
							|  |  |  |         raise CaskQuarantineError.new(download_path, "Insufficient parameters") | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         raise CaskQuarantineError.new(download_path, quarantiner.stderr) | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 21:11:29 +00:00
										 |  |  |     def propagate(from: nil, to: nil) | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  |       return if from.nil? || to.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       raise CaskError, "#{from} was not quarantined properly." unless detect(from) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       odebug "Propagating quarantine from #{from} to #{to}" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-08 20:20:25 +00:00
										 |  |  |       quarantine_status = toggle_no_translocation_bit(status(from)) | 
					
						
							| 
									
										
										
										
											2018-09-04 21:11:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       resolved_paths = Pathname.glob(to/"**/*", File::FNM_DOTMATCH) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-07 16:57:00 +00:00
										 |  |  |       system_command!("/bin/chmod", args: ["-R", "u+w", to]) | 
					
						
							| 
									
										
										
										
											2018-09-07 15:37:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 21:11:29 +00:00
										 |  |  |       quarantiner = system_command("/usr/bin/xargs", | 
					
						
							|  |  |  |                                    args: [ | 
					
						
							|  |  |  |                                      "-0", | 
					
						
							|  |  |  |                                      "--", | 
					
						
							|  |  |  |                                      "/usr/bin/xattr", | 
					
						
							|  |  |  |                                      "-w", | 
					
						
							|  |  |  |                                      "-s", | 
					
						
							|  |  |  |                                      QUARANTINE_ATTRIBUTE, | 
					
						
							|  |  |  |                                      quarantine_status, | 
					
						
							|  |  |  |                                    ], | 
					
						
							|  |  |  |                                    input: resolved_paths.join("\0"), | 
					
						
							|  |  |  |                                    print_stderr: false) | 
					
						
							| 
									
										
										
										
											2018-08-31 13:16:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return if quarantiner.success? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       raise CaskQuarantinePropagationError.new(to, quarantiner.stderr) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |