2
0

Element -> Site WIP

This commit is contained in:
Maarten Billemont 2014-09-21 10:39:09 -04:00
parent 68e6106ee7
commit 4396ce436e
39 changed files with 752 additions and 648 deletions

View File

@ -16,8 +16,8 @@
//
#import "MPKey.h"
#import "MPElementStoredEntity.h"
#import "MPElementGeneratedEntity.h"
#import "MPSiteStoredEntity.h"
#import "MPSiteGeneratedEntity.h"
#define MPAlgorithmDefaultVersion 1
#define MPAlgorithmDefault MPAlgorithmForVersion(MPAlgorithmDefaultVersion)
@ -44,48 +44,48 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack);
@required
- (NSUInteger)version;
- (BOOL)migrateUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc;
- (BOOL)migrateElement:(MPElementEntity *)element explicit:(BOOL)explicit;
- (BOOL)migrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit;
- (MPKey *)keyForPassword:(NSString *)password ofUserNamed:(NSString *)userName;
- (MPKey *)keyFromKeyData:(NSData *)keyData;
- (NSData *)keyIDForKeyData:(NSData *)keyData;
- (NSString *)scopeForVariant:(MPElementVariant)variant;
- (NSString *)nameOfType:(MPElementType)type;
- (NSString *)shortNameOfType:(MPElementType)type;
- (NSString *)classNameOfType:(MPElementType)type;
- (Class)classOfType:(MPElementType)type;
- (NSString *)scopeForVariant:(MPSiteVariant)variant;
- (NSString *)nameOfType:(MPSiteType)type;
- (NSString *)shortNameOfType:(MPSiteType)type;
- (NSString *)classNameOfType:(MPSiteType)type;
- (Class)classOfType:(MPSiteType)type;
- (NSArray *)allTypes;
- (NSArray *)allTypesStartingWith:(MPElementType)startingType;
- (MPElementType)nextType:(MPElementType)type;
- (MPElementType)previousType:(MPElementType)type;
- (NSArray *)allTypesStartingWith:(MPSiteType)startingType;
- (MPSiteType)nextType:(MPSiteType)type;
- (MPSiteType)previousType:(MPSiteType)type;
- (NSString *)generateLoginForSiteNamed:(NSString *)name usingKey:(MPKey *)key;
- (NSString *)generatePasswordForSiteNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter
- (NSString *)generatePasswordForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
usingKey:(MPKey *)key;
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter
variant:(MPElementVariant)variant usingKey:(MPKey *)key;
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
variant:(MPSiteVariant)variant usingKey:(MPKey *)key;
- (NSString *)storedLoginForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key;
- (NSString *)storedPasswordForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key;
- (NSString *)storedLoginForSite:(MPSiteStoredEntity *)site usingKey:(MPKey *)key;
- (NSString *)storedPasswordForSite:(MPSiteStoredEntity *)site usingKey:(MPKey *)key;
- (BOOL)savePassword:(NSString *)clearPassword toElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey;
- (BOOL)savePassword:(NSString *)clearPassword toSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
- (NSString *)resolveLoginForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey;
- (NSString *)resolvePasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey;
- (NSString *)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
- (NSString *)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
- (void)resolveLoginForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey
- (void)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey
result:(void ( ^ )(NSString *result))resultBlock;
- (void)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey
result:(void ( ^ )(NSString *result))resultBlock;
- (void)resolvePasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey
result:(void ( ^ )(NSString *result))resultBlock;
- (void)importProtectedPassword:(NSString *)protectedPassword protectedByKey:(MPKey *)importKey
intoElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey;
- (void)importClearTextPassword:(NSString *)clearPassword intoElement:(MPElementEntity *)element
usingKey:(MPKey *)elementKey;
- (NSString *)exportPasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey;
intoSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
- (void)importClearTextPassword:(NSString *)clearPassword intoSite:(MPSiteEntity *)site
usingKey:(MPKey *)siteKey;
- (NSString *)exportPasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPElementType)type byAttacker:(MPAttacker)attacker;
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPSiteType)type byAttacker:(MPAttacker)attacker;
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordString:(NSString *)password byAttacker:(MPAttacker)attacker;
@end

View File

@ -20,7 +20,7 @@
@interface MPAlgorithmV0 : NSObject<MPAlgorithm>
- (NSDictionary *)allCiphers;
- (NSArray *)ciphersForType:(MPElementType)type;
- (NSArray *)ciphersForType:(MPSiteType)type;
- (NSArray *)cipherClasses;
- (NSArray *)cipherClassCharacters;
- (NSString *)charactersForCipherClass:(NSString *)cipherClass;

View File

@ -75,7 +75,7 @@
- (BOOL)migrateUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc {
NSError *error = nil;
NSFetchRequest *migrationRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
NSFetchRequest *migrationRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
migrationRequest.predicate = [NSPredicate predicateWithFormat:@"version_ < %d AND user == %@", self.version, user];
NSArray *migrationElements = [moc executeFetchRequest:migrationRequest error:&error];
if (!migrationElements) {
@ -84,14 +84,14 @@
}
BOOL requiresExplicitMigration = NO;
for (MPElementEntity *migrationElement in migrationElements)
for (MPSiteEntity *migrationElement in migrationElements)
if (![migrationElement migrateExplicitly:NO])
requiresExplicitMigration = YES;
return requiresExplicitMigration;
}
- (BOOL)migrateElement:(MPElementEntity *)element explicit:(BOOL)explicit {
- (BOOL)migrateSite:(MPSiteEntity *)element explicit:(BOOL)explicit {
if (element.version != [self version] - 1)
// Only migrate from previous version.
@ -138,129 +138,138 @@
return [keyData hashWith:MP_hash];
}
- (NSString *)scopeForVariant:(MPElementVariant)variant {
- (NSString *)scopeForVariant:(MPSiteVariant)variant {
switch (variant) {
case MPElementVariantPassword:
case MPSiteVariantPassword:
return @"com.lyndir.masterpassword";
case MPElementVariantLogin:
case MPSiteVariantLogin:
return @"com.lyndir.masterpassword.login";
}
Throw( @"Unsupported variant: %ld", (long)variant );
}
- (NSString *)nameOfType:(MPElementType)type {
- (NSString *)nameOfType:(MPSiteType)type {
if (!type)
return nil;
switch (type) {
case MPElementTypeGeneratedMaximum:
case MPSiteTypeGeneratedMaximum:
return @"Maximum Security Password";
case MPElementTypeGeneratedLong:
case MPSiteTypeGeneratedLong:
return @"Long Password";
case MPElementTypeGeneratedMedium:
case MPSiteTypeGeneratedMedium:
return @"Medium Password";
case MPElementTypeGeneratedBasic:
case MPSiteTypeGeneratedBasic:
return @"Basic Password";
case MPElementTypeGeneratedShort:
case MPSiteTypeGeneratedShort:
return @"Short Password";
case MPElementTypeGeneratedPIN:
case MPSiteTypeGeneratedPIN:
return @"PIN";
case MPElementTypeGeneratedName:
case MPSiteTypeGeneratedName:
return @"Login Name";
case MPElementTypeStoredPersonal:
case MPSiteTypeGeneratedPhrase:
return @"Phrase";
case MPSiteTypeStoredPersonal:
return @"Personal Password";
case MPElementTypeStoredDevicePrivate:
case MPSiteTypeStoredDevicePrivate:
return @"Device Private Password";
}
Throw( @"Type not supported: %lu", (long)type );
}
- (NSString *)shortNameOfType:(MPElementType)type {
- (NSString *)shortNameOfType:(MPSiteType)type {
if (!type)
return nil;
switch (type) {
case MPElementTypeGeneratedMaximum:
case MPSiteTypeGeneratedMaximum:
return @"Maximum";
case MPElementTypeGeneratedLong:
case MPSiteTypeGeneratedLong:
return @"Long";
case MPElementTypeGeneratedMedium:
case MPSiteTypeGeneratedMedium:
return @"Medium";
case MPElementTypeGeneratedBasic:
case MPSiteTypeGeneratedBasic:
return @"Basic";
case MPElementTypeGeneratedShort:
case MPSiteTypeGeneratedShort:
return @"Short";
case MPElementTypeGeneratedPIN:
case MPSiteTypeGeneratedPIN:
return @"PIN";
case MPElementTypeGeneratedName:
case MPSiteTypeGeneratedName:
return @"Name";
case MPElementTypeStoredPersonal:
case MPSiteTypeGeneratedPhrase:
return @"Phrase";
case MPSiteTypeStoredPersonal:
return @"Personal";
case MPElementTypeStoredDevicePrivate:
case MPSiteTypeStoredDevicePrivate:
return @"Device";
}
Throw( @"Type not supported: %lu", (long)type );
}
- (NSString *)classNameOfType:(MPElementType)type {
- (NSString *)classNameOfType:(MPSiteType)type {
return NSStringFromClass( [self classOfType:type] );
}
- (Class)classOfType:(MPElementType)type {
- (Class)classOfType:(MPSiteType)type {
if (!type)
Throw( @"No type given." );
switch (type) {
case MPElementTypeGeneratedMaximum:
case MPSiteTypeGeneratedMaximum:
return [MPElementGeneratedEntity class];
case MPElementTypeGeneratedLong:
case MPSiteTypeGeneratedLong:
return [MPElementGeneratedEntity class];
case MPElementTypeGeneratedMedium:
case MPSiteTypeGeneratedMedium:
return [MPElementGeneratedEntity class];
case MPElementTypeGeneratedBasic:
case MPSiteTypeGeneratedBasic:
return [MPElementGeneratedEntity class];
case MPElementTypeGeneratedShort:
case MPSiteTypeGeneratedShort:
return [MPElementGeneratedEntity class];
case MPElementTypeGeneratedPIN:
case MPSiteTypeGeneratedPIN:
return [MPElementGeneratedEntity class];
case MPElementTypeGeneratedName:
case MPSiteTypeGeneratedName:
return [MPElementGeneratedEntity class];
case MPElementTypeStoredPersonal:
return [MPElementStoredEntity class];
case MPSiteTypeGeneratedPhrase:
return [MPElementGeneratedEntity class];
case MPElementTypeStoredDevicePrivate:
return [MPElementStoredEntity class];
case MPSiteTypeStoredPersonal:
return [MPSiteStoredEntity class];
case MPSiteTypeStoredDevicePrivate:
return [MPSiteStoredEntity class];
}
Throw( @"Type not supported: %lu", (long)type );
@ -268,13 +277,13 @@
- (NSArray *)allTypes {
return [self allTypesStartingWith:MPElementTypeGeneratedMaximum];
return [self allTypesStartingWith:MPSiteTypeGeneratedMaximum];
}
- (NSArray *)allTypesStartingWith:(MPElementType)startingType {
- (NSArray *)allTypesStartingWith:(MPSiteType)startingType {
NSMutableArray *allTypes = [[NSMutableArray alloc] initWithCapacity:8];
MPElementType currentType = startingType;
MPSiteType currentType = startingType;
do {
[allTypes addObject:@(currentType)];
} while ((currentType = [self nextType:currentType]) != startingType);
@ -282,33 +291,33 @@
return allTypes;
}
- (MPElementType)nextType:(MPElementType)type {
- (MPSiteType)nextType:(MPSiteType)type {
switch (type) {
case MPElementTypeGeneratedMaximum:
return MPElementTypeGeneratedLong;
case MPElementTypeGeneratedLong:
return MPElementTypeGeneratedMedium;
case MPElementTypeGeneratedMedium:
return MPElementTypeGeneratedBasic;
case MPElementTypeGeneratedBasic:
return MPElementTypeGeneratedShort;
case MPElementTypeGeneratedShort:
return MPElementTypeGeneratedPIN;
case MPElementTypeGeneratedPIN:
return MPElementTypeStoredPersonal;
case MPElementTypeStoredPersonal:
return MPElementTypeStoredDevicePrivate;
case MPElementTypeStoredDevicePrivate:
return MPElementTypeGeneratedMaximum;
case MPSiteTypeGeneratedMaximum:
return MPSiteTypeGeneratedLong;
case MPSiteTypeGeneratedLong:
return MPSiteTypeGeneratedMedium;
case MPSiteTypeGeneratedMedium:
return MPSiteTypeGeneratedBasic;
case MPSiteTypeGeneratedBasic:
return MPSiteTypeGeneratedShort;
case MPSiteTypeGeneratedShort:
return MPSiteTypeGeneratedPIN;
case MPSiteTypeGeneratedPIN:
return MPSiteTypeStoredPersonal;
case MPSiteTypeStoredPersonal:
return MPSiteTypeStoredDevicePrivate;
case MPSiteTypeStoredDevicePrivate:
return MPSiteTypeGeneratedMaximum;
default:
return MPElementTypeGeneratedLong;
return MPSiteTypeGeneratedLong;
}
}
- (MPElementType)previousType:(MPElementType)type {
- (MPSiteType)previousType:(MPSiteType)type {
MPElementType previousType = type, nextType = type;
MPSiteType previousType = type, nextType = type;
while ((nextType = [self nextType:nextType]) != type)
previousType = nextType;
@ -327,7 +336,7 @@
return ciphers;
}
- (NSArray *)ciphersForType:(MPElementType)type {
- (NSArray *)ciphersForType:(MPSiteType)type {
NSString *typeClass = [self classNameOfType:type];
NSString *typeName = [self nameOfType:type];
@ -351,19 +360,19 @@
- (NSString *)generateLoginForSiteNamed:(NSString *)name usingKey:(MPKey *)key {
return [self generateContentForSiteNamed:name ofType:MPElementTypeGeneratedName withCounter:1
variant:MPElementVariantLogin usingKey:key];
return [self generateContentForSiteNamed:name ofType:MPSiteTypeGeneratedName withCounter:1
variant:MPSiteVariantLogin usingKey:key];
}
- (NSString *)generatePasswordForSiteNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter
usingKey:(MPKey *)key {
- (NSString *)generatePasswordForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
usingKey:(MPKey *)key {
return [self generateContentForSiteNamed:name ofType:type withCounter:counter
variant:MPElementVariantPassword usingKey:key];
variant:MPSiteVariantPassword usingKey:key];
}
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter
variant:(MPElementVariant)variant usingKey:(MPKey *)key {
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
variant:(MPSiteVariant)variant usingKey:(MPKey *)key {
// Determine the seed whose bytes will be used for calculating a password
uint32_t ncounter = htonl( counter ), nnameLength = htonl( name.length );
@ -404,49 +413,50 @@
return content;
}
- (NSString *)storedLoginForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key {
- (NSString *)storedLoginForSite:(MPSiteStoredEntity *)element usingKey:(MPKey *)key {
return nil;
}
- (NSString *)storedPasswordForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key {
- (NSString *)storedPasswordForSite:(MPSiteStoredEntity *)element usingKey:(MPKey *)key {
return [self decryptContent:element.contentObject usingKey:key];
}
- (BOOL)savePassword:(NSString *)clearContent toElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
- (BOOL)savePassword:(NSString *)clearContent toSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
switch (element.type) {
case MPElementTypeGeneratedMaximum:
case MPElementTypeGeneratedLong:
case MPElementTypeGeneratedMedium:
case MPElementTypeGeneratedBasic:
case MPElementTypeGeneratedShort:
case MPElementTypeGeneratedPIN:
case MPElementTypeGeneratedName: {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
case MPSiteTypeGeneratedMedium:
case MPSiteTypeGeneratedBasic:
case MPSiteTypeGeneratedShort:
case MPSiteTypeGeneratedPIN:
case MPSiteTypeGeneratedName:
case MPSiteTypeGeneratedPhrase: {
wrn( @"Cannot save content to element with generated type %lu.", (long)element.type );
return NO;
}
case MPElementTypeStoredPersonal: {
if (![element isKindOfClass:[MPElementStoredEntity class]]) {
wrn( @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.",
case MPSiteTypeStoredPersonal: {
if (![element isKindOfClass:[MPSiteStoredEntity class]]) {
wrn( @"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.",
(long)element.type, [element class] );
return NO;
}
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
if ([((MPElementStoredEntity *)element).contentObject isEqualToData:encryptedContent])
if ([((MPSiteStoredEntity *)element).contentObject isEqualToData:encryptedContent])
return NO;
((MPElementStoredEntity *)element).contentObject = encryptedContent;
((MPSiteStoredEntity *)element).contentObject = encryptedContent;
return YES;
}
case MPElementTypeStoredDevicePrivate: {
if (![element isKindOfClass:[MPElementStoredEntity class]]) {
wrn( @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.",
case MPSiteTypeStoredDevicePrivate: {
if (![element isKindOfClass:[MPSiteStoredEntity class]]) {
wrn( @"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.",
(long)element.type, [element class] );
return NO;
}
@ -463,7 +473,7 @@
(__bridge id)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
#endif
}];
((MPElementStoredEntity *)element).contentObject = nil;
((MPSiteStoredEntity *)element).contentObject = nil;
return YES;
}
}
@ -471,12 +481,12 @@
Throw( @"Unsupported type: %ld", (long)element.type );
}
- (NSString *)resolveLoginForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
- (NSString *)resolveLoginForSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter( group );
__block NSString *result = nil;
[self resolveLoginForElement:element usingKey:elementKey result:^(NSString *result_) {
[self resolveLoginForSite:element usingKey:elementKey result:^(NSString *result_) {
result = result_;
dispatch_group_leave( group );
}];
@ -485,12 +495,12 @@
return result;
}
- (NSString *)resolvePasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
- (NSString *)resolvePasswordForSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter( group );
__block NSString *result = nil;
[self resolvePasswordForElement:element usingKey:elementKey result:^(NSString *result_) {
[self resolvePasswordForSite:element usingKey:elementKey result:^(NSString *result_) {
result = result_;
dispatch_group_leave( group );
}];
@ -499,7 +509,7 @@
return result;
}
- (void)resolveLoginForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey result:(void ( ^ )(NSString *result))resultBlock {
- (void)resolveLoginForSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey result:(void ( ^ )(NSString *result))resultBlock {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
NSString *name = element.name;
@ -521,25 +531,26 @@
} );
}
- (void)resolvePasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey result:(void ( ^ )(NSString *result))resultBlock {
- (void)resolvePasswordForSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey result:(void ( ^ )(NSString *result))resultBlock {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
switch (element.type) {
case MPElementTypeGeneratedMaximum:
case MPElementTypeGeneratedLong:
case MPElementTypeGeneratedMedium:
case MPElementTypeGeneratedBasic:
case MPElementTypeGeneratedShort:
case MPElementTypeGeneratedPIN:
case MPElementTypeGeneratedName: {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
case MPSiteTypeGeneratedMedium:
case MPSiteTypeGeneratedBasic:
case MPSiteTypeGeneratedShort:
case MPSiteTypeGeneratedPIN:
case MPSiteTypeGeneratedName:
case MPSiteTypeGeneratedPhrase: {
if (![element isKindOfClass:[MPElementGeneratedEntity class]]) {
wrn( @"Element with generated type %lu is not an MPElementGeneratedEntity, but a %@.",
wrn( @"Element with generated type %lu is not an MPSiteGeneratedEntity, but a %@.",
(long)element.type, [element class] );
break;
}
NSString *name = element.name;
MPElementType type = element.type;
MPSiteType type = element.type;
NSUInteger counter = ((MPElementGeneratedEntity *)element).counter;
id<MPAlgorithm> algorithm = nil;
if (!element.name.length)
@ -556,14 +567,14 @@
break;
}
case MPElementTypeStoredPersonal: {
if (![element isKindOfClass:[MPElementStoredEntity class]]) {
wrn( @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.",
case MPSiteTypeStoredPersonal: {
if (![element isKindOfClass:[MPSiteStoredEntity class]]) {
wrn( @"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.",
(long)element.type, [element class] );
break;
}
NSData *encryptedContent = ((MPElementStoredEntity *)element).contentObject;
NSData *encryptedContent = ((MPSiteStoredEntity *)element).contentObject;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
NSString *result = [self decryptContent:encryptedContent usingKey:elementKey];
@ -571,9 +582,9 @@
} );
break;
}
case MPElementTypeStoredDevicePrivate: {
NSAssert( [element isKindOfClass:[MPElementStoredEntity class]],
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type,
case MPSiteTypeStoredDevicePrivate: {
NSAssert( [element isKindOfClass:[MPSiteStoredEntity class]],
@"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.", (long)element.type,
[element class] );
NSDictionary *elementQuery = [self queryForDevicePrivateElementNamed:element.name];
@ -589,93 +600,96 @@
}
- (void)importProtectedPassword:(NSString *)protectedContent protectedByKey:(MPKey *)importKey
intoElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
intoSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
switch (element.type) {
case MPElementTypeGeneratedMaximum:
case MPElementTypeGeneratedLong:
case MPElementTypeGeneratedMedium:
case MPElementTypeGeneratedBasic:
case MPElementTypeGeneratedShort:
case MPElementTypeGeneratedPIN:
case MPElementTypeGeneratedName:
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
case MPSiteTypeGeneratedMedium:
case MPSiteTypeGeneratedBasic:
case MPSiteTypeGeneratedShort:
case MPSiteTypeGeneratedPIN:
case MPSiteTypeGeneratedName:
case MPSiteTypeGeneratedPhrase:
break;
case MPElementTypeStoredPersonal: {
if (![element isKindOfClass:[MPElementStoredEntity class]]) {
wrn( @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.",
case MPSiteTypeStoredPersonal: {
if (![element isKindOfClass:[MPSiteStoredEntity class]]) {
wrn( @"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.",
(long)element.type, [element class] );
break;
}
if ([importKey.keyID isEqualToData:elementKey.keyID])
((MPElementStoredEntity *)element).contentObject = [protectedContent decodeBase64];
((MPSiteStoredEntity *)element).contentObject = [protectedContent decodeBase64];
else {
NSString *clearContent = [self decryptContent:[protectedContent decodeBase64] usingKey:importKey];
[self importClearTextPassword:clearContent intoElement:element usingKey:elementKey];
[self importClearTextPassword:clearContent intoSite:element usingKey:elementKey];
}
break;
}
case MPElementTypeStoredDevicePrivate:
case MPSiteTypeStoredDevicePrivate:
break;
}
}
- (void)importClearTextPassword:(NSString *)clearContent intoElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
- (void)importClearTextPassword:(NSString *)clearContent intoSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
switch (element.type) {
case MPElementTypeGeneratedMaximum:
case MPElementTypeGeneratedLong:
case MPElementTypeGeneratedMedium:
case MPElementTypeGeneratedBasic:
case MPElementTypeGeneratedShort:
case MPElementTypeGeneratedPIN:
case MPElementTypeGeneratedName:
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
case MPSiteTypeGeneratedMedium:
case MPSiteTypeGeneratedBasic:
case MPSiteTypeGeneratedShort:
case MPSiteTypeGeneratedPIN:
case MPSiteTypeGeneratedName:
case MPSiteTypeGeneratedPhrase:
break;
case MPElementTypeStoredPersonal: {
[self savePassword:clearContent toElement:element usingKey:elementKey];
case MPSiteTypeStoredPersonal: {
[self savePassword:clearContent toSite:element usingKey:elementKey];
break;
}
case MPElementTypeStoredDevicePrivate:
case MPSiteTypeStoredDevicePrivate:
break;
}
}
- (NSString *)exportPasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
- (NSString *)exportPasswordForSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
if (!(element.type & MPElementFeatureExportContent))
if (!(element.type & MPSiteFeatureExportContent))
return nil;
NSString *result = nil;
switch (element.type) {
case MPElementTypeGeneratedMaximum:
case MPElementTypeGeneratedLong:
case MPElementTypeGeneratedMedium:
case MPElementTypeGeneratedBasic:
case MPElementTypeGeneratedShort:
case MPElementTypeGeneratedPIN:
case MPElementTypeGeneratedName: {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
case MPSiteTypeGeneratedMedium:
case MPSiteTypeGeneratedBasic:
case MPSiteTypeGeneratedShort:
case MPSiteTypeGeneratedPIN:
case MPSiteTypeGeneratedName:
case MPSiteTypeGeneratedPhrase: {
result = nil;
break;
}
case MPElementTypeStoredPersonal: {
if (![element isKindOfClass:[MPElementStoredEntity class]]) {
wrn( @"Element with stored type %lu is not an MPElementStoredEntity, but a %@.",
case MPSiteTypeStoredPersonal: {
if (![element isKindOfClass:[MPSiteStoredEntity class]]) {
wrn( @"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.",
(long)element.type, [element class] );
break;
}
result = [((MPElementStoredEntity *)element).contentObject encodeBase64];
result = [((MPSiteStoredEntity *)element).contentObject encodeBase64];
break;
}
case MPElementTypeStoredDevicePrivate: {
case MPSiteTypeStoredDevicePrivate: {
result = nil;
break;
}
@ -710,7 +724,7 @@
return [[NSString alloc] initWithBytes:decryptedContent.bytes length:decryptedContent.length encoding:NSUTF8StringEncoding];
}
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPElementType)type byAttacker:(MPAttacker)attacker {
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPSiteType)type byAttacker:(MPAttacker)attacker {
if (!type)
return NO;

View File

@ -25,14 +25,14 @@
return 1;
}
- (BOOL)migrateElement:(MPElementEntity *)element explicit:(BOOL)explicit {
- (BOOL)migrateSite:(MPSiteEntity *)element explicit:(BOOL)explicit {
if (element.version != [self version] - 1)
// Only migrate from previous version.
return NO;
if (!explicit) {
if (element.type & MPElementTypeClassGenerated) {
if (element.type & MPSiteTypeClassGenerated) {
// This migration requires explicit permission for types of the generated class.
element.requiresExplicitMigration = YES;
return NO;
@ -45,8 +45,8 @@
return YES;
}
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter
variant:(MPElementVariant)variant usingKey:(MPKey *)key {
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
variant:(MPSiteVariant)variant usingKey:(MPKey *)key {
// Determine the seed whose bytes will be used for calculating a password
uint32_t ncounter = htonl( counter ), nnameLength = htonl( name.length );

View File

@ -176,10 +176,10 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
(long)[user.elements count] )];
#endif
for (MPElementEntity *element in user.elements) {
if (element.type & MPElementTypeClassStored) {
for (MPSiteEntity *element in user.elements) {
if (element.type & MPSiteTypeClassStored) {
NSString *content;
while (!(content = [element.algorithm storedPasswordForElement:(MPElementStoredEntity *)element usingKey:recoverKey])) {
while (!(content = [element.algorithm storedPasswordForSite:(MPElementStoredEntity *)element usingKey:recoverKey])) {
// Failed to decrypt element with the current recoveryKey. Ask user for a new one to use.
__block NSString *masterPassword = nil;
@ -216,7 +216,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
break;
if (![recoverKey isEqualToKey:newKey])
[element.algorithm savePassword:content toElement:element usingKey:newKey];
[element.algorithm savePassword:content toSite:element usingKey:newKey];
}
}

View File

@ -29,8 +29,8 @@ 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, NSManagedObjectContext *context))completion;
- (MPElementEntity *)changeElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context toType:(MPElementType)type;
- (void)addSiteNamed:(NSString *)siteName completion:(void ( ^ )(MPSiteEntity *element, NSManagedObjectContext *context))completion;
- (MPSiteEntity *)changeSite:(MPSiteEntity *)site saveInContext:(NSManagedObjectContext *)context toType:(MPSiteType)type;
- (MPImportResult)importSites:(NSString *)importedSitesString
askImportPassword:(NSString *(^)(NSString *userName))importPassword
askUserPassword:(NSString *(^)(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))userPassword;

View File

@ -333,7 +333,7 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
#pragma mark - Utilities
- (void)addElementNamed:(NSString *)siteName completion:(void ( ^ )(MPElementEntity *element, NSManagedObjectContext *context))completion {
- (void)addSiteNamed:(NSString *)siteName completion:(void ( ^ )(MPSiteEntity *site, NSManagedObjectContext *context))completion {
if (![siteName length]) {
completion( nil, nil );
@ -348,61 +348,61 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
return;
}
MPElementType type = activeUser.defaultType;
MPSiteType type = activeUser.defaultType;
NSString *typeEntityName = [MPAlgorithmDefault classNameOfType:type];
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
element.name = siteName;
element.user = activeUser;
element.type = type;
element.lastUsed = [NSDate date];
element.version = MPAlgorithmDefaultVersion;
MPSiteEntity *site = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
site.name = siteName;
site.user = activeUser;
site.type = type;
site.lastUsed = [NSDate date];
site.version = MPAlgorithmDefaultVersion;
NSError *error = nil;
if (element.objectID.isTemporaryID && ![context obtainPermanentIDsForObjects:@[ element ] error:&error])
err( @"Failed to obtain a permanent object ID after creating new element: %@", error );
if (site.objectID.isTemporaryID && ![context obtainPermanentIDsForObjects:@[ site ] error:&error])
err( @"Failed to obtain a permanent object ID after creating new site: %@", error );
[context saveToStore];
completion( element, context );
completion( site, context );
}];
}
- (MPElementEntity *)changeElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context toType:(MPElementType)type {
- (MPSiteEntity *)changeSite:(MPSiteEntity *)site saveInContext:(NSManagedObjectContext *)context toType:(MPSiteType)type {
if (element.type == type)
return element;
if (site.type == type)
return site;
if ([element.algorithm classOfType:type] == element.typeClass) {
element.type = type;
if ([site.algorithm classOfType:type] == site.typeClass) {
site.type = type;
[context saveToStore];
}
else {
// Type requires a different class of element. Recreate the element.
NSString *typeEntityName = [element.algorithm classNameOfType:type];
MPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
newElement.type = type;
newElement.name = element.name;
newElement.user = element.user;
newElement.uses = element.uses;
newElement.lastUsed = element.lastUsed;
newElement.version = element.version;
newElement.loginName = element.loginName;
// Type requires a different class of site. Recreate the site.
NSString *typeEntityName = [site.algorithm classNameOfType:type];
MPSiteEntity *newSite = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
newSite.type = type;
newSite.name = site.name;
newSite.user = site.user;
newSite.uses = site.uses;
newSite.lastUsed = site.lastUsed;
newSite.version = site.version;
newSite.loginName = site.loginName;
NSError *error = nil;
if (![context obtainPermanentIDsForObjects:@[ newElement ] error:&error])
if (![context obtainPermanentIDsForObjects:@[ newSite ] error:&error])
err( @"Failed to obtain a permanent object ID after changing object type: %@", error );
[context deleteObject:element];
[context deleteObject:site];
[context saveToStore];
[[NSNotificationCenter defaultCenter] postNotificationName:MPElementUpdatedNotification object:element.objectID];
element = newElement;
[[NSNotificationCenter defaultCenter] postNotificationName:MPSiteUpdatedNotification object:site.objectID];
site = newSite;
}
[[NSNotificationCenter defaultCenter] postNotificationName:MPElementUpdatedNotification object:element.objectID];
return element;
[[NSNotificationCenter defaultCenter] postNotificationName:MPSiteUpdatedNotification object:site.objectID];
return site;
}
- (MPImportResult)importSites:(NSString *)importedSitesString
@ -467,9 +467,9 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
NSData *importKeyID = nil;
BOOL headerStarted = NO, headerEnded = NO, clearText = NO;
NSArray *importedSiteLines = [importedSitesString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSMutableSet *elementsToDelete = [NSMutableSet set];
NSMutableArray *importedSiteElements = [NSMutableArray arrayWithCapacity:[importedSiteLines count]];
NSFetchRequest *elementFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
NSMutableSet *sitesToDelete = [NSMutableSet set];
NSMutableArray *importedSiteSites = [NSMutableArray arrayWithCapacity:[importedSiteLines count]];
NSFetchRequest *siteFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
for (NSString *importedSiteLine in importedSiteLines) {
if ([importedSiteLine hasPrefix:@"#"]) {
// Comment or header
@ -491,10 +491,10 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
err( @"Invalid header format in line: %@", importedSiteLine );
return MPImportResultMalformedInput;
}
NSTextCheckingResult *headerElements = [[headerPattern matchesInString:importedSiteLine options:(NSMatchingOptions)0
NSTextCheckingResult *headerSites = [[headerPattern matchesInString:importedSiteLine options:(NSMatchingOptions)0
range:NSMakeRange( 0, [importedSiteLine length] )] lastObject];
NSString *headerName = [importedSiteLine substringWithRange:[headerElements rangeAtIndex:1]];
NSString *headerValue = [importedSiteLine substringWithRange:[headerElements rangeAtIndex:2]];
NSString *headerName = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:1]];
NSString *headerValue = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:2]];
if ([headerName isEqualToString:@"User Name"]) {
importUserName = headerValue;
@ -586,27 +586,27 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
// Find existing site.
if (user) {
elementFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND user == %@", siteName, user];
NSArray *existingSites = [context executeFetchRequest:elementFetchRequest error:&error];
siteFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND user == %@", siteName, user];
NSArray *existingSites = [context executeFetchRequest:siteFetchRequest error:&error];
if (!existingSites) {
err( @"Lookup of existing sites failed for site: %@, user: %@, error: %@", siteName, user.userID, error );
return MPImportResultInternalError;
}
if ([existingSites count]) {
dbg( @"Existing sites: %@", existingSites );
[elementsToDelete addObjectsFromArray:existingSites];
[sitesToDelete addObjectsFromArray:existingSites];
}
}
[importedSiteElements addObject:@[ lastUsed, uses, type, version, counter, loginName, siteName, exportContent ]];
[importedSiteSites addObject:@[ lastUsed, uses, type, version, counter, loginName, siteName, exportContent ]];
dbg( @"Will import site: lastUsed=%@, uses=%@, type=%@, version=%@, counter=%@, loginName=%@, siteName=%@, exportContent=%@",
lastUsed, uses, type, version, counter, loginName, siteName, exportContent );
}
// Ask for confirmation to import these sites and the master password of the user.
inf( @"Importing %lu sites, deleting %lu sites, for user: %@", (unsigned long)[importedSiteElements count],
(unsigned long)[elementsToDelete count], [MPUserEntity idFor:importUserName] );
NSString *userMasterPassword = askUserPassword( user? user.name: importUserName, [importedSiteElements count],
[elementsToDelete count] );
inf( @"Importing %lu sites, deleting %lu sites, for user: %@", (unsigned long)[importedSiteSites count],
(unsigned long)[sitesToDelete count], [MPUserEntity idFor:importUserName] );
NSString *userMasterPassword = askUserPassword( user? user.name: importUserName, [importedSiteSites count],
[sitesToDelete count] );
if (!userMasterPassword) {
inf( @"Import cancelled." );
return MPImportResultCancelled;
@ -622,8 +622,8 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
// Delete existing sites.
if (elementsToDelete.count)
[elementsToDelete enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
if (sitesToDelete.count)
[sitesToDelete enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
inf( @"Deleting site: %@, it will be replaced by an imported site.", [obj name] );
[context deleteObject:obj];
}];
@ -644,10 +644,10 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
}
// Import new sites.
for (NSArray *siteElements in importedSiteElements) {
for (NSArray *siteElements in importedSiteSites) {
NSDate *lastUsed = [[NSDateFormatter rfc3339DateFormatter] dateFromString:siteElements[0]];
NSUInteger uses = (unsigned)[siteElements[1] integerValue];
MPElementType type = (MPElementType)[siteElements[2] integerValue];
MPSiteType type = (MPSiteType)[siteElements[2] integerValue];
NSUInteger version = (unsigned)[siteElements[3] integerValue];
NSUInteger counter = [siteElements[4] length]? (unsigned)[siteElements[4] integerValue]: NSNotFound;
NSString *loginName = [siteElements[5] length]? siteElements[5]: nil;
@ -656,7 +656,7 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
// Create new site.
NSString *typeEntityName = [MPAlgorithmForVersion( version ) classNameOfType:type];
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
MPSiteEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
element.name = siteName;
element.loginName = loginName;
element.user = user;
@ -666,9 +666,9 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
element.version = version;
if ([exportContent length]) {
if (clearText)
[element.algorithm importClearTextPassword:exportContent intoElement:element usingKey:userKey];
[element.algorithm importClearTextPassword:exportContent intoSite:element usingKey:userKey];
else
[element.algorithm importProtectedPassword:exportContent protectedByKey:importKey intoElement:element usingKey:userKey];
[element.algorithm importProtectedPassword:exportContent protectedByKey:importKey intoSite:element usingKey:userKey];
}
if ([element isKindOfClass:[MPElementGeneratedEntity class]] && counter != NSNotFound)
((MPElementGeneratedEntity *)element).counter = counter;
@ -719,10 +719,10 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
[export appendFormat:@"# used used type name\t name\tpassword\n"];
// Sites.
for (MPElementEntity *element in activeUser.elements) {
for (MPSiteEntity *element in activeUser.elements) {
NSDate *lastUsed = element.lastUsed;
NSUInteger uses = element.uses;
MPElementType type = element.type;
MPSiteType type = element.type;
NSUInteger version = element.version;
NSUInteger counter = 0;
NSString *loginName = element.loginName;
@ -735,11 +735,11 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
// Determine the content to export.
if (!(type & MPElementFeatureDevicePrivate)) {
if (!(type & MPSiteFeatureDevicePrivate)) {
if (revealPasswords)
content = [element.algorithm resolvePasswordForElement:element usingKey:self.key];
else if (type & MPElementFeatureExportContent)
content = [element.algorithm exportPasswordForElement:element usingKey:self.key];
content = [element.algorithm resolvePasswordForSite:element usingKey:self.key];
else if (type & MPSiteFeatureExportContent)
content = [element.algorithm exportPasswordForSite:element usingKey:self.key];
}
[export appendFormat:@"%@ %8ld %8s %25s\t%25s\t%@\n",

View File

@ -1,27 +0,0 @@
//
// MPElementEntity.h
// MasterPassword-iOS
//
// Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2014 Lyndir. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class MPUserEntity;
@interface MPElementEntity : NSManagedObject
//@property (nonatomic, retain) id content; // Hide here, reveal in MPElementStoredEntity
@property (nonatomic, retain) NSDate * lastUsed;
@property (nonatomic, retain) NSString * loginName;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSNumber * requiresExplicitMigration_;
@property (nonatomic, retain) NSNumber * type_;
@property (nonatomic, retain) NSNumber * uses_;
@property (nonatomic, retain) NSNumber * version_;
@property (nonatomic, retain) NSNumber * loginGenerated_;
@property (nonatomic, retain) MPUserEntity *user;
@end

View File

@ -1,26 +0,0 @@
//
// MPElementEntity.m
// MasterPassword-iOS
//
// Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2014 Lyndir. All rights reserved.
//
#import "MPElementEntity.h"
#import "MPUserEntity.h"
@implementation MPElementEntity
//@dynamic content;
@dynamic lastUsed;
@dynamic loginName;
@dynamic name;
@dynamic requiresExplicitMigration_;
@dynamic type_;
@dynamic uses_;
@dynamic version_;
@dynamic loginGenerated_;
@dynamic user;
@end

View File

@ -1,18 +0,0 @@
//
// MPElementGeneratedEntity.h
// MasterPassword-iOS
//
// Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2014 Lyndir. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "MPElementEntity.h"
@interface MPElementGeneratedEntity : MPElementEntity
@property (nonatomic, retain) NSNumber * counter_;
@end

View File

@ -1,16 +0,0 @@
//
// MPElementGeneratedEntity.m
// MasterPassword-iOS
//
// Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2014 Lyndir. All rights reserved.
//
#import "MPElementGeneratedEntity.h"
@implementation MPElementGeneratedEntity
@dynamic counter_;
@end

View File

@ -1,18 +0,0 @@
//
// MPElementStoredEntity.h
// MasterPassword-iOS
//
// Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2014 Lyndir. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "MPElementEntity.h"
@interface MPElementStoredEntity : MPElementEntity
@property (nonatomic, retain) NSData * contentObject;
@end

View File

@ -1,16 +0,0 @@
//
// MPElementStoredEntity.m
// MasterPassword-iOS
//
// Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2014 Lyndir. All rights reserved.
//
#import "MPElementStoredEntity.h"
@implementation MPElementStoredEntity
@dynamic contentObject;
@end

View File

@ -1,5 +1,5 @@
//
// MPElementEntities.h
// MPEntities.h
// MasterPassword-iOS
//
// Created by Maarten Billemont on 31/05/12.
@ -7,9 +7,9 @@
//
#import <Foundation/Foundation.h>
#import "MPElementEntity.h"
#import "MPElementStoredEntity.h"
#import "MPElementGeneratedEntity.h"
#import "MPSiteEntity.h"
#import "MPSiteStoredEntity.h"
#import "MPSiteGeneratedEntity.h"
#import "MPUserEntity.h"
#import "MPAlgorithm.h"
#import "MPFixable.h"
@ -22,10 +22,10 @@
@end
@interface MPElementEntity(MP)<MPFixable>
@interface MPSiteEntity(MP)<MPFixable>
@property(assign) BOOL loginGenerated;
@property(assign) MPElementType type;
@property(assign) MPSiteType type;
@property(readonly) NSString *typeName;
@property(readonly) NSString *typeShortName;
@property(readonly) NSString *typeClassName;
@ -44,7 +44,7 @@
@end
@interface MPElementGeneratedEntity(MP)
@interface MPSiteGeneratedEntity(MP)
@property(assign) NSUInteger counter;
@ -54,7 +54,7 @@
@property(assign) NSUInteger avatar;
@property(assign) BOOL saveKey;
@property(assign) MPElementType defaultType;
@property(assign) MPSiteType defaultType;
@property(readonly) NSString *userID;
+ (NSString *)idFor:(NSString *)userName;

View File

@ -1,5 +1,5 @@
//
// MPElementEntities.m
// MPEntities.m
// MasterPassword-iOS
//
// Created by Maarten Billemont on 31/05/12.
@ -34,16 +34,16 @@
@end
@implementation MPElementEntity(MP)
@implementation MPSiteEntity(MP)
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
return MPFixableResultNoProblems;
}
- (MPElementType)type {
- (MPSiteType)type {
return (MPElementType)[self.type_ unsignedIntegerValue];
return (MPSiteType)[self.type_ unsignedIntegerValue];
}
- (void)setLoginGenerated:(BOOL)aLoginGenerated {
@ -56,7 +56,7 @@
return [self.loginGenerated_ boolValue];
}
- (void)setType:(MPElementType)aType {
- (void)setType:(MPSiteType)aType {
self.type_ = @(aType);
}
@ -138,11 +138,11 @@
- (BOOL)migrateExplicitly:(BOOL)explicit {
while (self.version < MPAlgorithmDefaultVersion)
if ([MPAlgorithmForVersion( self.version + 1 ) migrateElement:self explicit:explicit])
inf( @"%@ migration to version: %ld succeeded for element: %@",
if ([MPAlgorithmForVersion( self.version + 1 ) migrateSite:self explicit:explicit])
inf( @"%@ migration to version: %ld succeeded for site: %@",
explicit? @"Explicit": @"Automatic", (long)self.version + 1, self );
else {
wrn( @"%@ migration to version: %ld failed for element: %@",
wrn( @"%@ migration to version: %ld failed for site: %@",
explicit? @"Explicit": @"Automatic", (long)self.version + 1, self );
return NO;
}
@ -152,33 +152,33 @@
- (NSString *)resolveLoginUsingKey:(MPKey *)key {
return [self.algorithm resolveLoginForElement:self usingKey:key];
return [self.algorithm resolveLoginForSite:self usingKey:key];
}
- (NSString *)resolvePasswordUsingKey:(MPKey *)key {
return [self.algorithm resolvePasswordForElement:self usingKey:key];
return [self.algorithm resolvePasswordForSite:self usingKey:key];
}
- (void)resolveLoginUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result {
[self.algorithm resolveLoginForElement:self usingKey:key result:result];
[self.algorithm resolveLoginForSite:self usingKey:key result:result];
}
- (void)resolvePasswordUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result {
[self.algorithm resolvePasswordForElement:self usingKey:key result:result];
[self.algorithm resolvePasswordForSite:self usingKey:key result:result];
}
@end
@implementation MPElementGeneratedEntity(MP)
@implementation MPSiteGeneratedEntity(MP)
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
MPFixableResult result = [super findAndFixInconsistenciesInContext:context];
if (!self.type || self.type == (MPElementType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
if (!self.type || self.type == (MPSiteType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
// Invalid self.type
result = MPApplyFix( result, ^MPFixableResult {
wrn( @"Invalid type for: %@ of %@, type: %ld. Will use %ld instead.",
@ -186,18 +186,18 @@
self.type = self.user.defaultType;
return MPFixableResultProblemsFixed;
} );
if (!self.type || self.type == (MPElementType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
if (!self.type || self.type == (MPSiteType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
// Invalid self.user.defaultType
result = MPApplyFix( result, ^MPFixableResult {
wrn( @"Invalid type for: %@ of %@, type: %ld. Will use %ld instead.",
self.name, self.user.name, (long)self.type, (long)MPElementTypeGeneratedLong );
self.type = MPElementTypeGeneratedLong;
self.name, self.user.name, (long)self.type, (long)MPSiteTypeGeneratedLong );
self.type = MPSiteTypeGeneratedLong;
return MPFixableResultProblemsFixed;
} );
if (![self isKindOfClass:[self.algorithm classOfType:self.type]])
// Mismatch between self.type and self.class
result = MPApplyFix( result, ^MPFixableResult {
for (MPElementType newType = self.type; self.type != (newType = [self.algorithm nextType:newType]);)
for (MPSiteType newType = self.type; self.type != (newType = [self.algorithm nextType:newType]);)
if ([self isKindOfClass:[self.algorithm classOfType:newType]]) {
wrn( @"Mismatching type for: %@ of %@, type: %lu, class: %@. Will use %ld instead.",
self.name, self.user.name, (long)self.type, self.class, (long)newType );
@ -225,7 +225,7 @@
@end
@implementation MPElementStoredEntity(MP)
@implementation MPSiteStoredEntity(MP)
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
@ -236,7 +236,7 @@
MPKey *key = [MPAppDelegate_Shared get].key;
if (key && [[MPAppDelegate_Shared get] activeUserInContext:context] == self.user) {
wrn( @"Content object not encrypted for: %@ of %@. Will re-encrypt.", self.name, self.user.name );
[self.algorithm savePassword:[self.contentObject description] toElement:self usingKey:key];
[self.algorithm savePassword:[self.contentObject description] toSite:self usingKey:key];
return MPFixableResultProblemsFixed;
}
@ -271,12 +271,12 @@
self.saveKey_ = @(aSaveKey);
}
- (MPElementType)defaultType {
- (MPSiteType)defaultType {
return (MPElementType)[self.defaultType_ unsignedIntegerValue]?: MPElementTypeGeneratedLong;
return (MPSiteType)[self.defaultType_ unsignedIntegerValue]?: MPSiteTypeGeneratedLong;
}
- (void)setDefaultType:(MPElementType)aDefaultType {
- (void)setDefaultType:(MPSiteType)aDefaultType {
self.defaultType_ = @(aDefaultType);
}

View File

@ -8,38 +8,39 @@
#import "MPKey.h"
typedef NS_ENUM(NSUInteger, MPElementTypeClass) {
typedef NS_ENUM( NSUInteger, MPSiteTypeClass ) {
/** Generate the password. */
MPElementTypeClassGenerated = 1 << 4,
MPSiteTypeClassGenerated = 1 << 4,
/** Store the password. */
MPElementTypeClassStored = 1 << 5,
MPSiteTypeClassStored = 1 << 5,
};
typedef NS_ENUM(NSUInteger, MPElementVariant) {
typedef NS_ENUM( NSUInteger, MPSiteVariant ) {
/** Generate the password. */
MPElementVariantPassword,
MPSiteVariantPassword,
/** Generate the login name. */
MPElementVariantLogin,
MPSiteVariantLogin,
};
typedef NS_ENUM(NSUInteger, MPElementFeature) {
typedef NS_ENUM( NSUInteger, MPSiteFeature ) {
/** Export the key-protected content data. */
MPElementFeatureExportContent = 1 << 10,
MPSiteFeatureExportContent = 1 << 10,
/** Never export content. */
MPElementFeatureDevicePrivate = 1 << 11,
MPSiteFeatureDevicePrivate = 1 << 11,
};
typedef NS_ENUM(NSUInteger, MPElementType) {
MPElementTypeGeneratedMaximum = 0x0 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedLong = 0x1 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedMedium = 0x2 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedBasic = 0x4 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedShort = 0x3 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedPIN = 0x5 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedName = 0xF | MPElementTypeClassGenerated | 0x0,
typedef NS_ENUM(NSUInteger, MPSiteType) {
MPSiteTypeGeneratedMaximum = 0x0 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedLong = 0x1 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedMedium = 0x2 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedBasic = 0x4 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedShort = 0x3 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedPIN = 0x5 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedName = 0xE | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedPhrase = 0xF | MPSiteTypeClassGenerated | 0x0,
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
MPSiteTypeStoredPersonal = 0x0 | MPSiteTypeClassStored | MPSiteFeatureExportContent,
MPSiteTypeStoredDevicePrivate = 0x1 | MPSiteTypeClassStored | MPSiteFeatureDevicePrivate,
};
#define MPErrorDomain @"MPErrorDomain"
@ -52,7 +53,7 @@ typedef NS_ENUM(NSUInteger, MPElementType) {
#define MPCheckpointEditPassword @"MPCheckpointEditPassword"
#define MPCheckpointEditLoginName @"MPCheckpointEditLoginName"
#define MPCheckpointUseType @"MPCheckpointUseType"
#define MPCheckpointDeleteElement @"MPCheckpointDeleteElement"
#define MPCheckpointDeleteSite @"MPCheckpointDeleteSite"
#define MPCheckpointShowGuide @"MPCheckpointShowGuide"
#define MPCheckpointShowSetup @"MPCheckpointShowSetup"
#define MPCheckpointChangeMP @"MPCheckpointChangeMP"
@ -76,7 +77,7 @@ typedef NS_ENUM(NSUInteger, MPElementType) {
#define MPSignedInNotification @"MPSignedInNotification"
#define MPSignedOutNotification @"MPSignedOutNotification"
#define MPKeyForgottenNotification @"MPKeyForgottenNotification"
#define MPElementUpdatedNotification @"MPElementUpdatedNotification"
#define MPSiteUpdatedNotification @"MPSiteUpdatedNotification"
#define MPCheckConfigNotification @"MPCheckConfigNotification"
#define MPSitesImportedNotification @"MPSitesImportedNotification"
#define MPFoundInconsistenciesNotification @"MPFoundInconsistenciesNotification"
@ -85,6 +86,7 @@ typedef NS_ENUM(NSUInteger, MPElementType) {
#define MPInconsistenciesFixResultUserKey @"MPInconsistenciesFixResultUserKey"
#define MPProductGenerateLogins @"com.lyndir.masterpassword.products.generatelogins"
#define MPProductAdvancedExport @"com.lyndir.masterpassword.products.advancedexport"
static void MPCheckpoint(NSString *checkpoint, NSDictionary *attributes) {

View File

@ -2,14 +2,14 @@
// MPUserEntity.h
// MasterPassword-iOS
//
// Created by Maarten Billemont on 2014-09-14.
// Created by Maarten Billemont on 2014-09-21.
// Copyright (c) 2014 Lyndir. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class MPElementEntity;
@class MPSiteEntity;
@interface MPUserEntity : NSManagedObject
@ -24,8 +24,8 @@
@interface MPUserEntity (CoreDataGeneratedAccessors)
- (void)addElementsObject:(MPElementEntity *)value;
- (void)removeElementsObject:(MPElementEntity *)value;
- (void)addElementsObject:(MPSiteEntity *)value;
- (void)removeElementsObject:(MPSiteEntity *)value;
- (void)addElements:(NSSet *)values;
- (void)removeElements:(NSSet *)values;

View File

@ -2,12 +2,12 @@
// MPUserEntity.m
// MasterPassword-iOS
//
// Created by Maarten Billemont on 2014-09-14.
// Created by Maarten Billemont on 2014-09-21.
// Copyright (c) 2014 Lyndir. All rights reserved.
//
#import "MPUserEntity.h"
#import "MPElementEntity.h"
#import "MPSiteEntity.h"
@implementation MPUserEntity

View File

@ -17,12 +17,12 @@
//
#import <Foundation/Foundation.h>
@class MPElementEntity;
@class MPSiteEntity;
@interface MPElementModel : NSObject
@property (nonatomic) NSString *siteName;
@property (nonatomic) MPElementType type;
@property (nonatomic) MPSiteType type;
@property (nonatomic) NSString *typeName;
@property (nonatomic) NSString *content;
@property (nonatomic) NSString *contentDisplay;
@ -34,8 +34,8 @@
@property (nonatomic) BOOL generated;
@property (nonatomic) BOOL stored;
- (id)initWithEntity:(MPElementEntity *)entity;
- (MPElementEntity *)entityInContext:(NSManagedObjectContext *)moc;
- (id)initWithEntity:(MPSiteEntity *)entity;
- (MPSiteEntity *)entityInContext:(NSManagedObjectContext *)moc;
- (void)updateContent;
@end

View File

@ -17,7 +17,7 @@
//
#import "MPElementModel.h"
#import "MPElementEntity.h"
#import "MPSiteEntity.h"
#import "MPEntities.h"
#import "MPAppDelegate_Shared.h"
#import "MPAppDelegate_Store.h"
@ -28,7 +28,7 @@
BOOL _initialized;
}
- (id)initWithEntity:(MPElementEntity *)entity {
- (id)initWithEntity:(MPSiteEntity *)entity {
if (!(self = [super init]))
return nil;
@ -39,7 +39,7 @@
return self;
}
- (void)setEntity:(MPElementEntity *)entity {
- (void)setEntity:(MPSiteEntity *)entity {
if ([_entityOID isEqual:entity.objectID])
return;
@ -58,13 +58,13 @@
[self updateContent:entity];
}
- (MPElementEntity *)entityInContext:(NSManagedObjectContext *)moc {
- (MPSiteEntity *)entityInContext:(NSManagedObjectContext *)moc {
if (!_entityOID)
return nil;
NSError *error;
MPElementEntity *entity = (MPElementEntity *)[moc existingObjectWithID:_entityOID error:&error];
MPSiteEntity *entity = (MPSiteEntity *)[moc existingObjectWithID:_entityOID error:&error];
if (!entity)
err( @"Couldn't retrieve active element: %@", error );
@ -82,7 +82,7 @@
return;
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *entity = [self entityInContext:context];
MPSiteEntity *entity = [self entityInContext:context];
if ([entity isKindOfClass:[MPElementGeneratedEntity class]]) {
((MPElementGeneratedEntity *)entity).counter = counter;
[context saveToStore];
@ -94,22 +94,22 @@
- (BOOL)generated {
return self.type & MPElementTypeClassGenerated;
return self.type & MPSiteTypeClassGenerated;
}
- (BOOL)stored {
return self.type & MPElementTypeClassStored;
return self.type & MPSiteTypeClassStored;
}
- (void)updateContent {
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
[self updateContent:[MPElementEntity existingObjectWithID:_entityOID inContext:context]];
[self updateContent:[MPSiteEntity existingObjectWithID:_entityOID inContext:context]];
}];
}
- (void)updateContent:(MPElementEntity *)entity {
- (void)updateContent:(MPSiteEntity *)entity {
static NSRegularExpression *re_anyChar;
static dispatch_once_t once = 0;

View File

@ -229,7 +229,8 @@
switch (returnCode) {
case NSAlertFirstButtonReturn: {
// "Create" button.
[[MPMacAppDelegate get] addElementNamed:[self.siteField stringValue] completion:^(MPElementEntity *element, NSManagedObjectContext *context) {
[[MPMacAppDelegate get]
addSiteNamed:[self.siteField stringValue] completion:^(MPSiteEntity *element, NSManagedObjectContext *context) {
if (element)
PearlMainQueue( ^{ [self updateElements]; } );
}];
@ -243,10 +244,10 @@
switch (returnCode) {
case NSAlertFirstButtonReturn: {
// "Save" button.
MPElementType type = (MPElementType)[self.passwordTypesMatrix.selectedCell tag];
MPSiteType type = (MPSiteType)[self.passwordTypesMatrix.selectedCell tag];
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *entity = [[MPMacAppDelegate get] changeElement:[self.selectedElement entityInContext:context]
saveInContext:context toType:type];
MPSiteEntity *entity = [[MPMacAppDelegate get] changeSite:[self.selectedElement entityInContext:context]
saveInContext:context toType:type];
if ([entity isKindOfClass:[MPElementStoredEntity class]] && ![(MPElementStoredEntity *)entity contentObject].length)
PearlMainQueue( ^{
[self changePassword:nil];
@ -264,7 +265,7 @@
// "Save" button.
NSString *loginName = [(NSSecureTextField *)alert.accessoryView stringValue];
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *entity = [self.selectedElement entityInContext:context];
MPSiteEntity *entity = [self.selectedElement entityInContext:context];
entity.loginName = loginName;
[context saveToStore];
}];
@ -280,8 +281,8 @@
// "Save" button.
NSString *password = [(NSSecureTextField *)alert.accessoryView stringValue];
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *entity = [self.selectedElement entityInContext:context];
[entity.algorithm savePassword:password toElement:entity usingKey:[MPMacAppDelegate get].key];
MPSiteEntity *entity = [self.selectedElement entityInContext:context];
[entity.algorithm savePassword:password toSite:entity usingKey:[MPMacAppDelegate get].key];
[context saveToStore];
}];
break;
@ -397,12 +398,12 @@
- (IBAction)changeType:(id)sender {
MPElementModel *element = self.selectedElement;
NSArray *types = [element.algorithm allTypesStartingWith:MPElementTypeGeneratedPIN];
NSArray *types = [element.algorithm allTypesStartingWith:MPSiteTypeGeneratedPIN];
[self.passwordTypesMatrix renewRows:(NSInteger)[types count] columns:1];
for (NSUInteger t = 0; t < [types count]; ++t) {
MPElementType type = [types[t] unsignedIntegerValue];
MPSiteType type = [types[t] unsignedIntegerValue];
NSString *title = [element.algorithm nameOfType:type];
if (type & MPElementTypeClassGenerated)
if (type & MPSiteTypeClassGenerated)
title = [element.algorithm generatePasswordForSiteNamed:element.siteName ofType:type
withCounter:element.counter usingKey:[MPMacAppDelegate get].key];
@ -514,7 +515,7 @@
NSString *query = [self query];
[profiler finishJob:@"query"];
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"lastUsed" ascending:NO]];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(%@ == '' OR name BEGINSWITH[cd] %@) AND user == %@",
query, query, [[MPMacAppDelegate get] activeUserInContext:context]];
@ -529,7 +530,7 @@
[profiler finishJob:@"do fetch"];
NSMutableArray *newElements = [NSMutableArray arrayWithCapacity:[siteResults count]];
for (MPElementEntity *element in siteResults)
for (MPSiteEntity *element in siteResults)
[newElements addObject:[[MPElementModel alloc] initWithEntity:element]];
[profiler finishJob:@"make models"];
self.elements = newElements;

View File

@ -60,9 +60,6 @@
DA5E5CFA1724A667003798D8 /* MPAppDelegate_Shared.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CA01724A667003798D8 /* MPAppDelegate_Shared.m */; };
DA5E5CFB1724A667003798D8 /* MPAppDelegate_Store.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CA21724A667003798D8 /* MPAppDelegate_Store.m */; };
DA5E5CFC1724A667003798D8 /* MPConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CA41724A667003798D8 /* MPConfig.m */; };
DA5E5CFD1724A667003798D8 /* MPElementEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CA61724A667003798D8 /* MPElementEntity.m */; };
DA5E5CFE1724A667003798D8 /* MPElementGeneratedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CA81724A667003798D8 /* MPElementGeneratedEntity.m */; };
DA5E5CFF1724A667003798D8 /* MPElementStoredEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CAA1724A667003798D8 /* MPElementStoredEntity.m */; };
DA5E5D001724A667003798D8 /* MPEntities.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CAC1724A667003798D8 /* MPEntities.m */; };
DA5E5D011724A667003798D8 /* MPKey.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CAE1724A667003798D8 /* MPKey.m */; };
DA5E5D021724A667003798D8 /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CB11724A667003798D8 /* MPUserEntity.m */; };
@ -78,6 +75,10 @@
DA8ED895192906920099B726 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8ED891192906920099B726 /* PearlTween.m */; };
DA8ED896192906920099B726 /* PearlTween.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8ED892192906920099B726 /* PearlTween.h */; };
DA8ED897192906920099B726 /* map-macro.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8ED894192906920099B726 /* map-macro.h */; };
DA9521BD19CEA3FD002E3AD5 /* MPSiteStoredEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA9521B519CEA3FD002E3AD5 /* MPSiteStoredEntity.m */; };
DA9521BE19CEA3FD002E3AD5 /* MPSiteQuestion.m in Sources */ = {isa = PBXBuildFile; fileRef = DA9521B719CEA3FD002E3AD5 /* MPSiteQuestion.m */; };
DA9521BF19CEA3FD002E3AD5 /* MPSiteGeneratedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA9521B919CEA3FD002E3AD5 /* MPSiteGeneratedEntity.m */; };
DA9521C019CEA3FD002E3AD5 /* MPSiteEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA9521BB19CEA3FD002E3AD5 /* MPSiteEntity.m */; };
DAAA81B0195A8D1300FA30D9 /* gradient.png in Resources */ = {isa = PBXBuildFile; fileRef = DAAA81AF195A8D1300FA30D9 /* gradient.png */; };
DABC6C02175D8C85000C15D4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DABC6C15175D8CE1000C15D4 /* RHStatusItemView.m in Sources */ = {isa = PBXBuildFile; fileRef = DABC6C14175D8CE1000C15D4 /* RHStatusItemView.m */; };
@ -302,12 +303,6 @@
DA5E5CA21724A667003798D8 /* MPAppDelegate_Store.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppDelegate_Store.m; sourceTree = "<group>"; };
DA5E5CA31724A667003798D8 /* MPConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPConfig.h; sourceTree = "<group>"; };
DA5E5CA41724A667003798D8 /* MPConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPConfig.m; sourceTree = "<group>"; };
DA5E5CA51724A667003798D8 /* MPElementEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementEntity.h; sourceTree = "<group>"; };
DA5E5CA61724A667003798D8 /* MPElementEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementEntity.m; sourceTree = "<group>"; };
DA5E5CA71724A667003798D8 /* MPElementGeneratedEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementGeneratedEntity.h; sourceTree = "<group>"; };
DA5E5CA81724A667003798D8 /* MPElementGeneratedEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementGeneratedEntity.m; sourceTree = "<group>"; };
DA5E5CA91724A667003798D8 /* MPElementStoredEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementStoredEntity.h; sourceTree = "<group>"; };
DA5E5CAA1724A667003798D8 /* MPElementStoredEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementStoredEntity.m; sourceTree = "<group>"; };
DA5E5CAB1724A667003798D8 /* MPEntities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEntities.h; sourceTree = "<group>"; };
DA5E5CAC1724A667003798D8 /* MPEntities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEntities.m; sourceTree = "<group>"; };
DA5E5CAD1724A667003798D8 /* MPKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPKey.h; sourceTree = "<group>"; };
@ -734,6 +729,14 @@
DA8ED891192906920099B726 /* PearlTween.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlTween.m; sourceTree = "<group>"; };
DA8ED892192906920099B726 /* PearlTween.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlTween.h; sourceTree = "<group>"; };
DA8ED894192906920099B726 /* map-macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "map-macro.h"; sourceTree = "<group>"; };
DA9521B519CEA3FD002E3AD5 /* MPSiteStoredEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteStoredEntity.m; sourceTree = "<group>"; };
DA9521B619CEA3FD002E3AD5 /* MPSiteStoredEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteStoredEntity.h; sourceTree = "<group>"; };
DA9521B719CEA3FD002E3AD5 /* MPSiteQuestion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteQuestion.m; sourceTree = "<group>"; };
DA9521B819CEA3FD002E3AD5 /* MPSiteQuestion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteQuestion.h; sourceTree = "<group>"; };
DA9521B919CEA3FD002E3AD5 /* MPSiteGeneratedEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteGeneratedEntity.m; sourceTree = "<group>"; };
DA9521BA19CEA3FD002E3AD5 /* MPSiteGeneratedEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteGeneratedEntity.h; sourceTree = "<group>"; };
DA9521BB19CEA3FD002E3AD5 /* MPSiteEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteEntity.m; sourceTree = "<group>"; };
DA9521BC19CEA3FD002E3AD5 /* MPSiteEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteEntity.h; sourceTree = "<group>"; };
DAAA81AF195A8D1300FA30D9 /* gradient.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = gradient.png; sourceTree = "<group>"; };
DABB981515100B4000B05417 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
DABC6C01175D8C85000C15D4 /* libRHStatusItemView.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRHStatusItemView.a; sourceTree = BUILT_PRODUCTS_DIR; };
@ -995,6 +998,14 @@
DA5E5C961724A667003798D8 /* ObjC */ = {
isa = PBXGroup;
children = (
DA9521B519CEA3FD002E3AD5 /* MPSiteStoredEntity.m */,
DA9521B619CEA3FD002E3AD5 /* MPSiteStoredEntity.h */,
DA9521B719CEA3FD002E3AD5 /* MPSiteQuestion.m */,
DA9521B819CEA3FD002E3AD5 /* MPSiteQuestion.h */,
DA9521B919CEA3FD002E3AD5 /* MPSiteGeneratedEntity.m */,
DA9521BA19CEA3FD002E3AD5 /* MPSiteGeneratedEntity.h */,
DA9521BB19CEA3FD002E3AD5 /* MPSiteEntity.m */,
DA9521BC19CEA3FD002E3AD5 /* MPSiteEntity.h */,
DA3B8454190FC89700246EEA /* MPFixable.m */,
DA3B8455190FC89700246EEA /* MPFixable.h */,
DA5E5CB21724A667003798D8 /* Mac */,
@ -1012,12 +1023,6 @@
DA5E5CA21724A667003798D8 /* MPAppDelegate_Store.m */,
DA5E5CA31724A667003798D8 /* MPConfig.h */,
DA5E5CA41724A667003798D8 /* MPConfig.m */,
DA5E5CA51724A667003798D8 /* MPElementEntity.h */,
DA5E5CA61724A667003798D8 /* MPElementEntity.m */,
DA5E5CA71724A667003798D8 /* MPElementGeneratedEntity.h */,
DA5E5CA81724A667003798D8 /* MPElementGeneratedEntity.m */,
DA5E5CA91724A667003798D8 /* MPElementStoredEntity.h */,
DA5E5CAA1724A667003798D8 /* MPElementStoredEntity.m */,
DA5E5CAB1724A667003798D8 /* MPEntities.h */,
DA5E5CAC1724A667003798D8 /* MPEntities.m */,
DA5E5CAD1724A667003798D8 /* MPKey.h */,
@ -2137,22 +2142,23 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DA9521BF19CEA3FD002E3AD5 /* MPSiteGeneratedEntity.m in Sources */,
DA5E5CF61724A667003798D8 /* MPAlgorithm.m in Sources */,
DA5E5CF71724A667003798D8 /* MPAlgorithmV0.m in Sources */,
DA5E5CF81724A667003798D8 /* MPAlgorithmV1.m in Sources */,
DA9521BE19CEA3FD002E3AD5 /* MPSiteQuestion.m in Sources */,
DA5E5CF91724A667003798D8 /* MPAppDelegate_Key.m in Sources */,
DA5E5CFA1724A667003798D8 /* MPAppDelegate_Shared.m in Sources */,
DA5E5CFB1724A667003798D8 /* MPAppDelegate_Store.m in Sources */,
DA5E5CFC1724A667003798D8 /* MPConfig.m in Sources */,
DA5E5CFD1724A667003798D8 /* MPElementEntity.m in Sources */,
DA5E5CFE1724A667003798D8 /* MPElementGeneratedEntity.m in Sources */,
DA5E5CFF1724A667003798D8 /* MPElementStoredEntity.m in Sources */,
DA29992C19C6A89900AF7DF1 /* MasterPassword.xcdatamodeld in Sources */,
DA3B8456190FC89700246EEA /* MPFixable.m in Sources */,
DA5E5D001724A667003798D8 /* MPEntities.m in Sources */,
DA5E5D011724A667003798D8 /* MPKey.m in Sources */,
DA5E5D021724A667003798D8 /* MPUserEntity.m in Sources */,
DA9521BD19CEA3FD002E3AD5 /* MPSiteStoredEntity.m in Sources */,
DA5E5D031724A667003798D8 /* MPMacAppDelegate.m in Sources */,
DA9521C019CEA3FD002E3AD5 /* MPSiteEntity.m in Sources */,
DA5E5D041724A667003798D8 /* MPMacConfig.m in Sources */,
DA5E5D0C1724A667003798D8 /* main.m in Sources */,
93D39C5789EFA607CF788082 /* MPElementModel.m in Sources */,

View File

@ -1,19 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0"
lastSavedToolsVersion="1171" systemVersion="11E53" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="MPElementEntity" representedClassName="MPElementEntity" isAbstract="YES" syncable="YES">
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="6244" systemVersion="13E28" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="MPElementEntity" representedClassName="MPSiteEntity" isAbstract="YES" elementID="58EE245C-6827-4C11-BB7E-5722F2426EC2" syncable="YES">
<attribute name="content" optional="YES" transient="YES" attributeType="Transformable" syncable="YES"/>
<attribute name="lastUsed" attributeType="Date" syncable="YES"/>
<attribute name="name" attributeType="String" minValueString="1" indexed="YES" syncable="YES"/>
<attribute name="type_" attributeType="Integer 16" defaultValueString="17" syncable="YES"/>
<attribute name="uses_" attributeType="Integer 16" defaultValueString="0" syncable="YES"/>
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements"
inverseEntity="MPUserEntity" syncable="YES"/>
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements" inverseEntity="MPUserEntity" syncable="YES"/>
</entity>
<entity name="MPElementGeneratedEntity" representedClassName="MPElementGeneratedEntity" parentEntity="MPElementEntity" syncable="YES">
<entity name="MPElementGeneratedEntity" representedClassName="MPSiteGeneratedEntity" parentEntity="MPElementEntity" elementID="789304EA-070D-4982-8C20-54EECFC20CB6" syncable="YES">
<attribute name="counter_" optional="YES" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
</entity>
<entity name="MPElementStoredEntity" representedClassName="MPElementStoredEntity" parentEntity="MPElementEntity" syncable="YES">
<entity name="MPElementStoredEntity" representedClassName="MPSiteStoredEntity" parentEntity="MPElementEntity" elementID="BEEF1688-0CCD-4699-A86A-4D860FE2CEB8" syncable="YES">
<attribute name="contentObject" optional="YES" attributeType="Transformable" storedInTruthFile="YES" syncable="YES"/>
</entity>
<entity name="MPUserEntity" representedClassName="MPUserEntity" syncable="YES">
@ -22,9 +20,10 @@
<attribute name="keyID" optional="YES" attributeType="Binary" syncable="YES"/>
<attribute name="lastUsed" optional="YES" attributeType="Date" syncable="YES"/>
<attribute name="name" attributeType="String" syncable="YES"/>
<attribute name="saveKey_" attributeType="Boolean" defaultValueString="NO"/>
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity"
inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
<attribute name="saveKey_" attributeType="Boolean" defaultValueString="NO">
<userInfo/>
</attribute>
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
</entity>
<elements>
<element name="MPElementEntity" positionX="160" positionY="192" width="128" height="135"/>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0"
lastSavedToolsVersion="2057" systemVersion="12C60" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="MPElementEntity" representedClassName="MPElementEntity" isAbstract="YES" syncable="YES">
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="6244" systemVersion="13E28" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="MPElementEntity" representedClassName="MPSiteEntity" isAbstract="YES" elementID="58EE245C-6827-4C11-BB7E-5722F2426EC2" syncable="YES">
<attribute name="content" optional="YES" transient="YES" attributeType="Transformable" syncable="YES"/>
<attribute name="lastUsed" attributeType="Date" indexed="YES" syncable="YES"/>
<attribute name="name" attributeType="String" minValueString="1" indexed="YES" syncable="YES"/>
@ -12,13 +11,12 @@
<attribute name="userName" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="uses_" attributeType="Integer 16" defaultValueString="0" indexed="YES" syncable="YES"/>
<attribute name="version_" attributeType="Integer 16" minValueString="0" defaultValueString="0" syncable="YES"/>
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements"
inverseEntity="MPUserEntity" syncable="YES"/>
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements" inverseEntity="MPUserEntity" syncable="YES"/>
</entity>
<entity name="MPElementGeneratedEntity" representedClassName="MPElementGeneratedEntity" parentEntity="MPElementEntity" syncable="YES">
<entity name="MPElementGeneratedEntity" representedClassName="MPSiteGeneratedEntity" parentEntity="MPElementEntity" elementID="789304EA-070D-4982-8C20-54EECFC20CB6" syncable="YES">
<attribute name="counter_" optional="YES" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
</entity>
<entity name="MPElementStoredEntity" representedClassName="MPElementStoredEntity" parentEntity="MPElementEntity" syncable="YES">
<entity name="MPElementStoredEntity" representedClassName="MPSiteStoredEntity" parentEntity="MPElementEntity" elementID="BEEF1688-0CCD-4699-A86A-4D860FE2CEB8" syncable="YES">
<attribute name="contentObject" optional="YES" attributeType="Transformable" storedInTruthFile="YES" syncable="YES"/>
</entity>
<entity name="MPUserEntity" representedClassName="MPUserEntity" syncable="YES">
@ -31,8 +29,7 @@
<attribute name="saveKey_" attributeType="Boolean" defaultValueString="NO">
<userInfo/>
</attribute>
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity"
inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
</entity>
<elements>
<element name="MPElementEntity" positionX="0" positionY="0" width="128" height="180"/>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0"
lastSavedToolsVersion="1810" systemVersion="12B19" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="MPElementEntity" representedClassName="MPElementEntity" isAbstract="YES" syncable="YES">
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="6244" systemVersion="13E28" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="MPElementEntity" representedClassName="MPSiteEntity" isAbstract="YES" elementID="58EE245C-6827-4C11-BB7E-5722F2426EC2" syncable="YES">
<attribute name="content" optional="YES" transient="YES" attributeType="Transformable" syncable="YES"/>
<attribute name="lastUsed" attributeType="Date" indexed="YES" syncable="YES"/>
<attribute name="loginName" optional="YES" attributeType="String" elementID="A1B9F981-D33C-4BFE-9F94-C9D3E1F78E51" syncable="YES"/>
@ -12,13 +11,12 @@
<attribute name="type_" attributeType="Integer 16" defaultValueString="17" syncable="YES"/>
<attribute name="uses_" attributeType="Integer 16" defaultValueString="0" indexed="YES" syncable="YES"/>
<attribute name="version_" attributeType="Integer 16" minValueString="0" defaultValueString="0" syncable="YES"/>
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements"
inverseEntity="MPUserEntity" syncable="YES"/>
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements" inverseEntity="MPUserEntity" syncable="YES"/>
</entity>
<entity name="MPElementGeneratedEntity" representedClassName="MPElementGeneratedEntity" parentEntity="MPElementEntity" syncable="YES">
<entity name="MPElementGeneratedEntity" representedClassName="MPSiteGeneratedEntity" parentEntity="MPElementEntity" elementID="789304EA-070D-4982-8C20-54EECFC20CB6" syncable="YES">
<attribute name="counter_" optional="YES" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
</entity>
<entity name="MPElementStoredEntity" representedClassName="MPElementStoredEntity" parentEntity="MPElementEntity" syncable="YES">
<entity name="MPElementStoredEntity" representedClassName="MPSiteStoredEntity" parentEntity="MPElementEntity" elementID="BEEF1688-0CCD-4699-A86A-4D860FE2CEB8" syncable="YES">
<attribute name="contentObject" optional="YES" attributeType="Transformable" storedInTruthFile="YES" syncable="YES"/>
</entity>
<entity name="MPUserEntity" representedClassName="MPUserEntity" syncable="YES">
@ -31,8 +29,7 @@
<attribute name="saveKey_" attributeType="Boolean" defaultValueString="NO">
<userInfo/>
</attribute>
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity"
inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
</entity>
<elements>
<element name="MPElementEntity" positionX="-0" positionY="-286" width="128" height="178"/>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0"
lastSavedToolsVersion="2057" systemVersion="12C60" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="MPElementEntity" representedClassName="MPElementEntity" isAbstract="YES" syncable="YES">
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="6244" systemVersion="13E28" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="MPElementEntity" representedClassName="MPSiteEntity" isAbstract="YES" elementID="58EE245C-6827-4C11-BB7E-5722F2426EC2" syncable="YES">
<attribute name="content" optional="YES" transient="YES" attributeType="Transformable" syncable="YES"/>
<attribute name="lastUsed" attributeType="Date" indexed="YES" syncable="YES"/>
<attribute name="loginName" optional="YES" attributeType="String" elementID="A1B9F981-D33C-4BFE-9F94-C9D3E1F78E51" syncable="YES"/>
@ -12,13 +11,12 @@
<attribute name="type_" attributeType="Integer 16" defaultValueString="17" syncable="YES"/>
<attribute name="uses_" attributeType="Integer 16" defaultValueString="0" indexed="YES" syncable="YES"/>
<attribute name="version_" attributeType="Integer 16" minValueString="0" defaultValueString="0" syncable="YES"/>
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements"
inverseEntity="MPUserEntity" syncable="YES"/>
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements" inverseEntity="MPUserEntity" syncable="YES"/>
</entity>
<entity name="MPElementGeneratedEntity" representedClassName="MPElementGeneratedEntity" parentEntity="MPElementEntity" syncable="YES">
<entity name="MPElementGeneratedEntity" representedClassName="MPSiteGeneratedEntity" parentEntity="MPElementEntity" elementID="789304EA-070D-4982-8C20-54EECFC20CB6" syncable="YES">
<attribute name="counter_" optional="YES" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
</entity>
<entity name="MPElementStoredEntity" representedClassName="MPElementStoredEntity" parentEntity="MPElementEntity" syncable="YES">
<entity name="MPElementStoredEntity" representedClassName="MPSiteStoredEntity" parentEntity="MPElementEntity" elementID="BEEF1688-0CCD-4699-A86A-4D860FE2CEB8" syncable="YES">
<attribute name="contentObject" optional="YES" attributeType="Transformable" storedInTruthFile="YES" syncable="YES"/>
</entity>
<entity name="MPUserEntity" representedClassName="MPUserEntity" syncable="YES">
@ -30,8 +28,7 @@
<attribute name="saveKey_" attributeType="Boolean" defaultValueString="NO">
<userInfo/>
</attribute>
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity"
inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
</entity>
<elements>
<element name="MPElementEntity" positionX="-0" positionY="-286" width="128" height="178"/>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="6244" systemVersion="13E28" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="MPElementEntity" representedClassName="MPElementEntity" isAbstract="YES" syncable="YES">
<entity name="MPSiteEntity" representedClassName="MPSiteEntity" isAbstract="YES" elementID="58EE245C-6827-4C11-BB7E-5722F2426EC2" syncable="YES">
<attribute name="content" optional="YES" transient="YES" attributeType="Transformable" syncable="YES"/>
<attribute name="lastUsed" attributeType="Date" indexed="YES" syncable="YES"/>
<attribute name="loginGenerated_" attributeType="Boolean" defaultValueString="NO" syncable="YES"/>
@ -12,12 +12,17 @@
<attribute name="type_" attributeType="Integer 16" defaultValueString="17" syncable="YES"/>
<attribute name="uses_" attributeType="Integer 16" defaultValueString="0" indexed="YES" syncable="YES"/>
<attribute name="version_" attributeType="Integer 16" minValueString="0" defaultValueString="0" syncable="YES"/>
<relationship name="questions" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="MPSiteQuestion" inverseName="site" inverseEntity="MPSiteQuestion" syncable="YES"/>
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements" inverseEntity="MPUserEntity" syncable="YES"/>
</entity>
<entity name="MPElementGeneratedEntity" representedClassName="MPElementGeneratedEntity" parentEntity="MPElementEntity" syncable="YES">
<entity name="MPSiteGeneratedEntity" representedClassName="MPSiteGeneratedEntity" parentEntity="MPSiteEntity" elementID="789304EA-070D-4982-8C20-54EECFC20CB6" syncable="YES">
<attribute name="counter_" optional="YES" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
</entity>
<entity name="MPElementStoredEntity" representedClassName="MPElementStoredEntity" parentEntity="MPElementEntity" syncable="YES">
<entity name="MPSiteQuestion" representedClassName="MPSiteQuestion" syncable="YES">
<attribute name="keyword" attributeType="String" syncable="YES"/>
<relationship name="site" maxCount="1" deletionRule="Nullify" destinationEntity="MPSiteEntity" inverseName="questions" inverseEntity="MPSiteEntity" syncable="YES"/>
</entity>
<entity name="MPSiteStoredEntity" representedClassName="MPSiteStoredEntity" parentEntity="MPSiteEntity" elementID="BEEF1688-0CCD-4699-A86A-4D860FE2CEB8" syncable="YES">
<attribute name="contentObject" optional="YES" attributeType="Transformable" storedInTruthFile="YES" syncable="YES"/>
</entity>
<entity name="MPUserEntity" representedClassName="MPUserEntity" syncable="YES">
@ -29,12 +34,13 @@
<attribute name="saveKey_" attributeType="Boolean" defaultValueString="NO">
<userInfo/>
</attribute>
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPSiteEntity" inverseName="user" inverseEntity="MPSiteEntity" syncable="YES"/>
</entity>
<elements>
<element name="MPElementEntity" positionX="-0" positionY="-286" width="128" height="193"/>
<element name="MPElementGeneratedEntity" positionX="216" positionY="-288" width="128" height="58"/>
<element name="MPElementStoredEntity" positionX="214" positionY="-171" width="128" height="58"/>
<element name="MPSiteEntity" positionX="-0" positionY="-286" width="128" height="208"/>
<element name="MPSiteGeneratedEntity" positionX="216" positionY="-288" width="128" height="58"/>
<element name="MPSiteQuestion" positionX="-2" positionY="-9" width="128" height="73"/>
<element name="MPSiteStoredEntity" positionX="214" positionY="-171" width="128" height="58"/>
<element name="MPUserEntity" positionX="-218" positionY="-288" width="128" height="148"/>
</elements>
</model>

View File

@ -126,7 +126,7 @@
- (void)updatePassword {
NSString *siteName = self.siteField.text;
MPElementType siteType = [self siteType];
MPSiteType siteType = [self siteType];
NSUInteger siteCounter = (NSUInteger)self.counterStepper.value;
self.counterLabel.text = strf( @"%lu", (unsigned long)siteCounter );
@ -145,21 +145,21 @@
}];
}
- (enum MPElementType)siteType {
- (enum MPSiteType)siteType {
switch (self.typeControl.selectedSegmentIndex) {
case 0:
return MPElementTypeGeneratedMaximum;
return MPSiteTypeGeneratedMaximum;
case 1:
return MPElementTypeGeneratedLong;
return MPSiteTypeGeneratedLong;
case 2:
return MPElementTypeGeneratedMedium;
return MPSiteTypeGeneratedMedium;
case 3:
return MPElementTypeGeneratedBasic;
return MPSiteTypeGeneratedBasic;
case 4:
return MPElementTypeGeneratedShort;
return MPSiteTypeGeneratedShort;
case 5:
return MPElementTypeGeneratedPIN;
return MPSiteTypeGeneratedPIN;
default:
Throw(@"Unsupported type index: %ld", (long)self.typeControl.selectedSegmentIndex);
}

View File

@ -27,7 +27,7 @@ typedef NS_ENUM ( NSUInteger, MPPasswordCellMode ) {
@interface MPPasswordCell : MPCell <UIScrollViewDelegate, UITextFieldDelegate>
- (void)setElement:(MPElementEntity *)element animated:(BOOL)animated;
- (void)setElement:(MPSiteEntity *)element animated:(BOOL)animated;
- (void)setTransientSite:(NSString *)siteName animated:(BOOL)animated;
- (void)setMode:(MPPasswordCellMode)mode animated:(BOOL)animated;

View File

@ -155,7 +155,7 @@
[self updateAnimated:animated];
}
- (void)setElement:(MPElementEntity *)element animated:(BOOL)animated {
- (void)setElement:(MPSiteEntity *)element animated:(BOOL)animated {
_elementOID = [element objectID];
[self updateAnimated:animated];
@ -195,7 +195,7 @@
NSString *password = self.passwordField.text;
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
TimeToCrack timeToCrack;
MPElementEntity *element = [self elementInContext:context];
MPSiteEntity *element = [self elementInContext:context];
id<MPAlgorithm> algorithm = element.algorithm?: MPAlgorithmDefault;
MPAttacker attackHardware = [[MPConfig get].siteAttacker unsignedIntegerValue];
if ([algorithm timeToCrack:&timeToCrack passwordOfType:[self elementInContext:context].type byAttacker:attackHardware] ||
@ -214,12 +214,12 @@
NSString *text = textField.text;
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *element = [self elementInContext:context];
MPSiteEntity *element = [self elementInContext:context];
if (!element)
return;
if (textField == self.passwordField) {
if ([element.algorithm savePassword:text toElement:element usingKey:[MPiOSAppDelegate get].key])
if ([element.algorithm savePassword:text toSite:element usingKey:[MPiOSAppDelegate get].key])
[PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2];
}
else if (textField == self.loginNameField &&
@ -243,7 +243,7 @@
- (IBAction)doDelete:(UIButton *)sender {
MPElementEntity *element = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
MPSiteEntity *element = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
if (!element)
return;
@ -265,10 +265,10 @@
[PearlSheet showSheetWithTitle:@"Change Password Type" viewStyle:UIActionSheetStyleAutomatic
initSheet:^(UIActionSheet *sheet) {
MPElementEntity
MPSiteEntity
*mainElement = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
for (NSNumber *typeNumber in [MPAlgorithmDefault allTypes]) {
MPElementType type = [typeNumber unsignedIntegerValue];
MPSiteType type = [typeNumber unsignedIntegerValue];
NSString *typeName = [MPAlgorithmDefault nameOfType:type];
if (type == mainElement.type)
[sheet addButtonWithTitle:strf( @"● %@", typeName )];
@ -279,11 +279,11 @@
if (buttonIndex == [sheet cancelButtonIndex])
return;
MPElementType type = [[MPAlgorithmDefault allTypes][buttonIndex] unsignedIntegerValue]?: MPElementTypeGeneratedLong;
MPSiteType type = [[MPAlgorithmDefault allTypes][buttonIndex] unsignedIntegerValue]?: MPSiteTypeGeneratedLong;
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *element = [self elementInContext:context];
element = [[MPiOSAppDelegate get] changeElement:element saveInContext:context toType:type];
MPSiteEntity *element = [self elementInContext:context];
element = [[MPiOSAppDelegate get] changeSite:element saveInContext:context toType:type];
[self setElement:element animated:YES];
}];
} cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:nil];
@ -294,7 +294,7 @@
self.loginNameField.enabled = YES;
self.passwordField.enabled = YES;
if ([self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].type & MPElementTypeClassStored)
if ([self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].type & MPSiteTypeClassStored)
[self.passwordField becomeFirstResponder];
else
[self.loginNameField becomeFirstResponder];
@ -331,7 +331,7 @@
- (IBAction)doIncrementCounter:(UIButton *)sender {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *element = [self elementInContext:context];
MPSiteEntity *element = [self elementInContext:context];
if (!element || ![element isKindOfClass:[MPElementGeneratedEntity class]])
return;
@ -363,7 +363,7 @@
return;
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *element = [self elementInContext:context];
MPSiteEntity *element = [self elementInContext:context];
if (!element || ![element isKindOfClass:[MPElementGeneratedEntity class]])
return;
@ -393,7 +393,7 @@
}
[[MPiOSAppDelegate get]
addElementNamed:self.transientSite completion:^(MPElementEntity *element, NSManagedObjectContext *context) {
addSiteNamed:self.transientSite completion:^(MPSiteEntity *element, NSManagedObjectContext *context) {
[self copyContentOfElement:element saveInContext:context];
PearlMainQueueAfter( .3f, ^{
@ -424,7 +424,7 @@
}];
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *element = [self elementInContext:context];
MPSiteEntity *element = [self elementInContext:context];
if (![self copyLoginOfElement:element saveInContext:context]) {
element.loginGenerated = YES;
[context saveToStore];
@ -462,7 +462,7 @@
}
[UIView animateWithDuration:animated? .3f: 0 animations:^{
MPElementEntity *mainElement = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
MPSiteEntity *mainElement = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
// UI
self.upgradeButton.alpha = mainElement.requiresExplicitMigration? 1: 0;
@ -470,7 +470,7 @@
self.loginNameContainer.alpha = settingsMode || mainElement.loginGenerated || [mainElement.loginName length]? 0.7f: 0;
self.loginNameField.textColor = [UIColor colorWithHexString:mainElement.loginGenerated? @"5E636D": @"6D5E63"];
self.modeButton.alpha = self.transientSite? 0: settingsMode? 0.5f: 0.1f;
self.counterLabel.alpha = self.counterButton.alpha = mainElement.type & MPElementTypeClassGenerated? 0.5f: 0;
self.counterLabel.alpha = self.counterButton.alpha = mainElement.type & MPSiteTypeClassGenerated? 0.5f: 0;
self.modeButton.selected = settingsMode;
self.strengthLabel.gone = !settingsMode;
self.modeScrollView.scrollEnabled = !self.transientSite;
@ -491,17 +491,17 @@
// Site Password
self.passwordField.secureTextEntry = [[MPiOSConfig get].hidePasswords boolValue];
self.passwordField.attributedPlaceholder = stra(
mainElement.type & MPElementTypeClassStored? strl( @"No password" ):
mainElement.type & MPElementTypeClassGenerated? strl( @"..." ): @"", @{
mainElement.type & MPSiteTypeClassStored? strl( @"No password" ):
mainElement.type & MPSiteTypeClassGenerated? strl( @"..." ): @"", @{
NSForegroundColorAttributeName : [UIColor whiteColor]
} );
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *element = [self elementInContext:context];
MPSiteEntity *element = [self elementInContext:context];
MPKey *key = [MPiOSAppDelegate get].key;
NSString *password, *loginName = [element resolveLoginUsingKey:key];
if (self.transientSite)
password = [MPAlgorithmDefault generatePasswordForSiteNamed:self.transientSite ofType:
[[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPElementTypeGeneratedLong
[[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPSiteTypeGeneratedLong
withCounter:1 usingKey:key];
else if (element)
password = [element resolvePasswordUsingKey:key];
@ -549,7 +549,7 @@
}];
}
- (BOOL)copyContentOfElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context {
- (BOOL)copyContentOfElement:(MPSiteEntity *)element saveInContext:(NSManagedObjectContext *)context {
inf( @"Copying password for: %@", element.name );
NSString *password = [element resolvePasswordUsingKey:[MPAppDelegate_Shared get].key];
@ -566,10 +566,10 @@
return YES;
}
- (BOOL)copyLoginOfElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context {
- (BOOL)copyLoginOfElement:(MPSiteEntity *)element saveInContext:(NSManagedObjectContext *)context {
inf( @"Copying login for: %@", element.name );
NSString *loginName = [element.algorithm resolveLoginForElement:element usingKey:[MPiOSAppDelegate get].key];
NSString *loginName = [element.algorithm resolveLoginForSite:element usingKey:[MPiOSAppDelegate get].key];
if (![loginName length])
return NO;
@ -583,9 +583,9 @@
return YES;
}
- (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context {
- (MPSiteEntity *)elementInContext:(NSManagedObjectContext *)context {
return [MPElementEntity existingObjectWithID:_elementOID inContext:context];
return [MPSiteEntity existingObjectWithID:_elementOID inContext:context];
}
@end

View File

@ -16,7 +16,7 @@
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
@class MPElementEntity;
@class MPSiteEntity;
@class MPCoachmark;
@interface MPPasswordsViewController : UIViewController<UISearchBarDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>

View File

@ -423,7 +423,7 @@ referenceSizeForHeaderInSection:(NSInteger)section {
if (!_fetchedResultsController) {
_showTransientItem = NO;
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
fetchRequest.sortDescriptors = @[
[[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO]
];

View File

@ -102,7 +102,7 @@
self.generatedTypeControl.selectedSegmentIndex = -1;
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementType defaultType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType = [self typeForSelectedSegment];
MPSiteType defaultType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType = [self typeForSelectedSegment];
[context saveToStore];
PearlMainQueue( ^{
@ -179,31 +179,31 @@
return nil;
}
- (enum MPElementType)typeForSelectedSegment {
- (enum MPSiteType)typeForSelectedSegment {
NSInteger selectedGeneratedIndex = self.generatedTypeControl.selectedSegmentIndex;
NSInteger selectedStoredIndex = self.storedTypeControl.selectedSegmentIndex;
switch (selectedGeneratedIndex) {
case 0:
return MPElementTypeGeneratedMaximum;
return MPSiteTypeGeneratedMaximum;
case 1:
return MPElementTypeGeneratedLong;
return MPSiteTypeGeneratedLong;
case 2:
return MPElementTypeGeneratedMedium;
return MPSiteTypeGeneratedMedium;
case 3:
return MPElementTypeGeneratedBasic;
return MPSiteTypeGeneratedBasic;
case 4:
return MPElementTypeGeneratedShort;
return MPSiteTypeGeneratedShort;
case 5:
return MPElementTypeGeneratedPIN;
return MPSiteTypeGeneratedPIN;
default:
switch (selectedStoredIndex) {
case 0:
return MPElementTypeStoredPersonal;
return MPSiteTypeStoredPersonal;
case 1:
return MPElementTypeStoredDevicePrivate;
return MPSiteTypeStoredDevicePrivate;
default:
Throw( @"unsupported selected type index: generated=%ld, stored=%ld", (long)selectedGeneratedIndex,
(long)selectedStoredIndex );
@ -211,32 +211,32 @@
}
}
- (NSInteger)generatedSegmentIndexForType:(MPElementType)type {
- (NSInteger)generatedSegmentIndexForType:(MPSiteType)type {
switch (type) {
case MPElementTypeGeneratedMaximum:
case MPSiteTypeGeneratedMaximum:
return 0;
case MPElementTypeGeneratedLong:
case MPSiteTypeGeneratedLong:
return 1;
case MPElementTypeGeneratedMedium:
case MPSiteTypeGeneratedMedium:
return 2;
case MPElementTypeGeneratedBasic:
case MPSiteTypeGeneratedBasic:
return 3;
case MPElementTypeGeneratedShort:
case MPSiteTypeGeneratedShort:
return 4;
case MPElementTypeGeneratedPIN:
case MPSiteTypeGeneratedPIN:
return 5;
default:
return -1;
}
}
- (NSInteger)storedSegmentIndexForType:(MPElementType)type {
- (NSInteger)storedSegmentIndexForType:(MPSiteType)type {
switch (type) {
case MPElementTypeStoredPersonal:
case MPSiteTypeStoredPersonal:
return 0;
case MPElementTypeStoredDevicePrivate:
case MPSiteTypeStoredDevicePrivate:
return 1;
default:
return -1;

View File

@ -134,6 +134,8 @@
if ([productIdentifier isEqualToString:MPProductGenerateLogins])
return self.generateLoginCell;
if ([productIdentifier isEqualToString:MPProductAdvancedExport])
return self.advancedExportCell;
return nil;
}
@ -145,19 +147,24 @@
[hideCells addObjectsFromArray:self.allCellsBySection[0]];
for (SKProduct *product in products) {
[self showCell:self.generateLoginCell ifProduct:product hasProductIdentifier:MPProductGenerateLogins showingCells:showCells];
[self showCellForProductWithIdentifier:MPProductGenerateLogins ifProduct:product showingCells:showCells];
[self showCellForProductWithIdentifier:MPProductAdvancedExport ifProduct:product showingCells:showCells];
}
[hideCells removeObjectsInArray:showCells];
[self updateCellsHiding:hideCells showing:showCells animation:UITableViewRowAnimationAutomatic];
if ([self.tableView numberOfRowsInSection:0])
[self updateCellsHiding:hideCells showing:showCells animation:UITableViewRowAnimationAutomatic];
else
[self updateCellsHiding:hideCells showing:showCells animation:UITableViewRowAnimationNone];
}
- (void)showCell:(MPStoreProductCell *)cell ifProduct:(SKProduct *)product hasProductIdentifier:(NSString *)productIdentifier
showingCells:(NSMutableArray *)showCells {
- (void)showCellForProductWithIdentifier:(NSString *)productIdentifier ifProduct:(SKProduct *)product
showingCells:(NSMutableArray *)showCells {
if (![product.productIdentifier isEqualToString:productIdentifier])
return;
MPStoreProductCell *cell = [self cellForProductIdentifier:productIdentifier];
[showCells addObject:cell];
self.currencyFormatter.locale = product.priceLocale;

View File

@ -13,11 +13,11 @@
@protocol MPTypeDelegate<NSObject>
@required
- (void)didSelectType:(MPElementType)type;
- (MPElementType)selectedType;
- (void)didSelectType:(MPSiteType)type;
- (MPSiteType)selectedType;
@optional
- (MPElementEntity *)selectedElement;
- (MPSiteEntity *)selectedElement;
@end

View File

@ -12,7 +12,7 @@
@interface MPTypeViewController()
- (MPElementType)typeAtIndexPath:(NSIndexPath *)indexPath;
- (MPSiteType)typeAtIndexPath:(NSIndexPath *)indexPath;
@end
@ -63,15 +63,15 @@
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
MPElementEntity *selectedElement = nil;
MPSiteEntity *selectedElement = nil;
if ([self.delegate respondsToSelector:@selector(selectedElement)])
selectedElement = [self.delegate selectedElement];
MPElementType cellType = [self typeAtIndexPath:indexPath];
MPElementType selectedType = selectedElement? selectedElement.type: [self.delegate selectedType];
MPSiteType cellType = [self typeAtIndexPath:indexPath];
MPSiteType selectedType = selectedElement? selectedElement.type: [self.delegate selectedType];
cell.selected = (selectedType == cellType);
if (cellType != (MPElementType)NSNotFound && cellType & MPElementTypeClassGenerated) {
if (cellType != (MPSiteType)NSNotFound && cellType & MPSiteTypeClassGenerated) {
[(UITextField *)[cell viewWithTag:2] setText:@"..."];
NSString *name = selectedElement.name;
@ -96,8 +96,8 @@
NSAssert(self.navigationController.topViewController == self, @"Not the currently active navigation item.");
MPElementType type = [self typeAtIndexPath:indexPath];
if (type == (MPElementType)NSNotFound)
MPSiteType type = [self typeAtIndexPath:indexPath];
if (type == (MPSiteType)NSNotFound)
// Selected a non-type row.
return;
@ -105,28 +105,28 @@
[self.navigationController popViewControllerAnimated:YES];
}
- (MPElementType)typeAtIndexPath:(NSIndexPath *)indexPath {
- (MPSiteType)typeAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.section) {
case 0: {
// Generated
switch (indexPath.row) {
case 0:
return (MPElementType)NSNotFound;
return (MPSiteType)NSNotFound;
case 1:
return MPElementTypeGeneratedMaximum;
return MPSiteTypeGeneratedMaximum;
case 2:
return MPElementTypeGeneratedLong;
return MPSiteTypeGeneratedLong;
case 3:
return MPElementTypeGeneratedMedium;
return MPSiteTypeGeneratedMedium;
case 4:
return MPElementTypeGeneratedBasic;
return MPSiteTypeGeneratedBasic;
case 5:
return MPElementTypeGeneratedShort;
return MPSiteTypeGeneratedShort;
case 6:
return MPElementTypeGeneratedPIN;
return MPSiteTypeGeneratedPIN;
case 7:
return (MPElementType)NSNotFound;
return (MPSiteType)NSNotFound;
default: {
Throw(@"Unsupported row: %ld, when selecting generated element type.", (long)indexPath.row);
@ -138,13 +138,13 @@
// Stored
switch (indexPath.row) {
case 0:
return (MPElementType)NSNotFound;
return (MPSiteType)NSNotFound;
case 1:
return MPElementTypeStoredPersonal;
return MPSiteTypeStoredPersonal;
case 2:
return MPElementTypeStoredDevicePrivate;
return MPSiteTypeStoredDevicePrivate;
case 3:
return (MPElementType)NSNotFound;
return (MPSiteType)NSNotFound;
default: {
Throw(@"Unsupported row: %ld, when selecting stored element type.", (long)indexPath.row);

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
93D390C1B93F9D3AE37DD0A5 /* MPAnswersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39C426E03358384018E85 /* MPAnswersViewController.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 */; };
@ -157,6 +158,11 @@
DA854C8318D4CFBF00106317 /* avatar-add@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA854C8118D4CFBF00106317 /* avatar-add@2x.png */; };
DA854C8418D4CFBF00106317 /* avatar-add.png in Resources */ = {isa = PBXBuildFile; fileRef = DA854C8218D4CFBF00106317 /* avatar-add.png */; };
DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA945C8617E3F3FD0053236B /* Images.xcassets */; };
DA9521A819CEA3DE002E3AD5 /* MPSiteEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA9521A719CEA3DE002E3AD5 /* MPSiteEntity.m */; };
DA9521AB19CEA3DE002E3AD5 /* MPSiteQuestion.m in Sources */ = {isa = PBXBuildFile; fileRef = DA9521AA19CEA3DE002E3AD5 /* MPSiteQuestion.m */; };
DA9521AE19CEA3DE002E3AD5 /* MPSiteStoredEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA9521AD19CEA3DE002E3AD5 /* MPSiteStoredEntity.m */; };
DA9521B119CEA3DE002E3AD5 /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA9521B019CEA3DE002E3AD5 /* MPUserEntity.m */; };
DA9521B419CEA3DE002E3AD5 /* MPSiteGeneratedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA9521B319CEA3DE002E3AD5 /* MPSiteGeneratedEntity.m */; };
DA95D5F214DF0B2C008D1B94 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */; };
DAA141201922FF020032B392 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA1411C1922FF020032B392 /* PearlTween.m */; };
DAA141211922FF020032B392 /* PearlTween.h in Headers */ = {isa = PBXBuildFile; fileRef = DAA1411D1922FF020032B392 /* PearlTween.h */; };
@ -275,13 +281,14 @@
DACE2F6D19BA6A2A0010F92E /* PearlMutableStaticTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */; };
DACE2F6E19BA6A2A0010F92E /* UIView+FontScale.h in Headers */ = {isa = PBXBuildFile; fileRef = DACE2F6A19BA6A2A0010F92E /* UIView+FontScale.h */; };
DAD312C21552A22700A3F9ED /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD312C01552A20800A3F9ED /* libsqlite3.dylib */; };
DADB4EC719C66FB60065A78D /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DADB4EC619C66FB60065A78D /* MPUserEntity.m */; };
DADB4ECA19C66FB60065A78D /* MPElementEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DADB4EC919C66FB60065A78D /* MPElementEntity.m */; };
DADB4ECD19C66FB60065A78D /* MPElementGeneratedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DADB4ECC19C66FB60065A78D /* MPElementGeneratedEntity.m */; };
DADB4ED019C66FB70065A78D /* MPElementStoredEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DADB4ECF19C66FB70065A78D /* MPElementStoredEntity.m */; };
DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DAE1EF2417E942DE00BC0086 /* Localizable.strings */; };
DAE2725919C93B80007C5262 /* libInAppSettingsKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAFC5655172C573B00CB5CC5 /* libInAppSettingsKit.a */; };
DAE2725A19C93B8E007C5262 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA70EC7F1811B13C00F65DB2 /* StoreKit.framework */; };
DAE2725E19CA98A5007C5262 /* thumb_advanced_export.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE2725B19CA98A5007C5262 /* thumb_advanced_export.png */; };
DAE2725F19CA98A5007C5262 /* thumb_advanced_export@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE2725C19CA98A5007C5262 /* thumb_advanced_export@2x.png */; };
DAE2726019CA98A5007C5262 /* thumb_advanced_export@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE2725D19CA98A5007C5262 /* thumb_advanced_export@3x.png */; };
DAE2726319CE9CB3007C5262 /* UITableViewCell+PearlDeque.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE2726119CE9CB3007C5262 /* UITableViewCell+PearlDeque.m */; };
DAE2726419CE9CB3007C5262 /* UITableViewCell+PearlDeque.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE2726219CE9CB3007C5262 /* UITableViewCell+PearlDeque.h */; };
DAEBC45314F6364500987BF6 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
DAEC85B518E3DD9A007FC0DF /* UIView+Touches.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */; };
DAEC85B618E3DD9A007FC0DF /* PearlUINavigationBar.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEC85B218E3DD9A007FC0DF /* PearlUINavigationBar.m */; };
@ -438,12 +445,14 @@
93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUICollectionView.h; sourceTree = "<group>"; };
93D39B381350802A194BF332 /* MPAvatarCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAvatarCell.m; sourceTree = "<group>"; };
93D39BAA71DE51B4D8A1286C /* MPCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCell.m; sourceTree = "<group>"; };
93D39C426E03358384018E85 /* MPAnswersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAnswersViewController.m; sourceTree = "<group>"; };
93D39C44361BE57AF0B3071F /* MPPasswordsSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordsSegue.h; sourceTree = "<group>"; };
93D39C86E984EC65DA5ACB1D /* MPAppSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppSettingsViewController.h; sourceTree = "<group>"; };
93D39CC01630D0421205C4C4 /* MPNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNavigationController.m; sourceTree = "<group>"; };
93D39CDD434AFD6E1B0DA359 /* MPEmergencyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEmergencyViewController.h; sourceTree = "<group>"; };
93D39CECA10BCCB0BA581BF1 /* MPAppDelegate_InApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppDelegate_InApp.h; sourceTree = "<group>"; };
93D39CF8ADF4542CDC4CD385 /* MPCombinedViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCombinedViewController.h; sourceTree = "<group>"; };
93D39D6604447D7708039155 /* MPAnswersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAnswersViewController.h; sourceTree = "<group>"; };
93D39D8A953779B35403AF6E /* PearlUICollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUICollectionView.m; sourceTree = "<group>"; };
93D39DA27D768B53C8B1330C /* MPAvatarCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAvatarCell.h; sourceTree = "<group>"; };
93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+PearlAdjustInsets.h"; sourceTree = "<group>"; };
@ -529,6 +538,16 @@
DA854C8118D4CFBF00106317 /* avatar-add@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-add@2x.png"; sourceTree = "<group>"; };
DA854C8218D4CFBF00106317 /* avatar-add.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-add.png"; sourceTree = "<group>"; };
DA945C8617E3F3FD0053236B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
DA9521A619CEA3DE002E3AD5 /* MPSiteEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteEntity.h; sourceTree = "<group>"; };
DA9521A719CEA3DE002E3AD5 /* MPSiteEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteEntity.m; sourceTree = "<group>"; };
DA9521A919CEA3DE002E3AD5 /* MPSiteQuestion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteQuestion.h; sourceTree = "<group>"; };
DA9521AA19CEA3DE002E3AD5 /* MPSiteQuestion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteQuestion.m; sourceTree = "<group>"; };
DA9521AC19CEA3DE002E3AD5 /* MPSiteStoredEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteStoredEntity.h; sourceTree = "<group>"; };
DA9521AD19CEA3DE002E3AD5 /* MPSiteStoredEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteStoredEntity.m; sourceTree = "<group>"; };
DA9521AF19CEA3DE002E3AD5 /* MPUserEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUserEntity.h; sourceTree = "<group>"; };
DA9521B019CEA3DE002E3AD5 /* MPUserEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUserEntity.m; sourceTree = "<group>"; };
DA9521B219CEA3DE002E3AD5 /* MPSiteGeneratedEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteGeneratedEntity.h; sourceTree = "<group>"; };
DA9521B319CEA3DE002E3AD5 /* MPSiteGeneratedEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteGeneratedEntity.m; sourceTree = "<group>"; };
DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; };
DAA141191922FED80032B392 /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Crashlytics.framework; sourceTree = "<group>"; };
DAA1411C1922FF020032B392 /* PearlTween.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlTween.m; sourceTree = "<group>"; };
@ -1174,19 +1193,11 @@
DABD3BAB1711E2DC00CF925C /* MPAppDelegate_Store.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppDelegate_Store.m; sourceTree = "<group>"; };
DABD3BAC1711E2DC00CF925C /* MPConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPConfig.h; sourceTree = "<group>"; };
DABD3BAD1711E2DC00CF925C /* MPConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPConfig.m; sourceTree = "<group>"; };
DABD3BAE1711E2DC00CF925C /* MPElementEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementEntity.h; sourceTree = "<group>"; };
DABD3BAF1711E2DC00CF925C /* MPElementEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementEntity.m; sourceTree = "<group>"; };
DABD3BB01711E2DC00CF925C /* MPElementGeneratedEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementGeneratedEntity.h; sourceTree = "<group>"; };
DABD3BB11711E2DC00CF925C /* MPElementGeneratedEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementGeneratedEntity.m; sourceTree = "<group>"; };
DABD3BB21711E2DC00CF925C /* MPElementStoredEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementStoredEntity.h; sourceTree = "<group>"; };
DABD3BB31711E2DC00CF925C /* MPElementStoredEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementStoredEntity.m; sourceTree = "<group>"; };
DABD3BB41711E2DC00CF925C /* MPEntities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEntities.h; sourceTree = "<group>"; };
DABD3BB51711E2DC00CF925C /* MPEntities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEntities.m; sourceTree = "<group>"; };
DABD3BB61711E2DC00CF925C /* MPKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPKey.h; sourceTree = "<group>"; };
DABD3BB71711E2DC00CF925C /* MPKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPKey.m; sourceTree = "<group>"; };
DABD3BB81711E2DC00CF925C /* MPTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPTypes.h; sourceTree = "<group>"; };
DABD3BB91711E2DC00CF925C /* MPUserEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUserEntity.h; sourceTree = "<group>"; };
DABD3BBA1711E2DC00CF925C /* MPUserEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUserEntity.m; sourceTree = "<group>"; };
DABD3BD11711E2DC00CF925C /* MasterPassword 1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 1.xcdatamodel"; sourceTree = "<group>"; };
DABD3BD21711E2DC00CF925C /* MasterPassword 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 2.xcdatamodel"; sourceTree = "<group>"; };
DABD3BD31711E2DC00CF925C /* MasterPassword 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 3.xcdatamodel"; sourceTree = "<group>"; };
@ -1232,16 +1243,13 @@
DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlMutableStaticTableViewController.h; sourceTree = "<group>"; };
DACE2F6A19BA6A2A0010F92E /* UIView+FontScale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+FontScale.h"; sourceTree = "<group>"; };
DAD312C01552A20800A3F9ED /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
DADB4EC519C66FB50065A78D /* MPUserEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUserEntity.h; sourceTree = "<group>"; };
DADB4EC619C66FB60065A78D /* MPUserEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUserEntity.m; sourceTree = "<group>"; };
DADB4EC819C66FB60065A78D /* MPElementEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementEntity.h; sourceTree = "<group>"; };
DADB4EC919C66FB60065A78D /* MPElementEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementEntity.m; sourceTree = "<group>"; };
DADB4ECB19C66FB60065A78D /* MPElementGeneratedEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementGeneratedEntity.h; sourceTree = "<group>"; };
DADB4ECC19C66FB60065A78D /* MPElementGeneratedEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementGeneratedEntity.m; sourceTree = "<group>"; };
DADB4ECE19C66FB60065A78D /* MPElementStoredEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementStoredEntity.h; sourceTree = "<group>"; };
DADB4ECF19C66FB70065A78D /* MPElementStoredEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementStoredEntity.m; sourceTree = "<group>"; };
DADBB55918DB0CFC00D099FE /* keyboard-dark@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "keyboard-dark@2x.png"; sourceTree = "<group>"; };
DAE1EF2317E942DE00BC0086 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
DAE2725B19CA98A5007C5262 /* thumb_advanced_export.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thumb_advanced_export.png; sourceTree = "<group>"; };
DAE2725C19CA98A5007C5262 /* thumb_advanced_export@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_advanced_export@2x.png"; sourceTree = "<group>"; };
DAE2725D19CA98A5007C5262 /* thumb_advanced_export@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_advanced_export@3x.png"; sourceTree = "<group>"; };
DAE2726119CE9CB3007C5262 /* UITableViewCell+PearlDeque.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableViewCell+PearlDeque.m"; sourceTree = "<group>"; };
DAE2726219CE9CB3007C5262 /* UITableViewCell+PearlDeque.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableViewCell+PearlDeque.h"; sourceTree = "<group>"; };
DAE8E65119867AB500416A0F /* libopensslcrypto-ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopensslcrypto-ios.a"; sourceTree = "<group>"; };
DAEBC45214F6364500987BF6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Touches.m"; sourceTree = "<group>"; };
@ -1473,6 +1481,8 @@
DA5BFA45147E415C00F98B1E /* Products */,
93D39149A5F1F9B174D6D061 /* MPStoreViewController.h */,
93D3957D76F71A652716EECC /* MPStoreViewController.m */,
93D39C426E03358384018E85 /* MPAnswersViewController.m */,
93D39D6604447D7708039155 /* MPAnswersViewController.h */,
);
sourceTree = "<group>";
};
@ -1553,6 +1563,9 @@
DABD360D1711E29400CF925C /* Media */ = {
isa = PBXGroup;
children = (
DAE2725B19CA98A5007C5262 /* thumb_advanced_export.png */,
DAE2725C19CA98A5007C5262 /* thumb_advanced_export@2x.png */,
DAE2725D19CA98A5007C5262 /* thumb_advanced_export@3x.png */,
DA29993119C9132F00AF7DF1 /* thumb_generated_login@3x.png */,
DA29992D19C86F5700AF7DF1 /* thumb_generated_login@2x.png */,
DA29992E19C86F5700AF7DF1 /* thumb_generated_login.png */,
@ -2257,14 +2270,6 @@
isa = PBXGroup;
children = (
DABD3BD71711E2DC00CF925C /* iOS */,
DADB4ECE19C66FB60065A78D /* MPElementStoredEntity.h */,
DADB4ECF19C66FB70065A78D /* MPElementStoredEntity.m */,
DADB4ECB19C66FB60065A78D /* MPElementGeneratedEntity.h */,
DADB4ECC19C66FB60065A78D /* MPElementGeneratedEntity.m */,
DADB4EC819C66FB60065A78D /* MPElementEntity.h */,
DADB4EC919C66FB60065A78D /* MPElementEntity.m */,
DADB4EC519C66FB50065A78D /* MPUserEntity.h */,
DADB4EC619C66FB60065A78D /* MPUserEntity.m */,
DABD3BA01711E2DC00CF925C /* MPAlgorithm.h */,
DABD3BA11711E2DC00CF925C /* MPAlgorithm.m */,
DABD3BA21711E2DC00CF925C /* MPAlgorithmV0.h */,
@ -2279,20 +2284,22 @@
DABD3BAB1711E2DC00CF925C /* MPAppDelegate_Store.m */,
DABD3BAC1711E2DC00CF925C /* MPConfig.h */,
DABD3BAD1711E2DC00CF925C /* MPConfig.m */,
DABD3BAE1711E2DC00CF925C /* MPElementEntity.h */,
DABD3BAF1711E2DC00CF925C /* MPElementEntity.m */,
DABD3BB01711E2DC00CF925C /* MPElementGeneratedEntity.h */,
DABD3BB11711E2DC00CF925C /* MPElementGeneratedEntity.m */,
DABD3BB21711E2DC00CF925C /* MPElementStoredEntity.h */,
DABD3BB31711E2DC00CF925C /* MPElementStoredEntity.m */,
DABD3BB41711E2DC00CF925C /* MPEntities.h */,
DABD3BB51711E2DC00CF925C /* MPEntities.m */,
DABD3BB61711E2DC00CF925C /* MPKey.h */,
DABD3BB71711E2DC00CF925C /* MPKey.m */,
DABD3BB81711E2DC00CF925C /* MPTypes.h */,
DABD3BB91711E2DC00CF925C /* MPUserEntity.h */,
DABD3BBA1711E2DC00CF925C /* MPUserEntity.m */,
DABD3BD01711E2DC00CF925C /* MasterPassword.xcdatamodeld */,
DA9521AC19CEA3DE002E3AD5 /* MPSiteStoredEntity.h */,
DA9521AF19CEA3DE002E3AD5 /* MPUserEntity.h */,
DA9521B019CEA3DE002E3AD5 /* MPUserEntity.m */,
DA9521AD19CEA3DE002E3AD5 /* MPSiteStoredEntity.m */,
DA9521B219CEA3DE002E3AD5 /* MPSiteGeneratedEntity.h */,
DA9521B319CEA3DE002E3AD5 /* MPSiteGeneratedEntity.m */,
DA9521A919CEA3DE002E3AD5 /* MPSiteQuestion.h */,
DA9521AA19CEA3DE002E3AD5 /* MPSiteQuestion.m */,
DA9521A619CEA3DE002E3AD5 /* MPSiteEntity.h */,
DA9521A719CEA3DE002E3AD5 /* MPSiteEntity.m */,
93D399F244BB522A317811BB /* MPFixable.h */,
93D39A813CA9D7E192261ED2 /* MPFixable.m */,
93D394C78C7B879C9AD9152C /* MPAppDelegate_InApp.m */,
@ -2589,6 +2596,8 @@
DAFE460715039823003ABA7C /* Pearl-UIKit */ = {
isa = PBXGroup;
children = (
DAE2726119CE9CB3007C5262 /* UITableViewCell+PearlDeque.m */,
DAE2726219CE9CB3007C5262 /* UITableViewCell+PearlDeque.h */,
DAEFB01C19BCBD9E00525079 /* UIView+LayoutGone.m */,
DAEFB01D19BCBD9E00525079 /* UIView+LayoutGone.h */,
DACE2F6719BA6A2A0010F92E /* UIView+FontScale.m */,
@ -2725,6 +2734,7 @@
DAFE4A3415039824003ABA7C /* PearlCryptUtils.h in Headers */,
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
DAFE4A3815039824003ABA7C /* PearlRSAKey.h in Headers */,
DAE2726419CE9CB3007C5262 /* UITableViewCell+PearlDeque.h in Headers */,
DAFE4A3A15039824003ABA7C /* PearlSCrypt.h in Headers */,
DACE2F6E19BA6A2A0010F92E /* UIView+FontScale.h in Headers */,
DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */,
@ -3071,6 +3081,7 @@
DA250A031956484D00AC23F1 /* image-7@2x.png in Resources */,
DA25C5FA197CCAE00046CDCF /* icon_delete.png in Resources */,
DA25C601197DBF260046CDCF /* icon_trash@2x.png in Resources */,
DAE2725E19CA98A5007C5262 /* thumb_advanced_export.png in Resources */,
DABD39551711E29700CF925C /* avatar-6.png in Resources */,
DABD39561711E29700CF925C /* avatar-6@2x.png in Resources */,
DABD39571711E29700CF925C /* avatar-7.png in Resources */,
@ -3092,6 +3103,7 @@
DABD39881711E29700CF925C /* SourceCodePro-ExtraLight.otf in Resources */,
DABD39A01711E29700CF925C /* icon_action.png in Resources */,
DABD39A11711E29700CF925C /* icon_action@2x.png in Resources */,
DAE2726019CA98A5007C5262 /* thumb_advanced_export@3x.png in Resources */,
DABD39F21711E29700CF925C /* icon_cancel.png in Resources */,
DA25C5FB197CCAE00046CDCF /* icon_delete@2x.png in Resources */,
DA29993219C9132F00AF7DF1 /* thumb_generated_login@3x.png in Resources */,
@ -3106,6 +3118,7 @@
DABD3AA01711E29800CF925C /* icon_pause.png in Resources */,
DABD3AA11711E29800CF925C /* icon_pause@2x.png in Resources */,
DABD3AAA1711E29800CF925C /* icon_person.png in Resources */,
DAE2725F19CA98A5007C5262 /* thumb_advanced_export@2x.png in Resources */,
DABD3AAB1711E29800CF925C /* icon_person@2x.png in Resources */,
DABD3ABC1711E29800CF925C /* icon_play.png in Resources */,
DABD3ABD1711E29800CF925C /* icon_play@2x.png in Resources */,
@ -3209,19 +3222,19 @@
DABD3C081711E2DC00CF925C /* MPKey.m in Sources */,
DABD3C141711E2DC00CF925C /* MasterPassword.xcdatamodeld in Sources */,
DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */,
DA9521A819CEA3DE002E3AD5 /* MPSiteEntity.m in Sources */,
DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */,
DABD3C1E1711E2DC00CF925C /* MPPreferencesViewController.m in Sources */,
DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */,
DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */,
DABD3C271711E2DC00CF925C /* main.m in Sources */,
DADB4EC719C66FB60065A78D /* MPUserEntity.m in Sources */,
93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */,
DA9521AE19CEA3DE002E3AD5 /* MPSiteStoredEntity.m in Sources */,
DA095E75172F4CD8001C948B /* MPLogsViewController.m in Sources */,
93D39D596A2E376D6F6F5DA1 /* MPCombinedViewController.m in Sources */,
DADB4ECD19C66FB60065A78D /* MPElementGeneratedEntity.m in Sources */,
93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */,
93D39B8F90F58A5D158DDBA3 /* MPPasswordsViewController.m in Sources */,
DADB4ED019C66FB70065A78D /* MPElementStoredEntity.m in Sources */,
DA9521B419CEA3DE002E3AD5 /* MPSiteGeneratedEntity.m in Sources */,
93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */,
93D39392DEDA376F93C6C718 /* MPCell.m in Sources */,
93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */,
@ -3231,9 +3244,9 @@
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */,
93D39BA1EA3CAAC8A220B4A6 /* MPAppSettingsViewController.m in Sources */,
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */,
DADB4ECA19C66FB60065A78D /* MPElementEntity.m in Sources */,
93D39EAA4D064193074D3021 /* MPFixable.m in Sources */,
93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */,
DA9521B119CEA3DE002E3AD5 /* MPUserEntity.m in Sources */,
93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */,
93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */,
DA9521AB19CEA3DE002E3AD5 /* MPSiteQuestion.m in Sources */,
@ -3290,6 +3303,7 @@
DAFE4A4715039824003ABA7C /* PearlLayout.m in Sources */,
DA250A19195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m in Sources */,
DAFE4A4915039824003ABA7C /* PearlLayoutView.m in Sources */,
DAE2726319CE9CB3007C5262 /* UITableViewCell+PearlDeque.m in Sources */,
DAFE4A4B15039824003ABA7C /* PearlMessageView.m in Sources */,
DACE2F6519BA6A0A0010F92E /* PearlProfiler.m in Sources */,
DAFE4A4D15039824003ABA7C /* PearlRootViewController.m in Sources */,

View File

@ -26,6 +26,9 @@
<string>Exo2.0-Bold</string>
<string>Exo2.0-Bold</string>
<string>Exo2.0-Bold</string>
<string>Exo2.0-Bold</string>
<string>Exo2.0-Bold</string>
<string>Exo2.0-Bold</string>
</mutableArray>
<mutableArray key="Exo2.0-ExtraBold.otf">
<string>Exo2.0-ExtraBold</string>
@ -64,6 +67,7 @@
<string>Exo2.0-Regular</string>
<string>Exo2.0-Regular</string>
<string>Exo2.0-Regular</string>
<string>Exo2.0-Regular</string>
</mutableArray>
<mutableArray key="Exo2.0-Thin.otf">
<string>Exo2.0-Thin</string>
@ -82,11 +86,15 @@
<string>Exo2.0-Thin</string>
<string>Exo2.0-Thin</string>
<string>Exo2.0-Thin</string>
<string>Exo2.0-Thin</string>
<string>Exo2.0-Thin</string>
</mutableArray>
<mutableArray key="SourceCodePro-Black.otf">
<string>SourceCodePro-Black</string>
<string>SourceCodePro-Black</string>
<string>SourceCodePro-Black</string>
<string>SourceCodePro-Black</string>
<string>SourceCodePro-Black</string>
</mutableArray>
<mutableArray key="SourceCodePro-ExtraLight.otf">
<string>SourceCodePro-ExtraLight</string>
@ -581,7 +589,7 @@
</tabBarController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4Z1-Y7-eUn" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1408.5" y="1319.5"/>
<point key="canvasLocation" x="2016.5" y="1319.5"/>
</scene>
<!--Preferences-->
<scene sceneID="w0h-au-0xw">
@ -1035,7 +1043,7 @@
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="fk3-aq-W8p" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2016.5" y="2175.5"/>
<point key="canvasLocation" x="2624.5" y="2175.5"/>
</scene>
<!--Passwords View Controller-->
<scene sceneID="I40-Es-1gK">
@ -1575,6 +1583,7 @@
<outlet property="popdownToTopConstraint" destination="BdD-Kc-eHl" id="59Y-ap-Yn4"/>
<outlet property="popdownView" destination="XNM-XQ-rMe" id="FaW-4m-Fff"/>
<segue destination="z9O-w0-6oR" kind="modal" identifier="guide" id="Ql4-wf-T8u"/>
<segue destination="koB-V2-GYf" kind="modal" identifier="answers" id="PbR-2r-Ebm"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="APh-u5-vFI" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -1864,7 +1873,7 @@
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="PQz-c8-3Ww" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2016.5" y="1319.5"/>
<point key="canvasLocation" x="2624.5" y="1319.5"/>
</scene>
<!--Settings-->
<scene sceneID="fmc-CS-nuo">
@ -1899,7 +1908,7 @@
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="sDE-fE-FNc" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2656.5" y="1319.5"/>
<point key="canvasLocation" x="3264.5" y="1319.5"/>
</scene>
<!--Usage-->
<scene sceneID="9SY-7D-CE9">
@ -2099,7 +2108,7 @@ Suspendisse potenti. Etiam ut nisi id augue tempor ultrices et sit amet sapien.
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="SoG-sw-ghb" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1408.5" y="2175.5"/>
<point key="canvasLocation" x="2016.5" y="2175.5"/>
</scene>
<!--Pearl Navigation Controller-->
<scene sceneID="rfj-6W-TSu">
@ -2550,7 +2559,7 @@ See </string>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="thumb_generated_login.png" translatesAutoresizingMaskIntoConstraints="NO" id="dPE-KG-tzV">
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="thumb_advanced_export.png" translatesAutoresizingMaskIntoConstraints="NO" id="dPE-KG-tzV">
<rect key="frame" x="88" y="20" width="198" height="198"/>
</imageView>
<activityIndicatorView hidden="YES" opaque="NO" tag="2" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="27T-E7-pLh">
@ -2787,7 +2796,182 @@ See </string>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="WvF-bk-cgx" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2016.5" y="442.5"/>
<point key="canvasLocation" x="2624.5" y="463.5"/>
</scene>
<!--Preferences-->
<scene sceneID="u8w-6D-Zhe">
<objects>
<tableViewController automaticallyAdjustsScrollViewInsets="NO" id="koB-V2-GYf" customClass="MPAnswersViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="vKY-AK-ugj" customClass="MPTableView">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/>
<inset key="scrollIndicatorInsets" minX="0.0" minY="64" maxX="0.0" maxY="49"/>
<color key="separatorColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPGlobalAnswersCell" rowHeight="133" id="DT2-Vb-uXj" userLabel="Global Answer" customClass="MPGlobalAnswersCell">
<rect key="frame" x="0.0" y="0.0" width="320" height="97"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="DT2-Vb-uXj" id="URA-cl-MJP">
<rect key="frame" x="0.0" y="0.0" width="287" height="96"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="Answer for lyndir.com:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Tal-1I-HQw" userLabel="Title Label">
<rect key="frame" x="8" y="8" width="180" height="20.5"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="hok petwuvaqu xixo" textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="GfC-j4-Qx7" userLabel="Answer Field">
<rect key="frame" x="8" y="48" width="359" height="43"/>
<color key="textColor" red="0.40000000600000002" green="0.80000001190000003" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" name="SourceCodePro-Black" family="Source Code Pro" pointSize="24"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="alphabet" keyboardAppearance="alert" returnKeyType="next"/>
<connections>
<action selector="textFieldDidChange:" destination="W2g-yv-V3V" eventType="editingChanged" id="fY9-xg-DPG"/>
<outlet property="delegate" destination="W2g-yv-V3V" id="TeI-f1-KlA"/>
</connections>
</textField>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Use this as the answer for each of the security questions on this site." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EUe-A5-H8h">
<rect key="frame" x="8" y="99" width="359" height="13.5"/>
<fontDescription key="fontDescription" name="Exo2.0-Thin" family="Exo 2.0" pointSize="11"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="EUe-A5-H8h" secondAttribute="trailing" constant="8" id="076-4e-NlP"/>
<constraint firstItem="GfC-j4-Qx7" firstAttribute="top" secondItem="Tal-1I-HQw" secondAttribute="bottom" constant="20" id="A4A-ds-Uc4"/>
<constraint firstAttribute="bottom" secondItem="EUe-A5-H8h" secondAttribute="bottom" constant="20" symbolic="YES" id="AKM-6g-fhT"/>
<constraint firstItem="GfC-j4-Qx7" firstAttribute="leading" secondItem="URA-cl-MJP" secondAttribute="leading" constant="8" id="JHy-eG-ckd"/>
<constraint firstAttribute="trailing" secondItem="GfC-j4-Qx7" secondAttribute="trailing" constant="8" id="NAP-0S-Vda"/>
<constraint firstItem="Tal-1I-HQw" firstAttribute="leading" secondItem="URA-cl-MJP" secondAttribute="leading" constant="8" id="Udh-0D-wR7"/>
<constraint firstItem="EUe-A5-H8h" firstAttribute="leading" secondItem="URA-cl-MJP" secondAttribute="leading" constant="8" id="pEG-lI-KQN"/>
<constraint firstItem="Tal-1I-HQw" firstAttribute="top" secondItem="URA-cl-MJP" secondAttribute="top" constant="8" id="x6h-mG-HZ4"/>
<constraint firstItem="EUe-A5-H8h" firstAttribute="top" secondItem="GfC-j4-Qx7" secondAttribute="bottom" constant="8" symbolic="YES" id="xLP-uA-9z2"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<connections>
<outlet property="answerField" destination="GfC-j4-Qx7" id="egp-cZ-E1x"/>
<outlet property="titleLabel" destination="Tal-1I-HQw" id="9s2-2n-cB4"/>
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPSendAnswersCell" rowHeight="44" id="tvm-WZ-MDZ" userLabel="Send Answers" customClass="MPSendAnswersCell">
<rect key="frame" x="0.0" y="0.0" width="320" height="97"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tvm-WZ-MDZ" id="BTm-Lm-V9p">
<rect key="frame" x="0.0" y="0.0" width="287" height="96"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="Send the answer(s) to my email" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AAV-yg-dfK">
<rect key="frame" x="8" y="8" width="326" height="27.5"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="AAV-yg-dfK" secondAttribute="bottom" constant="8" id="LJV-LG-n0h"/>
<constraint firstAttribute="trailing" secondItem="AAV-yg-dfK" secondAttribute="trailing" constant="8" id="NBf-3q-dHH"/>
<constraint firstItem="AAV-yg-dfK" firstAttribute="leading" secondItem="BTm-Lm-V9p" secondAttribute="leading" constant="8" id="WpS-gx-b0s"/>
<constraint firstItem="AAV-yg-dfK" firstAttribute="top" secondItem="BTm-Lm-V9p" secondAttribute="top" constant="8" id="t5X-Jg-8Ai"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="checkmark" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPMultipleAnswersCell" rowHeight="44" id="5MB-qb-oPk" userLabel="Multiple Answers" customClass="MPMultipleAnswersCell">
<rect key="frame" x="0.0" y="0.0" width="320" height="97"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="5MB-qb-oPk" id="4wX-xO-9QU">
<rect key="frame" x="0.0" y="0.0" width="287" height="96"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="This site needs different answers for each question" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="een-0g-CMy">
<rect key="frame" x="8" y="8" width="320" height="27.5"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="een-0g-CMy" firstAttribute="top" secondItem="4wX-xO-9QU" secondAttribute="top" constant="8" id="9ZQ-yN-0jZ"/>
<constraint firstAttribute="bottom" secondItem="een-0g-CMy" secondAttribute="bottom" constant="8" id="JTE-x8-fAk"/>
<constraint firstAttribute="trailing" secondItem="een-0g-CMy" secondAttribute="trailing" constant="8" id="LMQ-CT-XDx"/>
<constraint firstItem="een-0g-CMy" firstAttribute="leading" secondItem="4wX-xO-9QU" secondAttribute="leading" constant="8" id="w3c-zJ-Mbm"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPAnswersQuestionCell" rowHeight="130" id="iFm-3w-hOv" userLabel="Question" customClass="MPAnswersQuestionCell">
<rect key="frame" x="0.0" y="0.0" width="320" height="97"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="iFm-3w-hOv" id="X5d-5g-uJa">
<rect key="frame" x="0.0" y="0.0" width="287" height="96"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="mother" textAlignment="center" minimumFontSize="14" clearButtonMode="unlessEditing" translatesAutoresizingMaskIntoConstraints="NO" id="T2F-PD-Nw8" userLabel="Question Field">
<rect key="frame" x="8" y="19" width="359" height="30"/>
<color key="backgroundColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="0.5" colorSpace="calibratedRGB"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="28"/>
<textInputTraits key="textInputTraits" keyboardType="namePhonePad" keyboardAppearance="alert" returnKeyType="done"/>
<connections>
<outlet property="delegate" destination="S8q-YF-Kt9" id="TtZ-rC-HTB"/>
</connections>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="pifm gup balvabi yiz" textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="3xA-ez-efa" userLabel="Answer Field">
<rect key="frame" x="20" y="90.5" width="335" height="31"/>
<color key="textColor" red="0.40000000600000002" green="0.80000001190000003" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" name="SourceCodePro-Black" family="Source Code Pro" pointSize="24"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="alphabet" keyboardAppearance="alert" returnKeyType="next"/>
<connections>
<action selector="textFieldDidChange:" destination="W2g-yv-V3V" eventType="editingChanged" id="nFl-TF-gF7"/>
<outlet property="delegate" destination="W2g-yv-V3V" id="U4z-82-k15"/>
</connections>
</textField>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Enter the single most significant word in the question above." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qqg-Ny-7Po">
<rect key="frame" x="8" y="57" width="359" height="13.5"/>
<fontDescription key="fontDescription" name="Exo2.0-Thin" family="Exo 2.0" pointSize="11"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="3xA-ez-efa" firstAttribute="leading" secondItem="X5d-5g-uJa" secondAttribute="leading" constant="20" symbolic="YES" id="01X-Q1-hbE"/>
<constraint firstAttribute="bottom" secondItem="3xA-ez-efa" secondAttribute="bottom" constant="8" id="7lO-8k-3xJ"/>
<constraint firstItem="3xA-ez-efa" firstAttribute="top" secondItem="Qqg-Ny-7Po" secondAttribute="bottom" constant="20" id="MnT-on-L2d"/>
<constraint firstItem="Qqg-Ny-7Po" firstAttribute="top" secondItem="T2F-PD-Nw8" secondAttribute="bottom" constant="8" id="Xla-SS-lW7"/>
<constraint firstItem="T2F-PD-Nw8" firstAttribute="leading" secondItem="X5d-5g-uJa" secondAttribute="leading" constant="8" id="YAl-Zz-fp3"/>
<constraint firstAttribute="trailing" secondItem="3xA-ez-efa" secondAttribute="trailing" constant="20" symbolic="YES" id="YSK-xt-QtB"/>
<constraint firstAttribute="trailing" secondItem="Qqg-Ny-7Po" secondAttribute="trailing" constant="8" id="ZKi-Kb-iF2"/>
<constraint firstItem="Qqg-Ny-7Po" firstAttribute="leading" secondItem="X5d-5g-uJa" secondAttribute="leading" constant="8" id="o3h-oy-hyw"/>
<constraint firstAttribute="trailing" secondItem="T2F-PD-Nw8" secondAttribute="trailing" constant="8" id="tCL-PD-pms"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<connections>
<outlet property="answerField" destination="3xA-ez-efa" id="xob-uu-1u7"/>
<outlet property="questionField" destination="T2F-PD-Nw8" id="Ekp-t8-Hli"/>
</connections>
</tableViewCell>
</prototypes>
<sections/>
<connections>
<outlet property="dataSource" destination="koB-V2-GYf" id="fwt-DL-nza"/>
<outlet property="delegate" destination="koB-V2-GYf" id="dJF-bd-2ux"/>
</connections>
</tableView>
<tabBarItem key="tabBarItem" title="Preferences" image="icon_person.png" id="GwN-2X-LQ6"/>
<nil key="simulatedStatusBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<connections>
<outlet property="showHelpCell" destination="5MB-qb-oPk" id="7Db-6P-bBY"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="kXh-18-fq5" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1408.5" y="2175.5"/>
</scene>
</scenes>
<resources>
@ -2807,6 +2991,7 @@ See </string>
<image name="icon_up.png" width="32" height="32"/>
<image name="identity.png" width="82" height="80"/>
<image name="image-0.png" width="320" height="568"/>
<image name="thumb_advanced_export.png" width="198" height="198"/>
<image name="thumb_generated_login.png" width="198" height="198"/>
<image name="tip_basic_black.png" width="210" height="60"/>
<image name="ui_spinner.png" width="75" height="75"/>

View File

@ -2,7 +2,7 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>MPElementGeneratedEntity</key>
<key>MPSiteGeneratedEntity</key>
<dict>
<key>Login Name</key>
<array>