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

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: Fix logic. 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
38 base::ScopedCFTypeRef<CFTypeRef> quarantine_properties;
39 OSStatus status = LSCopyItemAttribute(&file_ref, kLSRolesAll,
40 kLSItemQuarantineProperties, quarantine_properties.InitializeInto());
41 if (status != noErr)
42 return true;
43
44 CFDictionaryRef quarantine_properties_dict =
45 base::mac::CFCast<CFDictionaryRef>(quarantine_properties.get());
46 if (!quarantine_properties_dict) {
47 LOG(WARNING) << "kLSItemQuarantineProperties is not a dictionary on file "
48 << file.value();
49 return false;
50 }
51
52 properties->reset(
53 [base::mac::CFToNSCast(quarantine_properties_dict) mutableCopy]);
54 return true;
55 }
56
57 bool SetQuarantinePropertiesDeprecated(const base::FilePath& file,
58 NSDictionary* properties) {
59 FSRef file_ref;
60 if (!base::mac::FSRefFromPath(file.value(), &file_ref))
61 return false;
62 OSStatus os_error = LSSetItemAttribute(
63 &file_ref, kLSRolesAll, kLSItemQuarantineProperties, properties);
64 if (os_error != noErr) {
65 OSSTATUS_LOG(WARNING, os_error)
66 << "Unable to set quarantine attributes on file " << file.value();
67 return false;
68 }
69 return true;
70 }
71 #pragma clang diagnostic pop
72 #endif
73
74 bool GetQuarantineProperties(
75 const base::FilePath& file,
76 base::scoped_nsobject<NSMutableDictionary>* properties) {
77 base::scoped_nsobject<NSURL> file_url([[NSURL alloc]
78 initFileURLWithPath:base::SysUTF8ToNSString(file.value())]);
79 if (!file_url)
80 return false;
81
82 // NSURLQuarantinePropertiesKey is only available on macOS 10.10+.
83 #pragma clang diagnostic push
84 #pragma clang diagnostic ignored "-Wunguarded-availability"
85 NSError* error = nil;
86 id quarantine_properties = nil;
87 BOOL success = [file_url getResourceValue:&quarantine_properties
88 forKey:NSURLQuarantinePropertiesKey
89 error:&error];
90 #pragma clang diagnostic pop
91 if (!success) {
92 std::string error_message(error ? error.description.UTF8String : "");
93 LOG(WARNING) << "Unable to get quarantine attributes for file "
94 << file.value() << ". Error: " << error_message;
95 return false;
96 }
97
98 if (!quarantine_properties)
99 return true;
100
101 NSDictionary* quarantine_properties_dict =
102 base::mac::ObjCCast<NSDictionary>(quarantine_properties);
103 if (!quarantine_properties_dict) {
104 LOG(WARNING) << "Quarantine properties have wrong class: "
105 << [[[quarantine_properties class] description] UTF8String];
106 return false;
107 }
108
109 properties->reset([quarantine_properties_dict mutableCopy]);
110 return true;
111 }
112
113 bool SetQuarantineProperties(const base::FilePath& file,
114 NSDictionary* properties) {
115 base::scoped_nsobject<NSURL> file_url([[NSURL alloc]
116 initFileURLWithPath:base::SysUTF8ToNSString(file.value())]);
117 if (!file_url)
118 return false;
119
120 // NSURLQuarantinePropertiesKey is only available on macOS 10.10+.
121 #pragma clang diagnostic push
122 #pragma clang diagnostic ignored "-Wunguarded-availability"
123 NSError* error = nil;
124 bool success = [file_url setResourceValue:properties
125 forKey:NSURLQuarantinePropertiesKey
126 error:&error];
127 #pragma clang diagnostic pop
128 if (!success) {
129 std::string error_message(error ? error.description.UTF8String : "");
130 LOG(WARNING) << "Unable to set quarantine attributes on file "
131 << file.value() << ". Error: " << error_message;
132 return false;
133 }
134 return true;
135 }
136
137 } // namespace
138
19 namespace content { 139 namespace content {
20 140
21 namespace { 141 namespace {
22 142
23 // As of Mac OS X 10.4 ("Tiger"), files can be tagged with metadata describing 143 // 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 144 // various attributes. Metadata is integrated with the system's Spotlight
25 // feature and is searchable. Ordinarily, metadata can only be set by 145 // feature and is searchable. Ordinarily, metadata can only be set by
26 // Spotlight importers, which requires that the importer own the target file. 146 // Spotlight importers, which requires that the importer own the target file.
27 // However, there's an attribute intended to describe the origin of a 147 // 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. 148 // 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. 224 // the URL the user initiated the download from.
105 225
106 // The OS will automatically quarantine files due to the 226 // The OS will automatically quarantine files due to the
107 // LSFileQuarantineEnabled entry in our Info.plist, but it knows relatively 227 // LSFileQuarantineEnabled entry in our Info.plist, but it knows relatively
108 // little about the files. We add more information about the download to 228 // 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. 229 // improve the UI shown by the OS when the users tries to open the file.
110 bool AddQuarantineMetadataToFile(const base::FilePath& file, 230 bool AddQuarantineMetadataToFile(const base::FilePath& file,
111 const GURL& source, 231 const GURL& source,
112 const GURL& referrer) { 232 const GURL& referrer) {
113 base::ThreadRestrictions::AssertIOAllowed(); 233 base::ThreadRestrictions::AssertIOAllowed();
114 FSRef file_ref; 234 base::scoped_nsobject<NSMutableDictionary> properties;
115 if (!base::mac::FSRefFromPath(file.value(), &file_ref)) 235 bool success = false;
236 if (base::mac::IsAtLeastOS10_10()) {
237 success = GetQuarantineProperties(file, &properties);
238 } else {
239 success = GetQuarantinePropertiesDeprecated(file, &properties);
240 }
241
242 if (!success)
116 return false; 243 return false;
117 244
118 NSMutableDictionary* quarantine_properties = nil; 245 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 246 // 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). 247 // (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 248 // We don't want to add any metadata, because that will cause the file to
138 // be quarantined against the user's wishes. 249 // be quarantined against the user's wishes.
139 return true; 250 return true;
140 } 251 }
141 252
142 // kLSQuarantineAgentNameKey, kLSQuarantineAgentBundleIdentifierKey, and 253 // kLSQuarantineAgentNameKey, kLSQuarantineAgentBundleIdentifierKey, and
143 // kLSQuarantineTimeStampKey are set for us (see LSQuarantine.h), so we only 254 // kLSQuarantineTimeStampKey are set for us (see LSQuarantine.h), so we only
144 // need to set the values that the OS can't infer. 255 // need to set the values that the OS can't infer.
145 256
146 if (![quarantine_properties valueForKey:(NSString*)kLSQuarantineTypeKey]) { 257 if (![properties valueForKey:(NSString*)kLSQuarantineTypeKey]) {
147 CFStringRef type = source.SchemeIsHTTPOrHTTPS() 258 CFStringRef type = source.SchemeIsHTTPOrHTTPS()
148 ? kLSQuarantineTypeWebDownload 259 ? kLSQuarantineTypeWebDownload
149 : kLSQuarantineTypeOtherDownload; 260 : kLSQuarantineTypeOtherDownload;
150 [quarantine_properties setValue:(NSString*)type 261 [properties setValue:(NSString*)type
151 forKey:(NSString*)kLSQuarantineTypeKey]; 262 forKey:(NSString*)kLSQuarantineTypeKey];
152 } 263 }
153 264
154 if (![quarantine_properties 265 if (![properties valueForKey:(NSString*)kLSQuarantineOriginURLKey] &&
155 valueForKey:(NSString*)kLSQuarantineOriginURLKey] &&
156 referrer.is_valid()) { 266 referrer.is_valid()) {
157 NSString* referrer_url = 267 NSString* referrer_url =
158 [NSString stringWithUTF8String:referrer.spec().c_str()]; 268 [NSString stringWithUTF8String:referrer.spec().c_str()];
159 [quarantine_properties setValue:referrer_url 269 [properties setValue:referrer_url
160 forKey:(NSString*)kLSQuarantineOriginURLKey]; 270 forKey:(NSString*)kLSQuarantineOriginURLKey];
161 } 271 }
162 272
163 if (![quarantine_properties valueForKey:(NSString*)kLSQuarantineDataURLKey] && 273 if (![properties valueForKey:(NSString*)kLSQuarantineDataURLKey] &&
164 source.is_valid()) { 274 source.is_valid()) {
165 NSString* origin_url = 275 NSString* origin_url =
166 [NSString stringWithUTF8String:source.spec().c_str()]; 276 [NSString stringWithUTF8String:source.spec().c_str()];
167 [quarantine_properties setValue:origin_url 277 [properties setValue:origin_url forKey:(NSString*)kLSQuarantineDataURLKey];
168 forKey:(NSString*)kLSQuarantineDataURLKey];
169 } 278 }
170 279
171 OSStatus os_error = 280 if (base::mac::IsAtLeastOS10_10()) {
172 LSSetItemAttribute(&file_ref, kLSRolesAll, kLSItemQuarantineProperties, 281 return SetQuarantineProperties(file, properties);
173 quarantine_properties); 282 } else {
174 if (os_error != noErr) { 283 return SetQuarantinePropertiesDeprecated(file, properties);
175 OSSTATUS_LOG(WARNING, os_error)
176 << "Unable to set quarantine attributes on file " << file.value();
177 return false;
178 } 284 }
179 return true;
180 } 285 }
181 286
182 } // namespace 287 } // namespace
183 288
184 QuarantineFileResult QuarantineFile(const base::FilePath& file, 289 QuarantineFileResult QuarantineFile(const base::FilePath& file,
185 const GURL& source_url, 290 const GURL& source_url,
186 const GURL& referrer_url, 291 const GURL& referrer_url,
187 const std::string& client_guid) { 292 const std::string& client_guid) {
188 bool quarantine_succeeded = 293 bool quarantine_succeeded =
189 AddQuarantineMetadataToFile(file, source_url, referrer_url); 294 AddQuarantineMetadataToFile(file, source_url, referrer_url);
190 bool origin_succeeded = 295 bool origin_succeeded =
191 AddOriginMetadataToFile(file, source_url, referrer_url); 296 AddOriginMetadataToFile(file, source_url, referrer_url);
192 return quarantine_succeeded && origin_succeeded 297 return quarantine_succeeded && origin_succeeded
193 ? QuarantineFileResult::OK 298 ? QuarantineFileResult::OK
194 : QuarantineFileResult::ANNOTATION_FAILED; 299 : QuarantineFileResult::ANNOTATION_FAILED;
195 } 300 }
196 301
197 } // namespace content 302 } // 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