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

Unified Diff: components/open_from_clipboard/clipboard_recent_content_ios.mm

Issue 1288733002: Add hash to OFC pasteboard change detection (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: moved comment Created 5 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: components/open_from_clipboard/clipboard_recent_content_ios.mm
diff --git a/components/open_from_clipboard/clipboard_recent_content_ios.mm b/components/open_from_clipboard/clipboard_recent_content_ios.mm
index d27d2566eb2d3f4b2f893cdbe50c517cd46fbaef..7665e46731dd30992369991cabd68b0035c3ae39 100644
--- a/components/open_from_clipboard/clipboard_recent_content_ios.mm
+++ b/components/open_from_clipboard/clipboard_recent_content_ios.mm
@@ -4,6 +4,7 @@
#import "components/open_from_clipboard/clipboard_recent_content_ios.h"
+#import <CommonCrypto/CommonDigest.h>
#import <UIKit/UIKit.h>
#import "base/ios/ios_util.h"
@@ -48,7 +49,7 @@
object:[UIPasteboard generalPasteboard]];
[[NSNotificationCenter defaultCenter]
addObserver:self
- selector:@selector(pasteboardChangedNotification:)
+ selector:@selector(didBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
}
@@ -66,6 +67,17 @@
}
}
+- (void)didBecomeActive:(NSNotification*)notification {
+ if (_delegate) {
+ _delegate->LoadFromUserDefaults();
+ base::TimeDelta uptime =
+ base::TimeDelta::FromMilliseconds(base::SysInfo::Uptime());
+ if (_delegate->HasPasteboardChanged(uptime)) {
+ _delegate->PasteboardChanged();
+ }
+ }
+}
+
- (void)disconnect {
_delegate = nullptr;
}
@@ -80,8 +92,12 @@ NSString* kPasteboardChangeCountKey = @"PasteboardChangeCount";
// Key used to store the last date at which it was detected that the pasteboard
// changed. It is used to evaluate the age of the pasteboard's content.
NSString* kPasteboardChangeDateKey = @"PasteboardChangeDate";
-// Key used to store the
-NSString* kSuppressedPasteboardEntryCountKey = @"PasteboardSupressedEntryCount";
+// Key used to store the hash of the content of the pasteboard. Whenever the
+// hash changed, the pasteboard content is considered to have changed.
+NSString* kPasteboardEntryMD5Key = @"PasteboardEntryMD5";
+// Key used to store the date of the latest pasteboard entry displayed in the
+// omnibox. This is used to report metrics on pasteboard change.
+NSString* kLastDisplayedPasteboardEntryKey = @"LastDisplayedPasteboardEntry";
base::TimeDelta kMaximumAgeOfClipboard = base::TimeDelta::FromHours(3);
// Schemes accepted by the ClipboardRecentContentIOS.
const char* kAuthorizedSchemes[] = {
@@ -90,18 +106,29 @@ const char* kAuthorizedSchemes[] = {
url::kDataScheme,
url::kAboutScheme,
};
+
+// Compute a hash consisting of the first 4 bytes of the MD5 hash of |string|.
+// This value is used to detect pasteboard content change. Keeping only 4 bytes
+// is a privacy requirement to introduce collision and allow deniability of
+// having copied a given string.
+NSData* WeakMD5FromNSString(NSString* string) {
+ unsigned char hash[CC_MD5_DIGEST_LENGTH];
+ const char* c_string = [string UTF8String];
+ CC_MD5(c_string, strlen(c_string), hash);
+ NSData* data = [NSData dataWithBytes:hash length:4];
+ return data;
+}
+
} // namespace
bool ClipboardRecentContentIOS::GetRecentURLFromClipboard(GURL* url) const {
DCHECK(url);
- if (GetClipboardContentAge() > kMaximumAgeOfClipboard ||
- [UIPasteboard generalPasteboard].changeCount ==
- suppressedPasteboardEntryCount_) {
+ if (GetClipboardContentAge() > kMaximumAgeOfClipboard) {
return false;
}
- if (urlFromPasteboardCache_.is_valid()) {
- *url = urlFromPasteboardCache_;
+ if (url_from_pasteboard_cache_.is_valid()) {
+ *url = url_from_pasteboard_cache_;
return true;
}
return false;
@@ -109,81 +136,92 @@ bool ClipboardRecentContentIOS::GetRecentURLFromClipboard(GURL* url) const {
base::TimeDelta ClipboardRecentContentIOS::GetClipboardContentAge() const {
return base::TimeDelta::FromSeconds(
- static_cast<int64>(-[lastPasteboardChangeDate_ timeIntervalSinceNow]));
+ static_cast<int64>(-[last_pasteboard_change_date_ timeIntervalSinceNow]));
}
void ClipboardRecentContentIOS::SuppressClipboardContent() {
- suppressedPasteboardEntryCount_ =
- [UIPasteboard generalPasteboard].changeCount;
+ // User cleared the user data. The pasteboard entry must be removed from the
+ // omnibox list. Force entry expiration by setting copy date to 1970.
+ last_pasteboard_change_date_.reset(
+ [[NSDate alloc] initWithTimeIntervalSince1970:0]);
SaveToUserDefaults();
}
void ClipboardRecentContentIOS::PasteboardChanged() {
- urlFromPasteboardCache_ = URLFromPasteboard();
- if (!urlFromPasteboardCache_.is_empty()) {
+ url_from_pasteboard_cache_ = URLFromPasteboard();
+ if (!url_from_pasteboard_cache_.is_empty()) {
base::RecordAction(
base::UserMetricsAction("MobileOmniboxClipboardChanged"));
}
- lastPasteboardChangeDate_.reset([[NSDate date] retain]);
- lastPasteboardChangeCount_ = [UIPasteboard generalPasteboard].changeCount;
- if (lastPasteboardChangeCount_ != suppressedPasteboardEntryCount_) {
- suppressedPasteboardEntryCount_ = NSIntegerMax;
+ last_pasteboard_change_date_.reset([[NSDate date] retain]);
+ last_pasteboard_change_count_ = [UIPasteboard generalPasteboard].changeCount;
+ NSString* pasteboard_string = [[UIPasteboard generalPasteboard] string];
+ if (!pasteboard_string) {
+ pasteboard_string = @"";
}
+ NSData* MD5 = WeakMD5FromNSString(pasteboard_string);
+ last_pasteboard_entry_md5_.reset([MD5 retain]);
+ SaveToUserDefaults();
}
ClipboardRecentContentIOS::ClipboardRecentContentIOS(
- const std::string& application_scheme)
- : application_scheme_(application_scheme) {
+ const std::string& application_scheme,
+ NSUserDefaults* group_user_defaults)
+ : application_scheme_(application_scheme),
+ shared_user_defaults_([group_user_defaults retain]) {
Init(base::TimeDelta::FromMilliseconds(base::SysInfo::Uptime()));
}
ClipboardRecentContentIOS::ClipboardRecentContentIOS(
const std::string& application_scheme,
base::TimeDelta uptime)
- : application_scheme_(application_scheme) {
+ : application_scheme_(application_scheme),
+ shared_user_defaults_([[NSUserDefaults standardUserDefaults] retain]) {
Init(uptime);
}
+bool ClipboardRecentContentIOS::HasPasteboardChanged(base::TimeDelta uptime) {
+ // If |MD5Changed|, we know for sure there has been at least one pasteboard
+ // copy since last time it was checked.
+ // If the pasteboard content is still the same but the device was not
+ // rebooted, the change count can be checked to see if it changed.
+ // Note: due to a mismatch between the actual behavior and documentation, and
+ // lack of consistency on different reboot scenarios, the change count cannot
+ // be checked after a reboot.
+ // See radar://21833556 for more information.
+ NSInteger change_count = [UIPasteboard generalPasteboard].changeCount;
+ bool change_count_changed = change_count != last_pasteboard_change_count_;
+
+ bool not_rebooted = uptime > GetClipboardContentAge();
+ if (not_rebooted)
+ return change_count_changed;
+
+ NSString* pasteboard_string = [[UIPasteboard generalPasteboard] string];
+ if (!pasteboard_string) {
+ pasteboard_string = @"";
+ }
+ NSData* md5 = WeakMD5FromNSString(pasteboard_string);
+ BOOL md5_changed = ![md5 isEqualToData:last_pasteboard_entry_md5_];
+
+ return md5_changed;
+}
+
void ClipboardRecentContentIOS::Init(base::TimeDelta uptime) {
- lastPasteboardChangeCount_ = NSIntegerMax;
- suppressedPasteboardEntryCount_ = NSIntegerMax;
- urlFromPasteboardCache_ = URLFromPasteboard();
+ last_pasteboard_change_count_ = NSIntegerMax;
+ url_from_pasteboard_cache_ = URLFromPasteboard();
LoadFromUserDefaults();
- // On iOS 7 (unlike on iOS 8, despite what the documentation says), the change
- // count is reset when the device is rebooted.
- if (uptime < GetClipboardContentAge() &&
- !base::ios::IsRunningOnIOS8OrLater()) {
- if ([UIPasteboard generalPasteboard].changeCount == 0) {
- // The user hasn't pasted anything in the clipboard since the device's
- // reboot. |PasteboardChanged| isn't called because it would update
- // |lastPasteboardChangeData_|, and record metrics.
- lastPasteboardChangeCount_ = 0;
- if (suppressedPasteboardEntryCount_ != NSIntegerMax) {
- // If the last time Chrome was running the pasteboard was suppressed,
- // and the user has not copied anything since the device launched, then
- // supress this entry.
- suppressedPasteboardEntryCount_ = 0;
- }
- SaveToUserDefaults();
- } else {
- // The user pasted something in the clipboard since the device's reboot.
- PasteboardChanged();
- }
- } else {
- NSInteger changeCount = [UIPasteboard generalPasteboard].changeCount;
- if (changeCount != lastPasteboardChangeCount_) {
- PasteboardChanged();
- }
- }
- // Makes sure |lastPasteboardChangeCount_| was properly initialized.
- DCHECK_NE(lastPasteboardChangeCount_, NSIntegerMax);
- notificationBridge_.reset(
+ if (HasPasteboardChanged(uptime))
+ PasteboardChanged();
+
+ // Makes sure |last_pasteboard_change_count_| was properly initialized.
+ DCHECK_NE(last_pasteboard_change_count_, NSIntegerMax);
+ notification_bridge_.reset(
[[PasteboardNotificationListenerBridge alloc] initWithDelegate:this]);
}
ClipboardRecentContentIOS::~ClipboardRecentContentIOS() {
- [notificationBridge_ disconnect];
+ [notification_bridge_ disconnect];
}
GURL ClipboardRecentContentIOS::URLFromPasteboard() {
@@ -204,32 +242,37 @@ GURL ClipboardRecentContentIOS::URLFromPasteboard() {
return GURL::EmptyGURL();
}
-void ClipboardRecentContentIOS::LoadFromUserDefaults() {
- NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
-
- lastPasteboardChangeCount_ =
- [defaults integerForKey:kPasteboardChangeCountKey];
- lastPasteboardChangeDate_.reset(
- [[defaults objectForKey:kPasteboardChangeDateKey] retain]);
-
- if ([[[defaults dictionaryRepresentation] allKeys]
- containsObject:kSuppressedPasteboardEntryCountKey]) {
- suppressedPasteboardEntryCount_ =
- [defaults integerForKey:kSuppressedPasteboardEntryCountKey];
- } else {
- suppressedPasteboardEntryCount_ = NSIntegerMax;
+void ClipboardRecentContentIOS::RecentURLDisplayed() {
+ if ([last_pasteboard_change_date_
+ isEqualToDate:last_displayed_pasteboard_entry_.get()]) {
+ return;
}
+ base::RecordAction(base::UserMetricsAction("MobileOmniboxClipboardChanged"));
+ last_pasteboard_change_date_ = last_displayed_pasteboard_entry_;
+ SaveToUserDefaults();
+}
+
+void ClipboardRecentContentIOS::LoadFromUserDefaults() {
+ last_pasteboard_change_count_ =
+ [shared_user_defaults_ integerForKey:kPasteboardChangeCountKey];
+ last_pasteboard_change_date_.reset(
+ [[shared_user_defaults_ objectForKey:kPasteboardChangeDateKey] retain]);
+ last_pasteboard_entry_md5_.reset(
+ [[shared_user_defaults_ objectForKey:kPasteboardEntryMD5Key] retain]);
+ last_displayed_pasteboard_entry_.reset([[shared_user_defaults_
+ objectForKey:kLastDisplayedPasteboardEntryKey] retain]);
- DCHECK(!lastPasteboardChangeDate_ ||
- [lastPasteboardChangeDate_ isKindOfClass:[NSDate class]]);
+ DCHECK(!last_pasteboard_change_date_ ||
+ [last_pasteboard_change_date_ isKindOfClass:[NSDate class]]);
}
void ClipboardRecentContentIOS::SaveToUserDefaults() {
- NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
- [defaults setInteger:lastPasteboardChangeCount_
- forKey:kPasteboardChangeCountKey];
- [defaults setObject:lastPasteboardChangeDate_
- forKey:kPasteboardChangeDateKey];
- [defaults setInteger:suppressedPasteboardEntryCount_
- forKey:kSuppressedPasteboardEntryCountKey];
+ [shared_user_defaults_ setInteger:last_pasteboard_change_count_
+ forKey:kPasteboardChangeCountKey];
+ [shared_user_defaults_ setObject:last_pasteboard_change_date_
+ forKey:kPasteboardChangeDateKey];
+ [shared_user_defaults_ setObject:last_pasteboard_entry_md5_
+ forKey:kPasteboardEntryMD5Key];
+ [shared_user_defaults_ setObject:last_displayed_pasteboard_entry_
+ forKey:kLastDisplayedPasteboardEntryKey];
}

Powered by Google App Engine
This is Rietveld 408576698