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

Side by Side Diff: components/open_from_clipboard/clipboard_recent_content_impl_ios.mm

Issue 2782823003: Rewrite implementation of ClipboardRecentContent in Objective C. (Closed)
Patch Set: sdefresne's comments Created 3 years, 8 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
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "components/open_from_clipboard/clipboard_recent_content_impl_ios.h"
6
7 #import <CommonCrypto/CommonDigest.h>
8 #import <UIKit/UIKit.h>
9
10 #import "base/mac/foundation_util.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "base/sys_info.h"
13
14 #if !defined(__has_feature) || !__has_feature(objc_arc)
15 #error "This file requires ARC support."
16 #endif
17
18 namespace {
19 // Key used to store the pasteboard's current change count. If when resuming
20 // chrome the pasteboard's change count is different from the stored one, then
21 // it means that the pasteboard's content has changed.
22 NSString* kPasteboardChangeCountKey = @"PasteboardChangeCount";
marq (ping after 24h) 2017/04/05 07:58:10 NSString* const kPasteboardChangeCountKey ..., her
lody 2017/04/06 11:27:22 Done.
23 // Key used to store the last date at which it was detected that the pasteboard
24 // changed. It is used to evaluate the age of the pasteboard's content.
25 NSString* kPasteboardChangeDateKey = @"PasteboardChangeDate";
26 // Key used to store the hash of the content of the pasteboard. Whenever the
27 // hash changed, the pasteboard content is considered to have changed.
28 NSString* kPasteboardEntryMD5Key = @"PasteboardEntryMD5";
29 // Maximum age of clipboard in seconds.
30 NSTimeInterval kMaximumAgeOfClipboard = 3 * 60 * 60;
marq (ping after 24h) 2017/04/05 07:58:10 const?
lody 2017/04/06 11:27:22 Done.
31
32 // Compute a hash consisting of the first 4 bytes of the MD5 hash of |string|.
33 // This value is used to detect pasteboard content change. Keeping only 4 bytes
34 // is a privacy requirement to introduce collision and allow deniability of
35 // having copied a given string.
36 NSData* WeakMD5FromNSString(NSString* string) {
37 unsigned char hash[CC_MD5_DIGEST_LENGTH];
38 const std::string clipboard = base::SysNSStringToUTF8(string);
39 const char* c_string = clipboard.c_str();
40 CC_MD5(c_string, strlen(c_string), hash);
41 NSData* data = [NSData dataWithBytes:hash length:4];
42 return data;
43 }
44
45 } // namespace
46
47 @interface ClipboardRecentContentImplIOS ()
48
49 // The user defaults from the app group used to optimize the pasteboard change
50 // detection.
51 @property(nonatomic, strong) NSUserDefaults* sharedUserDefaults;
52 // The pasteboard's change count. Increases everytime the pasteboard changes.
53 @property(nonatomic) NSInteger lastPasteboardChangeCount;
54 // MD5 hash of the last registered pasteboard entry.
55 @property(nonatomic, strong) NSData* lastPasteboardEntryMD5;
56 // Contains the authorized schemes for URLs.
57 @property(nonatomic, readonly) NSSet* authorizedSchemes;
58 // Delegate for metrics.
59 @property(nonatomic, strong) id<ClipboardRecentContentDelegate> delegate;
60
61 // If the content of the pasteboard has changed, updates the change count,
62 // change date, and md5 of the latest pasteboard entry if necessary.
63 - (void)updateIfNeeded;
64
65 // Returns whether the pasteboard changed since the last time a pasteboard
66 // change was detected.
67 - (BOOL)hasPasteboardChanged;
68
69 // Loads information from the user defaults about the latest pasteboard entry.
70 - (void)loadFromUserDefaults;
71
72 // Returns the URL contained in the clipboard (if any).
73 - (NSURL*)URLFromPasteboard;
74
75 // Returns the uptime.
76 - (NSTimeInterval)uptime;
77
78 @end
79
80 @implementation ClipboardRecentContentImplIOS
81
82 @synthesize lastPasteboardChangeCount = _lastPasteboardChangeCount;
83 @synthesize lastPasteboardChangeDate = _lastPasteboardChangeDate;
84 @synthesize lastPasteboardEntryMD5 = _lastPasteboardEntryMD5;
85 @synthesize sharedUserDefaults = _sharedUserDefaults;
86 @synthesize authorizedSchemes = _authorizedSchemes;
87 @synthesize delegate = _delegate;
88
89 - (instancetype)initWithAuthorizedSchemes:(NSSet*)authorizedSchemes
90 userDefaults:(NSUserDefaults*)groupUserDefaults
91 delegate:(id<ClipboardRecentContentDelegate>)
92 delegate {
93 self = [super init];
94 if (self) {
95 _delegate = delegate;
96 _authorizedSchemes = authorizedSchemes;
97 _sharedUserDefaults = groupUserDefaults;
98
99 _lastPasteboardChangeCount = NSIntegerMax;
100 [self loadFromUserDefaults];
101 [self updateIfNeeded];
102
103 // Makes sure |last_pasteboard_change_count_| was properly initialized.
104 DCHECK_NE(_lastPasteboardChangeCount, NSIntegerMax);
105 [[NSNotificationCenter defaultCenter]
106 addObserver:self
107 selector:@selector(didBecomeActive:)
108 name:UIApplicationDidBecomeActiveNotification
109 object:nil];
110 }
111 return self;
112 }
113
114 - (void)dealloc {
115 [[NSNotificationCenter defaultCenter] removeObserver:self];
116 }
117
118 - (void)didBecomeActive:(NSNotification*)notification {
119 [self loadFromUserDefaults];
120 [self updateIfNeeded];
121 }
122
123 - (NSData*)getCurrentMD5 {
124 NSString* pasteboardString = [UIPasteboard generalPasteboard].string;
125 NSData* md5 = WeakMD5FromNSString(pasteboardString);
126
127 return md5;
128 }
129
130 - (BOOL)hasPasteboardChanged {
131 // If |MD5Changed|, we know for sure there has been at least one pasteboard
132 // copy since last time it was checked.
133 // If the pasteboard content is still the same but the device was not
134 // rebooted, the change count can be checked to see if it changed.
135 // Note: due to a mismatch between the actual behavior and documentation, and
136 // lack of consistency on different reboot scenarios, the change count cannot
137 // be checked after a reboot.
138 // See radar://21833556 for more information.
139 bool deviceRebooted = [self getClipboardContentAge] >= [self uptime];
marq (ping after 24h) 2017/04/05 07:58:10 BOOL
lody 2017/04/06 11:27:22 Done.
140 if (!deviceRebooted) {
141 NSInteger changeCount = [UIPasteboard generalPasteboard].changeCount;
142 bool changeCountChanged = changeCount != self.lastPasteboardChangeCount;
143 return changeCountChanged;
144 }
145
146 BOOL md5Changed =
147 ![[self getCurrentMD5] isEqualToData:self.lastPasteboardEntryMD5];
148 return md5Changed;
149 }
150
151 - (NSURL*)getRecentURLFromClipboard {
152 [self updateIfNeeded];
153 if ([self getClipboardContentAge] > kMaximumAgeOfClipboard) {
154 return nil;
155 }
156
157 NSURL* urlFromPasteboard = [self URLFromPasteboard];
158 if (urlFromPasteboard) {
marq (ping after 24h) 2017/04/05 07:58:10 If this conditional fails, that means |urlFromPast
lody 2017/04/06 11:27:22 Done.
159 return urlFromPasteboard;
160 }
161 return nil;
162 }
163
164 - (NSTimeInterval)getClipboardContentAge {
marq (ping after 24h) 2017/04/05 07:58:10 remove 'get'. Method needs a comment somewhere.
lody 2017/04/06 11:27:22 Done It's in the .h
165 return -[self.lastPasteboardChangeDate timeIntervalSinceNow];
166 }
167
168 - (void)suppressClipboardContent {
169 // User cleared the user data. The pasteboard entry must be removed from the
170 // omnibox list. Force entry expiration by setting copy date to 1970.
171 self.lastPasteboardChangeDate =
172 [[NSDate alloc] initWithTimeIntervalSince1970:0];
173 [self saveToUserDefaults];
174 }
175
176 - (void)updateIfNeeded {
177 if (![self hasPasteboardChanged]) {
178 return;
179 }
180
181 [self.delegate onClipboardChanged];
182
183 self.lastPasteboardChangeDate = [NSDate date];
184 self.lastPasteboardChangeCount = [UIPasteboard generalPasteboard].changeCount;
185 self.lastPasteboardEntryMD5 = [self getCurrentMD5];
186
187 [self saveToUserDefaults];
188 }
189
190 - (NSURL*)URLFromPasteboard {
191 NSString* clipboardString = [UIPasteboard generalPasteboard].string;
192 if (!clipboardString) {
marq (ping after 24h) 2017/04/05 07:58:10 You can remove a lot of the nil checking, since [N
lody 2017/04/06 11:27:22 Done.
193 return nil;
194 }
195
196 NSURL* url = [NSURL URLWithString:clipboardString];
197 if (!url || ![self.authorizedSchemes containsObject:url.scheme]) {
198 return nil;
199 }
200 return url;
201 }
202
203 - (void)loadFromUserDefaults {
204 self.lastPasteboardChangeCount =
205 [self.sharedUserDefaults integerForKey:kPasteboardChangeCountKey];
206 self.lastPasteboardChangeDate = base::mac::ObjCCastStrict<NSDate>(
207 [self.sharedUserDefaults objectForKey:kPasteboardChangeDateKey]);
208 self.lastPasteboardEntryMD5 =
marq (ping after 24h) 2017/04/05 07:58:10 Why not also cast this value?
lody 2017/04/06 11:27:22 Done.
209 [self.sharedUserDefaults objectForKey:kPasteboardEntryMD5Key];
210 }
211
212 - (void)saveToUserDefaults {
213 [self.sharedUserDefaults setInteger:self.lastPasteboardChangeCount
214 forKey:kPasteboardChangeCountKey];
215 [self.sharedUserDefaults setObject:self.lastPasteboardChangeDate
216 forKey:kPasteboardChangeDateKey];
217 [self.sharedUserDefaults setObject:self.lastPasteboardEntryMD5
218 forKey:kPasteboardEntryMD5Key];
219 }
220
221 - (NSTimeInterval)uptime {
222 return base::SysInfo::Uptime().InSecondsF();
223 }
224
225 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698