Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: content/browser/download/quarantine_mac.mm

Issue 2352763006: On macOS 10.10+, use NSURL methods in quarantine_mac. (Closed)
Patch Set: add ifdef. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | content/browser/download/quarantine_mac_unittest.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/download/quarantine.h" 5 #include "content/browser/download/quarantine.h"
6 6
7 #include <ApplicationServices/ApplicationServices.h> 7 #import <ApplicationServices/ApplicationServices.h>
8 #include <Foundation/Foundation.h> 8 #import <Foundation/Foundation.h>
9 9
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/mac/foundation_util.h" 12 #include "base/mac/foundation_util.h"
13 #include "base/mac/mac_logging.h" 13 #include "base/mac/mac_logging.h"
14 #include "base/mac/mac_util.h" 14 #include "base/mac/mac_util.h"
15 #include "base/mac/scoped_cftyperef.h" 15 #include "base/mac/scoped_cftyperef.h"
16 #include "base/mac/scoped_nsobject.h"
17 #include "base/strings/sys_string_conversions.h"
16 #include "base/threading/thread_restrictions.h" 18 #include "base/threading/thread_restrictions.h"
17 #include "url/gurl.h" 19 #include "url/gurl.h"
18 20
21 namespace {
22
23 // Once Chrome no longer supports macOS 10.9, this code will no longer be
24 // necessary. Note that LSCopyItemAttribute was deprecated in macOS 10.8, but
25 // the replacement to kLSItemQuarantineProperties did not exist until macOS
26 // 10.10.
27 #if !defined(MAC_OS_X_VERSION_10_10) || \
28 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
29 #pragma clang diagnostic push
30 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
31 bool GetQuarantinePropertiesDeprecated(
32 const base::FilePath& file,
33 base::scoped_nsobject<NSMutableDictionary>* properties) {
34 FSRef file_ref;
35 if (!base::mac::FSRefFromPath(file.value(), &file_ref))
36 return false;
37 CFTypeRef quarantine_properties_base = NULL;
Avi (use Gerrit) 2016/09/28 02:32:13 Can you do a ScopedCFTypeRef here and use Initiali
erikchen 2016/09/28 19:59:00 Done. Note that this was copy-pasted from the pr
38 bool success = true;
39 if (LSCopyItemAttribute(&file_ref, kLSRolesAll, kLSItemQuarantineProperties,
40 &quarantine_properties_base) == noErr) {
41 if (CFGetTypeID(quarantine_properties_base) == CFDictionaryGetTypeID()) {
Avi (use Gerrit) 2016/09/28 02:32:14 CFCast<>
erikchen 2016/09/28 19:59:00 Done.
42 // Quarantine properties will already exist if LSFileQuarantineEnabled
43 // is on and the file doesn't match an exclusion.
44 properties->reset(
45 [(NSDictionary*)quarantine_properties_base mutableCopy]);
Avi (use Gerrit) 2016/09/28 02:32:14 CFToNSCast
erikchen 2016/09/28 19:59:00 Done.
46 } else {
47 LOG(WARNING) << "kLSItemQuarantineProperties is not a dictionary on file "
48 << file.value();
49 success = false;
50 }
51 CFRelease(quarantine_properties_base);
Avi (use Gerrit) 2016/09/28 02:32:13 (then you wouldn't need this)
erikchen 2016/09/28 19:59:00 Done.
52 }
53 return success;
54 }
55
56 bool SetQuarantinePropertiesDeprecated(const base::FilePath& file,
57 NSDictionary* properties) {
58 FSRef file_ref;
59 if (!base::mac::FSRefFromPath(file.value(), &file_ref))
60 return false;
61 OSStatus os_error = LSSetItemAttribute(
62 &file_ref, kLSRolesAll, kLSItemQuarantineProperties, properties);
63 if (os_error != noErr) {
64 OSSTATUS_LOG(WARNING, os_error)
65 << "Unable to set quarantine attributes on file " << file.value();
66 return false;
67 }
68 return true;
69 }
70 #pragma clang diagnostic pop
71 #endif
72
73 bool GetQuarantineProperties(
74 const base::FilePath& file,
75 base::scoped_nsobject<NSMutableDictionary>* properties) {
76 base::scoped_nsobject<NSURL> file_url([[NSURL alloc]
77 initFileURLWithPath:base::SysUTF8ToNSString(file.value())]);
78 if (!file_url)
79 return false;
80
81 // NSURLQuarantinePropertiesKey is only available on macOS 10.10+.
82 #pragma clang diagnostic push
83 #pragma clang diagnostic ignored "-Wunguarded-availability"
84 NSError* error = nil;
85 NSDictionary* quarantine_properties = nil;
86 BOOL success = [file_url getResourceValue:&quarantine_properties
87 forKey:NSURLQuarantinePropertiesKey
88 error:&error];
89 #pragma clang diagnostic pop
90 if (!success) {
91 std::string error_message(error ? error.description.UTF8String : "");
92 LOG(WARNING) << "Unable to get quarantine attributes for file "
93 << file.value() << ". Error: " << error_message;
94 return false;
95 }
96
97 if (!quarantine_properties)
98 return true;
99
100 if (![quarantine_properties isKindOfClass:[NSDictionary class]]) {
Avi (use Gerrit) 2016/09/28 02:32:14 Rather than using an NSDictionary* up there, use a
erikchen 2016/09/28 19:59:00 Done.
101 LOG(WARNING) << "Quarantine properties have wrong class: "
102 << [[[quarantine_properties class] description] UTF8String];
103 return false;
104 }
105
106 properties->reset([quarantine_properties mutableCopy]);
107 return true;
108 }
109
110 bool SetQuarantineProperties(const base::FilePath& file,
111 NSDictionary* properties) {
112 base::scoped_nsobject<NSURL> file_url([[NSURL alloc]
113 initFileURLWithPath:base::SysUTF8ToNSString(file.value())]);
114 if (!file_url)
115 return false;
116
117 // NSURLQuarantinePropertiesKey is only available on macOS 10.10+.
118 #pragma clang diagnostic push
119 #pragma clang diagnostic ignored "-Wunguarded-availability"
120 NSError* error = nil;
121 bool success = [file_url setResourceValue:properties
122 forKey:NSURLQuarantinePropertiesKey
123 error:&error];
124 #pragma clang diagnostic pop
125 if (!success) {
126 std::string error_message(error ? error.description.UTF8String : "");
127 LOG(WARNING) << "Unable to set quarantine attributes on file "
128 << file.value() << ". Error: " << error_message;
129 return false;
130 }
131 return true;
132 }
133
134 } // namespace
135
19 namespace content { 136 namespace content {
20 137
21 namespace { 138 namespace {
22 139
23 // As of Mac OS X 10.4 ("Tiger"), files can be tagged with metadata describing 140 // As of Mac OS X 10.4 ("Tiger"), files can be tagged with metadata describing
24 // various attributes. Metadata is integrated with the system's Spotlight 141 // various attributes. Metadata is integrated with the system's Spotlight
25 // feature and is searchable. Ordinarily, metadata can only be set by 142 // feature and is searchable. Ordinarily, metadata can only be set by
26 // Spotlight importers, which requires that the importer own the target file. 143 // Spotlight importers, which requires that the importer own the target file.
27 // However, there's an attribute intended to describe the origin of a 144 // However, there's an attribute intended to describe the origin of a
28 // file, that can store the source URL and referrer of a downloaded file. 145 // file, that can store the source URL and referrer of a downloaded file.
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 // the URL the user initiated the download from. 221 // the URL the user initiated the download from.
105 222
106 // The OS will automatically quarantine files due to the 223 // The OS will automatically quarantine files due to the
107 // LSFileQuarantineEnabled entry in our Info.plist, but it knows relatively 224 // LSFileQuarantineEnabled entry in our Info.plist, but it knows relatively
108 // little about the files. We add more information about the download to 225 // little about the files. We add more information about the download to
109 // improve the UI shown by the OS when the users tries to open the file. 226 // improve the UI shown by the OS when the users tries to open the file.
110 bool AddQuarantineMetadataToFile(const base::FilePath& file, 227 bool AddQuarantineMetadataToFile(const base::FilePath& file,
111 const GURL& source, 228 const GURL& source,
112 const GURL& referrer) { 229 const GURL& referrer) {
113 base::ThreadRestrictions::AssertIOAllowed(); 230 base::ThreadRestrictions::AssertIOAllowed();
114 FSRef file_ref; 231 base::scoped_nsobject<NSMutableDictionary> properties;
115 if (!base::mac::FSRefFromPath(file.value(), &file_ref)) 232 bool success = false;
233 if (base::mac::IsAtLeastOS10_10()) {
234 success = GetQuarantineProperties(file, &properties);
235 } else {
236 success = GetQuarantinePropertiesDeprecated(file, &properties);
237 }
238
239 if (!success)
116 return false; 240 return false;
117 241
118 NSMutableDictionary* quarantine_properties = nil; 242 if (!properties) {
119 CFTypeRef quarantine_properties_base = NULL;
120 if (LSCopyItemAttribute(&file_ref, kLSRolesAll, kLSItemQuarantineProperties,
121 &quarantine_properties_base) == noErr) {
122 if (CFGetTypeID(quarantine_properties_base) == CFDictionaryGetTypeID()) {
123 // Quarantine properties will already exist if LSFileQuarantineEnabled
124 // is on and the file doesn't match an exclusion.
125 quarantine_properties =
126 [[(NSDictionary*)quarantine_properties_base mutableCopy] autorelease];
127 } else {
128 LOG(WARNING) << "kLSItemQuarantineProperties is not a dictionary on file "
129 << file.value();
130 }
131 CFRelease(quarantine_properties_base);
132 }
133
134 if (!quarantine_properties) {
135 // If there are no quarantine properties, then the file isn't quarantined 243 // If there are no quarantine properties, then the file isn't quarantined
136 // (e.g., because the user has set up exclusions for certain file types). 244 // (e.g., because the user has set up exclusions for certain file types).
137 // We don't want to add any metadata, because that will cause the file to 245 // We don't want to add any metadata, because that will cause the file to
138 // be quarantined against the user's wishes. 246 // be quarantined against the user's wishes.
139 return true; 247 return true;
140 } 248 }
141 249
142 // kLSQuarantineAgentNameKey, kLSQuarantineAgentBundleIdentifierKey, and 250 // kLSQuarantineAgentNameKey, kLSQuarantineAgentBundleIdentifierKey, and
143 // kLSQuarantineTimeStampKey are set for us (see LSQuarantine.h), so we only 251 // kLSQuarantineTimeStampKey are set for us (see LSQuarantine.h), so we only
144 // need to set the values that the OS can't infer. 252 // need to set the values that the OS can't infer.
145 253
146 if (![quarantine_properties valueForKey:(NSString*)kLSQuarantineTypeKey]) { 254 if (![properties valueForKey:(NSString*)kLSQuarantineTypeKey]) {
147 CFStringRef type = source.SchemeIsHTTPOrHTTPS() 255 CFStringRef type = source.SchemeIsHTTPOrHTTPS()
148 ? kLSQuarantineTypeWebDownload 256 ? kLSQuarantineTypeWebDownload
149 : kLSQuarantineTypeOtherDownload; 257 : kLSQuarantineTypeOtherDownload;
150 [quarantine_properties setValue:(NSString*)type 258 [properties setValue:(NSString*)type
151 forKey:(NSString*)kLSQuarantineTypeKey]; 259 forKey:(NSString*)kLSQuarantineTypeKey];
152 } 260 }
153 261
154 if (![quarantine_properties 262 if (![properties valueForKey:(NSString*)kLSQuarantineOriginURLKey] &&
155 valueForKey:(NSString*)kLSQuarantineOriginURLKey] &&
156 referrer.is_valid()) { 263 referrer.is_valid()) {
157 NSString* referrer_url = 264 NSString* referrer_url =
158 [NSString stringWithUTF8String:referrer.spec().c_str()]; 265 [NSString stringWithUTF8String:referrer.spec().c_str()];
159 [quarantine_properties setValue:referrer_url 266 [properties setValue:referrer_url
160 forKey:(NSString*)kLSQuarantineOriginURLKey]; 267 forKey:(NSString*)kLSQuarantineOriginURLKey];
161 } 268 }
162 269
163 if (![quarantine_properties valueForKey:(NSString*)kLSQuarantineDataURLKey] && 270 if (![properties valueForKey:(NSString*)kLSQuarantineDataURLKey] &&
164 source.is_valid()) { 271 source.is_valid()) {
165 NSString* origin_url = 272 NSString* origin_url =
166 [NSString stringWithUTF8String:source.spec().c_str()]; 273 [NSString stringWithUTF8String:source.spec().c_str()];
167 [quarantine_properties setValue:origin_url 274 [properties setValue:origin_url forKey:(NSString*)kLSQuarantineDataURLKey];
168 forKey:(NSString*)kLSQuarantineDataURLKey];
169 } 275 }
170 276
171 OSStatus os_error = 277 if (base::mac::IsAtLeastOS10_10()) {
172 LSSetItemAttribute(&file_ref, kLSRolesAll, kLSItemQuarantineProperties, 278 return SetQuarantineProperties(file, properties);
173 quarantine_properties); 279 } else {
174 if (os_error != noErr) { 280 return SetQuarantinePropertiesDeprecated(file, properties);
175 OSSTATUS_LOG(WARNING, os_error)
176 << "Unable to set quarantine attributes on file " << file.value();
177 return false;
178 } 281 }
179 return true;
180 } 282 }
181 283
182 } // namespace 284 } // namespace
183 285
184 QuarantineFileResult QuarantineFile(const base::FilePath& file, 286 QuarantineFileResult QuarantineFile(const base::FilePath& file,
185 const GURL& source_url, 287 const GURL& source_url,
186 const GURL& referrer_url, 288 const GURL& referrer_url,
187 const std::string& client_guid) { 289 const std::string& client_guid) {
188 bool quarantine_succeeded = 290 bool quarantine_succeeded =
189 AddQuarantineMetadataToFile(file, source_url, referrer_url); 291 AddQuarantineMetadataToFile(file, source_url, referrer_url);
190 bool origin_succeeded = 292 bool origin_succeeded =
191 AddOriginMetadataToFile(file, source_url, referrer_url); 293 AddOriginMetadataToFile(file, source_url, referrer_url);
192 return quarantine_succeeded && origin_succeeded 294 return quarantine_succeeded && origin_succeeded
193 ? QuarantineFileResult::OK 295 ? QuarantineFileResult::OK
194 : QuarantineFileResult::ANNOTATION_FAILED; 296 : QuarantineFileResult::ANNOTATION_FAILED;
195 } 297 }
196 298
197 } // namespace content 299 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | content/browser/download/quarantine_mac_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698