Skip to content

Commit efbbb8d

Browse files
committed
大改 OTPAuthURL ,说是同名账户不能保存多个
1 parent 409ed4e commit efbbb8d

3 files changed

Lines changed: 76 additions & 98 deletions

File tree

Coding_iOS/Ease_2FA/Controllers/OTPListViewController.m

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,31 @@ - (void)beginButtonClicked:(id)sender{
186186
}
187187

188188
- (void)addOneAuthURL:(OTPAuthURL *)authURL{
189-
[authURL saveToKeychain];
190-
[self.authURLs addObject:authURL];
191-
[self configUI];
189+
for (OTPAuthURL *item in self.authURLs) {
190+
if ([authURL.name isEqualToString:item.name]) {
191+
if ([authURL.otpCode isEqualToString:item.otpCode]) {
192+
kTipAlert(@"该二维码已被保存为账户名:%@", authURL.name);
193+
}else{
194+
UIAlertView *alertV = [UIAlertView bk_alertViewWithTitle:@"提示" message:[NSString stringWithFormat:@"账户名:%@ 已存在\n选择 '更新' 覆盖原账户。", authURL.name]];
195+
[alertV bk_setCancelButtonWithTitle:@"取消" handler:nil];
196+
[alertV bk_addButtonWithTitle:@"更新" handler:nil];
197+
@weakify(self);
198+
alertV.bk_didDismissBlock = ^(UIAlertView *alertView, NSInteger buttonIndex){
199+
if (buttonIndex == 1) {
200+
@strongify(self);
201+
[authURL saveToKeychain];
202+
if ([self.authURLs indexOfObject:item] != NSNotFound) {
203+
[self.authURLs replaceObjectAtIndex:[self.authURLs indexOfObject:item] withObject:authURL];
204+
[self configUI];
205+
[self showHudTipStr:@"更新成功"];
206+
}
207+
}
208+
};
209+
[alertV show];
210+
}
211+
break;
212+
}
213+
}
192214
}
193215

194216
- (void)deleteOneAuthURL:(OTPAuthURL *)authURL{

Coding_iOS/Ease_2FA/GoogleOTP/OTPAuthURL.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,12 @@ static NSString *const kOTPService = @"com.google.otp.authentication";
3030
@interface OTPAuthURL : NSObject
3131

3232
// |name| is an arbitrary UTF8 text string extracted from the url path.
33-
@property (nonatomic, copy) NSString *name, *issuer, *ease_SecAttrAccount;
33+
@property (nonatomic, copy) NSString *name, *issuer;
3434
@property (nonatomic, copy, readonly) NSString *otpCode;
3535
@property (nonatomic, copy, readonly) NSString *checkCode;
36-
@property (nonatomic, strong, readonly) NSData *keychainItemRef;
3736

3837
+ (OTPAuthURL *)authURLWithURL:(NSURL *)url
3938
secret:(NSData *)secret;
40-
+ (OTPAuthURL *)authURLWithKeychainItemRef:(NSData *)keychainItemRef;
4139

4240
+ (OTPAuthURL *)ease_authURLWithKeychainDictionary:(NSDictionary *)dict;//
4341

@@ -51,12 +49,6 @@ static NSString *const kOTPService = @"com.google.otp.authentication";
5149
// Removes the current object state from the keychain.
5250
- (BOOL)removeFromKeychain;
5351

54-
// Returns true if the object was loaded from or subsequently added to the
55-
// iPhone keychain.
56-
// It does not assert that the keychain is up to date with the latest
57-
// |generator| state.
58-
- (BOOL)isInKeychain;
59-
6052
- (NSString*)checkCode;
6153

6254
@end

Coding_iOS/Ease_2FA/GoogleOTP/OTPAuthURL.m

Lines changed: 50 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555

5656
@interface OTPAuthURL ()
5757

58-
@property (strong, nonatomic, readwrite) NSData *keychainItemRef;
5958
@property (strong, nonatomic) OTPGenerator *generator;
6059

6160
// Initialize an OTPAuthURL with a dictionary of attributes from a keychain.
@@ -149,29 +148,12 @@ + (OTPAuthURL *)authURLWithURL:(NSURL *)url
149148
return authURL;
150149
}
151150

152-
+ (OTPAuthURL *)authURLWithKeychainItemRef:(NSData *)data {
153-
OTPAuthURL *authURL = nil;
154-
NSDictionary *query = @{
155-
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
156-
(__bridge id)kSecValuePersistentRef: data,
157-
(__bridge id)kSecReturnAttributes: @YES,
158-
(__bridge id)kSecReturnData: @YES
159-
};
160-
CFDictionaryRef result = NULL;
161-
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
162-
if (status == noErr) {
163-
authURL = [self authURLWithKeychainDictionary:(__bridge_transfer NSDictionary *)result];
164-
[authURL setKeychainItemRef:data];
165-
}
166-
return authURL;
167-
}
168-
169151
+ (OTPAuthURL *)ease_authURLWithKeychainDictionary:(NSDictionary *)dict{
170152
OTPAuthURL *authURL = [self authURLWithKeychainDictionary:dict];
171153
if (authURL) {
172154
NSString *secAttrAccount = dict[(__bridge id)kSecAttrAccount];
173-
if (secAttrAccount.length > 0) {
174-
authURL.ease_SecAttrAccount = secAttrAccount;
155+
if (![secAttrAccount isEqualToString:authURL.name]) {
156+
authURL.name = secAttrAccount;
175157
}
176158
}
177159
return authURL;
@@ -216,81 +198,63 @@ - (NSURL *)url {
216198
return nil;
217199
}
218200

219-
- (BOOL)saveToKeychain {
220-
NSString *urlString = [[self url] absoluteString];
221-
NSData *urlData = [urlString dataUsingEncoding:NSUTF8StringEncoding];
222-
223-
NSMutableDictionary *attributes =
224-
[NSMutableDictionary dictionaryWithObject:urlData
225-
forKey:(__bridge id)kSecAttrGeneric];
226-
OSStatus status = noErr;
227-
228-
if ([self isInKeychain] || self.ease_SecAttrAccount.length > 0) {
229-
NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
230-
(__bridge id)kSecValuePersistentRef: self.keychainItemRef};
231-
232-
status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes);
201+
- (NSDictionary *)keychainQuery{
202+
return @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
203+
(__bridge id)kSecAttrAccount: self.name};
204+
}
233205

234-
OTPDevLog(@"SecItemUpdate(%@, %@) = %d", query, attributes, (int)status);
235-
} else {
206+
- (BOOL)saveToKeychain {
207+
NSString *urlString = [[self url] absoluteString];
208+
NSData *urlData = [urlString dataUsingEncoding:NSUTF8StringEncoding];
209+
210+
NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
236211
attributes[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
237212
attributes[(__bridge id)kSecReturnPersistentRef] = (id)kCFBooleanTrue;
238-
attributes[(__bridge id)kSecValueData] = self.generator.secret;
239213
attributes[(__bridge id)kSecAttrService] = kOTPService;
240-
if (self.issuer.length > 0) {
241-
attributes[(__bridge id)kSecAttrType] = self.issuer;
242-
}
243214

244-
CFDataRef ref = NULL;
245-
246-
// The name here has to be unique or else we will get a errSecDuplicateItem
247-
// so if we have two items with the same name, we will just append a
248-
// random number on the end until we get success. We will try at max of
249-
// 1000 times so as to not hang in shut down.
250-
// We do not display this name to the user, so anything will do.
251-
NSString *name = self.name;
252-
for (int i = 0; i < 1000; i++) {
253-
attributes[(__bridge id)kSecAttrAccount] = name;
254-
status = SecItemAdd((__bridge CFDictionaryRef)attributes, (CFTypeRef *)&ref);
255-
if (status == errSecDuplicateItem) {
256-
name = [NSString stringWithFormat:@"%@.%ld", self.name, random()];
257-
} else {
258-
break;
259-
}
215+
216+
attributes[(__bridge id)kSecAttrGeneric] = urlData;
217+
attributes[(__bridge id)kSecValueData] = self.generator.secret;
218+
if (self.issuer.length > 0) {
219+
attributes[(__bridge id)kSecAttrType] = self.issuer;
260220
}
261-
262-
OTPDevLog(@"SecItemAdd(%@, %@) = %d", attributes, ref, (int)status);
263-
264-
if (status == noErr) {
265-
self.keychainItemRef = (__bridge_transfer NSData *)ref;
221+
222+
OSStatus status = noErr;
223+
CFDataRef ref = NULL;
224+
status = SecItemAdd((__bridge CFDictionaryRef)attributes, (CFTypeRef *)&ref);
225+
if (status == errSecDuplicateItem) {//如果有同名的话,就直接覆盖
226+
[attributes removeObjectsForKeys:@[(__bridge id)kSecClass, (__bridge id)kSecReturnPersistentRef, (__bridge id)kSecAttrService]];
227+
NSDictionary *query = [self keychainQuery];
228+
status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes);
266229
}
267-
}
268-
269-
return status == noErr;
230+
return status == noErr;
270231
}
271232

272-
- (BOOL)removeFromKeychain {
273-
if (self.ease_SecAttrAccount.length > 0) {
274-
return [SSKeychain deletePasswordForService:kOTPService account:self.ease_SecAttrAccount];
275-
}
233+
- (BOOL)hotpUpdateToKeychain{
234+
NSString *urlString = [[self url] absoluteString];
235+
NSData *urlData = [urlString dataUsingEncoding:NSUTF8StringEncoding];
276236

277-
if (![self isInKeychain]) {
278-
return NO;
279-
}
280-
NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
281-
(__bridge id)kSecValuePersistentRef: [self keychainItemRef]};
282-
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
283-
284-
OTPDevLog(@"SecItemDelete(%@) = %d", query, (int)status);
285-
286-
if (status == noErr) {
287-
[self setKeychainItemRef:nil];
288-
}
289-
return status == noErr;
237+
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:urlData forKey:(__bridge id)kSecAttrGeneric];
238+
NSDictionary *query = [self keychainQuery];
239+
OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes);
240+
241+
OTPDevLog(@"SecItemUpdate(%@, %@) = %d", query, attributes, (int)status);
242+
243+
return status == noErr;
290244
}
291245

292-
- (BOOL)isInKeychain {
293-
return self.keychainItemRef != nil;
246+
- (BOOL)removeFromKeychain {
247+
if (self.name.length > 0) {
248+
NSDictionary *query = [self keychainQuery];
249+
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
250+
OTPDevLog(@"SecItemDelete(%@) = %d", query, (int)status);
251+
if (status == noErr) {
252+
self.name = nil;
253+
}
254+
return status == noErr;
255+
}else{
256+
return NO;
257+
}
294258
}
295259

296260
- (void)generateNextOTPCode {
@@ -302,8 +266,8 @@ - (NSString*)checkCode {
302266
}
303267

304268
- (NSString *)description {
305-
return [NSString stringWithFormat:@"<%@ %p> Name: %@ ref: %p checkCode: %@",
306-
[self class], self, self.name, self.keychainItemRef, self.checkCode];
269+
return [NSString stringWithFormat:@"<%@ %p> Name: %@ checkCode: %@",
270+
[self class], self, self.name, self.checkCode];
307271
}
308272

309273
#pragma mark -
@@ -515,7 +479,7 @@ - (id)initWithName:(NSString *)name
515479

516480
- (void)generateNextOTPCode {
517481
self.otpCode = [[self generator] generateOTP];
518-
[self saveToKeychain];
482+
[self hotpUpdateToKeychain];
519483
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
520484
[nc postNotificationName:OTPAuthURLDidGenerateNewOTPNotification object:self];
521485
}

0 commit comments

Comments
 (0)