diff --git a/External/Crashlytics.framework/Versions/A/Crashlytics b/External/Crashlytics.framework/Versions/A/Crashlytics index 36430ccc..6bf7ab8b 100644 Binary files a/External/Crashlytics.framework/Versions/A/Crashlytics and b/External/Crashlytics.framework/Versions/A/Crashlytics differ diff --git a/External/Crashlytics.framework/Versions/A/Headers/Crashlytics.h b/External/Crashlytics.framework/Versions/A/Headers/Crashlytics.h index a99b331a..2de40dbd 100644 --- a/External/Crashlytics.framework/Versions/A/Headers/Crashlytics.h +++ b/External/Crashlytics.framework/Versions/A/Headers/Crashlytics.h @@ -2,7 +2,7 @@ // Crashlytics.h // Crashlytics // -// Copyright 2012 Crashlytics, Inc. All rights reserved. +// Copyright 2013 Crashlytics, Inc. All rights reserved. // #import @@ -148,12 +148,27 @@ OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); /** * Returns the session identifier for the crash report. **/ -- (NSString *)identifier; +@property (nonatomic, readonly) NSString *identifier; /** * Returns the custom key value data for the crash report. **/ -- (NSDictionary *)customKeys; +@property (nonatomic, readonly) NSDictionary *customKeys; + +/** + * Returns the CFBundleVersion of the application that crashed. + **/ +@property (nonatomic, readonly) NSString *bundleVersion; + +/** + * Returns the CFBundleShortVersionString of the application that crashed. + **/ +@property (nonatomic, readonly) NSString *bundleShortVersionString; + +/** + * Returns the date that the application crashed at. + **/ +@property (nonatomic, readonly) NSDate *crashedOnDate; @end diff --git a/External/Crashlytics.framework/Versions/A/Resources/Info.plist b/External/Crashlytics.framework/Versions/A/Resources/Info.plist index 6a6df8e7..c7e9624d 100644 --- a/External/Crashlytics.framework/Versions/A/Resources/Info.plist +++ b/External/Crashlytics.framework/Versions/A/Resources/Info.plist @@ -15,13 +15,13 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.7 + 2.0.8 CFBundleSupportedPlatforms iPhoneOS CFBundleVersion - 0200.07.00 + 0200.08.00 DTPlatformName iphoneos MinimumOSVersion diff --git a/External/Crashlytics.framework/run b/External/Crashlytics.framework/run index 2920a270..0f5db516 100755 Binary files a/External/Crashlytics.framework/run and b/External/Crashlytics.framework/run differ diff --git a/MasterPassword/ObjC/MPAlgorithm.h b/MasterPassword/ObjC/MPAlgorithm.h index ce47b0ef..70f42e2d 100644 --- a/MasterPassword/ObjC/MPAlgorithm.h +++ b/MasterPassword/ObjC/MPAlgorithm.h @@ -38,6 +38,7 @@ - (Class)classOfType:(MPElementType)type; - (NSString *)generateContentForElement:(MPElementGeneratedEntity *)element usingKey:(MPKey *)key; +- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key; @end diff --git a/MasterPassword/ObjC/MPAlgorithmV0.m b/MasterPassword/ObjC/MPAlgorithmV0.m index 1e7bf8ea..32d5c306 100644 --- a/MasterPassword/ObjC/MPAlgorithmV0.m +++ b/MasterPassword/ObjC/MPAlgorithmV0.m @@ -205,8 +205,6 @@ - (NSString *)generateContentForElement:(MPElementGeneratedEntity *)element usingKey:(MPKey *)key { - static NSDictionary *MPTypes_ciphers = nil; - if (!element) return nil; @@ -223,19 +221,25 @@ return nil; } + return [self generateContentNamed:element.name ofType:element.type withCounter:element.counter usingKey:key]; +} + +- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key { + + static NSDictionary *MPTypes_ciphers = nil; if (MPTypes_ciphers == nil) - MPTypes_ciphers = [NSDictionary dictionaryWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ciphers" - withExtension:@"plist"]]; + MPTypes_ciphers = [NSDictionary dictionaryWithContentsOfURL: + [[NSBundle mainBundle] URLForResource:@"ciphers" withExtension:@"plist"]]; // Determine the seed whose bytes will be used for calculating a password - uint32_t ncounter = htonl(element.counter), nnameLength = htonl(element.name.length); + uint32_t ncounter = htonl(counter), nnameLength = htonl(name.length); NSData *counterBytes = [NSData dataWithBytes:&ncounter length:sizeof(ncounter)]; NSData *nameLengthBytes = [NSData dataWithBytes:&nnameLength length:sizeof(nnameLength)]; - trc(@"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %@ | %@ | %@)", [key.keyData encodeBase64], [nameLengthBytes encodeHex], element.name, [counterBytes encodeHex]); + trc(@"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %@ | %@ | %@)", [key.keyData encodeBase64], [nameLengthBytes encodeHex], name, [counterBytes encodeHex]); NSData *seed = [[NSData dataByConcatenatingDatas: [@"com.lyndir.masterpassword" dataUsingEncoding:NSUTF8StringEncoding], nameLengthBytes, - [element.name dataUsingEncoding:NSUTF8StringEncoding], + [name dataUsingEncoding:NSUTF8StringEncoding], counterBytes, nil] hmacWith:PearlHashSHA256 key:key.keyData]; @@ -244,10 +248,10 @@ // Determine the cipher from the first seed byte. assert([seed length]); - NSArray *typeCiphers = [[MPTypes_ciphers valueForKey:[self classNameOfType:element.type]] - valueForKey:[self nameOfType:element.type]]; + NSArray *typeCiphers = [[MPTypes_ciphers valueForKey:[self classNameOfType:type]] + valueForKey:[self nameOfType:type]]; NSString *cipher = [typeCiphers objectAtIndex:htons(seedBytes[0]) % [typeCiphers count]]; - trc(@"type %@, ciphers: %@, selected: %@", [self nameOfType:element.type], typeCiphers, cipher); + trc(@"type %@, ciphers: %@, selected: %@", [self nameOfType:type], typeCiphers, cipher); // Encode the content, character by character, using subsequent seed bytes and the cipher. assert([seed length] >= [cipher length] + 1); diff --git a/MasterPassword/ObjC/MPAlgorithmV1.m b/MasterPassword/ObjC/MPAlgorithmV1.m index e379a717..7758f94e 100644 --- a/MasterPassword/ObjC/MPAlgorithmV1.m +++ b/MasterPassword/ObjC/MPAlgorithmV1.m @@ -46,39 +46,22 @@ return YES; } -- (NSString *)generateContentForElement:(MPElementGeneratedEntity *)element usingKey:(MPKey *)key { +- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key { static NSDictionary *MPTypes_ciphers = nil; - - if (!element) - return nil; - - if (!(element.type & MPElementTypeClassGenerated)) { - err(@"Incorrect type (is not MPElementTypeClassGenerated): %@, for: %@", [self nameOfType:element.type], element.name); - return nil; - } - if (!element.name.length) { - err(@"Missing name."); - return nil; - } - if (!key.keyData.length) { - err(@"Missing key."); - return nil; - } - if (MPTypes_ciphers == nil) - MPTypes_ciphers = [NSDictionary dictionaryWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ciphers" - withExtension:@"plist"]]; + MPTypes_ciphers = [NSDictionary dictionaryWithContentsOfURL: + [[NSBundle mainBundle] URLForResource:@"ciphers" withExtension:@"plist"]]; // Determine the seed whose bytes will be used for calculating a password - uint32_t ncounter = htonl(element.counter), nnameLength = htonl(element.name.length); + uint32_t ncounter = htonl(counter), nnameLength = htonl(name.length); NSData *counterBytes = [NSData dataWithBytes:&ncounter length:sizeof(ncounter)]; NSData *nameLengthBytes = [NSData dataWithBytes:&nnameLength length:sizeof(nnameLength)]; - trc(@"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %@ | %@ | %@)", [key.keyData encodeBase64], [nameLengthBytes encodeHex], element.name, [counterBytes encodeHex]); + trc(@"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %@ | %@ | %@)", [key.keyData encodeBase64], [nameLengthBytes encodeHex], name, [counterBytes encodeHex]); NSData *seed = [[NSData dataByConcatenatingDatas: [@"com.lyndir.masterpassword" dataUsingEncoding:NSUTF8StringEncoding], nameLengthBytes, - [element.name dataUsingEncoding:NSUTF8StringEncoding], + [name dataUsingEncoding:NSUTF8StringEncoding], counterBytes, nil] hmacWith:PearlHashSHA256 key:key.keyData]; @@ -87,10 +70,10 @@ // Determine the cipher from the first seed byte. assert([seed length]); - NSArray *typeCiphers = [[MPTypes_ciphers valueForKey:[self classNameOfType:element.type]] - valueForKey:[self nameOfType:element.type]]; + NSArray *typeCiphers = [[MPTypes_ciphers valueForKey:[self classNameOfType:type]] + valueForKey:[self nameOfType:type]]; NSString *cipher = [typeCiphers objectAtIndex:seedBytes[0] % [typeCiphers count]]; - trc(@"type %@, ciphers: %@, selected: %@", [self nameOfType:element.type], typeCiphers, cipher); + trc(@"type %@, ciphers: %@, selected: %@", [self nameOfType:type], typeCiphers, cipher); // Encode the content, character by character, using subsequent seed bytes and the cipher. assert([seed length] >= [cipher length] + 1); diff --git a/MasterPassword/ObjC/iOS/MPMainViewController.m b/MasterPassword/ObjC/iOS/MPMainViewController.m index 721ffa9b..846463b7 100644 --- a/MasterPassword/ObjC/iOS/MPMainViewController.m +++ b/MasterPassword/ObjC/iOS/MPMainViewController.m @@ -761,11 +761,11 @@ } } cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil otherTitles: - @"? FAQ", - @"ℹ Quick Guide", - @"⚙ Preferences", - @"⬇ Other Apps", - @"✉ Feedback", + @"? FAQ ", + @"ⓘ Quick Guide ", + @"⚙ Preferences ", + @"⚐ Other Apps ", + @"✎ Feedback ", nil]; } diff --git a/MasterPassword/ObjC/iOS/MPTypeViewController.m b/MasterPassword/ObjC/iOS/MPTypeViewController.m index 85c44d46..8ca946e6 100644 --- a/MasterPassword/ObjC/iOS/MPTypeViewController.m +++ b/MasterPassword/ObjC/iOS/MPTypeViewController.m @@ -78,28 +78,17 @@ if (cellType != NSNotFound && cellType & MPElementTypeClassGenerated) { [(UITextField *) [cell viewWithTag:2] setText:@"..."]; - NSManagedObjectID *selectedElementOID = [selectedElement objectID]; - [MPAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) { - NSError *error; - MPElementGeneratedEntity *selectedElement_ = (MPElementGeneratedEntity *) [moc existingObjectWithID:selectedElementOID error:&error]; - if (!selectedElement_) { - err(@"Failed to retrieve element for password preview: %@", error); - return; - } + NSString *name = selectedElement.name; + NSUInteger counter = ((MPElementGeneratedEntity *)selectedElement).counter; - MPElementGeneratedEntity *cellElement = [NSEntityDescription insertNewObjectForEntityForName:[MPAlgorithmDefault classNameOfType:cellType] - inManagedObjectContext:moc]; - cellElement.type = cellType; - cellElement.name = selectedElement_.name; - cellElement.user = selectedElement_.user; - cellElement.loginName = selectedElement_.loginName; - cellElement.version = MPAlgorithmDefaultVersion; + dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{ + NSString *typeContent = [MPAlgorithmDefault generateContentNamed:name ofType:cellType + withCounter:counter usingKey:[MPAppDelegate get].key]; - NSString *typeContent = [cellElement.algorithm generateContentForElement:cellElement usingKey:[MPAppDelegate get].key]; - dispatch_async(dispatch_get_main_queue(), ^{ - [(UITextField *) [[tableView cellForRowAtIndexPath:indexPath] viewWithTag:2] setText:typeContent]; - }); - }]; + dispatch_async( dispatch_get_main_queue(), ^{ + [(UITextField *)[[tableView cellForRowAtIndexPath:indexPath] viewWithTag:2] setText:typeContent]; + } ); + } ); } return cell; diff --git a/MasterPassword/ObjC/iOS/MPUnlockViewController.h b/MasterPassword/ObjC/iOS/MPUnlockViewController.h index 0030463a..8f483d70 100644 --- a/MasterPassword/ObjC/iOS/MPUnlockViewController.h +++ b/MasterPassword/ObjC/iOS/MPUnlockViewController.h @@ -26,6 +26,14 @@ @property (strong, nonatomic) IBOutlet UILongPressGestureRecognizer *targetedUserActionGesture; @property (weak, nonatomic) IBOutlet UIView *uiContainer; @property (weak, nonatomic) IBOutlet UIWebView *newsView; +@property (weak, nonatomic) IBOutlet UIView *emergencyGeneratorContainer; +@property (weak, nonatomic) IBOutlet UITextField *emergencyName; +@property (weak, nonatomic) IBOutlet UITextField *emergencyMasterPassword; +@property (weak, nonatomic) IBOutlet UITextField *emergencySite; +@property (weak, nonatomic) IBOutlet UIStepper *emergencyCounterStepper; +@property (weak, nonatomic) IBOutlet UISegmentedControl *emergencyType; +@property (weak, nonatomic) IBOutlet UILabel *emergencyCounter; +@property (weak, nonatomic) IBOutlet UITextField *emergencyPassword; @property (nonatomic, strong) UIColor *avatarShadowColor; @@ -35,5 +43,6 @@ - (IBAction)google:(UIButton *)sender; - (IBAction)mail:(UIButton *)sender; - (IBAction)add:(UIButton *)sender; +- (IBAction)closeEmergency; @end diff --git a/MasterPassword/ObjC/iOS/MPUnlockViewController.m b/MasterPassword/ObjC/iOS/MPUnlockViewController.m index d2dcb2f3..d5ba73ad 100644 --- a/MasterPassword/ObjC/iOS/MPUnlockViewController.m +++ b/MasterPassword/ObjC/iOS/MPUnlockViewController.m @@ -20,6 +20,9 @@ @property (nonatomic) BOOL wordWallAnimating; @property (nonatomic, strong) NSArray *wordList; +@property(nonatomic, strong) NSOperationQueue *emergencyQueue; +@property(nonatomic, strong) MPKey *emergencyKey; + @end @implementation MPUnlockViewController { @@ -104,12 +107,12 @@ } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { - + return UIInterfaceOrientationPortrait; } - (void)viewDidLoad { - + [self.newsView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.masterpasswordapp.com/news.html"]]]; self.avatarToUserOID = [NSMutableDictionary dictionaryWithCapacity:3]; @@ -117,11 +120,24 @@ [self.avatarsView addGestureRecognizer:self.targetedUserActionGesture]; self.avatarsView.decelerationRate = UIScrollViewDecelerationRateFast; self.avatarsView.clipsToBounds = NO; + self.tip.text = @""; self.nameLabel.layer.cornerRadius = 5; self.avatarTemplate.hidden = YES; self.spinner.alpha = 0; self.passwordTipView.hidden = NO; self.createPasswordTipView.hidden = NO; + self.emergencyPassword.text = @""; + self.emergencyGeneratorContainer.alpha = 0; + self.emergencyGeneratorContainer.hidden = YES; + self.emergencyQueue = [NSOperationQueue new]; + [self.emergencyCounterStepper addTargetBlock:^(id sender, UIControlEvents event) { + self.emergencyCounter.text = PearlString( @"%d", (NSUInteger)self.emergencyCounterStepper.value); + + [self updateEmergencyPassword]; + } forControlEvents:UIControlEventValueChanged]; + [self.emergencyType addTargetBlock:^(id sender, UIControlEvents event) { + [self updateEmergencyPassword]; + } forControlEvents:UIControlEventValueChanged]; NSMutableArray *wordListLines = [NSMutableArray arrayWithCapacity:27413]; [[[NSString alloc] initWithData:[NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"dictionary" withExtension:@"lst"]] @@ -147,6 +163,7 @@ }]; [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:nil usingBlock:^(NSNotification *note) { + [self closeEmergencyAnimated:NO]; self.uiContainer.alpha = 0; }]; [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:nil @@ -198,6 +215,8 @@ - (void)viewWillDisappear:(BOOL)animated { inf(@"Lock screen will disappear"); + [self closeEmergencyAnimated:animated]; + [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide]; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self.navigationController setNavigationBarHidden:NO animated:animated]; @@ -206,6 +225,26 @@ [super viewWillDisappear:animated]; } +- (BOOL)canBecomeFirstResponder { + + return YES; +} + +- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { + + if (motion == UIEventSubtypeMotionShake) { + [[self.view findFirstResponderInHierarchy] resignFirstResponder]; + + self.emergencyGeneratorContainer.alpha = 0; + self.emergencyGeneratorContainer.hidden = NO; + [UIView animateWithDuration:1 animations:^{ + self.emergencyGeneratorContainer.alpha = 1; + } completion:^(BOOL finished) { + [self.emergencyName becomeFirstResponder]; + }]; + } +} + - (void)updateUsers { NSManagedObjectContext *moc = [MPAppDelegate managedObjectContextForThreadIfReady]; @@ -316,7 +355,7 @@ - (void)showNewUserNameAlertFor:(MPUserEntity *)newUser inContext:(NSManagedObjectContext *)moc completion:(void (^)(BOOL finished))completion { - + [PearlAlert showAlertWithTitle:@"Enter Your Name" message:nil viewStyle:UIAlertViewStylePlainTextInput initAlert:^(UIAlertView *alert, UITextField *firstField) { @@ -339,7 +378,7 @@ } cancelTitle:@"Try Again" otherTitles:nil]; return; } - + // Save [moc performBlockAndWait:^{ newUser.name = name; @@ -694,41 +733,149 @@ [textField resignFirstResponder]; - [self setSpinnerActive:YES]; + if (textField == self.emergencyName) { + if (![self.emergencyMasterPassword.text length]) + [self.emergencyMasterPassword becomeFirstResponder]; + } - if (self.selectedUser.keyID) - [self tryMasterPassword]; + else if (textField == self.emergencyMasterPassword) { + if (![self.emergencySite.text length]) + [self.emergencySite becomeFirstResponder]; + } - else - [PearlAlert showAlertWithTitle:@"New Master Password" - message:@"Please confirm the spelling of this new master password." - viewStyle:UIAlertViewStyleSecureTextInput - initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { - [self setSpinnerActive:NO]; - - if (buttonIndex == [alert cancelButtonIndex]) - return; - - if (![[alert textFieldAtIndex:0].text isEqualToString:textField.text]) { - [PearlAlert showAlertWithTitle:@"Incorrect Master Password" - message: - @"The password you entered doesn't match with the master password you tried to use. " - @"You've probably mistyped one of them.\n\n" - @"Give it another try." - viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil - cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; - return; - } + else if (textField == self.passwordField) { + [self setSpinnerActive:YES]; + if (self.selectedUser.keyID) [self tryMasterPassword]; - } - cancelTitle:[PearlStrings get].commonButtonCancel - otherTitles:[PearlStrings get].commonButtonContinue, nil]; + else + [PearlAlert showAlertWithTitle:@"New Master Password" + message:@"Please confirm the spelling of this new master password." + viewStyle:UIAlertViewStyleSecureTextInput + initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { + [self setSpinnerActive:NO]; + + if (buttonIndex == [alert cancelButtonIndex]) + return; + + if (![[alert textFieldAtIndex:0].text isEqualToString:textField.text]) { + [PearlAlert showAlertWithTitle:@"Incorrect Master Password" + message: + @"The password you entered doesn't match with the master password you tried to use. " + @"You've probably mistyped one of them.\n\n" + @"Give it another try." + viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil + cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; + return; + } + + [self tryMasterPassword]; + } + cancelTitle:[PearlStrings get].commonButtonCancel + otherTitles:[PearlStrings get].commonButtonContinue, nil]; + } return YES; } +- (void)textFieldDidEndEditing:(UITextField *)textField { + + if (textField == self.emergencyName || textField == self.emergencyMasterPassword) + [self updateEmergencyKey]; + + if (textField == self.emergencySite) + [self updateEmergencyPassword]; +} + +- (void)updateEmergencyKey { + + if (![self.emergencyMasterPassword.text length] || ![self.emergencyName.text length]) + return; + + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + self.emergencyPassword.text = @"..."; + + NSString *masterPassword = self.emergencyMasterPassword.text; + NSString *userName = self.emergencyName.text; + + [self.emergencyQueue addOperationWithBlock:^{ + self.emergencyKey = [MPAlgorithmDefault keyForPassword:masterPassword ofUserNamed:userName]; + + [self updateEmergencyPassword]; + }]; + }]; +} + +- (void)updateEmergencyPassword { + + if (!self.emergencyKey || ![self.emergencySite.text length]) + return; + + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + self.emergencyPassword.text = @"..."; + + NSString *name = self.emergencySite.text; + NSUInteger counter = (NSUInteger)self.emergencyCounterStepper.value; + MPElementType type; + switch (self.emergencyType.selectedSegmentIndex) { + case 0: + type = MPElementTypeGeneratedMaximum; + break; + case 1: + type = MPElementTypeGeneratedLong; + break; + case 2: + type = MPElementTypeGeneratedMedium; + break; + case 3: + type = MPElementTypeGeneratedBasic; + break; + case 4: + type = MPElementTypeGeneratedShort; + break; + case 5: + type = MPElementTypeGeneratedPIN; + break; + default: + Throw(@"Unsupported type index: %d", self.emergencyType.selectedSegmentIndex); + } + + [self.emergencyQueue addOperationWithBlock:^{ + NSString *content = [MPAlgorithmDefault generateContentNamed:name ofType:type withCounter:counter usingKey:self.emergencyKey]; + + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + self.emergencyPassword.text = content; + }]; + }]; + }]; +} + +- (IBAction)closeEmergency { + + [self closeEmergencyAnimated:YES]; +} + +- (void)closeEmergencyAnimated:(BOOL)animated { + + [[self.emergencyGeneratorContainer findFirstResponderInHierarchy] resignFirstResponder]; + + if (animated) { + [UIView animateWithDuration:0.5 animations:^{ + [self closeEmergencyAnimated:NO]; + }]; + return; + } + + self.emergencyName.text = @""; + self.emergencyMasterPassword.text = @""; + self.emergencySite.text = @""; + self.emergencyCounterStepper.value = 0; + self.emergencyPassword.text = @""; + self.emergencyGeneratorContainer.alpha = 0; + self.emergencyGeneratorContainer.hidden = YES; +} + #pragma mark - UIScrollViewDelegate - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity @@ -756,12 +903,12 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { - + if (navigationType == UIWebViewNavigationTypeLinkClicked) { [[UIApplication sharedApplication] openURL:[request URL]]; return NO; } - + return YES; } @@ -815,7 +962,7 @@ viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil cancelTitle:nil otherTitles:@"OK", nil]; return; } - + SLComposeViewController *vc = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook]; [vc setInitialText:@"I've started doing passwords properly thanks to Master Password for iOS."]; [vc addImage:[UIImage imageNamed:@"iTunesArtwork-Rounded"]]; @@ -922,7 +1069,7 @@ MPUserEntity *selectedUser = (MPUserEntity *)[moc existingObjectWithID:_selectedUserOID error:&error]; if (!selectedUser) err(@"Failed to retrieve selected user: %@", error); - + return selectedUser; } diff --git a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard b/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard index 56844a4a..06b334bb 100644 --- a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard +++ b/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard @@ -535,7 +535,7 @@ Your passwords will be AES-encrypted with your master password. - + @@ -1092,7 +1092,7 @@ L4m3P4sSw0rD - + @@ -1455,6 +1455,145 @@ You could use the word wall for inspiration in finding a memorable master passw + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1467,6 +1606,14 @@ You could use the word wall for inspiration in finding a memorable master passw + + + + + + + + @@ -2649,178 +2796,6 @@ However, it means that anyone who finds your device unlocked can do the same. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -