diff --git a/External/InAppSettingsKit b/External/InAppSettingsKit index fcc72db0..b58b7256 160000 --- a/External/InAppSettingsKit +++ b/External/InAppSettingsKit @@ -1 +1 @@ -Subproject commit fcc72db0d54cd181f27b71e81901fc66958d71bf +Subproject commit b58b72563acecb727da1f7ca151798a911229593 diff --git a/External/Pearl b/External/Pearl index bde28af7..a4c734e0 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit bde28af789996972e55a4398b7034088de14d6d8 +Subproject commit a4c734e07c7441b4a49e83ae0a5de02158095ed7 diff --git a/External/iOS/Crashlytics.framework/Versions/A/Crashlytics b/External/iOS/Crashlytics.framework/Versions/A/Crashlytics index b0a896a0..552e04bb 100644 Binary files a/External/iOS/Crashlytics.framework/Versions/A/Crashlytics and b/External/iOS/Crashlytics.framework/Versions/A/Crashlytics differ diff --git a/External/iOS/Crashlytics.framework/Versions/A/Resources/Info.plist b/External/iOS/Crashlytics.framework/Versions/A/Resources/Info.plist index a97463cf..48c7bd50 100644 --- a/External/iOS/Crashlytics.framework/Versions/A/Resources/Info.plist +++ b/External/iOS/Crashlytics.framework/Versions/A/Resources/Info.plist @@ -15,13 +15,13 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.2.1 + 2.2.2 CFBundleSupportedPlatforms iPhoneOS CFBundleVersion - 35 + 36 DTPlatformName iphoneos MinimumOSVersion diff --git a/External/iOS/Crashlytics.framework/run b/External/iOS/Crashlytics.framework/run index ca71288d..42c401d3 100755 Binary files a/External/iOS/Crashlytics.framework/run and b/External/iOS/Crashlytics.framework/run differ diff --git a/External/iOS/Crashlytics.framework/submit b/External/iOS/Crashlytics.framework/submit index 668294e4..6c092c73 100755 Binary files a/External/iOS/Crashlytics.framework/submit and b/External/iOS/Crashlytics.framework/submit differ diff --git a/MasterPassword/ObjC/MPAlgorithm.h b/MasterPassword/ObjC/MPAlgorithm.h index b7dd2e3b..b8f356fb 100644 --- a/MasterPassword/ObjC/MPAlgorithm.h +++ b/MasterPassword/ObjC/MPAlgorithm.h @@ -22,6 +22,23 @@ #define MPAlgorithmDefaultVersion 1 #define MPAlgorithmDefault MPAlgorithmForVersion(MPAlgorithmDefaultVersion) +id MPAlgorithmForVersion(NSUInteger version); +id MPAlgorithmDefaultForBundleVersion(NSString *bundleVersion); + +PearlEnum( MPAttacker, + MPAttacker1, MPAttacker5K, MPAttacker20M, MPAttacker5B ); + +typedef struct TimeToCrack { + unsigned long long hours; + unsigned long long days; + unsigned long long weeks; + unsigned long long months; + unsigned long long years; + unsigned long long universes; +} TimeToCrack; + +NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack); + @protocol MPAlgorithm @required @@ -56,7 +73,7 @@ usingKey:(MPKey *)elementKey; - (NSString *)exportContentForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey; -@end +- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPElementType)type byAttacker:(MPAttacker)attacker; +- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordString:(NSString *)password byAttacker:(MPAttacker)attacker; -id MPAlgorithmForVersion(NSUInteger version); -id MPAlgorithmDefaultForBundleVersion(NSString *bundleVersion); +@end diff --git a/MasterPassword/ObjC/MPAlgorithm.m b/MasterPassword/ObjC/MPAlgorithm.m index 190c85e5..7b92652d 100644 --- a/MasterPassword/ObjC/MPAlgorithm.m +++ b/MasterPassword/ObjC/MPAlgorithm.m @@ -38,3 +38,21 @@ id MPAlgorithmDefaultForBundleVersion(NSString *bundleVersion) { return MPAlgorithmDefault; } + +NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack) { + + if (timeToCrack.universes > 1) + return strl( @"> age of the universe" ); + else if (timeToCrack.years > 1) + return strl( @"%d years", timeToCrack.years ); + else if (timeToCrack.months > 1) + return strl( @"%d months", timeToCrack.months ); + else if (timeToCrack.weeks > 1) + return strl( @"%d weeks", timeToCrack.weeks ); + else if (timeToCrack.days > 1) + return strl( @"%d days", timeToCrack.days ); + else if (timeToCrack.hours > 1) + return strl( @"%d hours", timeToCrack.hours ); + else + return strl( @"trivial" ); +} diff --git a/MasterPassword/ObjC/MPAlgorithmV0.h b/MasterPassword/ObjC/MPAlgorithmV0.h index 9204e0e4..ff081d8b 100644 --- a/MasterPassword/ObjC/MPAlgorithmV0.h +++ b/MasterPassword/ObjC/MPAlgorithmV0.h @@ -18,4 +18,11 @@ #import "MPAlgorithm.h" @interface MPAlgorithmV0 : NSObject + +- (NSDictionary *)allCiphers; +- (NSArray *)ciphersForType:(MPElementType)type; +- (NSArray *)cipherClasses; +- (NSArray *)cipherClassCharacters; +- (NSString *)charactersForCipherClass:(NSString *)cipherClass; + @end diff --git a/MasterPassword/ObjC/MPAlgorithmV0.m b/MasterPassword/ObjC/MPAlgorithmV0.m index efa47966..815f4b51 100644 --- a/MasterPassword/ObjC/MPAlgorithmV0.m +++ b/MasterPassword/ObjC/MPAlgorithmV0.m @@ -17,6 +17,8 @@ #import "MPAlgorithmV0.h" #import "MPEntities.h" +#include +#include #define MP_N 32768 #define MP_r 8 @@ -24,7 +26,29 @@ #define MP_dkLen 64 #define MP_hash PearlHashSHA256 -@implementation MPAlgorithmV0 +/* An AMD HD 7970 calculates 2495M SHA-1 hashes per second at a cost of ~350$ per GPU */ +#define CRACKING_PER_SECOND 2495000000UL +#define CRACKING_PRICE 350 + +@implementation MPAlgorithmV0 { + BN_CTX *ctx; +} + +- (id)init { + + if (!(self = [super init])) + return nil; + + ctx = BN_CTX_new(); + + return self; +} + +- (void)dealloc { + + BN_CTX_free( ctx ); + ctx = NULL; +} - (NSUInteger)version { @@ -239,21 +263,21 @@ switch (type) { case MPElementTypeGeneratedMaximum: - return MPElementTypeStoredDevicePrivate; - case MPElementTypeGeneratedLong: - return MPElementTypeGeneratedMaximum; - case MPElementTypeGeneratedMedium: return MPElementTypeGeneratedLong; - case MPElementTypeGeneratedBasic: + case MPElementTypeGeneratedLong: return MPElementTypeGeneratedMedium; - case MPElementTypeGeneratedShort: + case MPElementTypeGeneratedMedium: return MPElementTypeGeneratedBasic; - case MPElementTypeGeneratedPIN: + case MPElementTypeGeneratedBasic: return MPElementTypeGeneratedShort; - case MPElementTypeStoredPersonal: + case MPElementTypeGeneratedShort: return MPElementTypeGeneratedPIN; - case MPElementTypeStoredDevicePrivate: + case MPElementTypeGeneratedPIN: return MPElementTypeStoredPersonal; + case MPElementTypeStoredPersonal: + return MPElementTypeStoredDevicePrivate; + case MPElementTypeStoredDevicePrivate: + return MPElementTypeGeneratedMaximum; default: return MPElementTypeGeneratedLong; } @@ -268,12 +292,41 @@ return previousType; } -- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key { +- (NSDictionary *)allCiphers { - static NSDictionary *MPTypes_ciphers = nil; - if (MPTypes_ciphers == nil) - MPTypes_ciphers = [NSDictionary dictionaryWithContentsOfURL: + static NSDictionary *ciphers = nil; + static dispatch_once_t once = 0; + dispatch_once( &once, ^{ + ciphers = [NSDictionary dictionaryWithContentsOfURL: [[NSBundle mainBundle] URLForResource:@"ciphers" withExtension:@"plist"]]; + } ); + + return ciphers; +} + +- (NSArray *)ciphersForType:(MPElementType)type { + + NSString *typeClass = [self classNameOfType:type]; + NSString *typeName = [self nameOfType:type]; + return [[[self allCiphers] valueForKey:typeClass] valueForKey:typeName]; +} + +- (NSArray *)cipherClasses { + + return [[[self allCiphers] valueForKey:@"MPCharacterClasses"] allKeys]; +} + +- (NSArray *)cipherClassCharacters { + + return [[[self allCiphers] valueForKey:@"MPCharacterClasses"] allValues]; +} + +- (NSString *)charactersForCipherClass:(NSString *)cipherClass { + + return [NSNullToNil( [NSNullToNil( [[self allCiphers] valueForKey:@"MPCharacterClasses"] ) valueForKey:cipherClass] ) copy]; +} + +- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key { // Determine the seed whose bytes will be used for calculating a password uint32_t ncounter = htonl( counter ), nnameLength = htonl( name.length ); @@ -291,12 +344,9 @@ // Determine the cipher from the first seed byte. NSAssert( [seed length], @"Missing seed." ); - NSString *typeClass = [self classNameOfType:type]; - NSString *typeName = [self nameOfType:type]; - id classCiphers = [MPTypes_ciphers valueForKey:typeClass]; - NSArray *typeCiphers = [classCiphers valueForKey:typeName]; + NSArray *typeCiphers = [self ciphersForType:type]; NSString *cipher = typeCiphers[htons( seedBytes[0] ) % [typeCiphers count]]; - trc( @"type %@, ciphers: %@, selected: %@", typeName, typeCiphers, cipher ); + trc( @"type %@, ciphers: %@, selected: %@", [self nameOfType:type], typeCiphers, cipher ); // Encode the content, character by character, using subsequent seed bytes and the cipher. NSAssert( [seed length] >= [cipher length] + 1, @"Insufficient seed bytes to encode cipher." ); @@ -304,7 +354,7 @@ for (NSUInteger c = 0; c < [cipher length]; ++c) { uint16_t keyByte = htons( seedBytes[c + 1] ); NSString *cipherClass = [cipher substringWithRange:NSMakeRange( c, 1 )]; - NSString *cipherClassCharacters = [[MPTypes_ciphers valueForKey:@"MPCharacterClasses"] valueForKey:cipherClass]; + NSString *cipherClassCharacters = [self charactersForCipherClass:cipherClass]; NSString *character = [cipherClassCharacters substringWithRange:NSMakeRange( keyByte % [cipherClassCharacters length], 1 )]; trc( @"class %@ has characters: %@, index: %u, selected: %@", cipherClass, cipherClassCharacters, keyByte, character ); @@ -334,9 +384,11 @@ } case MPElementTypeStoredPersonal: { - NSAssert( [element isKindOfClass:[MPElementStoredEntity class]], - @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type, - [element class] ); + if (![element isKindOfClass:[MPElementStoredEntity class]]) { + wrn( @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", + (long)element.type, [element class] ); + break; + } NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding] encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES]; @@ -344,9 +396,11 @@ break; } case MPElementTypeStoredDevicePrivate: { - NSAssert( [element isKindOfClass:[MPElementStoredEntity class]], - @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type, - [element class] ); + if (![element isKindOfClass:[MPElementStoredEntity class]]) { + wrn( @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", + (long)element.type, [element class] ); + break; + } NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding] encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES]; @@ -355,7 +409,7 @@ [PearlKeyChain deleteItemForQuery:elementQuery]; else [PearlKeyChain addOrUpdateItemForQuery:elementQuery withAttributes:@{ - (__bridge id)kSecValueData : encryptedContent, + (__bridge id)kSecValueData : encryptedContent, #if TARGET_OS_IPHONE (__bridge id)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleWhenUnlockedThisDeviceOnly, #endif @@ -390,9 +444,11 @@ case MPElementTypeGeneratedBasic: case MPElementTypeGeneratedShort: case MPElementTypeGeneratedPIN: { - NSAssert( [element isKindOfClass:[MPElementGeneratedEntity class]], - @"Element with generated type %lu is not an MPElementGeneratedEntity, but a %@.", (long)element.type, - [element class] ); + if (![element isKindOfClass:[MPElementGeneratedEntity class]]) { + wrn( @"Element with generated type %lu is not an MPElementGeneratedEntity, but a %@.", + (long)element.type, [element class] ); + break; + } NSString *name = element.name; MPElementType type = element.type; @@ -413,9 +469,11 @@ } case MPElementTypeStoredPersonal: { - NSAssert( [element isKindOfClass:[MPElementStoredEntity class]], - @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type, - [element class] ); + if (![element isKindOfClass:[MPElementStoredEntity class]]) { + wrn( @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", + (long)element.type, [element class] ); + break; + } NSData *encryptedContent = ((MPElementStoredEntity *)element).contentObject; @@ -456,9 +514,11 @@ break; case MPElementTypeStoredPersonal: { - NSAssert( [element isKindOfClass:[MPElementStoredEntity class]], - @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type, - [element class] ); + if (![element isKindOfClass:[MPElementStoredEntity class]]) { + wrn( @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", + (long)element.type, [element class] ); + break; + } if ([importKey.keyID isEqualToData:elementKey.keyID]) ((MPElementStoredEntity *)element).contentObject = [protectedContent decodeBase64]; @@ -515,9 +575,11 @@ } case MPElementTypeStoredPersonal: { - NSAssert( [element isKindOfClass:[MPElementStoredEntity class]], - @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type, - [element class] ); + if (![element isKindOfClass:[MPElementStoredEntity class]]) { + wrn( @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", + (long)element.type, [element class] ); + break; + } result = [((MPElementStoredEntity *)element).contentObject encodeBase64]; break; } @@ -557,4 +619,145 @@ return [[NSString alloc] initWithBytes:decryptedContent.bytes length:decryptedContent.length encoding:NSUTF8StringEncoding]; } +- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPElementType)type byAttacker:(MPAttacker)attacker { + + if (!type) + return NO; + NSArray *ciphers = [self ciphersForType:type]; + if (!ciphers) + return NO; + + BIGNUM *permutations = BN_new(), *cipherPermutations = BN_new(); + for (NSString *cipher in ciphers) { + BN_one( cipherPermutations ); + + for (NSUInteger c = 0; c < [cipher length]; ++c) + BN_mul_word( cipherPermutations, + (BN_ULONG)[[self charactersForCipherClass:[cipher substringWithRange:NSMakeRange( c, 1 )]] length] ); + + BN_add( permutations, permutations, cipherPermutations ); + } + BN_free( cipherPermutations ); + + return [self timeToCrack:timeToCrack permutations:permutations forAttacker:attacker]; +} + +- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordString:(NSString *)password byAttacker:(MPAttacker)attacker { + + BIGNUM *permutations = BN_new(); + BN_one( permutations ); + + NSMutableString *cipher = [NSMutableString new]; + for (NSUInteger c = 0; c < [password length]; ++c) { + NSString *passwordCharacter = [password substringWithRange:NSMakeRange( c, 1 )]; + + unsigned int characterEntropy = 0; + for (NSString *cipherClass in @[ @"v", @"c", @"a", @"x" ]) { + NSString *charactersForClass = [self charactersForCipherClass:cipherClass]; + + if ([charactersForClass rangeOfString:passwordCharacter].location != NSNotFound) { + // Found class for password character. + characterEntropy = (BN_ULONG)[charactersForClass length]; + [cipher appendString:cipherClass]; + break; + } + } + if (!characterEntropy) { + [cipher appendString:@"b"]; + characterEntropy = 256 /* a byte */; + } + + BN_mul_word( permutations, characterEntropy ); + } + + return [self timeToCrack:timeToCrack permutations:permutations forAttacker:attacker]; +} + +- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack permutations:(BIGNUM *)permutations forAttacker:(MPAttacker)attacker { + + // Determine base seconds needed to calculate the permutations. + BIGNUM *secondsToCrack = BN_dup( permutations ); + BN_div_word( secondsToCrack, CRACKING_PER_SECOND ); + + // Modify seconds needed by applying our hardware budget. + switch (attacker) { + case MPAttacker1: + break; + case MPAttacker5K: + BN_mul_word( secondsToCrack, CRACKING_PRICE ); + BN_div_word( secondsToCrack, 5000 ); + break; + case MPAttacker20M: + BN_mul_word( secondsToCrack, CRACKING_PRICE ); + BN_div_word( secondsToCrack, 20000000 ); + break; + case MPAttacker5B: + BN_mul_word( secondsToCrack, CRACKING_PRICE ); + BN_div_word( secondsToCrack, 5000 ); + BN_div_word( secondsToCrack, 1000000 ); + break; + } + + BIGNUM *max = BN_new(); + BN_set_word( max, (BN_ULONG)-1 ); + + BIGNUM *hoursToCrack = BN_dup( secondsToCrack ); + BN_div_word( hoursToCrack, 3600 ); + if (BN_cmp( hoursToCrack, max ) < 0) + timeToCrack->hours = BN_get_word( hoursToCrack ); + else + timeToCrack->hours = (BN_ULONG)-1; + + BIGNUM *daysToCrack = BN_dup( hoursToCrack ); + BN_div_word( daysToCrack, 24 ); + if (BN_cmp( daysToCrack, max ) < 0) + timeToCrack->days = BN_get_word( daysToCrack ); + else + timeToCrack->days = (BN_ULONG)-1; + + BIGNUM *weeksToCrack = BN_dup( daysToCrack ); + BN_div_word( weeksToCrack, 7 ); + if (BN_cmp( weeksToCrack, max ) < 0) + timeToCrack->weeks = BN_get_word( weeksToCrack ); + else + timeToCrack->weeks = (BN_ULONG)-1; + + BIGNUM *monthsToCrack = BN_dup( daysToCrack ); + BN_div_word( monthsToCrack, 31 ); + if (BN_cmp( monthsToCrack, max ) < 0) + timeToCrack->months = BN_get_word( monthsToCrack ); + else + timeToCrack->months = (BN_ULONG)-1; + + BIGNUM *yearsToCrack = BN_dup( daysToCrack ); + BN_div_word( yearsToCrack, 356 ); + if (BN_cmp( yearsToCrack, max ) < 0) + timeToCrack->years = BN_get_word( yearsToCrack ); + else + timeToCrack->years = (BN_ULONG)-1; + + BIGNUM *universesToCrack = BN_dup( yearsToCrack ); + BN_div_word( universesToCrack, 14000 ); + BN_div_word( universesToCrack, 1000000 ); + if (BN_cmp( universesToCrack, max ) < 0) + timeToCrack->universes = BN_get_word( universesToCrack ); + else + timeToCrack->universes = (BN_ULONG)-1; + + for (unsigned long error = ERR_get_error(); error; error = ERR_get_error()) + err( @"bignum error: %lu", error ); + + BN_free( max ); + BN_free( permutations ); + BN_free( secondsToCrack ); + BN_free( hoursToCrack ); + BN_free( daysToCrack ); + BN_free( weeksToCrack ); + BN_free( monthsToCrack ); + BN_free( yearsToCrack ); + BN_free( universesToCrack ); + + return YES; +} + @end diff --git a/MasterPassword/ObjC/MPAlgorithmV1.m b/MasterPassword/ObjC/MPAlgorithmV1.m index a95db09b..6ef54659 100644 --- a/MasterPassword/ObjC/MPAlgorithmV1.m +++ b/MasterPassword/ObjC/MPAlgorithmV1.m @@ -1,12 +1,12 @@ /** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ +* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) +* +* See the enclosed file LICENSE for license information (LGPLv3). If you did +* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt +* +* @author Maarten Billemont +* @license http://www.gnu.org/licenses/lgpl-3.0.txt +*/ // // MPAlgorithmV1 @@ -28,7 +28,7 @@ - (BOOL)migrateElement:(MPElementEntity *)element explicit:(BOOL)explicit { if (element.version != [self version] - 1) - // Only migrate from previous version. + // Only migrate from previous version. return NO; if (!explicit) { @@ -47,18 +47,12 @@ - (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key { - static __strong NSDictionary *MPTypes_ciphers = nil; - static dispatch_once_t once = 0; - dispatch_once(&once, ^{ - 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(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], name, [counterBytes encodeHex]); + 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], + name, [counterBytes encodeHex] ); NSData *seed = [[NSData dataByConcatenatingDatas: [@"com.lyndir.masterpassword" dataUsingEncoding:NSUTF8StringEncoding], nameLengthBytes, @@ -66,25 +60,25 @@ counterBytes, nil] hmacWith:PearlHashSHA256 key:key.keyData]; - trc(@"seed is: %@", [seed encodeBase64]); + trc( @"seed is: %@", [seed encodeBase64] ); const unsigned char *seedBytes = seed.bytes; // Determine the cipher from the first seed byte. - NSAssert([seed length], @"Missing seed."); - NSArray *typeCiphers = [[MPTypes_ciphers valueForKey:[self classNameOfType:type]] valueForKey:[self nameOfType:type]]; + NSAssert( [seed length], @"Missing seed." ); + NSArray *typeCiphers = [self ciphersForType:type]; NSString *cipher = typeCiphers[seedBytes[0] % [typeCiphers count]]; - trc(@"type %@, ciphers: %@, selected: %@", [self nameOfType: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. - NSAssert([seed length] >= [cipher length] + 1, @"Insufficient seed bytes to encode cipher."); + NSAssert( [seed length] >= [cipher length] + 1, @"Insufficient seed bytes to encode cipher." ); NSMutableString *content = [NSMutableString stringWithCapacity:[cipher length]]; for (NSUInteger c = 0; c < [cipher length]; ++c) { uint16_t keyByte = seedBytes[c + 1]; NSString *cipherClass = [cipher substringWithRange:NSMakeRange( c, 1 )]; - NSString *cipherClassCharacters = [[MPTypes_ciphers valueForKey:@"MPCharacterClasses"] valueForKey:cipherClass]; + NSString *cipherClassCharacters = [self charactersForCipherClass:cipherClass]; NSString *character = [cipherClassCharacters substringWithRange:NSMakeRange( keyByte % [cipherClassCharacters length], 1 )]; - trc(@"class %@ has characters: %@, index: %u, selected: %@", cipherClass, cipherClassCharacters, keyByte, character); + trc( @"class %@ has characters: %@, index: %u, selected: %@", cipherClass, cipherClassCharacters, keyByte, character ); [content appendString:character]; } diff --git a/MasterPassword/ObjC/MPAppDelegate_Store.h b/MasterPassword/ObjC/MPAppDelegate_Store.h index edbc2605..96891b53 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Store.h +++ b/MasterPassword/ObjC/MPAppDelegate_Store.h @@ -31,7 +31,7 @@ typedef NS_ENUM( NSUInteger, MPImportResult ) { - (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context; /** @param completion The block to execute after adding the element, executed from the main thread with the new element in the main MOC. */ -- (void)addElementNamed:(NSString *)siteName completion:(void (^)(MPElementEntity *element))completion; +- (void)addElementNamed:(NSString *)siteName completion:(void ( ^ )(MPElementEntity *element, NSManagedObjectContext *context))completion; - (MPElementEntity *)changeElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context toType:(MPElementType)type; - (MPImportResult)importSites:(NSString *)importedSitesString askImportPassword:(NSString *(^)(NSString *userName))importPassword diff --git a/MasterPassword/ObjC/MPAppDelegate_Store.m b/MasterPassword/ObjC/MPAppDelegate_Store.m index de1f10d5..ede27300 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Store.m +++ b/MasterPassword/ObjC/MPAppDelegate_Store.m @@ -136,9 +136,8 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext ^(NSNotification *note) { [[self mainManagedObjectContext] saveToStore]; }]; - [[NSNotificationCenter defaultCenter] - addObserverForName:UIApplicationWillResignActiveNotification object:UIApp - queue:[NSOperationQueue mainQueue] usingBlock: + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:UIApp + queue:[NSOperationQueue mainQueue] usingBlock: ^(NSNotification *note) { [[self mainManagedObjectContext] saveToStore]; }]; @@ -436,10 +435,10 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext #pragma mark - Utilities -- (void)addElementNamed:(NSString *)siteName completion:(void ( ^ )(MPElementEntity *element))completion { +- (void)addElementNamed:(NSString *)siteName completion:(void ( ^ )(MPElementEntity *element, NSManagedObjectContext *context))completion { if (![siteName length]) { - completion( nil ); + completion( nil, nil ); return; } @@ -447,7 +446,7 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext MPUserEntity *activeUser = [self activeUserInContext:context]; NSAssert( activeUser, @"Missing user." ); if (!activeUser) { - completion( nil ); + completion( nil, nil ); return; } @@ -467,7 +466,7 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext [context saveToStore]; - completion( element ); + completion( element, context ); }]; } diff --git a/MasterPassword/ObjC/MPConfig.h b/MasterPassword/ObjC/MPConfig.h index 31cd30da..dee9d553 100644 --- a/MasterPassword/ObjC/MPConfig.h +++ b/MasterPassword/ObjC/MPConfig.h @@ -17,4 +17,6 @@ @property(nonatomic, retain) NSNumber *iCloudDecided; @property(nonatomic, retain) NSNumber *checkInconsistency; +@property(nonatomic, strong) NSNumber *siteAttacker; + @end diff --git a/MasterPassword/ObjC/MPConfig.m b/MasterPassword/ObjC/MPConfig.m index a1bbda82..4ecb16a1 100644 --- a/MasterPassword/ObjC/MPConfig.m +++ b/MasterPassword/ObjC/MPConfig.m @@ -10,7 +10,7 @@ @implementation MPConfig -@dynamic sendInfo, rememberLogin, iCloudDecided, checkInconsistency, hidePasswords; +@dynamic sendInfo, rememberLogin, iCloudDecided, checkInconsistency, hidePasswords, siteAttacker; - (id)init { @@ -24,7 +24,8 @@ NSStringFromSelector( @selector( rememberLogin ) ) : @NO, NSStringFromSelector( @selector( hidePasswords ) ) : @NO, NSStringFromSelector( @selector( iCloudDecided ) ) : @NO, - NSStringFromSelector( @selector( checkInconsistency ) ) : @NO + NSStringFromSelector( @selector( checkInconsistency ) ) : @NO, + NSStringFromSelector( @selector( siteAttacker ) ) : @(MPAttacker1), }]; self.delegate = [MPAppDelegate_Shared get]; diff --git a/MasterPassword/ObjC/MPEntities.m b/MasterPassword/ObjC/MPEntities.m index 00d7ee7c..c9b37552 100644 --- a/MasterPassword/ObjC/MPEntities.m +++ b/MasterPassword/ObjC/MPEntities.m @@ -20,11 +20,11 @@ @try { NSError *error = nil; if (!(success = [self save:&error])) - err(@"While saving: %@", error); + err( @"While saving: %@", error ); } @catch (NSException *exception) { success = NO; - err(@"While saving: %@", exception); + err( @"While saving: %@", exception ); } }]; } @@ -115,7 +115,8 @@ - (NSString *)debugDescription { return strf( @"{%@: name=%@, user=%@, type=%lu, uses=%ld, lastUsed=%@, version=%ld, loginName=%@, requiresExplicitMigration=%d}", - NSStringFromClass( [self class] ), self.name, self.user.name, (long)self.type, (long)self.uses, self.lastUsed, (long)self.version, + NSStringFromClass( [self class] ), self.name, self.user.name, (long)self.type, (long)self.uses, self.lastUsed, + (long)self.version, self.loginName, self.requiresExplicitMigration ); } @@ -123,9 +124,11 @@ while (self.version < MPAlgorithmDefaultVersion) if ([MPAlgorithmForVersion( self.version + 1 ) migrateElement:self explicit:explicit]) - inf(@"%@ migration to version: %ld succeeded for element: %@", explicit? @"Explicit": @"Automatic", (long)self.version + 1, self); + inf( @"%@ migration to version: %ld succeeded for element: %@", + explicit? @"Explicit": @"Automatic", (long)self.version + 1, self ); else { - wrn(@"%@ migration to version: %ld failed for element: %@", explicit? @"Explicit": @"Automatic", (long)self.version + 1, self); + wrn( @"%@ migration to version: %ld failed for element: %@", + explicit? @"Explicit": @"Automatic", (long)self.version + 1, self ); return NO; } @@ -137,7 +140,7 @@ return [self.algorithm resolveContentForElement:self usingKey:key]; } -- (void)resolveContentUsingKey:(MPKey *)key result:(void (^)(NSString *))result { +- (void)resolveContentUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result { [self.algorithm resolveContentForElement:self usingKey:key result:result]; } diff --git a/MasterPassword/ObjC/Mac/MPInitialWindow.xib b/MasterPassword/ObjC/Mac/MPInitialWindow.xib index 3aa11128..18b30af0 100644 --- a/MasterPassword/ObjC/Mac/MPInitialWindow.xib +++ b/MasterPassword/ObjC/Mac/MPInitialWindow.xib @@ -1,5 +1,5 @@ - + @@ -7,7 +7,6 @@ - @@ -17,26 +16,23 @@ - + - + - + - + - - - - + @@ -51,7 +47,7 @@ from anywhere. - + @@ -64,7 +60,7 @@ from anywhere. - + - - - @@ -137,16 +116,13 @@ from anywhere. - - - - + diff --git a/MasterPassword/ObjC/Mac/MPInitialWindowController.h b/MasterPassword/ObjC/Mac/MPInitialWindowController.h index 57f4eaaa..ee7d2863 100644 --- a/MasterPassword/ObjC/Mac/MPInitialWindowController.h +++ b/MasterPassword/ObjC/Mac/MPInitialWindowController.h @@ -21,7 +21,6 @@ @interface MPInitialWindowController : NSWindowController @property(nonatomic, weak) IBOutlet NSButton *openAtLoginButton; -@property(nonatomic, weak) IBOutlet NSButton *enableCloudButton; - (IBAction)iphoneAppStore:(id)sender; - (IBAction)togglePreference:(id)sender; diff --git a/MasterPassword/ObjC/Mac/MPInitialWindowController.m b/MasterPassword/ObjC/Mac/MPInitialWindowController.m index 1f97239e..e1d299ee 100644 --- a/MasterPassword/ObjC/Mac/MPInitialWindowController.m +++ b/MasterPassword/ObjC/Mac/MPInitialWindowController.m @@ -44,15 +44,6 @@ - (IBAction)togglePreference:(id)sender { - if (sender == self.enableCloudButton) { - if (([MPMacAppDelegate get].storeManager.cloudEnabled = self.enableCloudButton.state == NSOnState)) { - NSAlert *alert = [NSAlert new]; - alert.messageText = @"iCloud Enabled"; - alert.informativeText = @"If you already have a user on another iCloud-enabled device, " - @"it may take a moment for that user to sync down to this device."; - [alert runModal]; - } - } if (sender == self.openAtLoginButton) [[MPMacAppDelegate get] setLoginItemEnabled:self.openAtLoginButton.state == NSOnState]; } diff --git a/MasterPassword/ObjC/Mac/MPMacAppDelegate.h b/MasterPassword/ObjC/Mac/MPMacAppDelegate.h index 08630db6..0825e76d 100644 --- a/MasterPassword/ObjC/Mac/MPMacAppDelegate.h +++ b/MasterPassword/ObjC/Mac/MPMacAppDelegate.h @@ -20,7 +20,6 @@ @property(nonatomic, weak) IBOutlet NSMenuItem *lockItem; @property(nonatomic, weak) IBOutlet NSMenuItem *showItem; @property(nonatomic, strong) IBOutlet NSMenu *statusMenu; -@property(nonatomic, weak) IBOutlet NSMenuItem *useCloudItem; @property(nonatomic, weak) IBOutlet NSMenuItem *hidePasswordsItem; @property(nonatomic, weak) IBOutlet NSMenuItem *rememberPasswordItem; @property(nonatomic, weak) IBOutlet NSMenuItem *openAtLoginItem; @@ -34,8 +33,6 @@ - (IBAction)togglePreference:(id)sender; - (IBAction)newUser:(NSMenuItem *)sender; - (IBAction)lock:(id)sender; -- (IBAction)rebuildCloud:(id)sender; -- (IBAction)corruptCloud:(id)sender; - (IBAction)terminate:(id)sender; - (IBAction)showPopup:(id)sender; diff --git a/MasterPassword/ObjC/Mac/MPMacAppDelegate.m b/MasterPassword/ObjC/Mac/MPMacAppDelegate.m index a8a41a6f..b00a4ca1 100644 --- a/MasterPassword/ObjC/Mac/MPMacAppDelegate.m +++ b/MasterPassword/ObjC/Mac/MPMacAppDelegate.m @@ -16,12 +16,6 @@ #define LOGIN_HELPER_BUNDLE_ID @"com.lyndir.lhunath.MasterPassword.Mac.LoginHelper" -@interface UbiquityStoreManager(Private) - -- (void)markCloudStoreCorrupted; - -@end - @implementation MPMacAppDelegate #pragma clang diagnostic push @@ -32,8 +26,8 @@ static EventHotKeyID MPLockHotKey = { .signature = 'lock', .id = 1 }; + (void)initialize { - static dispatch_once_t initialize = 0; - dispatch_once( &initialize, ^{ + static dispatch_once_t once = 0; + dispatch_once( &once, ^{ [MPMacConfig get]; #ifdef DEBUG @@ -79,11 +73,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven [weakSelf updateMenuItems]; } ); } forKeyPath:@"activeUser" options:0 context:nil]; - [self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) { - dispatch_async( dispatch_get_main_queue(), ^{ - [weakSelf updateMenuItems]; - } ); - } forKeyPath:@"storeManager.cloudAvailable" options:0 context:nil]; // Status item. self.statusView = [[RHStatusItemView alloc] initWithStatusBarItem: @@ -126,8 +115,9 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven err( @"Error registering 'lock' hotkey: %i", (int)status ); // Initial display. - if ([[MPMacConfig get].firstRun boolValue]){ - [(self.initialWindowController = [[MPInitialWindowController alloc] initWithWindowNibName:@"MPInitialWindow"]).window makeKeyAndOrderFront:self]; + if ([[MPMacConfig get].firstRun boolValue]) { + [(self.initialWindowController = [[MPInitialWindowController alloc] initWithWindowNibName:@"MPInitialWindow"]) + .window makeKeyAndOrderFront:self]; [NSApp activateIgnoringOtherApps:YES]; } } @@ -314,8 +304,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven - (IBAction)togglePreference:(id)sender { - if (sender == self.useCloudItem) - [self storeManager].cloudEnabled = self.useCloudItem.state != NSOnState; if (sender == self.hidePasswordsItem) [MPConfig get].hidePasswords = [NSNumber numberWithBool:![[MPConfig get].hidePasswords boolValue]]; if (sender == self.rememberPasswordItem) @@ -393,26 +381,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven self.key = nil; } -- (IBAction)rebuildCloud:(id)sender { - - if ([[NSAlert alertWithMessageText:@"iCloud Truth Push" defaultButton:@"Continue" - alternateButton:nil otherButton:@"Cancel" - informativeTextWithFormat:@"This action will force all your iCloud enabled devices to switch to this device's version of the truth." - @"\n\nThis is only necessary if you notice that your devices aren't syncing properly anymore. " - "Any data on other devices not available from here will be lost."] runModal] == NSAlertDefaultReturn) - [self.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:NO]; -} - -- (IBAction)corruptCloud:(id)sender { - - if ([[NSAlert alertWithMessageText:@"iCloud Truth Pull" defaultButton:@"Continue" - alternateButton:nil otherButton:@"Cancel" - informativeTextWithFormat:@"This action will force another iCloud enabled device to push their version of the truth on all." - @"\n\nThis is only necessary if you notice that your devices aren't syncing properly anymore. " - "Any data on this device not available from the other will be lost."] runModal] == NSAlertDefaultReturn) - [self.storeManager markCloudStoreCorrupted]; -} - - (IBAction)terminate:(id)sender { [self.passwordWindowController close]; @@ -547,8 +515,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven if (![users count]) { NSMenuItem *noUsersItem = [self.usersItem.submenu addItemWithTitle:@"No users" action:NULL keyEquivalent:@""]; noUsersItem.enabled = NO; - noUsersItem.toolTip = @"Use the iOS app to create users and make sure iCloud is enabled in its preferences as well. " - @"Then give iCloud some time to sync the new user to your Mac."; + noUsersItem.toolTip = @"Begin by creating a user."; } self.usersItem.state = NSMixedState; @@ -627,17 +594,29 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven self.savePasswordItem.enabled = YES; self.savePasswordItem.toolTip = nil; } +} - self.useCloudItem.state = self.storeManager.cloudEnabled? NSOnState: NSOffState; - self.initialWindowController.enableCloudButton.state = self.storeManager.cloudEnabled? NSOnState: NSOffState; - self.useCloudItem.enabled = self.storeManager.cloudAvailable; - if (self.storeManager.cloudAvailable) { - self.useCloudItem.title = @"Use iCloud"; - self.useCloudItem.toolTip = nil; - } - else { - self.useCloudItem.title = @"Use iCloud (Unavailable)"; - self.useCloudItem.toolTip = @"iCloud is not set up for your Mac user."; +#pragma mark - UbiquityStoreManagerDelegate + +- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didLoadStoreForCoordinator:(NSPersistentStoreCoordinator *)coordinator + isCloud:(BOOL)isCloudStore { + + [super ubiquityStoreManager:manager didLoadStoreForCoordinator:coordinator isCloud:isCloudStore]; + + if (isCloudStore) { + NSAlert *alert = [NSAlert new]; + alert.messageText = @"iCloud Support Deprecated"; + alert.informativeText = @"Master Password is moving away from iCloud due to limited platform support and reliability issues. " + @"\n\nMaster Password's generated passwords do not require syncing. " + @"Your sites will always have the same passwords on all your devices. " + @"\n\niCloud continues to work for now but will be deactivated in a future update. " + @"Disable iCloud now to copy your iCloud sites to your device and avoid losing them when iCloud becomes discontinued."; + [alert addButtonWithTitle:@"Disable iCloud"]; + [alert addButtonWithTitle:@"Ignore For Now"]; + + NSInteger response = [alert runModal]; + if (response == NSAlertFirstButtonReturn) + [[self storeManager] migrateCloudToLocal]; } } diff --git a/MasterPassword/ObjC/Mac/MPPasswordWindowController.h b/MasterPassword/ObjC/Mac/MPPasswordWindowController.h index dcc1ff66..11928b4c 100644 --- a/MasterPassword/ObjC/Mac/MPPasswordWindowController.h +++ b/MasterPassword/ObjC/Mac/MPPasswordWindowController.h @@ -28,6 +28,7 @@ @property(nonatomic) NSString *masterPassword; @property(nonatomic) BOOL alternatePressed; @property(nonatomic) BOOL locked; +@property(nonatomic) BOOL newUser; @property(nonatomic, weak) IBOutlet NSArrayController *elementsController; @property(nonatomic, weak) IBOutlet NSImageView *blurView; diff --git a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m index 4330f2a7..4a41a485 100644 --- a/MasterPassword/ObjC/Mac/MPPasswordWindowController.m +++ b/MasterPassword/ObjC/Mac/MPPasswordWindowController.m @@ -229,7 +229,7 @@ switch (returnCode) { case NSAlertFirstButtonReturn: { // "Create" button. - [[MPMacAppDelegate get] addElementNamed:[self.siteField stringValue] completion:^(MPElementEntity *element) { + [[MPMacAppDelegate get] addElementNamed:[self.siteField stringValue] completion:^(MPElementEntity *element, NSManagedObjectContext *context) { if (element) PearlMainQueue( ^{ [self updateElements]; } ); }]; @@ -476,12 +476,15 @@ [MPMacAppDelegate managedObjectContextForMainThreadPerformBlock:^(NSManagedObjectContext *mainContext) { self.locked = YES; + self.newUser = YES; self.inputLabel.stringValue = @""; self.siteField.stringValue = @""; MPUserEntity *mainActiveUser = [[MPMacAppDelegate get] activeUserInContext:mainContext]; if (mainActiveUser) { + self.newUser = mainActiveUser.keyID == nil; + if ([MPMacAppDelegate get].key) { self.inputLabel.stringValue = strf( @"%@'s password for:", mainActiveUser.name ); self.locked = NO; diff --git a/MasterPassword/ObjC/Mac/MPPasswordWindowController.xib b/MasterPassword/ObjC/Mac/MPPasswordWindowController.xib index fb10cca6..c4448d3e 100644 --- a/MasterPassword/ObjC/Mac/MPPasswordWindowController.xib +++ b/MasterPassword/ObjC/Mac/MPPasswordWindowController.xib @@ -1,5 +1,5 @@ - + @@ -86,7 +86,6 @@ - @@ -139,13 +138,13 @@ - + - + @@ -450,12 +449,8 @@ - + - - - - NSNegateBoolean @@ -467,8 +462,12 @@ - + + + + + NSNegateBoolean @@ -486,6 +485,15 @@ + + + + + + + NSNegateBoolean + + NSNegateBoolean @@ -510,6 +518,15 @@ + + + + + + + NSNegateBoolean + + NSNegateBoolean @@ -529,7 +546,7 @@ - @@ -55,23 +54,6 @@ - - - - - - - - - - - - - - - - - @@ -199,47 +181,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MasterPassword/ObjC/iOS/MPAvatarCell.m b/MasterPassword/ObjC/iOS/MPAvatarCell.m index 8c4481f5..9b16d7d7 100644 --- a/MasterPassword/ObjC/iOS/MPAvatarCell.m +++ b/MasterPassword/ObjC/iOS/MPAvatarCell.m @@ -17,7 +17,6 @@ // #import "MPAvatarCell.h" -#import "MPPasswordLargeCell.h" const long MPAvatarAdd = 10000; @@ -207,10 +206,10 @@ const long MPAvatarAdd = 10000; switch (self.mode) { case MPAvatarModeLowered: { - [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height]; - [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; - [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; - [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; + [[self.avatarSizeConstraint updateConstant:self.avatarImageView.image.size.height] layoutIfNeeded]; + [[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow] layoutIfNeeded]; + [[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow] layoutIfNeeded]; + [[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow] layoutIfNeeded]; self.nameContainer.alpha = self.visibility; self.nameContainer.backgroundColor = [UIColor clearColor]; self.avatarImageView.alpha = self.visibility / 0.7f + 0.3f; @@ -218,10 +217,10 @@ const long MPAvatarAdd = 10000; break; } case MPAvatarModeRaisedButInactive: { - [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height]; - [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; - [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; - [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; + [[self.avatarSizeConstraint updateConstant:self.avatarImageView.image.size.height] layoutIfNeeded]; + [[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded]; + [[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow] layoutIfNeeded]; + [[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow] layoutIfNeeded]; self.nameContainer.alpha = self.visibility; self.nameContainer.backgroundColor = [UIColor clearColor]; self.avatarImageView.alpha = 0; @@ -229,10 +228,10 @@ const long MPAvatarAdd = 10000; break; } case MPAvatarModeRaisedAndActive: { - [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height]; - [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; - [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; - [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; + [[self.avatarSizeConstraint updateConstant:self.avatarImageView.image.size.height] layoutIfNeeded]; + [[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded]; + [[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow] layoutIfNeeded]; + [[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded]; self.nameContainer.alpha = self.visibility; self.nameContainer.backgroundColor = [UIColor blackColor]; self.avatarImageView.alpha = 1; @@ -240,10 +239,10 @@ const long MPAvatarAdd = 10000; break; } case MPAvatarModeRaisedAndHidden: { - [self.avatarSizeConstraint layoutWithConstant:self.avatarImageView.image.size.height]; - [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; - [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; - [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; + [[self.avatarSizeConstraint updateConstant:self.avatarImageView.image.size.height] layoutIfNeeded]; + [[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded]; + [[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow] layoutIfNeeded]; + [[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded]; self.nameContainer.alpha = 0; self.nameContainer.backgroundColor = [UIColor blackColor]; self.avatarImageView.alpha = 0; @@ -251,10 +250,10 @@ const long MPAvatarAdd = 10000; break; } case MPAvatarModeRaisedAndMinimized: { - [self.avatarSizeConstraint layoutWithConstant:36]; - [self.avatarRaisedConstraint layoutWithPriority:UILayoutPriorityDefaultLow]; - [self.avatarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; - [self.nameToCenterConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; + [[self.avatarSizeConstraint updateConstant:36] layoutIfNeeded]; + [[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow] layoutIfNeeded]; + [[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded]; + [[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded]; self.nameContainer.alpha = 0; self.nameContainer.backgroundColor = [UIColor blackColor]; self.avatarImageView.alpha = 1; diff --git a/MasterPassword/ObjC/iOS/MPPasswordCell.h b/MasterPassword/ObjC/iOS/MPPasswordCell.h index 5eba3dbe..891c1957 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordCell.h +++ b/MasterPassword/ObjC/iOS/MPPasswordCell.h @@ -20,9 +20,15 @@ #import "MPEntities.h" #import "MPCell.h" -@interface MPPasswordCell : MPCell +typedef NS_ENUM ( NSUInteger, MPPasswordCellMode ) { + MPPasswordCellModePassword, + MPPasswordCellModeSettings, +}; -/** Populate our UI to reflect the current state. */ -- (void)updateAnimated:(BOOL)animated; +@interface MPPasswordCell : MPCell + +- (void)setElement:(MPElementEntity *)element animated:(BOOL)animated; +- (void)setTransientSite:(NSString *)siteName animated:(BOOL)animated; +- (void)setMode:(MPPasswordCellMode)mode animated:(BOOL)animated; @end diff --git a/MasterPassword/ObjC/iOS/MPPasswordCell.m b/MasterPassword/ObjC/iOS/MPPasswordCell.m index 2c69f422..30650425 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordCell.m +++ b/MasterPassword/ObjC/iOS/MPPasswordCell.m @@ -1,12 +1,12 @@ /** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ +* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) +* +* See the enclosed file LICENSE for license information (LGPLv3). If you did +* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt +* +* @author Maarten Billemont +* @license http://www.gnu.org/licenses/lgpl-3.0.txt +*/ // // MPAvatarCell.h @@ -20,40 +20,336 @@ #import "MPiOSAppDelegate.h" #import "MPAppDelegate_Store.h" -@implementation MPPasswordCell +@interface MPPasswordCell() + +@property(nonatomic, strong) IBOutlet UILabel *siteNameLabel; +@property(nonatomic, strong) IBOutlet UITextField *passwordField; +@property(nonatomic, strong) IBOutlet UITextField *loginNameField; +@property(nonatomic, strong) IBOutlet UIPageControl *pageControl; +@property(nonatomic, strong) IBOutlet UILabel *strengthLabel; +@property(nonatomic, strong) IBOutlet UILabel *counterLabel; +@property(nonatomic, strong) IBOutlet UIButton *counterButton; +@property(nonatomic, strong) IBOutlet UIButton *upgradeButton; +@property(nonatomic, strong) IBOutlet UIButton *modeButton; +@property(nonatomic, strong) IBOutlet UIButton *loginModeButton; +@property(nonatomic, strong) IBOutlet UIButton *editButton; +@property(nonatomic, strong) IBOutlet UIScrollView *modeScrollView; +@property(nonatomic, strong) IBOutlet UIButton *selectionButton; + +@property(nonatomic) MPPasswordCellMode mode; +@property(nonatomic, copy) NSString *transientSite; + +@end + +@implementation MPPasswordCell { + NSManagedObjectID *_elementOID; +} #pragma mark - Life cycle +- (void)awakeFromNib { + + [super awakeFromNib]; + + [self addGestureRecognizer: + [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector( doRevealPassword: )]]; + [self.counterButton addGestureRecognizer: + [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector( doResetCounter: )]]; + + self.selectionButton.layer.cornerRadius = 5; + self.selectionButton.layer.shadowOffset = CGSizeZero; + self.selectionButton.layer.shadowRadius = 5; + self.selectionButton.layer.shadowOpacity = 0; + self.selectionButton.layer.shadowColor = [UIColor whiteColor].CGColor; + + self.pageControl.transform = CGAffineTransformMakeScale( 0.4f, 0.4f ); + + [self.selectionButton observeKeyPath:@"highlighted" + withBlock:^(id from, id to, NSKeyValueChange cause, UIButton *button) { + button.layer.shadowOpacity = button.selected? 1: button.highlighted? 0.3f: 0; + }]; + [self.selectionButton observeKeyPath:@"selected" + withBlock:^(id from, id to, NSKeyValueChange cause, UIButton *button) { + button.layer.shadowOpacity = button.selected? 1: button.highlighted? 0.3f: 0; + }]; +} + - (void)prepareForReuse { [super prepareForReuse]; + + _elementOID = nil; + self.loginModeButton.selected = NO; + self.mode = MPPasswordCellModePassword; [self updateAnimated:NO]; } -// Unblocks animations for all CALayer properties (eg. shadowOpacity) -- (id)actionForLayer:(CALayer *)layer forKey:(NSString *)event { +#pragma mark - State - id defaultAction = [super actionForLayer:layer forKey:event]; - if (defaultAction == (id)[NSNull null] && [event isEqualToString:@"position"]) - return defaultAction; +- (void)setMode:(MPPasswordCellMode)mode animated:(BOOL)animated { - return NSNullToNil(defaultAction); + if (mode == _mode) + return; + + _mode = mode; + [self updateAnimated:animated]; } -#pragma mark - Properties +- (void)setElement:(MPElementEntity *)element animated:(BOOL)animated { -- (void)setSelected:(BOOL)selected { + _elementOID = [element objectID]; + [self updateAnimated:animated]; +} - [super setSelected:selected]; +- (void)setTransientSite:(NSString *)siteName animated:(BOOL)animated { + + self.transientSite = siteName; + [self updateAnimated:animated]; +} + +#pragma mark - UITextFieldDelegate + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + + [textField resignFirstResponder]; + return YES; +} + +- (void)textFieldDidBeginEditing:(UITextField *)textField { + + UICollectionView *collectionView = [UICollectionView findAsSuperviewOf:self]; + [collectionView scrollToItemAtIndexPath:[collectionView indexPathForCell:self] + atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES]; +} + +- (IBAction)textFieldDidChange:(UITextField *)textField { + + if (textField == self.passwordField) { + NSString *password = self.passwordField.text; + [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + TimeToCrack timeToCrack; + MPElementEntity *element = [self elementInContext:context]; + id algorithm = element.algorithm?: MPAlgorithmDefault; + MPAttacker attackHardware = [[MPConfig get].siteAttacker unsignedIntegerValue]; + if ([algorithm timeToCrack:&timeToCrack passwordOfType:[self elementInContext:context].type byAttacker:attackHardware] || + [algorithm timeToCrack:&timeToCrack passwordString:password byAttacker:attackHardware]) + PearlMainQueue( ^{ + self.strengthLabel.text = NSStringFromTimeToCrack( timeToCrack ); + } ); + }]; + } +} + +- (void)textFieldDidEndEditing:(UITextField *)textField { + + if (textField == self.passwordField || textField == self.loginNameField) { + NSString *text = textField.text; + textField.enabled = NO; + + [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + MPElementEntity *element = [self elementInContext:context]; + if (!element) + return; + + if (textField == self.passwordField) { + [element.algorithm saveContent:text toElement:element usingKey:[MPiOSAppDelegate get].key]; + [PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2]; + } + else if (textField == self.loginNameField) { + element.loginName = text; + [PearlOverlay showTemporaryOverlayWithTitle:@"Login Updated" dismissAfter:2]; + } + + [context saveToStore]; + [self updateAnimated:YES]; + }]; + } +} + +#pragma mark - Actions + +- (IBAction)doLoginMode:(UIButton *)sender { + + self.loginModeButton.selected = !self.loginModeButton.selected; + [self updateAnimated:YES]; +} + +- (IBAction)doDelete:(UIButton *)sender { + + MPElementEntity *element = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]; + if (!element) + return; + + [PearlSheet showSheetWithTitle:strf( @"Delete %@?", element.name ) viewStyle:UIActionSheetStyleAutomatic + initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) { + if (buttonIndex == [sheet cancelButtonIndex]) + return; + + [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + [context deleteObject:[self elementInContext:context]]; + [context saveToStore]; + }]; + } cancelTitle:@"Cancel" destructiveTitle:@"Delete Site" otherTitles:nil]; +} + +- (IBAction)doChangeType:(UIButton *)sender { + + [self setMode:MPPasswordCellModePassword animated:YES]; + + [PearlSheet showSheetWithTitle:@"Change Password Type" viewStyle:UIActionSheetStyleAutomatic + initSheet:^(UIActionSheet *sheet) { + MPElementEntity *mainElement = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]; + for (NSNumber *typeNumber in [MPAlgorithmDefault allTypes]) { + MPElementType type = [typeNumber unsignedIntegerValue]; + NSString *typeName = [MPAlgorithmDefault nameOfType:type]; + if (type == mainElement.type) + [sheet addButtonWithTitle:strf( @"● %@", typeName )]; + else + [sheet addButtonWithTitle:typeName]; + } + } tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) { + if (buttonIndex == [sheet cancelButtonIndex]) + return; + + MPElementType type = [[MPAlgorithmDefault allTypes][buttonIndex] unsignedIntegerValue]?: MPElementTypeGeneratedLong; + + [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + MPElementEntity *element = [self elementInContext:context]; + element = [[MPiOSAppDelegate get] changeElement:element saveInContext:context toType:type]; + [self setElement:element animated:YES]; + }]; + } cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:nil]; +} + +- (IBAction)doEdit:(UIButton *)sender { + + if (self.loginModeButton.selected) { + self.loginNameField.enabled = YES; + [self.loginNameField becomeFirstResponder]; + } + else if ([self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].type & MPElementTypeClassStored) { + self.passwordField.enabled = YES; + [self.passwordField becomeFirstResponder]; + } +} + +- (IBAction)doMode:(UIButton *)sender { + + switch (self.mode) { + case MPPasswordCellModePassword: + [self setMode:MPPasswordCellModeSettings animated:YES]; + break; + case MPPasswordCellModeSettings: + [self setMode:MPPasswordCellModePassword animated:YES]; + break; + } [self updateAnimated:YES]; } -- (void)setHighlighted:(BOOL)highlighted { +- (IBAction)doUpgrade:(UIButton *)sender { - [super setHighlighted:highlighted]; + [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + if (![[self elementInContext:context] migrateExplicitly:YES]) { + [PearlOverlay showTemporaryOverlayWithTitle:@"Couldn't Upgrade Site" dismissAfter:2]; + return; + } - [self updateAnimated:YES]; + [context saveToStore]; + [PearlOverlay showTemporaryOverlayWithTitle:@"Site Upgraded" dismissAfter:2]; + [self updateAnimated:YES]; + }]; +} + +- (IBAction)doIncrementCounter:(UIButton *)sender { + + [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + MPElementEntity *element = [self elementInContext:context]; + if (!element || ![element isKindOfClass:[MPElementGeneratedEntity class]]) + return; + + ++((MPElementGeneratedEntity *)element).counter; + [context saveToStore]; + + [PearlOverlay showTemporaryOverlayWithTitle:@"Generating New Password" dismissAfter:2]; + [self updateAnimated:YES]; + }]; +} + +- (IBAction)doRevealPassword:(UILongPressGestureRecognizer *)recognizer { + + if (recognizer.state != UIGestureRecognizerStateBegan) + return; + + if (self.passwordField.secureTextEntry) { + self.passwordField.secureTextEntry = NO; + + PearlMainQueueAfter( 3, ^{ + self.passwordField.secureTextEntry = [[MPiOSConfig get].hidePasswords boolValue]; + } ); + } +} + +- (IBAction)doResetCounter:(UILongPressGestureRecognizer *)recognizer { + + if (recognizer.state != UIGestureRecognizerStateBegan) + return; + + [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + MPElementEntity *element = [self elementInContext:context]; + if (!element || ![element isKindOfClass:[MPElementGeneratedEntity class]]) + return; + + ((MPElementGeneratedEntity *)element).counter = 1; + [context saveToStore]; + + [PearlOverlay showTemporaryOverlayWithTitle:@"Counter Reset" dismissAfter:2]; + [self updateAnimated:YES]; + }]; +} + +- (IBAction)doUse:(id)sender { + + self.selectionButton.selected = YES; + + if (self.transientSite) { + [[UIResponder findFirstResponder] resignFirstResponder]; + [PearlAlert showAlertWithTitle:@"Create Site" + message:strf( @"Remember site named:\n%@", self.transientSite ) + viewStyle:UIAlertViewStyleDefault + initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { + if (buttonIndex == [alert cancelButtonIndex]) { + self.selectionButton.selected = NO; + return; + } + + [[MPiOSAppDelegate get] + addElementNamed:self.transientSite completion:^(MPElementEntity *element, NSManagedObjectContext *context) { + [self copyContentOfElement:element saveInContext:context]; + PearlMainQueue( ^{ + self.selectionButton.selected = NO; + } ); + }]; + } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil]; + return; + } + + [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + [self copyContentOfElement:[self elementInContext:context] saveInContext:context]; + PearlMainQueue( ^{ + self.selectionButton.selected = NO; + } ); + }]; +} + +#pragma mark - UIScrollViewDelegate + +- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { + + if (roundf( (float)(scrollView.contentOffset.x / self.bounds.size.width) ) == 0.0f) + [self setMode:MPPasswordCellModePassword animated:YES]; + else + [self setMode:MPPasswordCellModeSettings animated:YES]; } #pragma mark - Private @@ -68,8 +364,107 @@ } [UIView animateWithDuration:animated? 0.3f: 0 animations:^{ - self.layer.shadowOpacity = self.selected? 1: self.highlighted? 0.3f: 0; + MPElementEntity *mainElement = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]; + + // UI + self.selectionButton.layer.shadowOpacity = self.selectionButton.selected? 1: self.selectionButton.highlighted? 0.3f: 0; + self.upgradeButton.alpha = mainElement.requiresExplicitMigration? 1: 0; + self.passwordField.alpha = self.loginModeButton.selected? 0: 1; + self.loginNameField.alpha = self.loginModeButton.selected? 1: 0; + self.modeButton.alpha = self.transientSite? 0: 1; + self.counterLabel.alpha = self.counterButton.alpha = mainElement.type & MPElementTypeClassGenerated? 1: 0; + self.modeButton.selected = self.mode == MPPasswordCellModeSettings; + self.pageControl.currentPage = self.mode == MPPasswordCellModePassword? 0: 1; + self.strengthLabel.alpha = self.mode == MPPasswordCellModePassword? 0: 1; + self.editButton.enabled = self.loginModeButton.selected || mainElement.type & MPElementTypeClassStored; + [self.modeScrollView setContentOffset:CGPointMake( self.mode * self.modeScrollView.frame.size.width, 0 ) animated:animated]; + + // Site Name + self.siteNameLabel.text = strl( @"%@ - %@", self.transientSite?: mainElement.name, + self.transientSite? @"Tap to create": [mainElement.algorithm shortNameOfType:mainElement.type] ); + + // Site Password + self.passwordField.enabled = NO; + self.passwordField.secureTextEntry = [[MPiOSConfig get].hidePasswords boolValue]; + self.passwordField.attributedPlaceholder = stra( + mainElement.type & MPElementTypeClassStored? strl( @"No password" ): + mainElement.type & MPElementTypeClassGenerated? strl( @"..." ): @"", @{ + NSForegroundColorAttributeName : [UIColor whiteColor] + } ); + [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { + NSString *password; + if (self.transientSite) + password = [MPAlgorithmDefault generateContentNamed:self.transientSite ofType: + [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPElementTypeGeneratedLong + withCounter:1 usingKey:[MPiOSAppDelegate get].key]; + else + password = [[self elementInContext:context] resolveContentUsingKey:[MPiOSAppDelegate get].key]; + + TimeToCrack timeToCrack; + NSString *timeToCrackString = nil; + id algorithm = mainElement.algorithm?: MPAlgorithmDefault; + MPAttacker attackHardware = [[MPConfig get].siteAttacker unsignedIntegerValue]; + if ([algorithm timeToCrack:&timeToCrack passwordOfType:[self elementInContext:context].type byAttacker:attackHardware] || + [algorithm timeToCrack:&timeToCrack passwordString:password byAttacker:attackHardware]) + timeToCrackString = NSStringFromTimeToCrack( timeToCrack ); + + PearlMainQueue( ^{ + self.passwordField.text = password; + self.strengthLabel.text = timeToCrackString; + } ); + }]; + + // Site Counter + if ([mainElement isKindOfClass:[MPElementGeneratedEntity class]]) + self.counterLabel.text = strf( @"%lu", (unsigned long)((MPElementGeneratedEntity *)mainElement).counter ); + + // Site Login Name + self.loginNameField.enabled = NO; + self.loginNameField.text = mainElement.loginName; + self.loginNameField.attributedPlaceholder = stra( strl( @"Set login name" ), @{ + NSForegroundColorAttributeName : [UIColor whiteColor] + } ); }]; } +- (void)copyContentOfElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context { + + // Copy content. + if (self.loginModeButton.selected) { + // Login Mode + inf( @"Copying login for: %@", element.name ); + NSString *loginName = element.loginName; + if (![loginName length]) + return; + + PearlMainQueue( ^{ + [PearlOverlay showTemporaryOverlayWithTitle:strl( @"Login Name Copied" ) dismissAfter:2]; + [UIPasteboard generalPasteboard].string = loginName; + } ); + + [element use]; + [context saveToStore]; + } + else { + // Password Mode + inf( @"Copying password for: %@", element.name ); + NSString *password = [element resolveContentUsingKey:[MPAppDelegate_Shared get].key]; + if (![password length]) + return; + + PearlMainQueue( ^{ + [PearlOverlay showTemporaryOverlayWithTitle:strl( @"Password Copied" ) dismissAfter:2]; + [UIPasteboard generalPasteboard].string = password; + } ); + + [element use]; + [context saveToStore]; + } +} + +- (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context { + + return [MPElementEntity existingObjectWithID:_elementOID inContext:context]; +} + @end diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeCell.h b/MasterPassword/ObjC/iOS/MPPasswordLargeCell.h deleted file mode 100644 index b2daa321..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeCell.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPAvatarCell.h -// MPAvatarCell -// -// Created by lhunath on 2014-03-11. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import -#import "MPEntities.h" -#import "MPCell.h" -#import "MPPasswordCell.h" - -typedef NS_ENUM (NSUInteger, MPContentFieldMode) { - MPContentFieldModePassword, - MPContentFieldModeUser, -}; - -@interface MPPasswordLargeCell : MPPasswordCell - -@property(nonatomic) MPElementType type; -@property(nonatomic) MPContentFieldMode contentFieldMode; -@property(nonatomic, strong) IBOutlet UILabel *typeLabel; -@property(nonatomic, strong) IBOutlet UITextField *contentField; -@property(nonatomic, strong) IBOutlet UIButton *upgradeButton; -@property(nonatomic, strong) IBOutlet UILabel *nameLabel; -@property(nonatomic, strong) IBOutlet UIButton *loginButton; - -+ (instancetype)dequeueCellWithType:(MPElementType)type fromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath; - -- (void)update; -- (void)updateWithElement:(MPElementEntity *)mainElement; -- (void)updateWithTransientSite:(NSString *)siteName; - -- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void (^)(NSString *result))resultBlock; -- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *result))resultBlock; - -- (void)willBeginDragging; -- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context; - -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeCell.m b/MasterPassword/ObjC/iOS/MPPasswordLargeCell.m deleted file mode 100644 index bf949b4f..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeCell.m +++ /dev/null @@ -1,271 +0,0 @@ -/** -* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) -* -* See the enclosed file LICENSE for license information (LGPLv3). If you did -* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt -* -* @author Maarten Billemont -* @license http://www.gnu.org/licenses/lgpl-3.0.txt -*/ - -// -// MPAvatarCell.h -// MPAvatarCell -// -// Created by lhunath on 2014-03-11. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import "MPPasswordLargeCell.h" -#import "MPiOSAppDelegate.h" -#import "MPAppDelegate_Store.h" -#import "MPPasswordLargeGeneratedCell.h" -#import "MPPasswordLargeStoredCell.h" -#import "MPPasswordTypesCell.h" - -@implementation MPPasswordLargeCell - -#pragma mark - Life - -+ (instancetype)dequeueCellWithType:(MPElementType)type fromCollectionView:(UICollectionView *)collectionView - atIndexPath:(NSIndexPath *)indexPath { - - NSAssert( type != 0 && type != (MPElementType)NSNotFound, @"Cannot dequeue a password cell without a type." ); - - NSString *reuseIdentifier; - if (type & MPElementTypeClassGenerated) - reuseIdentifier = NSStringFromClass( [MPPasswordLargeGeneratedCell class] ); - else if (type & MPElementTypeClassStored) - reuseIdentifier = NSStringFromClass( [MPPasswordLargeStoredCell class] ); - else - Throw( @"Unexpected password type: %@", [MPAlgorithmDefault nameOfType:type] ); - - MPPasswordLargeCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath]; - cell.type = type; - - return cell; -} - -- (void)awakeFromNib { - - [super awakeFromNib]; - - self.layer.cornerRadius = 5; - self.layer.shadowOffset = CGSizeZero; - self.layer.shadowRadius = 5; - self.layer.shadowOpacity = 0; - self.layer.shadowColor = [UIColor whiteColor].CGColor; - - [self addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector( didLongPress: )]]; - - [self prepareForReuse]; -} - -- (void)didLongPress:(UILongPressGestureRecognizer *)recognizer { - - if (recognizer.state != UIGestureRecognizerStateBegan) - return; - - if (self.contentField.secureTextEntry) { - self.contentField.secureTextEntry = NO; - PearlMainQueueAfter( 3, ^{ - self.contentField.secureTextEntry = [[MPiOSConfig get].hidePasswords boolValue]; - } ); - } -} - -- (void)prepareForReuse { - - _contentFieldMode = 0; - self.contentField.text = nil; - - [super prepareForReuse]; -} - -- (void)update { - - self.loginButton.alpha = 0; - self.upgradeButton.alpha = 0; - self.nameLabel.text = @""; - self.typeLabel.text = @""; - self.contentField.text = @""; - self.contentField.secureTextEntry = [[MPiOSConfig get].hidePasswords boolValue]; - self.contentField.attributedPlaceholder = nil; - self.contentField.enabled = self.contentFieldMode == MPContentFieldModeUser; - self.loginButton.selected = self.contentFieldMode == MPContentFieldModeUser; - - switch (self.contentFieldMode) { - case MPContentFieldModePassword: { - self.contentField.keyboardType = UIKeyboardTypeDefault; - if (self.type & MPElementTypeClassStored) - self.contentField.attributedPlaceholder = stra( strl( @"Set custom password" ), @{ - NSForegroundColorAttributeName : [UIColor whiteColor] - } ); - else if (self.type & MPElementTypeClassGenerated) - self.contentField.attributedPlaceholder = stra( strl( @"Generating..." ), @{ - NSForegroundColorAttributeName : [UIColor whiteColor] - } ); - break; - } - case MPContentFieldModeUser: { - self.contentField.keyboardType = UIKeyboardTypeEmailAddress; - self.contentField.attributedPlaceholder = stra( strl( @"Enter your login name" ), @{ - NSForegroundColorAttributeName : [UIColor whiteColor] - } ); - break; - } - } -} - -- (void)updateWithTransientSite:(NSString *)siteName { - - [self update]; - - self.nameLabel.text = strl( @"%@ - Tap to create", siteName ); - self.typeLabel.text = [MPAlgorithmDefault nameOfType:self.type]; - - [self resolveContentOfCellTypeForTransientSite:siteName usingKey:[MPiOSAppDelegate get].key result:^(NSString *result) { - PearlMainQueue( ^{ self.contentField.text = result; } ); - }]; -} - -- (void)updateWithElement:(MPElementEntity *)mainElement { - - [self update]; - - if (!mainElement) - return; - - self.loginButton.alpha = 1; - if (mainElement.requiresExplicitMigration) - self.upgradeButton.alpha = 1; - - self.nameLabel.text = mainElement.name; - if (self.type == (MPElementType)NSNotFound) - self.typeLabel.text = @"Delete"; - else - self.typeLabel.text = [mainElement.algorithm nameOfType:self.type]; - - switch (self.contentFieldMode) { - case MPContentFieldModePassword: { - MPKey *key = [MPiOSAppDelegate get].key; - if (self.type == mainElement.type) - [mainElement resolveContentUsingKey:key result:^(NSString *result) { - PearlMainQueue( ^{ self.contentField.text = result; } ); - }]; - else - [self resolveContentOfCellTypeForElement:mainElement usingKey:key result:^(NSString *result) { - PearlMainQueue( ^{ self.contentField.text = result; } ); - }]; - break; - } - case MPContentFieldModeUser: { - self.contentField.text = mainElement.loginName; - break; - } - } -} - -- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void ( ^ )(NSString *))resultBlock { - - resultBlock( nil ); -} - -- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void ( ^ )(NSString *))resultBlock { - - resultBlock( nil ); -} - -- (void)willBeginDragging { -} - -- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context { - - return [[MPiOSAppDelegate get] changeElement:element saveInContext:context toType:self.type]; -} - -#pragma mark - UITextFieldDelegate - -- (BOOL)textFieldShouldReturn:(UITextField *)textField { - - [textField resignFirstResponder]; - return YES; -} - -- (void)textFieldDidBeginEditing:(UITextField *)textField { - - UICollectionView *collectionView = [UICollectionView findAsSuperviewOf:self]; - [collectionView scrollToItemAtIndexPath:[collectionView indexPathForCell:self] - atScrollPosition:UICollectionViewScrollPositionTop animated:YES]; -} - -- (void)textFieldDidEndEditing:(UITextField *)textField { - - if (textField == self.contentField) { - NSString *newContent = textField.text; - textField.enabled = NO; - - if (self.contentFieldMode == MPContentFieldModeUser) - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - MPElementEntity *element = [[MPPasswordTypesCell findAsSuperviewOf:self] elementInContext:context]; - if (!element) - return; - - element.loginName = newContent; - [context saveToStore]; - - PearlMainQueue( ^{ - [self updateAnimated:YES]; - [PearlOverlay showTemporaryOverlayWithTitle:@"Login Updated" dismissAfter:2]; - } ); - }]; - } -} - -#pragma mark - Actions - -- (IBAction)doUser:(id)sender { - - switch (self.contentFieldMode) { - case MPContentFieldModePassword: { - self.contentFieldMode = MPContentFieldModeUser; - break; - } - case MPContentFieldModeUser: { - self.contentFieldMode = MPContentFieldModePassword; - break; - } - } -} - -- (IBAction)doUpgrade:(UIButton *)sender { - - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - if ([[[MPPasswordTypesCell findAsSuperviewOf:self] elementInContext:context] migrateExplicitly:YES]) { - [context saveToStore]; - - PearlMainQueue( ^{ - [[MPPasswordTypesCell findAsSuperviewOf:self] reloadData]; - [PearlOverlay showTemporaryOverlayWithTitle:@"Site Upgraded" dismissAfter:2]; - } ); - } - else - PearlMainQueue( ^{ - [PearlOverlay showTemporaryOverlayWithTitle:@"Site Not Upgraded" dismissAfter:2]; - } ); - }]; -} - -#pragma mark - Properties - -- (void)setContentFieldMode:(MPContentFieldMode)contentFieldMode { - - if (_contentFieldMode == contentFieldMode) - return; - - _contentFieldMode = contentFieldMode; - - [[MPPasswordTypesCell findAsSuperviewOf:self] reloadData:self]; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeDeleteCell.h b/MasterPassword/ObjC/iOS/MPPasswordLargeDeleteCell.h deleted file mode 100644 index 93de5523..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeDeleteCell.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPPasswordLargeDeleteCell.h -// MPPasswordLargeDeleteCell -// -// Created by lhunath on 2014-03-19. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import -#import "MPPasswordLargeCell.h" - -@interface MPPasswordLargeDeleteCell : MPPasswordLargeCell - -+ (MPPasswordLargeCell *)dequeueCellFromCollectionView:(UICollectionView *)view atIndexPath:(NSIndexPath *)path; -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeDeleteCell.m b/MasterPassword/ObjC/iOS/MPPasswordLargeDeleteCell.m deleted file mode 100644 index 05db27a5..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeDeleteCell.m +++ /dev/null @@ -1,39 +0,0 @@ -/** -* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) -* -* See the enclosed file LICENSE for license information (LGPLv3). If you did -* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt -* -* @author Maarten Billemont -* @license http://www.gnu.org/licenses/lgpl-3.0.txt -*/ - -// -// MPPasswordLargeDeleteCell.h -// MPPasswordLargeDeleteCell -// -// Created by lhunath on 2014-03-19. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import "MPPasswordLargeDeleteCell.h" - -@implementation MPPasswordLargeDeleteCell - -#pragma mark - Lifecycle - -+ (MPPasswordLargeCell *)dequeueCellFromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath { - - MPPasswordLargeCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass( [self class] ) - forIndexPath:indexPath]; - cell.type = (MPElementType)NSNotFound; - - return cell; -} - -- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context { - - return element; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.h b/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.h deleted file mode 100644 index 34d6b655..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPPasswordLargeGeneratedCell.h -// MPPasswordLargeGeneratedCell -// -// Created by lhunath on 2014-03-19. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import -#import "MPPasswordLargeCell.h" - -@interface MPPasswordLargeGeneratedCell : MPPasswordLargeCell - -@property(strong, nonatomic) IBOutlet UILabel *strengthLabel; -@property(strong, nonatomic) IBOutlet UILabel *counterLabel; -@property(strong, nonatomic) IBOutlet UIButton *counterButton; - -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.m b/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.m deleted file mode 100644 index 0ac1466a..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.m +++ /dev/null @@ -1,200 +0,0 @@ -/** -* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) -* -* See the enclosed file LICENSE for license information (LGPLv3). If you did -* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt -* -* @author Maarten Billemont -* @license http://www.gnu.org/licenses/lgpl-3.0.txt -*/ - -// -// MPPasswordLargeGeneratedCell.h -// MPPasswordLargeGeneratedCell -// -// Created by lhunath on 2014-03-19. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import "MPPasswordLargeGeneratedCell.h" -#import "MPiOSAppDelegate.h" -#import "MPAppDelegate_Store.h" -#import "MPPasswordTypesCell.h" - -@interface MPPasswordLargeGeneratedCell() - -@property(nonatomic, weak) NSTimer *hideStrengthTimer; -@end - -@implementation MPPasswordLargeGeneratedCell - -- (void)awakeFromNib { - - [super awakeFromNib]; - - UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc] - initWithTarget:self action:@selector( doResetCounterRecognizer: )]; - [self.counterButton addGestureRecognizer:gestureRecognizer]; -} - -- (void)prepareForReuse { - - [super prepareForReuse]; - - self.strengthLabel.alpha = 0; -} - -- (void)willBeginDragging { - - [super willBeginDragging]; - - [UIView animateWithDuration:0.3f animations:^{ - self.strengthLabel.alpha = 1; - }]; - - [self.hideStrengthTimer invalidate]; - self.hideStrengthTimer = [NSTimer scheduledTimerWithTimeInterval:1 block:^(NSTimer *timer) { - [UIView animateWithDuration:0.3f animations:^{ - self.strengthLabel.alpha = 0; - }]; - } repeats:NO]; -} - -- (void)update { - - [super update]; - - self.counterLabel.alpha = self.counterButton.alpha = 0; -} - -- (void)updateWithElement:(MPElementEntity *)mainElement { - - [super updateWithElement:mainElement]; - - MPElementGeneratedEntity *generatedElement = [self generatedElement:mainElement]; - if (generatedElement) - self.counterLabel.text = strf( @"%lu", (unsigned long)generatedElement.counter ); - else - self.counterLabel.text = @"1"; - - if (mainElement && !mainElement.requiresExplicitMigration) - self.counterLabel.alpha = self.counterButton.alpha = 1; -} - -- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void ( ^ )(NSString *))resultBlock { - - PearlNotMainQueue( ^{ - resultBlock( [MPAlgorithmDefault generateContentNamed:siteName ofType:self.type withCounter:1 usingKey:key] ); - } ); -} - -- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void ( ^ )(NSString *))resultBlock { - - id algorithm = element.algorithm; - NSString *siteName = element.name; - - PearlNotMainQueue( ^{ - resultBlock( [algorithm generateContentNamed:siteName ofType:self.type withCounter:1 usingKey:key] ); - } ); -} - -- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context { - - element = [super saveContentTypeWithElement:element saveInContext:context]; - - MPElementGeneratedEntity *generatedElement = [self generatedElement:element]; - if (generatedElement) { - generatedElement.counter = [self.counterLabel.text intValue]; - [context saveToStore]; - } - - return element; -} - -#pragma mark - Actions - -- (IBAction)doIncrementCounter:(UIButton *)sender { - - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - MPElementGeneratedEntity *generatedElement = [self generatedElementInContext:context]; - if (!generatedElement) - return; - - ++generatedElement.counter; - [context saveToStore]; - - PearlMainQueue( ^{ - [self updateAnimated:YES]; - [PearlOverlay showTemporaryOverlayWithTitle:@"Counter Incremented" dismissAfter:2]; - } ); - }]; -} - -- (void)doResetCounterRecognizer:(UILongPressGestureRecognizer *)gestureRecognizer { - - if (gestureRecognizer.state != UIGestureRecognizerStateBegan) - return; - - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - MPElementGeneratedEntity *generatedElement = [self generatedElementInContext:context]; - if (!generatedElement) - return; - - generatedElement.counter = 1; - [context saveToStore]; - - PearlMainQueue( ^{ - [self updateAnimated:YES]; - [PearlOverlay showTemporaryOverlayWithTitle:@"Counter Reset" dismissAfter:2]; - } ); - }]; -} - -#pragma mark - Properties - -- (void)setType:(MPElementType)type { - - [super setType:type]; - - switch (type) { - case MPElementTypeGeneratedMaximum: - self.strengthLabel.text = @"422 quintillion years"; - break; - case MPElementTypeGeneratedLong: - self.strengthLabel.text = @"1.4 years"; - break; - case MPElementTypeGeneratedMedium: - self.strengthLabel.text = @"2 seconds"; - break; - case MPElementTypeGeneratedBasic: - self.strengthLabel.text = @"trivial"; - break; - case MPElementTypeGeneratedShort: - self.strengthLabel.text = @"trivial"; - break; - case MPElementTypeGeneratedPIN: - self.strengthLabel.text = @"trivial"; - break; - case MPElementTypeStoredPersonal: - self.strengthLabel.text = @""; - break; - case MPElementTypeStoredDevicePrivate: - self.strengthLabel.text = @""; - break; - } -} - -- (MPElementGeneratedEntity *)generatedElementInContext:(NSManagedObjectContext *)context { - - return [self generatedElement:[[MPPasswordTypesCell findAsSuperviewOf:self] elementInContext:context]]; -} - -- (MPElementGeneratedEntity *)generatedElement:(MPElementEntity *)element { - - if (![element isKindOfClass:[MPElementGeneratedEntity class]]) - return nil; - - return (MPElementGeneratedEntity *)element; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.h b/MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.h deleted file mode 100644 index 3f8e4da4..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPPasswordLargeStoredCell.h -// MPPasswordLargeStoredCell -// -// Created by lhunath on 2014-03-19. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import -#import "MPPasswordLargeCell.h" - -@interface MPPasswordLargeStoredCell : MPPasswordLargeCell - -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.m b/MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.m deleted file mode 100644 index 83757f87..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.m +++ /dev/null @@ -1,102 +0,0 @@ -/** -* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) -* -* See the enclosed file LICENSE for license information (LGPLv3). If you did -* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt -* -* @author Maarten Billemont -* @license http://www.gnu.org/licenses/lgpl-3.0.txt -*/ - -// -// MPPasswordLargeGeneratedCell.h -// MPPasswordLargeGeneratedCell -// -// Created by lhunath on 2014-03-19. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import "MPPasswordLargeStoredCell.h" -#import "MPiOSAppDelegate.h" -#import "MPAppDelegate_Store.h" -#import "MPPasswordTypesCell.h" - -@interface MPPasswordLargeStoredCell() - -@property(strong, nonatomic) IBOutlet UIButton *editButton; - -@end - -@implementation MPPasswordLargeStoredCell - -#pragma mark - Lifecycle - -- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void ( ^ )(NSString *))resultBlock { - - if (element.type & MPElementTypeClassStored) - [element resolveContentUsingKey:key result:resultBlock]; - else - [super resolveContentOfCellTypeForElement:element usingKey:key result:resultBlock]; -} - -- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context { - - element = [super saveContentTypeWithElement:element saveInContext:context]; - MPElementStoredEntity *storedElement = [self storedElement:element]; - [storedElement.algorithm saveContent:self.contentField.text toElement:storedElement usingKey:[MPiOSAppDelegate get].key]; - [context saveToStore]; - - return element; -} - -#pragma mark - Actions - -- (IBAction)doEditContent:(UIButton *)sender { - - UITextField *textField = self.contentField; - textField.enabled = YES; - [textField becomeFirstResponder]; -} - -#pragma mark - UITextFieldDelegate - -- (void)textFieldDidEndEditing:(UITextField *)textField { - - [super textFieldDidEndEditing:textField]; - - if (textField == self.contentField) { - NSString *newContent = textField.text; - - if (self.contentFieldMode == MPContentFieldModePassword) - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - MPElementStoredEntity *storedElement = [self storedElementInContext:context]; - if (!storedElement) - return; - - [storedElement.algorithm saveContent:newContent toElement:storedElement usingKey:[MPiOSAppDelegate get].key]; - [context saveToStore]; - - PearlMainQueue( ^{ - [self updateAnimated:YES]; - [PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2]; - } ); - }]; - } -} - -#pragma mark - Properties - -- (MPElementStoredEntity *)storedElementInContext:(NSManagedObjectContext *)context { - - return [self storedElement:[[MPPasswordTypesCell findAsSuperviewOf:self] elementInContext:context]]; -} - -- (MPElementStoredEntity *)storedElement:(MPElementEntity *)element { - - if (![element isKindOfClass:[MPElementStoredEntity class]]) - return nil; - - return (MPElementStoredEntity *)element; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordTypesCell.h b/MasterPassword/ObjC/iOS/MPPasswordTypesCell.h deleted file mode 100644 index 25f19da8..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordTypesCell.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPPasswordTypesCell.h -// MPPasswordTypesCell -// -// Created by lhunath on 2014-03-27. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import -#import "MPCell.h" -#import "MPPasswordCell.h" -#import "MPPasswordsViewController.h" -#import "MPPasswordLargeCell.h" - -@interface MPPasswordTypesCell : MPPasswordCell - -@property(nonatomic, strong) IBOutlet UICollectionView *contentCollectionView; - -@property(nonatomic, weak) MPPasswordsViewController *passwordsViewController; -@property(nonatomic, copy) NSString *transientSite; - -@property(nonatomic, strong) id algorithm; -@property(nonatomic) MPElementType activeType; - -- (MPElementEntity *)mainElement; -- (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context; -- (void)setElement:(MPElementEntity *)element; -- (void)reloadData; -- (void)reloadData:(MPPasswordLargeCell *)cell; - -+ (instancetype)dequeueCellForElement:(MPElementEntity *)element - fromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath; -+ (instancetype)dequeueCellForTransientSite:(NSString *)siteName - fromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath; - -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordTypesCell.m b/MasterPassword/ObjC/iOS/MPPasswordTypesCell.m deleted file mode 100644 index c67192d0..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordTypesCell.m +++ /dev/null @@ -1,411 +0,0 @@ -/** -* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) -* -* See the enclosed file LICENSE for license information (LGPLv3). If you did -* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt -* -* @author Maarten Billemont -* @license http://www.gnu.org/licenses/lgpl-3.0.txt -*/ - -// -// MPPasswordTypesCell.h -// MPPasswordTypesCell -// -// Created by lhunath on 2014-03-27. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import "MPPasswordTypesCell.h" -#import "MPPasswordLargeCell.h" -#import "MPiOSAppDelegate.h" -#import "MPAppDelegate_Store.h" -#import "MPPasswordLargeDeleteCell.h" - -@implementation MPPasswordTypesCell { - NSManagedObjectID *_elementOID; - BOOL _scrolling; -} - -#pragma mark - Lifecycle - -+ (instancetype)dequeueCellForTransientSite:(NSString *)siteName fromCollectionView:(UICollectionView *)collectionView - atIndexPath:(NSIndexPath *)indexPath { - - MPPasswordTypesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass( [MPPasswordTypesCell class] ) - forIndexPath:indexPath]; - [cell setTransientSite:siteName]; - - return cell; -} - -+ (instancetype)dequeueCellForElement:(MPElementEntity *)element fromCollectionView:(UICollectionView *)collectionView - atIndexPath:(NSIndexPath *)indexPath { - - MPPasswordTypesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass( [MPPasswordTypesCell class] ) - forIndexPath:indexPath]; - [cell setElement:element]; - - return cell; -} - -- (void)awakeFromNib { - - [super awakeFromNib]; - - self.backgroundColor = [UIColor clearColor]; - self.layer.shadowColor = [UIColor clearColor].CGColor; - - [self prepareForReuse]; -} - -- (void)prepareForReuse { - - _elementOID = nil; - _transientSite = nil; - _activeType = 0; - _algorithm = MPAlgorithmDefault; - - [super prepareForReuse]; -} - -- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes { - - [super applyLayoutAttributes:layoutAttributes]; - - [self.contentCollectionView.collectionViewLayout invalidateLayout]; - [self scrollToActiveType]; -} - -#pragma mark - UICollectionViewDataSource - -- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout - sizeForItemAtIndexPath:(NSIndexPath *)indexPath { - - return collectionView.bounds.size; -} - -- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - - if (!self.algorithm) - return 0; - - if (self.transientSite) - return [[self.algorithm allTypes] count]; - - return [[self.algorithm allTypes] count] + 1 /* Delete */; -} - -- (MPPasswordLargeCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { - - MPPasswordLargeCell *cell; - if (!self.transientSite && indexPath.item == 0) { - cell = [MPPasswordLargeDeleteCell dequeueCellFromCollectionView:collectionView atIndexPath:indexPath]; - [cell updateWithElement:self.mainElement]; - } - else { - cell = [MPPasswordLargeCell dequeueCellWithType:[self typeForContentIndexPath:indexPath] fromCollectionView:collectionView - atIndexPath:indexPath]; - - [cell prepareForReuse]; - - if (self.transientSite) - [cell updateWithTransientSite:self.transientSite]; - else - [cell updateWithElement:self.mainElement]; - } - - if (_scrolling) - [cell willBeginDragging]; - - return cell; -} - -#pragma mark - UICollectionViewDelegateFlowLayout - -- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { - - NSString *newSiteName = self.transientSite; - if (newSiteName) { - [[UIResponder findFirstResponder] resignFirstResponder]; - [PearlAlert showAlertWithTitle:@"Create Site" - message:strf( @"Do you want to create a new site named:\n%@", newSiteName ) - viewStyle:UIAlertViewStyleDefault - initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { - if (buttonIndex == [alert cancelButtonIndex]) { - // Cancel - for (NSIndexPath *selectedIndexPath in [collectionView indexPathsForSelectedItems]) - [collectionView deselectItemAtIndexPath:selectedIndexPath animated:YES]; - return; - } - - // Create - [[MPiOSAppDelegate get] addElementNamed:newSiteName completion:^(MPElementEntity *element) { - [self copyContentOfElement:element inCell:nil]; - PearlMainQueue( ^{ - [self.passwordsViewController updatePasswords]; - } ); - }]; - } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil]; - return; - } - - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - BOOL used = NO; - MPElementEntity *element = [self elementInContext:context]; - MPPasswordLargeCell *cell = (MPPasswordLargeCell *)[self.contentCollectionView cellForItemAtIndexPath:indexPath]; - if (!element) - wrn( @"No element to use for: %@", self ); - else if (indexPath.item == 0) { - [context deleteObject:element]; - [context saveToStore]; - } - else - used = [self copyContentOfElement:element inCell:cell]; - - PearlMainQueueAfter( 0.2f, ^{ - for (NSIndexPath *selectedIndexPath in [collectionView indexPathsForSelectedItems]) - [collectionView deselectItemAtIndexPath:selectedIndexPath animated:YES]; - - if (used) - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context_) { - [[self elementInContext:context_] use]; - [context_ saveToStore]; - }]; - } ); - }]; -} - -- (BOOL)copyContentOfElement:(MPElementEntity *)element inCell:(MPPasswordLargeCell *)cell { - - NSString *used, *pasteboardContent; - switch (cell.contentFieldMode) { - case MPContentFieldModePassword: - inf( @"Copying password for: %@", element.name ); - used = strl( @"Password" ); - pasteboardContent = [element resolveContentUsingKey:[MPAppDelegate_Shared get].key]; - break; - case MPContentFieldModeUser: - inf( @"Copying login for: %@", element.name ); - used = strl( @"Login" ); - pasteboardContent = element.loginName; - break; - } - - if ([pasteboardContent length]) { - [UIPasteboard generalPasteboard].string = pasteboardContent; - [PearlOverlay showTemporaryOverlayWithTitle:strl(@"%@ Copied", used) dismissAfter:2]; - return YES; - } - - return NO; -} - -#pragma mark - UIScrollViewDelegate - -- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { - - _scrolling = YES; - for (MPPasswordLargeCell *cell in [self.contentCollectionView visibleCells]) - [cell willBeginDragging]; -} - -- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity - targetContentOffset:(inout CGPoint *)targetContentOffset { - - if (scrollView == self.contentCollectionView) { - NSIndexPath *targetIndexPath = [self.contentCollectionView indexPathForItemAtPoint: - CGPointPlusCGPoint( *targetContentOffset, self.contentCollectionView.center )]; - *targetContentOffset = CGRectGetTopLeft( - [self.contentCollectionView layoutAttributesForItemAtIndexPath:targetIndexPath].frame ); - } -} - -- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { - - _scrolling = NO; - if (scrollView == self.contentCollectionView && !decelerate) - [self saveContentType]; -} - -- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { - - _scrolling = NO; - if (scrollView == self.contentCollectionView) - [self saveContentType]; -} - -#pragma mark - Private - -- (void)reloadData { - - if (self.transientSite) - PearlMainQueue( ^{ - self.algorithm = MPAlgorithmDefault; - self.activeType = [[MPiOSAppDelegate get] activeUserForMainThread].defaultType?: MPElementTypeGeneratedLong; - - for (NSInteger section = 0; section < [self.contentCollectionView numberOfSections]; ++section) - for (NSInteger item = 0; item < [self.contentCollectionView numberOfItemsInSection:section]; ++item) - [(MPPasswordLargeCell *)[self.contentCollectionView cellForItemAtIndexPath: - [NSIndexPath indexPathForItem:item inSection:section]] updateWithTransientSite:self.transientSite]; - } ); - else - [MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) { - MPElementEntity *mainElement = self.transientSite? nil: [self elementInContext:mainContext]; - - self.algorithm = mainElement.algorithm?: MPAlgorithmDefault; - self.activeType = mainElement.type?: [[MPiOSAppDelegate get] activeUserInContext:mainContext].defaultType?: - MPElementTypeGeneratedLong; - - for (NSInteger section = 0; section < [self.contentCollectionView numberOfSections]; ++section) - for (NSInteger item = 0; item < [self.contentCollectionView numberOfItemsInSection:section]; ++item) { - MPPasswordLargeCell *cell = (MPPasswordLargeCell *)[self.contentCollectionView cellForItemAtIndexPath: - [NSIndexPath indexPathForItem:item inSection:section]]; - [self reloadData:cell withElement:mainElement]; - } - }]; -} - -- (void)reloadData:(MPPasswordLargeCell *)cell { - - [MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) { - [self reloadData:cell withElement:[self elementInContext:mainContext]]; - }]; -} - -- (void)reloadData:(MPPasswordLargeCell *)cell withElement:(MPElementEntity *)element { - - if (element) - [cell updateWithElement:element]; - else - [cell updateWithTransientSite:self.transientSite]; -} - -- (void)scrollToActiveType { - - if (self.activeType && self.activeType != (MPElementType)NSNotFound) - [self.contentCollectionView scrollToItemAtIndexPath:[self contentIndexPathForType:self.activeType] - atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO]; -} - -- (MPElementType)typeForContentIndexPath:(NSIndexPath *)indexPath { - - if (self.transientSite) - return [[self.algorithm allTypesStartingWith:MPElementTypeGeneratedPIN][indexPath.item] unsignedIntegerValue]; - - if (indexPath.item == 0) - return (MPElementType)NSNotFound; - - return [[self.algorithm allTypesStartingWith:MPElementTypeGeneratedPIN][indexPath.item - 1] unsignedIntegerValue]; -} - -- (NSIndexPath *)contentIndexPathForType:(MPElementType)type { - - NSArray *types = [self.algorithm allTypesStartingWith:MPElementTypeGeneratedPIN]; - for (NSInteger t = 0; t < [types count]; ++t) - if ([types[t] unsignedIntegerValue] == type) { - if (self.transientSite) - return [NSIndexPath indexPathForItem:t inSection:0]; - else - return [NSIndexPath indexPathForItem:t + 1 inSection:0]; - } - - Throw( @"Unsupported type: %lud", (long)type ); -} - -- (void)saveContentType { - - CGPoint centerPoint = CGRectGetCenter( self.contentCollectionView.bounds ); - NSIndexPath *centerIndexPath = [self.contentCollectionView indexPathForItemAtPoint:centerPoint]; - MPElementType type = [self typeForContentIndexPath:centerIndexPath]; - if (type == ((MPElementType)NSNotFound)) - // Active cell is not a type cell. - return; - - self.activeType = type; - - if (self.transientSite) - return; - - [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { - MPPasswordLargeCell *cell = (MPPasswordLargeCell *)[self.contentCollectionView cellForItemAtIndexPath:centerIndexPath]; - if (!cell) { - err( @"Couldn't find cell to change type: centerIndexPath=%@", centerIndexPath ); - return; - } - - MPElementEntity *element = [self elementInContext:context]; - if (!element || element.type == cell.type) - // Nothing changed. - return; - - self.element = [cell saveContentTypeWithElement:element saveInContext:context]; - }]; -} - -#pragma mark - State - -- (void)setTransientSite:(NSString *)transientSite { - - if ([_transientSite isEqualToString:transientSite]) - return; - - dbg( @"transientSite: %@ -> %@", _transientSite, transientSite ); - - _transientSite = transientSite; - _elementOID = nil; - - [self updateAnimated:YES]; - [self reloadData]; -} - -- (void)setElement:(MPElementEntity *)element { - - NSManagedObjectID *newElementOID = element.objectID; - NSAssert( !newElementOID.isTemporaryID, @"Element doesn't have a permanent objectID: %@", element ); - if ([_elementOID isEqual:newElementOID]) - return; - - dbg( @"element: %@ -> %@", _elementOID, newElementOID ); - - _transientSite = nil; - _elementOID = newElementOID; - - [self updateAnimated:YES]; - [self reloadData]; -} - -- (MPElementEntity *)mainElement { - - return [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]; -} - -- (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context { - - return [MPElementEntity existingObjectWithID:_elementOID inContext:context]; -} - -- (void)setActiveType:(MPElementType)activeType { - - _activeType = activeType; - - [self scrollToActiveType]; -} - -- (void)setSelected:(BOOL)selected { - - [super setSelected:selected]; - - if (!selected) - for (NSIndexPath *indexPath in [self.contentCollectionView indexPathsForSelectedItems]) - [self.contentCollectionView deselectItemAtIndexPath:indexPath animated:YES]; -} - -- (void)setAlgorithm:(id)algorithm { - - _algorithm = algorithm; - - [self.contentCollectionView reloadData]; -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordsCoachmarkViewController.h b/MasterPassword/ObjC/iOS/MPPasswordsCoachmarkViewController.h deleted file mode 100644 index 4d224383..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordsCoachmarkViewController.h +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPPasswordsCoachmarkViewController.h -// MPPasswordsCoachmarkViewController -// -// Created by lhunath on 2014-04-23. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import -#import "MPCoachmarkViewController.h" - -@interface MPPasswordsCoachmarkViewController : MPCoachmarkViewController -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordsCoachmarkViewController.m b/MasterPassword/ObjC/iOS/MPPasswordsCoachmarkViewController.m deleted file mode 100644 index 1198589a..00000000 --- a/MasterPassword/ObjC/iOS/MPPasswordsCoachmarkViewController.m +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ - -// -// MPPasswordsCoachmarkViewController.h -// MPPasswordsCoachmarkViewController -// -// Created by lhunath on 2014-04-23. -// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved. -// - -#import "MPPasswordsCoachmarkViewController.h" -#import "MPPasswordLargeGeneratedCell.h" -#import "MPPasswordLargeStoredCell.h" - -@implementation MPPasswordsCoachmarkViewController - -- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - - return 2; -} - -- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { - - if (indexPath.item == 0) { - MPPasswordLargeGeneratedCell *cell = [MPPasswordLargeGeneratedCell dequeueCellWithType:MPElementTypeGeneratedLong - fromCollectionView:collectionView atIndexPath:indexPath]; - [cell updateWithTransientSite:@"apple.com"]; - - return cell; - } - else if (indexPath.item == 1) { - MPPasswordLargeStoredCell *cell = [MPPasswordLargeStoredCell dequeueCellWithType:MPElementTypeStoredPersonal - fromCollectionView:collectionView atIndexPath:indexPath]; - [cell updateWithTransientSite:@"gmail.com"]; - [cell.contentField setText:@"PaS$w0rD"]; - - return cell; - } - - Throw(@"Unexpected item for indexPath: %@", indexPath); -} - -@end diff --git a/MasterPassword/ObjC/iOS/MPPasswordsViewController.m b/MasterPassword/ObjC/iOS/MPPasswordsViewController.m index ccc4c06d..c516ed85 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordsViewController.m +++ b/MasterPassword/ObjC/iOS/MPPasswordsViewController.m @@ -1,12 +1,12 @@ /** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ +* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) +* +* See the enclosed file LICENSE for license information (LGPLv3). If you did +* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt +* +* @author Maarten Billemont +* @license http://www.gnu.org/licenses/lgpl-3.0.txt +*/ // // MPPasswordsViewController.h @@ -19,11 +19,9 @@ #import "MPPasswordsViewController.h" #import "MPiOSAppDelegate.h" #import "MPAppDelegate_Store.h" -#import "MPPasswordLargeCell.h" -#import "MPPasswordTypesCell.h" #import "MPPopdownSegue.h" #import "MPAppDelegate_Key.h" -#import "MPCoachmarkViewController.h" +#import "MPPasswordCell.h" @interface MPPasswordsViewController() @@ -58,7 +56,7 @@ [self.passwordsSearchBar enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) { if ([subview isKindOfClass:[UITextField class]]) ((UITextField *)subview).keyboardAppearance = UIKeyboardAppearanceDark; - } recurse:YES]; + } recurse:YES]; } - (void)viewWillAppear:(BOOL)animated { @@ -103,54 +101,34 @@ referenceSizeForHeaderInSection:(NSInteger)section { - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { - if (collectionView == self.passwordCollectionView) { - UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)collectionViewLayout; - CGFloat itemWidth = UIEdgeInsetsInsetRect(self.passwordCollectionView.bounds, layout.sectionInset).size.width; - return CGSizeMake( itemWidth, 100 ); - } - - Throw(@"Unexpected collection view: %@", collectionView); + UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)collectionViewLayout; + CGFloat itemWidth = UIEdgeInsetsInsetRect( self.passwordCollectionView.bounds, layout.sectionInset ).size.width; + return CGSizeMake( itemWidth, 100 ); } #pragma mark - UICollectionViewDataSource - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { - if (collectionView == self.passwordCollectionView) - return [self.fetchedResultsController.sections count]; - - Throw(@"Unexpected collection view: %@", collectionView); + return [self.fetchedResultsController.sections count]; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - if (collectionView == self.passwordCollectionView) - return ![MPiOSAppDelegate get].activeUserOID? 0: - ((id)self.fetchedResultsController.sections[section]).numberOfObjects + - (!_exactMatch && [[self query] length]? 1: 0); - - Throw(@"Unexpected collection view: %@", collectionView); + return ![MPiOSAppDelegate get].activeUserOID? 0: + ((id)self.fetchedResultsController.sections[section]).numberOfObjects + + (!_exactMatch && [[self query] length]? 1: 0); } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { - if (collectionView == self.passwordCollectionView) { - [UIView setAnimationsEnabled:NO]; - MPPasswordTypesCell *cell; - if (indexPath.item < ((id)self.fetchedResultsController.sections[indexPath.section]).numberOfObjects) { - MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath]; - cell = [MPPasswordTypesCell dequeueCellForElement:element fromCollectionView:collectionView atIndexPath:indexPath]; - } - else - // New Site. - cell = [MPPasswordTypesCell dequeueCellForTransientSite:self.query fromCollectionView:collectionView atIndexPath:indexPath]; - cell.passwordsViewController = self; + MPPasswordCell *cell = [MPPasswordCell dequeueCellFromCollectionView:collectionView indexPath:indexPath]; + if (indexPath.item < ((id)self.fetchedResultsController.sections[indexPath.section]).numberOfObjects) + [cell setElement:[self.fetchedResultsController objectAtIndexPath:indexPath] animated:NO]; + else + [cell setTransientSite:self.query animated:NO]; - [UIView setAnimationsEnabled:YES]; - return cell; - } - - Throw(@"Unexpected collection view: %@", collectionView); + return cell; } - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind @@ -159,15 +137,35 @@ referenceSizeForHeaderInSection:(NSInteger)section { return [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"MPPasswordHeader" forIndexPath:indexPath]; } +#pragma mark - UIScrollDelegate + +- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { + + if (scrollView == self.passwordCollectionView) + for (MPPasswordCell *cell in [self.passwordCollectionView visibleCells]) + [cell setMode:MPPasswordCellModePassword animated:YES]; +} + #pragma mark - NSFetchedResultsControllerDelegate - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { if (controller == _fetchedResultsController) { - [self.passwordCollectionView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section]]; - if (![newIndexPath isEqual:indexPath]) - [self.passwordCollectionView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section]]; + switch (type) { + case NSFetchedResultsChangeInsert: + [self.passwordCollectionView insertItemsAtIndexPaths:@[ newIndexPath ]]; + break; + case NSFetchedResultsChangeDelete: + [self.passwordCollectionView deleteItemsAtIndexPaths:@[ indexPath ]]; + break; + case NSFetchedResultsChangeMove: + [self.passwordCollectionView moveItemAtIndexPath:indexPath toIndexPath:newIndexPath]; + break; + case NSFetchedResultsChangeUpdate: + [self.passwordCollectionView reloadItemsAtIndexPaths:@[ indexPath ]]; + break; + } } } @@ -229,7 +227,6 @@ referenceSizeForHeaderInSection:(NSInteger)section { [self updatePasswords]; } - #pragma mark - Private - (void)registerObservers { @@ -237,19 +234,19 @@ referenceSizeForHeaderInSection:(NSInteger)section { if ([_notificationObservers count]) return; - Weakify(self); + Weakify( self ); _notificationObservers = @[ [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify(self); + Strongify( self ); self.passwordSelectionContainer.alpha = 0; }], [[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil queue:nil usingBlock:^(NSNotification *note) { - Strongify(self); + Strongify( self ); _fetchedResultsController = nil; self.passwordsSearchBar.text = nil; @@ -258,7 +255,7 @@ referenceSizeForHeaderInSection:(NSInteger)section { [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify(self); + Strongify( self ); [self updatePasswords]; [UIView animateWithDuration:1 animations:^{ @@ -282,7 +279,7 @@ referenceSizeForHeaderInSection:(NSInteger)section { - (void)observeStore { - Weakify(self); + Weakify( self ); NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady]; if (!_mocObserver && mainContext) @@ -296,7 +293,7 @@ referenceSizeForHeaderInSection:(NSInteger)section { _storeObserver = [[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify(self); + Strongify( self ); _fetchedResultsController = nil; [self updatePasswords]; }]; @@ -312,9 +309,9 @@ referenceSizeForHeaderInSection:(NSInteger)section { - (void)updateConfigKey:(NSString *)key { - if (!key || [key isEqualToString:NSStringFromSelector( @selector(dictationSearch) )]) + if (!key || [key isEqualToString:NSStringFromSelector( @selector( dictationSearch ) )]) self.passwordsSearchBar.keyboardType = [[MPiOSConfig get].dictationSearch boolValue]? UIKeyboardTypeDefault: UIKeyboardTypeURL; - if (!key || [key isEqualToString:NSStringFromSelector( @selector(hidePasswords) )]) + if (!key || [key isEqualToString:NSStringFromSelector( @selector( hidePasswords ) )]) [self updatePasswords]; } @@ -338,7 +335,7 @@ referenceSizeForHeaderInSection:(NSInteger)section { [NSPredicate predicateWithFormat:@"user == %@ AND name BEGINSWITH[cd] %@", activeUserOID, query]: [NSPredicate predicateWithFormat:@"user == %@", activeUserOID]; if (![self.fetchedResultsController performFetch:&error]) - err(@"Couldn't fetch elements: %@", error); + err( @"Couldn't fetch elements: %@", error ); _exactMatch = NO; for (MPElementEntity *entity in self.fetchedResultsController.fetchedObjects) @@ -351,17 +348,17 @@ referenceSizeForHeaderInSection:(NSInteger)section { [self.passwordCollectionView performBatchUpdates:^{ NSInteger fromSections = self.passwordCollectionView.numberOfSections; NSInteger toSections = [self numberOfSectionsInCollectionView:self.passwordCollectionView]; - for (int section = 0; section < MAX(toSections, fromSections); section++) { + for (int section = 0; section < MAX( toSections, fromSections ); section++) { if (section >= fromSections) { - dbg(@"insertSections:%d", section); + dbg( @"insertSections:%d", section ); [self.passwordCollectionView insertSections:[NSIndexSet indexSetWithIndex:section]]; } else if (section >= toSections) { - dbg(@"deleteSections:%d", section); + dbg( @"deleteSections:%d", section ); [self.passwordCollectionView deleteSections:[NSIndexSet indexSetWithIndex:section]]; } else { - dbg(@"reloadSections:%d", section); + dbg( @"reloadSections:%d", section ); [self.passwordCollectionView reloadSections:[NSIndexSet indexSetWithIndex:section]]; } } @@ -387,7 +384,7 @@ referenceSizeForHeaderInSection:(NSInteger)section { [MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) { NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )]; fetchRequest.sortDescriptors = @[ - [[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector(lastUsed) ) ascending:NO] + [[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO] ]; fetchRequest.fetchBatchSize = 10; _fetchedResultsController = [[NSFetchedResultsController alloc] @@ -405,13 +402,13 @@ referenceSizeForHeaderInSection:(NSInteger)section { [self setActive:active animated:NO completion:nil]; } -- (void)setActive:(BOOL)active animated:(BOOL)animated completion:(void (^)(BOOL finished))completion { +- (void)setActive:(BOOL)active animated:(BOOL)animated completion:(void ( ^ )(BOOL finished))completion { _active = active; [UIView animateWithDuration:animated? 0.4f: 0 animations:^{ - [self.navigationBarToTopConstraint layoutWithPriority:active? 1: UILayoutPriorityDefaultHigh]; - [self.passwordsToBottomConstraint layoutWithPriority:active? 1: UILayoutPriorityDefaultHigh]; + [[self.navigationBarToTopConstraint updatePriority:active? 1: UILayoutPriorityDefaultHigh] layoutIfNeeded]; + [[self.passwordsToBottomConstraint updatePriority:active? 1: UILayoutPriorityDefaultHigh] layoutIfNeeded]; } completion:completion]; } diff --git a/MasterPassword/ObjC/iOS/MPPopdownSegue.m b/MasterPassword/ObjC/iOS/MPPopdownSegue.m index 8856f1ad..73acef12 100644 --- a/MasterPassword/ObjC/iOS/MPPopdownSegue.m +++ b/MasterPassword/ObjC/iOS/MPPopdownSegue.m @@ -38,7 +38,7 @@ metrics:nil views:NSDictionaryOfVariableBindings(popdownView)]; [UIView animateWithDuration:0.3f animations:^{ - [passwordsVC.popdownToTopConstraint layoutWithPriority:1]; + [[passwordsVC.popdownToTopConstraint updatePriority:1] layoutIfNeeded]; } completion:^(BOOL finished) { [popdownVC didMoveToParentViewController:passwordsVC]; }]; @@ -49,7 +49,7 @@ [popdownVC willMoveToParentViewController:nil]; [UIView animateWithDuration:0.3f delay:0 options:UIViewAnimationOptionOverrideInheritedDuration animations:^{ - [passwordsVC.popdownToTopConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; + [[passwordsVC.popdownToTopConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded]; } completion:^(BOOL finished) { [popdownVC.view removeFromSuperview]; [popdownVC removeFromParentViewController]; diff --git a/MasterPassword/ObjC/iOS/MPUsersViewController.m b/MasterPassword/ObjC/iOS/MPUsersViewController.m index 2d486a18..14eff51f 100644 --- a/MasterPassword/ObjC/iOS/MPUsersViewController.m +++ b/MasterPassword/ObjC/iOS/MPUsersViewController.m @@ -786,7 +786,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) { // Manage the entry container depending on whether a user is activate or not. switch (activeUserState) { case MPActiveUserStateNone: { - self.navigationBarToTopConstraint.priority = UILayoutPriorityDefaultHigh; + [[self.navigationBarToTopConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded]; self.avatarCollectionView.scrollEnabled = YES; self.entryContainer.alpha = 0; self.footerContainer.alpha = 1; @@ -796,7 +796,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) { case MPActiveUserStateUserName: case MPActiveUserStateMasterPasswordChoice: case MPActiveUserStateMasterPasswordConfirmation: { - [self.navigationBarToTopConstraint layoutWithPriority:UILayoutPriorityDefaultHigh]; + [[self.navigationBarToTopConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded]; self.avatarCollectionView.scrollEnabled = NO; self.entryContainer.alpha = 1; self.footerContainer.alpha = 1; @@ -804,7 +804,7 @@ typedef NS_ENUM(NSUInteger, MPActiveUserState) { break; } case MPActiveUserStateMinimized: { - [self.navigationBarToTopConstraint layoutWithPriority:1]; + [[self.navigationBarToTopConstraint updatePriority:1] layoutIfNeeded]; self.avatarCollectionView.scrollEnabled = NO; self.entryContainer.alpha = 0; self.footerContainer.alpha = 0; diff --git a/MasterPassword/ObjC/iOS/MPWebViewController.m b/MasterPassword/ObjC/iOS/MPWebViewController.m index 94ccc45c..98c9bcc1 100644 --- a/MasterPassword/ObjC/iOS/MPWebViewController.m +++ b/MasterPassword/ObjC/iOS/MPWebViewController.m @@ -24,7 +24,7 @@ [super viewDidLoad]; - [self.view adjustContentInsets]; + [self.webView.scrollView insetOcclusion]; } - (void)viewWillAppear:(BOOL)animated { diff --git a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj index 7b9ac689..a09b8a4d 100644 --- a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj +++ b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 93D391C07818F4C2DC1B6956 /* MPPasswordsCoachmarkViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D397E3650384498E7E53C4 /* MPPasswordsCoachmarkViewController.m */; }; 93D391ECBD9BD2C64115B5DD /* PearlSizedTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39156E806BB78E04F78B9 /* PearlSizedTextView.m */; }; 93D391ED37C9F687FA51EAA1 /* MPEmergencySegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3937712BF1B67623E5764 /* MPEmergencySegue.m */; }; 93D3922A53E41A54832E90D9 /* PearlOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390FADEB325D8D54A957D /* PearlOverlay.m */; }; @@ -19,7 +18,6 @@ 93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39A4759186F6D2D34AA6B /* PearlSizedTextView.h */; }; 93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */; }; 93D394B5036C882B33C71872 /* MPPasswordsSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E7A12CC352B2825AA66 /* MPPasswordsSegue.m */; }; - 93D394F6D3F6E2553AA0D684 /* MPPasswordLargeStoredCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3947F6BB69CA9A9124A5D /* MPPasswordLargeStoredCell.m */; }; 93D39536EB550E811CCD04BC /* UIResponder+PearlFirstResponder.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */; }; 93D3954E96236384AFA00453 /* UIScrollView+PearlAdjustInsets.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390FB3110DCCE68E600DC /* UIScrollView+PearlAdjustInsets.m */; }; 93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */; }; @@ -31,10 +29,8 @@ 93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */; }; 93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */; }; 93D3980046016EFD05B35BC5 /* PearlUICollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */; }; - 93D398BD8B83FEE8BE4EFFFC /* MPPasswordLargeDeleteCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39EFBC4D6BA3C8581865F /* MPPasswordLargeDeleteCell.m */; }; 93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */; }; 93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */; }; - 93D399278165FD6D950F0025 /* MPPasswordTypesCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39097C0AAE62C1C321BFC /* MPPasswordTypesCell.m */; }; 93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; }; 93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; }; 93D399BBC0A7EC746CB1B19B /* MPLogsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D391943675426839501BB8 /* MPLogsViewController.h */; }; @@ -45,14 +41,12 @@ 93D39B8F90F58A5D158DDBA3 /* MPPasswordsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3924EE15017F8A12CB436 /* MPPasswordsViewController.m */; }; 93D39BA1EA3CAAC8A220B4A6 /* MPAppSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3916C1D8F1427DFBDEBCA /* MPAppSettingsViewController.m */; }; 93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; }; - 93D39CB5E2EC1078E898F46A /* MPPasswordLargeCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3937863061C3916AF7AD2 /* MPPasswordLargeCell.m */; }; 93D39D596A2E376D6F6F5DA1 /* MPCombinedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D393310223DDB35218467A /* MPCombinedViewController.m */; }; 93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39CC01630D0421205C4C4 /* MPNavigationController.m */; }; 93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; }; 93D39E34FD28D24FE3442C48 /* UITextView+PearlAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3977321EB249981821AB0 /* UITextView+PearlAttributes.m */; }; 93D39EAA4D064193074D3021 /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A813CA9D7E192261ED2 /* MPFixable.m */; }; 93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A28369954D147E239BA /* MPSetupViewController.m */; }; - 93D39FA97F4C3F69A75D5A03 /* MPPasswordLargeGeneratedCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3993422E207BF0B21D089 /* MPPasswordLargeGeneratedCell.m */; }; DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */; }; DA071BF3190187FE00179766 /* empty@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA071BF1190187FE00179766 /* empty@2x.png */; }; DA071BF4190187FE00179766 /* empty.png in Resources */ = {isa = PBXBuildFile; fileRef = DA071BF2190187FE00179766 /* empty.png */; }; @@ -85,6 +79,18 @@ DA250A18195665A100AC23F1 /* UITableView+PearlReloadFromArray.h in Headers */ = {isa = PBXBuildFile; fileRef = DA250A14195665A100AC23F1 /* UITableView+PearlReloadFromArray.h */; }; DA250A19195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m in Sources */ = {isa = PBXBuildFile; fileRef = DA250A15195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m */; }; DA250A1A195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h in Headers */ = {isa = PBXBuildFile; fileRef = DA250A16195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h */; }; + DA25C5F8197AFFB40046CDCF /* icon_tools.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD384C1711E29700CF925C /* icon_tools.png */; }; + DA25C5F9197AFFB40046CDCF /* icon_tools@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD384D1711E29700CF925C /* icon_tools@2x.png */; }; + DA25C5FA197CCAE00046CDCF /* icon_delete.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37541711E29500CF925C /* icon_delete.png */; }; + DA25C5FB197CCAE00046CDCF /* icon_delete@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37551711E29500CF925C /* icon_delete@2x.png */; }; + DA25C5FC197CCAF70046CDCF /* icon_list-names.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37A61711E29600CF925C /* icon_list-names.png */; }; + DA25C5FD197CCAF70046CDCF /* icon_list-names@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37A71711E29600CF925C /* icon_list-names@2x.png */; }; + DA25C5FE197DBF200046CDCF /* icon_thumbs-up.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD384A1711E29700CF925C /* icon_thumbs-up.png */; }; + DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD384B1711E29700CF925C /* icon_thumbs-up@2x.png */; }; + DA25C600197DBF260046CDCF /* icon_trash.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38501711E29700CF925C /* icon_trash.png */; }; + DA25C601197DBF260046CDCF /* icon_trash@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38511711E29700CF925C /* icon_trash@2x.png */; }; + DA25C6B41980D3C50046CDCF /* openssl in Headers */ = {isa = PBXBuildFile; fileRef = DA25C6B31980D3C10046CDCF /* openssl */; settings = {ATTRIBUTES = (Public, ); }; }; + DA25C6B61980D3DF0046CDCF /* scrypt in Headers */ = {isa = PBXBuildFile; fileRef = DA25C6B51980D3DD0046CDCF /* scrypt */; settings = {ATTRIBUTES = (Public, ); }; }; DA2CA4DD18D28859007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */; }; DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4DA18D28859007798F8 /* NSArray+Pearl.h */; }; DA2CA4DF18D28859007798F8 /* NSTimer+PearlBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4DB18D28859007798F8 /* NSTimer+PearlBlock.m */; }; @@ -265,92 +271,12 @@ DACA29BF1705E2DE002C6C22 /* UIColor+HSV.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA29BB1705E2DE002C6C22 /* UIColor+HSV.m */; }; DAD312C21552A22700A3F9ED /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD312C01552A20800A3F9ED /* libsqlite3.dylib */; }; DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DAE1EF2417E942DE00BC0086 /* Localizable.strings */; }; - DAEB933318AA537D000490CC /* crypto_aesctr.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92E118AA537D000490CC /* crypto_aesctr.h */; }; - DAEB933418AA537D000490CC /* crypto_scrypt.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92E218AA537D000490CC /* crypto_scrypt.h */; }; - DAEB933518AA537D000490CC /* memlimit.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92E318AA537D000490CC /* memlimit.h */; }; - DAEB933618AA537D000490CC /* readpass.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92E418AA537D000490CC /* readpass.h */; }; - DAEB933718AA537D000490CC /* scryptenc.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92E518AA537D000490CC /* scryptenc.h */; }; - DAEB933818AA537D000490CC /* scryptenc_cpuperf.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92E618AA537D000490CC /* scryptenc_cpuperf.h */; }; - DAEB933918AA537D000490CC /* sha256.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92E718AA537D000490CC /* sha256.h */; }; - DAEB933A18AA537D000490CC /* sysendian.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92E818AA537D000490CC /* sysendian.h */; }; - DAEB933B18AA537D000490CC /* warn.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92E918AA537D000490CC /* warn.h */; }; - DAEB933C18AA537D000490CC /* aes.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92EB18AA537D000490CC /* aes.h */; }; - DAEB933D18AA537D000490CC /* asn1.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92EC18AA537D000490CC /* asn1.h */; }; - DAEB933E18AA537D000490CC /* asn1_mac.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92ED18AA537D000490CC /* asn1_mac.h */; }; - DAEB933F18AA537D000490CC /* asn1t.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92EE18AA537D000490CC /* asn1t.h */; }; - DAEB934018AA537D000490CC /* bio.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92EF18AA537D000490CC /* bio.h */; }; - DAEB934118AA537D000490CC /* blowfish.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92F018AA537D000490CC /* blowfish.h */; }; - DAEB934218AA537D000490CC /* bn.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92F118AA537D000490CC /* bn.h */; }; - DAEB934318AA537D000490CC /* buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92F218AA537D000490CC /* buffer.h */; }; - DAEB934418AA537D000490CC /* camellia.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92F318AA537D000490CC /* camellia.h */; }; - DAEB934518AA537D000490CC /* cast.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92F418AA537D000490CC /* cast.h */; }; - DAEB934618AA537D000490CC /* cms.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92F518AA537D000490CC /* cms.h */; }; - DAEB934718AA537D000490CC /* comp.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92F618AA537D000490CC /* comp.h */; }; - DAEB934818AA537D000490CC /* conf.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92F718AA537D000490CC /* conf.h */; }; - DAEB934918AA537D000490CC /* conf_api.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92F818AA537D000490CC /* conf_api.h */; }; - DAEB934A18AA537D000490CC /* crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92F918AA537D000490CC /* crypto.h */; }; - DAEB934B18AA537D000490CC /* des.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92FA18AA537D000490CC /* des.h */; }; - DAEB934C18AA537D000490CC /* des_old.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92FB18AA537D000490CC /* des_old.h */; }; - DAEB934D18AA537D000490CC /* dh.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92FC18AA537D000490CC /* dh.h */; }; - DAEB934E18AA537D000490CC /* dsa.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92FD18AA537D000490CC /* dsa.h */; }; - DAEB934F18AA537D000490CC /* dso.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92FE18AA537D000490CC /* dso.h */; }; - DAEB935018AA537D000490CC /* dtls1.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB92FF18AA537D000490CC /* dtls1.h */; }; - DAEB935118AA537D000490CC /* e_os2.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930018AA537D000490CC /* e_os2.h */; }; - DAEB935218AA537D000490CC /* ebcdic.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930118AA537D000490CC /* ebcdic.h */; }; - DAEB935318AA537D000490CC /* ec.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930218AA537D000490CC /* ec.h */; }; - DAEB935418AA537D000490CC /* ecdh.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930318AA537D000490CC /* ecdh.h */; }; - DAEB935518AA537D000490CC /* ecdsa.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930418AA537D000490CC /* ecdsa.h */; }; - DAEB935618AA537D000490CC /* engine.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930518AA537D000490CC /* engine.h */; }; - DAEB935718AA537D000490CC /* err.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930618AA537D000490CC /* err.h */; }; - DAEB935818AA537D000490CC /* evp.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930718AA537D000490CC /* evp.h */; }; - DAEB935918AA537D000490CC /* hmac.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930818AA537D000490CC /* hmac.h */; }; - DAEB935A18AA537D000490CC /* idea.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930918AA537D000490CC /* idea.h */; }; - DAEB935B18AA537D000490CC /* krb5_asn.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930A18AA537D000490CC /* krb5_asn.h */; }; - DAEB935C18AA537D000490CC /* kssl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930B18AA537D000490CC /* kssl.h */; }; - DAEB935D18AA537D000490CC /* lhash.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930C18AA537D000490CC /* lhash.h */; }; - DAEB935E18AA537D000490CC /* md4.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930D18AA537D000490CC /* md4.h */; }; - DAEB935F18AA537D000490CC /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930E18AA537D000490CC /* md5.h */; }; - DAEB936018AA537D000490CC /* mdc2.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB930F18AA537D000490CC /* mdc2.h */; }; - DAEB936118AA537D000490CC /* modes.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931018AA537D000490CC /* modes.h */; }; - DAEB936218AA537D000490CC /* obj_mac.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931118AA537D000490CC /* obj_mac.h */; }; - DAEB936318AA537D000490CC /* objects.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931218AA537D000490CC /* objects.h */; }; - DAEB936418AA537D000490CC /* ocsp.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931318AA537D000490CC /* ocsp.h */; }; - DAEB936518AA537D000490CC /* opensslconf.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931418AA537D000490CC /* opensslconf.h */; }; - DAEB936618AA537D000490CC /* opensslv.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931518AA537D000490CC /* opensslv.h */; }; - DAEB936718AA537D000490CC /* ossl_typ.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931618AA537D000490CC /* ossl_typ.h */; }; - DAEB936818AA537D000490CC /* pem.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931718AA537D000490CC /* pem.h */; }; - DAEB936918AA537D000490CC /* pem2.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931818AA537D000490CC /* pem2.h */; }; - DAEB936A18AA537D000490CC /* pkcs12.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931918AA537D000490CC /* pkcs12.h */; }; - DAEB936B18AA537D000490CC /* pkcs7.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931A18AA537D000490CC /* pkcs7.h */; }; - DAEB936C18AA537D000490CC /* pqueue.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931B18AA537D000490CC /* pqueue.h */; }; - DAEB936D18AA537D000490CC /* rand.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931C18AA537D000490CC /* rand.h */; }; - DAEB936E18AA537D000490CC /* rc2.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931D18AA537D000490CC /* rc2.h */; }; - DAEB936F18AA537D000490CC /* rc4.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931E18AA537D000490CC /* rc4.h */; }; - DAEB937018AA537D000490CC /* ripemd.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB931F18AA537D000490CC /* ripemd.h */; }; - DAEB937118AA537D000490CC /* rsa.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932018AA537D000490CC /* rsa.h */; }; - DAEB937218AA537D000490CC /* safestack.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932118AA537D000490CC /* safestack.h */; }; - DAEB937318AA537D000490CC /* seed.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932218AA537D000490CC /* seed.h */; }; - DAEB937418AA537D000490CC /* sha.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932318AA537D000490CC /* sha.h */; }; - DAEB937518AA537D000490CC /* ssl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932418AA537D000490CC /* ssl.h */; }; - DAEB937618AA537D000490CC /* ssl2.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932518AA537D000490CC /* ssl2.h */; }; - DAEB937718AA537D000490CC /* ssl23.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932618AA537D000490CC /* ssl23.h */; }; - DAEB937818AA537D000490CC /* ssl3.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932718AA537D000490CC /* ssl3.h */; }; - DAEB937918AA537D000490CC /* stack.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932818AA537D000490CC /* stack.h */; }; - DAEB937A18AA537D000490CC /* symhacks.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932918AA537D000490CC /* symhacks.h */; }; - DAEB937B18AA537D000490CC /* tls1.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932A18AA537D000490CC /* tls1.h */; }; - DAEB937C18AA537D000490CC /* ts.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932B18AA537D000490CC /* ts.h */; }; - DAEB937D18AA537D000490CC /* txt_db.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932C18AA537D000490CC /* txt_db.h */; }; - DAEB937E18AA537D000490CC /* ui.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932D18AA537D000490CC /* ui.h */; }; - DAEB937F18AA537D000490CC /* ui_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932E18AA537D000490CC /* ui_compat.h */; }; - DAEB938018AA537D000490CC /* whrlpool.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB932F18AA537D000490CC /* whrlpool.h */; }; - DAEB938118AA537D000490CC /* x509.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB933018AA537D000490CC /* x509.h */; }; - DAEB938218AA537D000490CC /* x509_vfy.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB933118AA537D000490CC /* x509_vfy.h */; }; - DAEB938318AA537D000490CC /* x509v3.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB933218AA537D000490CC /* x509v3.h */; }; + DAE8E65219867AB500416A0F /* libopensslcrypto-ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE8E65119867AB500416A0F /* libopensslcrypto-ios.a */; }; DAEBC45314F6364500987BF6 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; }; - DAEC85B518E3DD9A007FC0DF /* PearlUIView.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEC85B118E3DD9A007FC0DF /* PearlUIView.m */; }; + DAEC85B518E3DD9A007FC0DF /* UIView+Touches.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */; }; DAEC85B618E3DD9A007FC0DF /* PearlUINavigationBar.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEC85B218E3DD9A007FC0DF /* PearlUINavigationBar.m */; }; DAEC85B718E3DD9A007FC0DF /* PearlUINavigationBar.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEC85B318E3DD9A007FC0DF /* PearlUINavigationBar.h */; }; - DAEC85B818E3DD9A007FC0DF /* PearlUIView.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEC85B418E3DD9A007FC0DF /* PearlUIView.h */; }; + DAEC85B818E3DD9A007FC0DF /* UIView+Touches.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEC85B418E3DD9A007FC0DF /* UIView+Touches.h */; }; DAF4EF50190A81E400023C90 /* NSManagedObject+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DAF4EF4E190A81E400023C90 /* NSManagedObject+Pearl.m */; }; DAF4EF51190A81E400023C90 /* NSManagedObject+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAF4EF4F190A81E400023C90 /* NSManagedObject+Pearl.h */; }; DAFC5656172C573B00CB5CC5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; @@ -455,11 +381,8 @@ /* Begin PBXFileReference section */ 93D390519405B76CC6A57C4F /* MPCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCell.h; sourceTree = ""; }; 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = ""; }; - 93D39097C0AAE62C1C321BFC /* MPPasswordTypesCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordTypesCell.m; sourceTree = ""; }; 93D390FADEB325D8D54A957D /* PearlOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlOverlay.m; sourceTree = ""; }; 93D390FB3110DCCE68E600DC /* UIScrollView+PearlAdjustInsets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+PearlAdjustInsets.m"; sourceTree = ""; }; - 93D390FD93EFCFECB5193DEF /* MPPasswordsCoachmarkViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordsCoachmarkViewController.h; sourceTree = ""; }; - 93D391243F64A77798B4D6A4 /* MPPasswordTypesCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordTypesCell.h; sourceTree = ""; }; 93D3914D7597F9A28DB9D85E /* MPPasswordsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordsViewController.h; sourceTree = ""; }; 93D39156E806BB78E04F78B9 /* PearlSizedTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlSizedTextView.m; sourceTree = ""; }; 93D3916C1D8F1427DFBDEBCA /* MPAppSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppSettingsViewController.m; sourceTree = ""; }; @@ -468,27 +391,21 @@ 93D392876BE5C011DE73B43F /* MPPopdownSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPopdownSegue.h; sourceTree = ""; }; 93D393310223DDB35218467A /* MPCombinedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCombinedViewController.m; sourceTree = ""; }; 93D3937712BF1B67623E5764 /* MPEmergencySegue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEmergencySegue.m; sourceTree = ""; }; - 93D3937863061C3916AF7AD2 /* MPPasswordLargeCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeCell.m; sourceTree = ""; }; 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = ""; }; 93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = ""; }; 93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; }; 93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = ""; }; 93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIResponder+PearlFirstResponder.h"; sourceTree = ""; }; - 93D3947F6BB69CA9A9124A5D /* MPPasswordLargeStoredCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeStoredCell.m; sourceTree = ""; }; 93D3956915634581E737B38C /* PearlNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlNavigationController.m; sourceTree = ""; }; - 93D395BA6B2CFF5F49A4D25F /* MPPasswordLargeStoredCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeStoredCell.h; sourceTree = ""; }; - 93D3966B527CA47A0A661CE2 /* MPPasswordLargeDeleteCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeDeleteCell.h; sourceTree = ""; }; 93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = ""; }; 93D3970502644794E8A027BE /* MPNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPNavigationController.h; sourceTree = ""; }; 93D3971FE104BB4052484151 /* MPUsersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUsersViewController.h; sourceTree = ""; }; 93D39730673227EFF6DEFF19 /* MPSetupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSetupViewController.h; sourceTree = ""; }; 93D3977321EB249981821AB0 /* UITextView+PearlAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITextView+PearlAttributes.m"; sourceTree = ""; }; 93D3979190DACEBD1F6AE9F4 /* MPLogsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPLogsViewController.m; sourceTree = ""; }; - 93D397E3650384498E7E53C4 /* MPPasswordsCoachmarkViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordsCoachmarkViewController.m; sourceTree = ""; }; 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlNavigationController.h; sourceTree = ""; }; 93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = ""; }; 93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPWebViewController.m; sourceTree = ""; }; - 93D3993422E207BF0B21D089 /* MPPasswordLargeGeneratedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeGeneratedCell.m; sourceTree = ""; }; 93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCoachmarkViewController.m; sourceTree = ""; }; 93D39975CE5AEC99E3F086C7 /* MPPasswordCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordCell.h; sourceTree = ""; }; 93D3999693660C89A7465F4E /* MPCoachmarkViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCoachmarkViewController.h; sourceTree = ""; }; @@ -510,15 +427,12 @@ 93D39C86E984EC65DA5ACB1D /* MPAppSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppSettingsViewController.h; sourceTree = ""; }; 93D39CC01630D0421205C4C4 /* MPNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNavigationController.m; sourceTree = ""; }; 93D39CDD434AFD6E1B0DA359 /* MPEmergencyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEmergencyViewController.h; sourceTree = ""; }; - 93D39CE1138FDA4D3D1B847A /* MPPasswordLargeGeneratedCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeGeneratedCell.h; sourceTree = ""; }; 93D39CF8ADF4542CDC4CD385 /* MPCombinedViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCombinedViewController.h; sourceTree = ""; }; 93D39D8A953779B35403AF6E /* PearlUICollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUICollectionView.m; sourceTree = ""; }; 93D39DA27D768B53C8B1330C /* MPAvatarCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAvatarCell.h; sourceTree = ""; }; 93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+PearlAdjustInsets.h"; sourceTree = ""; }; 93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordCell.m; sourceTree = ""; }; - 93D39E02F69CACAB61C056F8 /* MPPasswordLargeCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordLargeCell.h; sourceTree = ""; }; 93D39E7A12CC352B2825AA66 /* MPPasswordsSegue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordsSegue.m; sourceTree = ""; }; - 93D39EFBC4D6BA3C8581865F /* MPPasswordLargeDeleteCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordLargeDeleteCell.m; sourceTree = ""; }; 93D39F556F2F142740A65E59 /* MPWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPWebViewController.h; sourceTree = ""; }; 93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlEMail.h; sourceTree = ""; }; 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = ""; }; @@ -553,6 +467,8 @@ DA250A14195665A100AC23F1 /* UITableView+PearlReloadFromArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+PearlReloadFromArray.h"; sourceTree = ""; }; DA250A15195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UICollectionReusableView+PearlDequeue.m"; sourceTree = ""; }; DA250A16195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionReusableView+PearlDequeue.h"; sourceTree = ""; }; + DA25C6B31980D3C10046CDCF /* openssl */ = {isa = PBXFileReference; lastKnownFileType = folder; path = openssl; sourceTree = ""; }; + DA25C6B51980D3DD0046CDCF /* scrypt */ = {isa = PBXFileReference; lastKnownFileType = folder; path = scrypt; sourceTree = ""; }; DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = ""; }; DA2CA4DA18D28859007798F8 /* NSArray+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Pearl.h"; sourceTree = ""; }; DA2CA4DB18D28859007798F8 /* NSTimer+PearlBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+PearlBlock.m"; sourceTree = ""; }; @@ -1272,7 +1188,6 @@ DABD3BF91711E2DC00CF925C /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; DABD3BFB1711E2DC00CF925C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; DABD3BFC1711E2DC00CF925C /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - DABD3FC617122ADD00CF925C /* libscrypt-bin-ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libscrypt-bin-ios.a"; path = "../../../External/Pearl/External/iOSPorts/ports/security/scrypt/build/Release-iphoneos/libscrypt-bin-ios.a"; sourceTree = ""; }; DABD3FC81712446200CF925C /* cloud.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cloud.png; sourceTree = ""; }; DABD3FC91712446200CF925C /* cloud@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cloud@2x.png"; sourceTree = ""; }; DABD3FCC1714F45B00CF925C /* identity.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = identity.png; sourceTree = ""; }; @@ -1298,92 +1213,12 @@ DAD312C01552A20800A3F9ED /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; DADBB55918DB0CFC00D099FE /* keyboard-dark@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "keyboard-dark@2x.png"; sourceTree = ""; }; DAE1EF2317E942DE00BC0086 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - DAEB92E118AA537D000490CC /* crypto_aesctr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_aesctr.h; sourceTree = ""; }; - DAEB92E218AA537D000490CC /* crypto_scrypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_scrypt.h; sourceTree = ""; }; - DAEB92E318AA537D000490CC /* memlimit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memlimit.h; sourceTree = ""; }; - DAEB92E418AA537D000490CC /* readpass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = readpass.h; sourceTree = ""; }; - DAEB92E518AA537D000490CC /* scryptenc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scryptenc.h; sourceTree = ""; }; - DAEB92E618AA537D000490CC /* scryptenc_cpuperf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scryptenc_cpuperf.h; sourceTree = ""; }; - DAEB92E718AA537D000490CC /* sha256.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sha256.h; sourceTree = ""; }; - DAEB92E818AA537D000490CC /* sysendian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sysendian.h; sourceTree = ""; }; - DAEB92E918AA537D000490CC /* warn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = warn.h; sourceTree = ""; }; - DAEB92EB18AA537D000490CC /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = ""; }; - DAEB92EC18AA537D000490CC /* asn1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asn1.h; sourceTree = ""; }; - DAEB92ED18AA537D000490CC /* asn1_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asn1_mac.h; sourceTree = ""; }; - DAEB92EE18AA537D000490CC /* asn1t.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asn1t.h; sourceTree = ""; }; - DAEB92EF18AA537D000490CC /* bio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bio.h; sourceTree = ""; }; - DAEB92F018AA537D000490CC /* blowfish.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blowfish.h; sourceTree = ""; }; - DAEB92F118AA537D000490CC /* bn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bn.h; sourceTree = ""; }; - DAEB92F218AA537D000490CC /* buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = buffer.h; sourceTree = ""; }; - DAEB92F318AA537D000490CC /* camellia.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = camellia.h; sourceTree = ""; }; - DAEB92F418AA537D000490CC /* cast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cast.h; sourceTree = ""; }; - DAEB92F518AA537D000490CC /* cms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cms.h; sourceTree = ""; }; - DAEB92F618AA537D000490CC /* comp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = comp.h; sourceTree = ""; }; - DAEB92F718AA537D000490CC /* conf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conf.h; sourceTree = ""; }; - DAEB92F818AA537D000490CC /* conf_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conf_api.h; sourceTree = ""; }; - DAEB92F918AA537D000490CC /* crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto.h; sourceTree = ""; }; - DAEB92FA18AA537D000490CC /* des.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = des.h; sourceTree = ""; }; - DAEB92FB18AA537D000490CC /* des_old.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = des_old.h; sourceTree = ""; }; - DAEB92FC18AA537D000490CC /* dh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dh.h; sourceTree = ""; }; - DAEB92FD18AA537D000490CC /* dsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsa.h; sourceTree = ""; }; - DAEB92FE18AA537D000490CC /* dso.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dso.h; sourceTree = ""; }; - DAEB92FF18AA537D000490CC /* dtls1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dtls1.h; sourceTree = ""; }; - DAEB930018AA537D000490CC /* e_os2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = e_os2.h; sourceTree = ""; }; - DAEB930118AA537D000490CC /* ebcdic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ebcdic.h; sourceTree = ""; }; - DAEB930218AA537D000490CC /* ec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ec.h; sourceTree = ""; }; - DAEB930318AA537D000490CC /* ecdh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ecdh.h; sourceTree = ""; }; - DAEB930418AA537D000490CC /* ecdsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ecdsa.h; sourceTree = ""; }; - DAEB930518AA537D000490CC /* engine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = engine.h; sourceTree = ""; }; - DAEB930618AA537D000490CC /* err.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = err.h; sourceTree = ""; }; - DAEB930718AA537D000490CC /* evp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = evp.h; sourceTree = ""; }; - DAEB930818AA537D000490CC /* hmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hmac.h; sourceTree = ""; }; - DAEB930918AA537D000490CC /* idea.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = idea.h; sourceTree = ""; }; - DAEB930A18AA537D000490CC /* krb5_asn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = krb5_asn.h; sourceTree = ""; }; - DAEB930B18AA537D000490CC /* kssl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kssl.h; sourceTree = ""; }; - DAEB930C18AA537D000490CC /* lhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lhash.h; sourceTree = ""; }; - DAEB930D18AA537D000490CC /* md4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md4.h; sourceTree = ""; }; - DAEB930E18AA537D000490CC /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md5.h; sourceTree = ""; }; - DAEB930F18AA537D000490CC /* mdc2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mdc2.h; sourceTree = ""; }; - DAEB931018AA537D000490CC /* modes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modes.h; sourceTree = ""; }; - DAEB931118AA537D000490CC /* obj_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = obj_mac.h; sourceTree = ""; }; - DAEB931218AA537D000490CC /* objects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objects.h; sourceTree = ""; }; - DAEB931318AA537D000490CC /* ocsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ocsp.h; sourceTree = ""; }; - DAEB931418AA537D000490CC /* opensslconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opensslconf.h; sourceTree = ""; }; - DAEB931518AA537D000490CC /* opensslv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opensslv.h; sourceTree = ""; }; - DAEB931618AA537D000490CC /* ossl_typ.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ossl_typ.h; sourceTree = ""; }; - DAEB931718AA537D000490CC /* pem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pem.h; sourceTree = ""; }; - DAEB931818AA537D000490CC /* pem2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pem2.h; sourceTree = ""; }; - DAEB931918AA537D000490CC /* pkcs12.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pkcs12.h; sourceTree = ""; }; - DAEB931A18AA537D000490CC /* pkcs7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pkcs7.h; sourceTree = ""; }; - DAEB931B18AA537D000490CC /* pqueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pqueue.h; sourceTree = ""; }; - DAEB931C18AA537D000490CC /* rand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rand.h; sourceTree = ""; }; - DAEB931D18AA537D000490CC /* rc2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rc2.h; sourceTree = ""; }; - DAEB931E18AA537D000490CC /* rc4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rc4.h; sourceTree = ""; }; - DAEB931F18AA537D000490CC /* ripemd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ripemd.h; sourceTree = ""; }; - DAEB932018AA537D000490CC /* rsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rsa.h; sourceTree = ""; }; - DAEB932118AA537D000490CC /* safestack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = safestack.h; sourceTree = ""; }; - DAEB932218AA537D000490CC /* seed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seed.h; sourceTree = ""; }; - DAEB932318AA537D000490CC /* sha.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sha.h; sourceTree = ""; }; - DAEB932418AA537D000490CC /* ssl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl.h; sourceTree = ""; }; - DAEB932518AA537D000490CC /* ssl2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl2.h; sourceTree = ""; }; - DAEB932618AA537D000490CC /* ssl23.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl23.h; sourceTree = ""; }; - DAEB932718AA537D000490CC /* ssl3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl3.h; sourceTree = ""; }; - DAEB932818AA537D000490CC /* stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack.h; sourceTree = ""; }; - DAEB932918AA537D000490CC /* symhacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = symhacks.h; sourceTree = ""; }; - DAEB932A18AA537D000490CC /* tls1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tls1.h; sourceTree = ""; }; - DAEB932B18AA537D000490CC /* ts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ts.h; sourceTree = ""; }; - DAEB932C18AA537D000490CC /* txt_db.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = txt_db.h; sourceTree = ""; }; - DAEB932D18AA537D000490CC /* ui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui.h; sourceTree = ""; }; - DAEB932E18AA537D000490CC /* ui_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui_compat.h; sourceTree = ""; }; - DAEB932F18AA537D000490CC /* whrlpool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = whrlpool.h; sourceTree = ""; }; - DAEB933018AA537D000490CC /* x509.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509.h; sourceTree = ""; }; - DAEB933118AA537D000490CC /* x509_vfy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509_vfy.h; sourceTree = ""; }; - DAEB933218AA537D000490CC /* x509v3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509v3.h; sourceTree = ""; }; + DAE8E65119867AB500416A0F /* libopensslcrypto-ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopensslcrypto-ios.a"; sourceTree = ""; }; DAEBC45214F6364500987BF6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; - DAEC85B118E3DD9A007FC0DF /* PearlUIView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUIView.m; sourceTree = ""; }; + DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Touches.m"; sourceTree = ""; }; DAEC85B218E3DD9A007FC0DF /* PearlUINavigationBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUINavigationBar.m; sourceTree = ""; }; DAEC85B318E3DD9A007FC0DF /* PearlUINavigationBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUINavigationBar.h; sourceTree = ""; }; - DAEC85B418E3DD9A007FC0DF /* PearlUIView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUIView.h; sourceTree = ""; }; + DAEC85B418E3DD9A007FC0DF /* UIView+Touches.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Touches.h"; sourceTree = ""; }; DAF4EF4E190A81E400023C90 /* NSManagedObject+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObject+Pearl.m"; sourceTree = ""; }; DAF4EF4F190A81E400023C90 /* NSManagedObject+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSManagedObject+Pearl.h"; sourceTree = ""; }; DAFC5655172C573B00CB5CC5 /* libInAppSettingsKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libInAppSettingsKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1524,6 +1359,7 @@ DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */, DA672D3014F9413D004A189C /* libPearl.a in Frameworks */, DA672D2F14F92C6B004A189C /* libz.dylib in Frameworks */, + DAE8E65219867AB500416A0F /* libopensslcrypto-ios.a in Frameworks */, DAEBC45314F6364500987BF6 /* QuartzCore.framework in Frameworks */, DA95D5F214DF0B2C008D1B94 /* MessageUI.framework in Frameworks */, DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */, @@ -1614,8 +1450,6 @@ DACA22121705DDC5002C6C22 /* External */, DA5BFA47147E415C00F98B1E /* Frameworks */, DA5BFA45147E415C00F98B1E /* Products */, - 93D3966B527CA47A0A661CE2 /* MPPasswordLargeDeleteCell.h */, - 93D39EFBC4D6BA3C8581865F /* MPPasswordLargeDeleteCell.m */, ); sourceTree = ""; }; @@ -1637,7 +1471,6 @@ children = ( DA3B844D190FC5DF00246EEA /* Crashlytics.framework */, DA70EC7F1811B13C00F65DB2 /* StoreKit.framework */, - DABD3FC617122ADD00CF925C /* libscrypt-bin-ios.a */, DA6701DF16406BB400B61001 /* AdSupport.framework */, DA6701DD16406B7300B61001 /* Social.framework */, DA6701B716406A4100B61001 /* Accounts.framework */, @@ -1661,6 +1494,7 @@ DA5E5C6317248959003798D8 /* lib */ = { isa = PBXGroup; children = ( + DAE8E65119867AB500416A0F /* libopensslcrypto-ios.a */, DAFFC63E17EDDA7C007BB020 /* libscryptenc-ios.a */, DA5E5C6417248959003798D8 /* include */, ); @@ -1670,8 +1504,8 @@ DA5E5C6417248959003798D8 /* include */ = { isa = PBXGroup; children = ( - DAEB92E018AA537D000490CC /* scrypt */, - DAEB92EA18AA537D000490CC /* openssl */, + DA25C6B51980D3DD0046CDCF /* scrypt */, + DA25C6B31980D3C10046CDCF /* openssl */, ); path = include; sourceTree = ""; @@ -2441,6 +2275,7 @@ DABD3BD71711E2DC00CF925C /* iOS */ = { isa = PBXGroup; children = ( + DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */, 93D39975CE5AEC99E3F086C7 /* MPPasswordCell.h */, 93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */, 93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */, @@ -2469,21 +2304,12 @@ 93D3914D7597F9A28DB9D85E /* MPPasswordsViewController.h */, 93D393310223DDB35218467A /* MPCombinedViewController.m */, 93D39CF8ADF4542CDC4CD385 /* MPCombinedViewController.h */, - DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */, 93D39B381350802A194BF332 /* MPAvatarCell.m */, 93D39DA27D768B53C8B1330C /* MPAvatarCell.h */, - 93D3993422E207BF0B21D089 /* MPPasswordLargeGeneratedCell.m */, - 93D39CE1138FDA4D3D1B847A /* MPPasswordLargeGeneratedCell.h */, 93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */, 93D3971FE104BB4052484151 /* MPUsersViewController.h */, - 93D39E02F69CACAB61C056F8 /* MPPasswordLargeCell.h */, - 93D3937863061C3916AF7AD2 /* MPPasswordLargeCell.m */, - 93D395BA6B2CFF5F49A4D25F /* MPPasswordLargeStoredCell.h */, - 93D3947F6BB69CA9A9124A5D /* MPPasswordLargeStoredCell.m */, 93D39BAA71DE51B4D8A1286C /* MPCell.m */, 93D390519405B76CC6A57C4F /* MPCell.h */, - 93D39097C0AAE62C1C321BFC /* MPPasswordTypesCell.m */, - 93D391243F64A77798B4D6A4 /* MPPasswordTypesCell.h */, 93D3937712BF1B67623E5764 /* MPEmergencySegue.m */, 93D39A41340CF778E00D0E6D /* MPEmergencySegue.h */, 93D39E7A12CC352B2825AA66 /* MPPasswordsSegue.m */, @@ -2494,8 +2320,6 @@ 93D39C86E984EC65DA5ACB1D /* MPAppSettingsViewController.h */, 93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */, 93D3999693660C89A7465F4E /* MPCoachmarkViewController.h */, - 93D397E3650384498E7E53C4 /* MPPasswordsCoachmarkViewController.m */, - 93D390FD93EFCFECB5193DEF /* MPPasswordsCoachmarkViewController.h */, 93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */, 93D39F556F2F142740A65E59 /* MPWebViewController.h */, 93D39CC01630D0421205C4C4 /* MPNavigationController.m */, @@ -2593,101 +2417,6 @@ path = "External/uicolor-utilities"; sourceTree = ""; }; - DAEB92E018AA537D000490CC /* scrypt */ = { - isa = PBXGroup; - children = ( - DAEB92E118AA537D000490CC /* crypto_aesctr.h */, - DAEB92E218AA537D000490CC /* crypto_scrypt.h */, - DAEB92E318AA537D000490CC /* memlimit.h */, - DAEB92E418AA537D000490CC /* readpass.h */, - DAEB92E518AA537D000490CC /* scryptenc.h */, - DAEB92E618AA537D000490CC /* scryptenc_cpuperf.h */, - DAEB92E718AA537D000490CC /* sha256.h */, - DAEB92E818AA537D000490CC /* sysendian.h */, - DAEB92E918AA537D000490CC /* warn.h */, - ); - path = scrypt; - sourceTree = ""; - }; - DAEB92EA18AA537D000490CC /* openssl */ = { - isa = PBXGroup; - children = ( - DAEB92EB18AA537D000490CC /* aes.h */, - DAEB92EC18AA537D000490CC /* asn1.h */, - DAEB92ED18AA537D000490CC /* asn1_mac.h */, - DAEB92EE18AA537D000490CC /* asn1t.h */, - DAEB92EF18AA537D000490CC /* bio.h */, - DAEB92F018AA537D000490CC /* blowfish.h */, - DAEB92F118AA537D000490CC /* bn.h */, - DAEB92F218AA537D000490CC /* buffer.h */, - DAEB92F318AA537D000490CC /* camellia.h */, - DAEB92F418AA537D000490CC /* cast.h */, - DAEB92F518AA537D000490CC /* cms.h */, - DAEB92F618AA537D000490CC /* comp.h */, - DAEB92F718AA537D000490CC /* conf.h */, - DAEB92F818AA537D000490CC /* conf_api.h */, - DAEB92F918AA537D000490CC /* crypto.h */, - DAEB92FA18AA537D000490CC /* des.h */, - DAEB92FB18AA537D000490CC /* des_old.h */, - DAEB92FC18AA537D000490CC /* dh.h */, - DAEB92FD18AA537D000490CC /* dsa.h */, - DAEB92FE18AA537D000490CC /* dso.h */, - DAEB92FF18AA537D000490CC /* dtls1.h */, - DAEB930018AA537D000490CC /* e_os2.h */, - DAEB930118AA537D000490CC /* ebcdic.h */, - DAEB930218AA537D000490CC /* ec.h */, - DAEB930318AA537D000490CC /* ecdh.h */, - DAEB930418AA537D000490CC /* ecdsa.h */, - DAEB930518AA537D000490CC /* engine.h */, - DAEB930618AA537D000490CC /* err.h */, - DAEB930718AA537D000490CC /* evp.h */, - DAEB930818AA537D000490CC /* hmac.h */, - DAEB930918AA537D000490CC /* idea.h */, - DAEB930A18AA537D000490CC /* krb5_asn.h */, - DAEB930B18AA537D000490CC /* kssl.h */, - DAEB930C18AA537D000490CC /* lhash.h */, - DAEB930D18AA537D000490CC /* md4.h */, - DAEB930E18AA537D000490CC /* md5.h */, - DAEB930F18AA537D000490CC /* mdc2.h */, - DAEB931018AA537D000490CC /* modes.h */, - DAEB931118AA537D000490CC /* obj_mac.h */, - DAEB931218AA537D000490CC /* objects.h */, - DAEB931318AA537D000490CC /* ocsp.h */, - DAEB931418AA537D000490CC /* opensslconf.h */, - DAEB931518AA537D000490CC /* opensslv.h */, - DAEB931618AA537D000490CC /* ossl_typ.h */, - DAEB931718AA537D000490CC /* pem.h */, - DAEB931818AA537D000490CC /* pem2.h */, - DAEB931918AA537D000490CC /* pkcs12.h */, - DAEB931A18AA537D000490CC /* pkcs7.h */, - DAEB931B18AA537D000490CC /* pqueue.h */, - DAEB931C18AA537D000490CC /* rand.h */, - DAEB931D18AA537D000490CC /* rc2.h */, - DAEB931E18AA537D000490CC /* rc4.h */, - DAEB931F18AA537D000490CC /* ripemd.h */, - DAEB932018AA537D000490CC /* rsa.h */, - DAEB932118AA537D000490CC /* safestack.h */, - DAEB932218AA537D000490CC /* seed.h */, - DAEB932318AA537D000490CC /* sha.h */, - DAEB932418AA537D000490CC /* ssl.h */, - DAEB932518AA537D000490CC /* ssl2.h */, - DAEB932618AA537D000490CC /* ssl23.h */, - DAEB932718AA537D000490CC /* ssl3.h */, - DAEB932818AA537D000490CC /* stack.h */, - DAEB932918AA537D000490CC /* symhacks.h */, - DAEB932A18AA537D000490CC /* tls1.h */, - DAEB932B18AA537D000490CC /* ts.h */, - DAEB932C18AA537D000490CC /* txt_db.h */, - DAEB932D18AA537D000490CC /* ui.h */, - DAEB932E18AA537D000490CC /* ui_compat.h */, - DAEB932F18AA537D000490CC /* whrlpool.h */, - DAEB933018AA537D000490CC /* x509.h */, - DAEB933118AA537D000490CC /* x509_vfy.h */, - DAEB933218AA537D000490CC /* x509v3.h */, - ); - path = openssl; - sourceTree = ""; - }; DAFC5662172C57EC00CB5CC5 /* InAppSettingsKit */ = { isa = PBXGroup; children = ( @@ -2846,10 +2575,10 @@ DA250A14195665A100AC23F1 /* UITableView+PearlReloadFromArray.h */, DA250A15195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m */, DA250A16195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h */, - DAEC85B118E3DD9A007FC0DF /* PearlUIView.m */, + DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */, DAEC85B218E3DD9A007FC0DF /* PearlUINavigationBar.m */, DAEC85B318E3DD9A007FC0DF /* PearlUINavigationBar.h */, - DAEC85B418E3DD9A007FC0DF /* PearlUIView.h */, + DAEC85B418E3DD9A007FC0DF /* UIView+Touches.h */, DA2CA4E518D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m */, DA2CA4E218D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h */, 93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */, @@ -2954,146 +2683,67 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - DAEB938118AA537D000490CC /* x509.h in Headers */, + DA25C6B61980D3DF0046CDCF /* scrypt in Headers */, + DA25C6B41980D3C50046CDCF /* openssl in Headers */, DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */, - DAEB936118AA537D000490CC /* modes.h in Headers */, DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */, DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */, - DAEB936F18AA537D000490CC /* rc4.h in Headers */, - DAEB933318AA537D000490CC /* crypto_aesctr.h in Headers */, - DAEB936718AA537D000490CC /* ossl_typ.h in Headers */, DA250A1A195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h in Headers */, - DAEB937018AA537D000490CC /* ripemd.h in Headers */, - DAEB933F18AA537D000490CC /* asn1t.h in Headers */, - DAEB936418AA537D000490CC /* ocsp.h in Headers */, - DAEB934518AA537D000490CC /* cast.h in Headers */, - DAEB936E18AA537D000490CC /* rc2.h in Headers */, - DAEB937718AA537D000490CC /* ssl23.h in Headers */, - DAEB937918AA537D000490CC /* stack.h in Headers */, - DAEB936B18AA537D000490CC /* pkcs7.h in Headers */, DAFE4A1915039824003ABA7C /* Pearl.h in Headers */, DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */, - DAEB938218AA537D000490CC /* x509_vfy.h in Headers */, - DAEB937118AA537D000490CC /* rsa.h in Headers */, - DAEB936318AA537D000490CC /* objects.h in Headers */, DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */, - DAEB935018AA537D000490CC /* dtls1.h in Headers */, DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */, DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */, - DAEB934E18AA537D000490CC /* dsa.h in Headers */, - DAEB935A18AA537D000490CC /* idea.h in Headers */, - DAEB933A18AA537D000490CC /* sysendian.h in Headers */, DAFE4A2415039824003ABA7C /* PearlInfoPlist.h in Headers */, DA2CA4E418D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h in Headers */, DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */, DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */, - DAEB934418AA537D000490CC /* camellia.h in Headers */, DAFE4A2A15039824003ABA7C /* PearlObjectUtils.h in Headers */, DA250A18195665A100AC23F1 /* UITableView+PearlReloadFromArray.h in Headers */, - DAEB936D18AA537D000490CC /* rand.h in Headers */, DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */, DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */, DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */, - DAEB935318AA537D000490CC /* ec.h in Headers */, - DAEB937818AA537D000490CC /* ssl3.h in Headers */, - DAEB935E18AA537D000490CC /* md4.h in Headers */, DA2CA4E018D28859007798F8 /* NSTimer+PearlBlock.h in Headers */, - DAEB933518AA537D000490CC /* memlimit.h in Headers */, DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */, - DAEB937318AA537D000490CC /* seed.h in Headers */, - DAEB935918AA537D000490CC /* hmac.h in Headers */, - DAEB936018AA537D000490CC /* mdc2.h in Headers */, DAFE4A3415039824003ABA7C /* PearlCryptUtils.h in Headers */, - DAEB933918AA537D000490CC /* sha256.h in Headers */, DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */, - DAEB936818AA537D000490CC /* pem.h in Headers */, DAFE4A3815039824003ABA7C /* PearlRSAKey.h in Headers */, - DAEB934618AA537D000490CC /* cms.h in Headers */, - DAEB935F18AA537D000490CC /* md5.h in Headers */, - DAEB934B18AA537D000490CC /* des.h in Headers */, - DAEB934018AA537D000490CC /* bio.h in Headers */, DAFE4A3A15039824003ABA7C /* PearlSCrypt.h in Headers */, - DAEB933C18AA537D000490CC /* aes.h in Headers */, - DAEB937618AA537D000490CC /* ssl2.h in Headers */, DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */, - DAEC85B818E3DD9A007FC0DF /* PearlUIView.h in Headers */, - DAEB935B18AA537D000490CC /* krb5_asn.h in Headers */, - DAEB935818AA537D000490CC /* evp.h in Headers */, - DAEB934118AA537D000490CC /* blowfish.h in Headers */, - DAEB935218AA537D000490CC /* ebcdic.h in Headers */, - DAEB937218AA537D000490CC /* safestack.h in Headers */, + DAEC85B818E3DD9A007FC0DF /* UIView+Touches.h in Headers */, DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */, DAFE4A3E15039824003ABA7C /* PearlAlert.h in Headers */, DAFE4A4015039824003ABA7C /* PearlArrayTVC.h in Headers */, - DAEB934718AA537D000490CC /* comp.h in Headers */, - DAEB933E18AA537D000490CC /* asn1_mac.h in Headers */, DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */, - DAEB936618AA537D000490CC /* opensslv.h in Headers */, - DAEB936518AA537D000490CC /* opensslconf.h in Headers */, - DAEB935D18AA537D000490CC /* lhash.h in Headers */, - DAEB937E18AA537D000490CC /* ui.h in Headers */, - DAEB935518AA537D000490CC /* ecdsa.h in Headers */, - DAEB935718AA537D000490CC /* err.h in Headers */, DAFE4A4415039824003ABA7C /* PearlGradientView.h in Headers */, - DAEB937C18AA537D000490CC /* ts.h in Headers */, DAFE4A4615039824003ABA7C /* PearlLayout.h in Headers */, - DAEB937A18AA537D000490CC /* symhacks.h in Headers */, DAFE4A4815039824003ABA7C /* PearlLayoutView.h in Headers */, - DAEB933618AA537D000490CC /* readpass.h in Headers */, DAFE4A4A15039824003ABA7C /* PearlMessageView.h in Headers */, - DAEB934818AA537D000490CC /* conf.h in Headers */, DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */, DAFE4A4E15039824003ABA7C /* PearlSheet.h in Headers */, DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */, DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */, - DAEB937418AA537D000490CC /* sha.h in Headers */, - DAEB938018AA537D000490CC /* whrlpool.h in Headers */, - DAEB933718AA537D000490CC /* scryptenc.h in Headers */, DAFE4A5415039824003ABA7C /* PearlValidatingTextField.h in Headers */, - DAEB933D18AA537D000490CC /* asn1.h in Headers */, - DAEB933B18AA537D000490CC /* warn.h in Headers */, DAFE4A5615039824003ABA7C /* PearlWebViewController.h in Headers */, - DAEB934318AA537D000490CC /* buffer.h in Headers */, - DAEB936A18AA537D000490CC /* pkcs12.h in Headers */, DAFE4A5815039824003ABA7C /* UIImage+PearlScaling.h in Headers */, DAFE4A63150399FF003ABA7C /* PearlAppDelegate.h in Headers */, DA30E9CE15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h in Headers */, DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */, - DAEB936918AA537D000490CC /* pem2.h in Headers */, - DAEB937F18AA537D000490CC /* ui_compat.h in Headers */, DAA141211922FF020032B392 /* PearlTween.h in Headers */, DAFE4A63150399FF003ABA84 /* UIControl+PearlBlocks.h in Headers */, - DAEB934A18AA537D000490CC /* crypto.h in Headers */, - DAEB935618AA537D000490CC /* engine.h in Headers */, - DAEB935118AA537D000490CC /* e_os2.h in Headers */, DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */, DAFE4A63150399FF003ABA8C /* UIControl+PearlSelect.h in Headers */, DAFE4A63150399FF003ABA90 /* UIScrollView+PearlFlashingIndicators.h in Headers */, - DAEB934F18AA537D000490CC /* dso.h in Headers */, DAFE4A63150399FF003ABA94 /* NSDateFormatter+RFC3339.h in Headers */, - DAEB934C18AA537D000490CC /* des_old.h in Headers */, 93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */, - DAEB936C18AA537D000490CC /* pqueue.h in Headers */, - DAEB937B18AA537D000490CC /* tls1.h in Headers */, - DAEB933818AA537D000490CC /* scryptenc_cpuperf.h in Headers */, DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */, 93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */, - DAEB935418AA537D000490CC /* ecdh.h in Headers */, - DAEB937D18AA537D000490CC /* txt_db.h in Headers */, 93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */, - DAEB934D18AA537D000490CC /* dh.h in Headers */, - DAEB938318AA537D000490CC /* x509v3.h in Headers */, - DAEB935C18AA537D000490CC /* kssl.h in Headers */, - DAEB933418AA537D000490CC /* crypto_scrypt.h in Headers */, DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */, DAEC85B718E3DD9A007FC0DF /* PearlUINavigationBar.h in Headers */, - DAEB934918AA537D000490CC /* conf_api.h in Headers */, 93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */, - DAEB937518AA537D000490CC /* ssl.h in Headers */, 93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */, 93D39B842AB9A5D072810D76 /* NSError+PearlFullDescription.h in Headers */, - DAEB936218AA537D000490CC /* obj_mac.h in Headers */, - DAEB934218AA537D000490CC /* bn.h in Headers */, DAF4EF51190A81E400023C90 /* NSManagedObject+Pearl.h in Headers */, DAA141221922FF020032B392 /* map-macro.h in Headers */, 93D39B76DD5AB108BA8928E8 /* UIScrollView+PearlAdjustInsets.h in Headers */, @@ -3181,9 +2831,10 @@ isa = PBXNativeTarget; buildConfigurationList = DAC77CB7148291A600BCF976 /* Build configuration list for PBXNativeTarget "Pearl" */; buildPhases = ( + DA25C6C91983702E0046CDCF /* ShellScript */, + DAC77CAB148291A600BCF976 /* Headers */, DAC77CA9148291A600BCF976 /* Sources */, DAC77CAA148291A600BCF976 /* Frameworks */, - DAC77CAB148291A600BCF976 /* Headers */, ); buildRules = ( ); @@ -3360,6 +3011,7 @@ DABD39371711E29700CF925C /* avatar-0.png in Resources */, DABD39381711E29700CF925C /* avatar-0@2x.png in Resources */, DA250A041956484D00AC23F1 /* image-7.png in Resources */, + DA25C5FC197CCAF70046CDCF /* icon_list-names.png in Resources */, DABD39391711E29700CF925C /* avatar-1.png in Resources */, DA7304E5194E025900E72520 /* tip_basic_black.png in Resources */, DABD393A1711E29700CF925C /* avatar-10.png in Resources */, @@ -3384,6 +3036,7 @@ DA250A091956484D00AC23F1 /* image-4@2x.png in Resources */, DABD39481711E29700CF925C /* avatar-17.png in Resources */, DABD39491711E29700CF925C /* avatar-17@2x.png in Resources */, + DA25C5FD197CCAF70046CDCF /* icon_list-names@2x.png in Resources */, DAC8DF47192831E100BA7D71 /* icon_key.png in Resources */, DA250A071956484D00AC23F1 /* image-5@2x.png in Resources */, DAC8DF48192831E100BA7D71 /* icon_key@2x.png in Resources */, @@ -3398,6 +3051,7 @@ DABD394F1711E29700CF925C /* avatar-3.png in Resources */, DA67460F18DE7F0C00DFE240 /* Exo2.0-ExtraBold.otf in Resources */, DABD39501711E29700CF925C /* avatar-3@2x.png in Resources */, + DA25C600197DBF260046CDCF /* icon_trash.png in Resources */, DABD39511711E29700CF925C /* avatar-4.png in Resources */, DA2509FD1956484D00AC23F1 /* image-10@2x.png in Resources */, DABD39521711E29700CF925C /* avatar-4@2x.png in Resources */, @@ -3405,6 +3059,8 @@ DA73049E194E022700E72520 /* ui_spinner@2x.png in Resources */, DABD39541711E29700CF925C /* avatar-5@2x.png in Resources */, DA250A031956484D00AC23F1 /* image-7@2x.png in Resources */, + DA25C5FA197CCAE00046CDCF /* icon_delete.png in Resources */, + DA25C601197DBF260046CDCF /* icon_trash@2x.png in Resources */, DABD39551711E29700CF925C /* avatar-6.png in Resources */, DABD39561711E29700CF925C /* avatar-6@2x.png in Resources */, DABD39571711E29700CF925C /* avatar-7.png in Resources */, @@ -3420,12 +3076,14 @@ DABD395E1711E29700CF925C /* background@2x.png in Resources */, DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */, DA250A101956484D00AC23F1 /* image-1.png in Resources */, + DA25C5FE197DBF200046CDCF /* icon_thumbs-up.png in Resources */, DABD39871711E29700CF925C /* SourceCodePro-Black.otf in Resources */, DA2509FE1956484D00AC23F1 /* image-10.png in Resources */, DABD39881711E29700CF925C /* SourceCodePro-ExtraLight.otf in Resources */, DABD39A01711E29700CF925C /* icon_action.png in Resources */, DABD39A11711E29700CF925C /* icon_action@2x.png in Resources */, DABD39F21711E29700CF925C /* icon_cancel.png in Resources */, + DA25C5FB197CCAE00046CDCF /* icon_delete@2x.png in Resources */, DA73049F194E022B00E72520 /* ui_textfield.png in Resources */, DABD39F31711E29700CF925C /* icon_cancel@2x.png in Resources */, DA250A0C1956484D00AC23F1 /* image-3.png in Resources */, @@ -3452,6 +3110,7 @@ DABD3B8D1711E29800CF925C /* keypad.png in Resources */, DABD3B8E1711E29800CF925C /* logo-bare.png in Resources */, DA7304E6194E025900E72520 /* tip_basic_black@2x.png in Resources */, + DA25C5F9197AFFB40046CDCF /* icon_tools@2x.png in Resources */, DABD3B8F1711E29800CF925C /* menu-icon.png in Resources */, DABD3B901711E29800CF925C /* menu-icon@2x.png in Resources */, DABD3B951711E29800CF925C /* pull-down.png in Resources */, @@ -3466,6 +3125,7 @@ DABD3C241711E2DC00CF925C /* MasterPassword.entitlements in Resources */, DABD3C251711E2DC00CF925C /* Settings.bundle in Resources */, DABD3C261711E2DC00CF925C /* InfoPlist.strings in Resources */, + DA25C5F8197AFFB40046CDCF /* icon_tools.png in Resources */, DA2509FB1956484D00AC23F1 /* image-11@2x.png in Resources */, DA250A0B1956484D00AC23F1 /* image-3@2x.png in Resources */, DABD3FCA1712446200CF925C /* cloud.png in Resources */, @@ -3473,6 +3133,7 @@ DABD3FCE1714F45C00CF925C /* identity.png in Resources */, DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */, DA45224B190628B2008F650A /* icon_gear.png in Resources */, + DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */, DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */, DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */, DA250A021956484D00AC23F1 /* image-8.png in Resources */, @@ -3489,6 +3150,19 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + DA25C6C91983702E0046CDCF /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = ":"; + }; DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3560,11 +3234,7 @@ 93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */, 93D39B8F90F58A5D158DDBA3 /* MPPasswordsViewController.m in Sources */, 93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */, - 93D39CB5E2EC1078E898F46A /* MPPasswordLargeCell.m in Sources */, - 93D39FA97F4C3F69A75D5A03 /* MPPasswordLargeGeneratedCell.m in Sources */, - 93D394F6D3F6E2553AA0D684 /* MPPasswordLargeStoredCell.m in Sources */, 93D39392DEDA376F93C6C718 /* MPCell.m in Sources */, - 93D399278165FD6D950F0025 /* MPPasswordTypesCell.m in Sources */, 93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */, 93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */, 93D391ED37C9F687FA51EAA1 /* MPEmergencySegue.m in Sources */, @@ -3572,10 +3242,8 @@ 93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */, 93D39BA1EA3CAAC8A220B4A6 /* MPAppSettingsViewController.m in Sources */, 93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */, - 93D391C07818F4C2DC1B6956 /* MPPasswordsCoachmarkViewController.m in Sources */, 93D39EAA4D064193074D3021 /* MPFixable.m in Sources */, 93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */, - 93D398BD8B83FEE8BE4EFFFC /* MPPasswordLargeDeleteCell.m in Sources */, 93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3643,7 +3311,7 @@ DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */, DAFE4A63150399FF003ABA82 /* UIControl+PearlBlocks.m in Sources */, DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */, - DAEC85B518E3DD9A007FC0DF /* PearlUIView.m in Sources */, + DAEC85B518E3DD9A007FC0DF /* UIView+Touches.m in Sources */, DA2CA4DD18D28859007798F8 /* NSArray+Pearl.m in Sources */, DAFE4A63150399FF003ABA8A /* UIControl+PearlSelect.m in Sources */, DAFE4A63150399FF003ABA8E /* UIScrollView+PearlFlashingIndicators.m in Sources */, @@ -3925,13 +3593,17 @@ GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch"; INFOPLIST_FILE = "MasterPassword-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "/Users/lhunath/Documents/workspace/lyndir/MasterPassword/External/Pearl/Pearl-Crypto/lib", + ); OTHER_LDFLAGS = ( "$(inherited)", "-framework", Reveal, ); PROVISIONING_PROFILE = ""; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = "1F49F193-0915-40B1-8792-BBDE74185E45"; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "94333D7F-68F7-473D-B3B1-86AA41F33449"; SKIP_INSTALL = NO; TARGETED_DEVICE_FAMILY = 1; }; @@ -3953,6 +3625,10 @@ GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch"; INFOPLIST_FILE = "MasterPassword-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "/Users/lhunath/Documents/workspace/lyndir/MasterPassword/External/Pearl/Pearl-Crypto/lib", + ); PROVISIONING_PROFILE = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = "6407ECED-9FF3-4F04-B40E-5B3E771D603D"; SKIP_INSTALL = NO; @@ -4065,6 +3741,10 @@ GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch"; INFOPLIST_FILE = "MasterPassword-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "/Users/lhunath/Documents/workspace/lyndir/MasterPassword/External/Pearl/Pearl-Crypto/lib", + ); PROVISIONING_PROFILE = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = "36641E9D-D5E0-4E80-94F4-B2CF898CFE10"; SKIP_INSTALL = NO; @@ -4081,6 +3761,7 @@ GCC_PREFIX_HEADER = "../Pearl/Pearl-Prefix.pch"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = "../../BuildProductsPath/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/include"; SKIP_INSTALL = YES; }; name = "AppStore-iOS"; @@ -4165,6 +3846,7 @@ GCC_PREFIX_HEADER = "../Pearl/Pearl-Prefix.pch"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = "../../BuildProductsPath/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/include"; SKIP_INSTALL = YES; }; name = "Debug-iOS"; @@ -4177,6 +3859,7 @@ GCC_PREFIX_HEADER = "../Pearl/Pearl-Prefix.pch"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = "../../BuildProductsPath/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/include"; SKIP_INSTALL = YES; }; name = "AdHoc-iOS"; @@ -4184,6 +3867,7 @@ DAFC565F172C573B00CB5CC5 /* Debug-iOS */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; GCC_WARN_INHIBIT_ALL_WARNINGS = YES; }; name = "Debug-iOS"; @@ -4191,6 +3875,7 @@ DAFC5660172C573B00CB5CC5 /* AdHoc-iOS */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; GCC_WARN_INHIBIT_ALL_WARNINGS = YES; }; name = "AdHoc-iOS"; @@ -4198,6 +3883,7 @@ DAFC5661172C573B00CB5CC5 /* AppStore-iOS */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; GCC_WARN_INHIBIT_ALL_WARNINGS = YES; }; name = "AppStore-iOS"; diff --git a/MasterPassword/ObjC/iOS/Settings.bundle/Root.plist b/MasterPassword/ObjC/iOS/Settings.bundle/Root.plist index 892d73ff..ca7a66a0 100644 --- a/MasterPassword/ObjC/iOS/Settings.bundle/Root.plist +++ b/MasterPassword/ObjC/iOS/Settings.bundle/Root.plist @@ -108,6 +108,44 @@ To see a site's password anyway, tap and hold your finger down for a while Type PSToggleSwitchSpecifier + + FooterText + The password strength indicator estimates the time necessary to break the password from a stolen database of SHA-1 hashes. Use this setting to choose the budget the attacker is willing to devote to breaking your site password. + Title + + Type + PSGroupSpecifier + + + DefaultValue + 0 + Key + siteAttacker + Title + Attacker Budget + Type + PSMultiValueSpecifier + Titles + + Regular Hardware + Dedicated GPUs, 5000 $ US + Large Organization, 20 M$ US + State Department, 5 B$ US + + ShortTitles + + Regular + 5k $ + 20M $ + 5B $ + + Values + + 0 + 1 + 2 + + Type PSGroupSpecifier diff --git a/MasterPassword/ObjC/iOS/Storyboard.storyboard b/MasterPassword/ObjC/iOS/Storyboard.storyboard index 0b692f56..49a9efe0 100644 --- a/MasterPassword/ObjC/iOS/Storyboard.storyboard +++ b/MasterPassword/ObjC/iOS/Storyboard.storyboard @@ -1,5 +1,5 @@ - + @@ -150,7 +150,7 @@ - + @@ -236,7 +236,7 @@ - + @@ -483,8 +483,8 @@ - + @@ -980,11 +980,11 @@ - + - + @@ -1004,371 +1004,349 @@ - + - + - - - - - - - - - - + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + @@ -1527,7 +1505,7 @@ - + @@ -1817,6 +1795,22 @@ + + + + + + + + + + + + + + + + @@ -1850,7 +1844,7 @@ - + @@ -1996,7 +1990,7 @@ CgoKCgoKCgoKCgoKCg - + @@ -2529,7 +2523,7 @@ See - + @@ -2541,8 +2535,12 @@ See + + + +