2
0

Emergency generator, action pictograms.

[ADDED]     Emergency Generator!
[ADDED]     Easier method for just using the master password algorithm bare.
[UPDATED]   Pictograms in action popup and centering of text.
This commit is contained in:
Maarten Billemont 2013-04-19 00:43:01 -04:00
parent c31df49599
commit ac1358a0ec
12 changed files with 397 additions and 274 deletions

View File

@ -2,7 +2,7 @@
// Crashlytics.h
// Crashlytics
//
// Copyright 2012 Crashlytics, Inc. All rights reserved.
// Copyright 2013 Crashlytics, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@ -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

View File

@ -15,13 +15,13 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.0.7</string>
<string>2.0.8</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>0200.07.00</string>
<string>0200.08.00</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>MinimumOSVersion</key>

Binary file not shown.

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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];
}

View File

@ -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;

View File

@ -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

View File

@ -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 {
@ -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];
@ -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

View File

@ -535,7 +535,7 @@ Your passwords will be AES-encrypted with your master password.</string>
<color key="shadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="S3cre7^Pa$swcrD" textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" id="fiX-10-fif" userLabel="Text Field - Content">
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="SadwGafy7^Sidu" textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" id="fiX-10-fif" userLabel="Text Field - Content">
<rect key="frame" x="20" y="26" width="280" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" hint=""/>
@ -1092,7 +1092,7 @@ L4m3P4sSw0rD</string>
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<view contentMode="scaleToFill" id="PHH-XC-9QQ">
<view contentMode="scaleToFill" id="PHH-XC-9QQ" userLabel="View - UI Container">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
@ -1455,6 +1455,145 @@ You could use the word wall for inspiration in finding a memorable master passw
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view alpha="0.30000000000000016" contentMode="scaleToFill" id="KNa-Xb-RuE" userLabel="View - Emergency Generator">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" id="vdf-Kn-Sle">
<rect key="frame" x="0.0" y="20" width="320" height="346"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_panel_display.png" id="jLf-TI-anP">
<rect key="frame" x="11" y="0.0" width="298" height="346"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.050000000000000003" y="0.10000000000000001" width="0.89999999999999991" height="0.79999999999999982"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Emergency Generator" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" id="shF-6G-WyQ">
<rect key="frame" x="30" y="20" width="260" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Bold" family="Gill Sans" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Generate your password without logging in. Great for if you're borrowing a friend's device or are having trouble logging in." lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" id="cgB-L6-VbR">
<rect key="frame" x="30" y="49" width="260" height="52"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="GillSans-LightItalic" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Your Name" minimumFontSize="17" id="esC-1q-bE7">
<rect key="frame" x="41" y="109" width="240" height="30"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="words" keyboardAppearance="alert" returnKeyType="next" enablesReturnKeyAutomatically="YES"/>
<connections>
<outlet property="delegate" destination="Nbn-Rv-sP1" id="yRn-2W-KeI"/>
</connections>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Your Master Password" minimumFontSize="17" id="Yvd-Hm-fuw">
<rect key="frame" x="41" y="147" width="240" height="30"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardAppearance="alert" returnKeyType="next" enablesReturnKeyAutomatically="YES" secureTextEntry="YES"/>
<connections>
<outlet property="delegate" destination="Nbn-Rv-sP1" id="tqK-8C-p2c"/>
</connections>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Site Name" minimumFontSize="17" id="YeH-3J-oY4">
<rect key="frame" x="41" y="185" width="240" height="30"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL" keyboardAppearance="alert" returnKeyType="done" enablesReturnKeyAutomatically="YES"/>
<connections>
<outlet property="delegate" destination="Nbn-Rv-sP1" id="w1h-rQ-fIF"/>
</connections>
</textField>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Counter" lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" id="pa9-d6-vQt">
<rect key="frame" x="41" y="262" width="285" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<stepper opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" maximumValue="100" id="D49-fo-7FA">
<rect key="frame" x="187" y="260" width="94" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
</stepper>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="0" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="TJC-xD-fjQ">
<rect key="frame" x="79" y="263" width="100" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="TmC-YR-JKg">
<rect key="frame" x="265" y="0.0" width="44" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" hint="" label="Close"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="icon_cancel.png">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="closeEmergency" destination="Nbn-Rv-sP1" eventType="touchUpInside" id="TgI-O2-XiW"/>
</connections>
</button>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="Kucy9-RimuTich" textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" id="WAX-03-cSy" userLabel="Text Field - Content">
<rect key="frame" x="20" y="292" width="280" height="54"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<accessibility key="accessibilityConfiguration" hint=""/>
<color key="textColor" red="0.47450980390000003" green="0.86666666670000003" blue="0.98431372549999996" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" name="AmericanTypewriter-Bold" family="American Typewriter" pointSize="30"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done"/>
</textField>
<view hidden="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="sD9-hR-UAI" userLabel="View - Content Tip">
<rect key="frame" x="55" y="320" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" id="Lua-xm-WX6">
<rect key="frame" x="0.0" y="0.0" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Copied!" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" id="fXa-HL-2OW">
<rect key="frame" x="19" y="9" width="171" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bar" selectedSegmentIndex="1" id="LfH-XT-9Vt">
<rect key="frame" x="41" y="223" width="240" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<segments>
<segment title="Max"/>
<segment title="Long"/>
<segment title="Med"/>
<segment title="Basic"/>
<segment title="Short"/>
<segment title="PIN"/>
</segments>
<color key="tintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
</segmentedControl>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</view>
@ -1467,6 +1606,14 @@ You could use the word wall for inspiration in finding a memorable master passw
<outlet property="avatarTemplate" destination="Ten-ig-gog" id="0ZZ-z5-d5m"/>
<outlet property="avatarsView" destination="Blg-F1-9NA" id="2NL-jU-IMI"/>
<outlet property="createPasswordTipView" destination="xWL-xQ-KjX" id="Pa1-Bk-pW2"/>
<outlet property="emergencyCounter" destination="TJC-xD-fjQ" id="jrf-nb-soB"/>
<outlet property="emergencyCounterStepper" destination="D49-fo-7FA" id="hj2-CL-zxq"/>
<outlet property="emergencyGeneratorContainer" destination="KNa-Xb-RuE" id="6jt-vU-L2Q"/>
<outlet property="emergencyMasterPassword" destination="Yvd-Hm-fuw" id="pnx-sH-P8R"/>
<outlet property="emergencyName" destination="esC-1q-bE7" id="ifH-bh-MhW"/>
<outlet property="emergencyPassword" destination="WAX-03-cSy" id="lLN-BO-OQ8"/>
<outlet property="emergencySite" destination="YeH-3J-oY4" id="h0w-om-4vd"/>
<outlet property="emergencyType" destination="LfH-XT-9Vt" id="pku-x3-i9h"/>
<outlet property="nameLabel" destination="0NM-NI-7UR" id="GBg-Ry-sqj"/>
<outlet property="newsView" destination="rGU-aZ-XVm" id="p1r-Wf-YIY"/>
<outlet property="oldNameLabel" destination="8s0-nT-Aoq" id="plu-1H-MVc"/>
@ -2649,178 +2796,6 @@ However, it means that anyone who finds your device unlocked can do the same.</s
<image name="ui_textfield.png" width="158" height="34"/>
<image name="unlocked.png" width="84" height="80"/>
</resources>
<classes>
<class className="MPAppViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPAppViewController.h"/>
<relationships>
<relationship kind="action" name="deblock:" candidateClass="UIButton"/>
<relationship kind="action" name="gorillas:" candidateClass="UIButton"/>
</relationships>
</class>
<class className="MPAppsViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPAppsViewController.h"/>
<relationships>
<relationship kind="action" name="exit"/>
<relationship kind="outlet" name="pagePositionView" candidateClass="UIImageView"/>
</relationships>
</class>
<class className="MPElementListAllViewController" superclassName="MPElementListController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPElementListAllViewController.h"/>
<relationships>
<relationship kind="action" name="add:"/>
<relationship kind="action" name="close:"/>
<relationship kind="outlet" name="navigationBar" candidateClass="UINavigationBar"/>
</relationships>
</class>
<class className="MPElementListController" superclassName="UITableViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPElementListController.h"/>
<relationships>
<relationship kind="outlet" name="delegate"/>
</relationships>
</class>
<class className="MPElementListSearchController" superclassName="MPElementListController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPElementListSearchController.h"/>
<relationships>
<relationship kind="outlet" name="searchDisplayController" candidateClass="UISearchDisplayController"/>
<relationship kind="outlet" name="searchTipContainer" candidateClass="UIView"/>
</relationships>
</class>
<class className="MPGuideViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPGuideViewController.h"/>
<relationships>
<relationship kind="action" name="close"/>
<relationship kind="action" name="play"/>
<relationship kind="action" name="toggleVolume"/>
<relationship kind="outlet" name="content" candidateClass="UIView"/>
<relationship kind="outlet" name="contentButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="contentText" candidateClass="UITextField"/>
<relationship kind="outlet" name="contentTip" candidateClass="UIView"/>
<relationship kind="outlet" name="contentTipText" candidateClass="UILabel"/>
<relationship kind="outlet" name="largePlayButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="progress" candidateClass="UIProgressView"/>
<relationship kind="outlet" name="siteNameTip" candidateClass="UIView"/>
<relationship kind="outlet" name="smallPlayButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="toolButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="toolTip" candidateClass="UIView"/>
<relationship kind="outlet" name="typeButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="typeTip" candidateClass="UIView"/>
<relationship kind="outlet" name="usernameButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="usernameTip" candidateClass="UIView"/>
<relationship kind="outlet" name="volumeButton" candidateClass="UIButton"/>
</relationships>
</class>
<class className="MPMainViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPMainViewController.h"/>
<relationships>
<relationship kind="action" name="action:" candidateClass="UIBarButtonItem"/>
<relationship kind="action" name="closeAlert"/>
<relationship kind="action" name="closeOutdatedAlert"/>
<relationship kind="action" name="copyContent"/>
<relationship kind="action" name="editLoginName:" candidateClass="UILongPressGestureRecognizer"/>
<relationship kind="action" name="editPassword"/>
<relationship kind="action" name="incrementPasswordCounter"/>
<relationship kind="action" name="infoOutdatedAlert"/>
<relationship kind="action" name="panHelpDown:" candidateClass="UIPanGestureRecognizer"/>
<relationship kind="action" name="panHelpUp:" candidateClass="UIPanGestureRecognizer"/>
<relationship kind="action" name="resetPasswordCounter:" candidateClass="UILongPressGestureRecognizer"/>
<relationship kind="action" name="searchOutdatedElements"/>
<relationship kind="action" name="toggleUser"/>
<relationship kind="action" name="upgradePassword"/>
<relationship kind="outlet" name="actionsTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="alertBody" candidateClass="UITextView"/>
<relationship kind="outlet" name="alertContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="alertTitle" candidateClass="UILabel"/>
<relationship kind="outlet" name="contentContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="contentField" candidateClass="UITextField"/>
<relationship kind="outlet" name="contentTipBody" candidateClass="UILabel"/>
<relationship kind="outlet" name="contentTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="displayContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="helpContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="helpView" candidateClass="UIWebView"/>
<relationship kind="outlet" name="loginNameContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="loginNameField" candidateClass="UITextField"/>
<relationship kind="outlet" name="loginNameTipBody" candidateClass="UILabel"/>
<relationship kind="outlet" name="loginNameTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="outdatedAlertBack" candidateClass="UIImageView"/>
<relationship kind="outlet" name="outdatedAlertCloseButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="outdatedAlertContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="passwordCounter" candidateClass="UILabel"/>
<relationship kind="outlet" name="passwordEdit" candidateClass="UIButton"/>
<relationship kind="outlet" name="passwordIncrementer" candidateClass="UIButton"/>
<relationship kind="outlet" name="passwordUpgrade" candidateClass="UIButton"/>
<relationship kind="outlet" name="passwordUser" candidateClass="UIButton"/>
<relationship kind="outlet" name="pullDownGesture" candidateClass="UIPanGestureRecognizer"/>
<relationship kind="outlet" name="pullDownView" candidateClass="UIImageView"/>
<relationship kind="outlet" name="pullUpGesture" candidateClass="UIPanGestureRecognizer"/>
<relationship kind="outlet" name="pullUpView" candidateClass="UIImageView"/>
<relationship kind="outlet" name="searchDelegate" candidateClass="MPElementListSearchController"/>
<relationship kind="outlet" name="searchTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="siteName" candidateClass="UILabel"/>
<relationship kind="outlet" name="toolTipBody" candidateClass="UILabel"/>
<relationship kind="outlet" name="toolTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="toolTipEditIcon" candidateClass="UIImageView"/>
<relationship kind="outlet" name="typeButton" candidateClass="UIButton"/>
<relationship kind="outlet" name="typeTipContainer" candidateClass="UIView"/>
</relationships>
</class>
<class className="MPPreferencesViewController" superclassName="UITableViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPPreferencesViewController.h"/>
<relationships>
<relationship kind="action" name="didToggleSwitch:" candidateClass="UISwitch"/>
<relationship kind="action" name="settings:"/>
<relationship kind="outlet" name="avatarTemplate" candidateClass="UIButton"/>
<relationship kind="outlet" name="avatarsView" candidateClass="UIScrollView"/>
<relationship kind="outlet" name="changeMPCell" candidateClass="UITableViewCell"/>
<relationship kind="outlet" name="defaultTypeLabel" candidateClass="UILabel"/>
<relationship kind="outlet" name="exportCell" candidateClass="UITableViewCell"/>
<relationship kind="outlet" name="savePasswordSwitch" candidateClass="UISwitch"/>
</relationships>
</class>
<class className="MPSetupViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPSetupViewController.h"/>
<relationships>
<relationship kind="action" name="close:" candidateClass="UIBarButtonItem"/>
<relationship kind="outlet" name="cloudSwitch" candidateClass="UISwitch"/>
<relationship kind="outlet" name="rememberLoginSwitch" candidateClass="UISwitch"/>
</relationships>
</class>
<class className="MPTypeViewController" superclassName="UITableViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPTypeViewController.h"/>
<relationships>
<relationship kind="outlet" name="recommendedTipContainer" candidateClass="UIView"/>
</relationships>
</class>
<class className="MPUnlockViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPUnlockViewController.h"/>
<relationships>
<relationship kind="action" name="add:" candidateClass="UIButton"/>
<relationship kind="action" name="facebook:" candidateClass="UIButton"/>
<relationship kind="action" name="google:" candidateClass="UIButton"/>
<relationship kind="action" name="mail:" candidateClass="UIButton"/>
<relationship kind="action" name="targetedUserAction:" candidateClass="UILongPressGestureRecognizer"/>
<relationship kind="action" name="twitter:" candidateClass="UIButton"/>
<relationship kind="outlet" name="avatarTemplate" candidateClass="UIButton"/>
<relationship kind="outlet" name="avatarsView" candidateClass="UIScrollView"/>
<relationship kind="outlet" name="createPasswordTipView" candidateClass="UIView"/>
<relationship kind="outlet" name="nameLabel" candidateClass="UILabel"/>
<relationship kind="outlet" name="newsView" candidateClass="UIWebView"/>
<relationship kind="outlet" name="oldNameLabel" candidateClass="UILabel"/>
<relationship kind="outlet" name="passwordField" candidateClass="UITextField"/>
<relationship kind="outlet" name="passwordFieldLabel" candidateClass="UILabel"/>
<relationship kind="outlet" name="passwordTipLabel" candidateClass="UILabel"/>
<relationship kind="outlet" name="passwordTipView" candidateClass="UIView"/>
<relationship kind="outlet" name="passwordView" candidateClass="UIView"/>
<relationship kind="outlet" name="spinner" candidateClass="UIImageView"/>
<relationship kind="outlet" name="targetedUserActionGesture" candidateClass="UILongPressGestureRecognizer"/>
<relationship kind="outlet" name="tip" candidateClass="UILabel"/>
<relationship kind="outlet" name="uiContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="wordWall" candidateClass="UIView"/>
</relationships>
</class>
<class className="PearlNavigationController" superclassName="UINavigationController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/PearlNavigationController.h"/>
</class>
</classes>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<nil key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>