Element -> Site
This commit is contained in:
parent
b3a0b6a7c0
commit
5b85ba3a4b
@ -16,8 +16,8 @@
|
||||
//
|
||||
|
||||
#import "MPKey.h"
|
||||
#import "MPSiteStoredEntity.h"
|
||||
#import "MPSiteGeneratedEntity.h"
|
||||
#import "MPStoredSiteEntity.h"
|
||||
#import "MPGeneratedSiteEntity.h"
|
||||
|
||||
#define MPAlgorithmDefaultVersion 1
|
||||
#define MPAlgorithmDefault MPAlgorithmForVersion(MPAlgorithmDefaultVersion)
|
||||
@ -66,8 +66,8 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack);
|
||||
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
|
||||
variant:(MPSiteVariant)variant usingKey:(MPKey *)key;
|
||||
|
||||
- (NSString *)storedLoginForSite:(MPSiteStoredEntity *)site usingKey:(MPKey *)key;
|
||||
- (NSString *)storedPasswordForSite:(MPSiteStoredEntity *)site usingKey:(MPKey *)key;
|
||||
- (NSString *)storedLoginForSite:(MPStoredSiteEntity *)site usingKey:(MPKey *)key;
|
||||
- (NSString *)storedPasswordForSite:(MPStoredSiteEntity *)site usingKey:(MPKey *)key;
|
||||
|
||||
- (BOOL)savePassword:(NSString *)clearPassword toSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
|
||||
|
||||
|
@ -77,35 +77,35 @@
|
||||
NSError *error = nil;
|
||||
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) {
|
||||
err( @"While looking for elements to migrate: %@", error );
|
||||
NSArray *migrationSites = [moc executeFetchRequest:migrationRequest error:&error];
|
||||
if (!migrationSites) {
|
||||
err( @"While looking for sites to migrate: %@", error );
|
||||
return NO;
|
||||
}
|
||||
|
||||
BOOL requiresExplicitMigration = NO;
|
||||
for (MPSiteEntity *migrationElement in migrationElements)
|
||||
if (![migrationElement migrateExplicitly:NO])
|
||||
for (MPSiteEntity *migrationSite in migrationSites)
|
||||
if (![migrationSite migrateExplicitly:NO])
|
||||
requiresExplicitMigration = YES;
|
||||
|
||||
return requiresExplicitMigration;
|
||||
}
|
||||
|
||||
- (BOOL)migrateSite:(MPSiteEntity *)element explicit:(BOOL)explicit {
|
||||
- (BOOL)migrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit {
|
||||
|
||||
if (element.version != [self version] - 1)
|
||||
if (site.version != [self version] - 1)
|
||||
// Only migrate from previous version.
|
||||
return NO;
|
||||
|
||||
if (!explicit) {
|
||||
// This migration requires explicit permission.
|
||||
element.requiresExplicitMigration = YES;
|
||||
site.requiresExplicitMigration = YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Apply migration.
|
||||
element.requiresExplicitMigration = NO;
|
||||
element.version = [self version];
|
||||
site.requiresExplicitMigration = NO;
|
||||
site.version = [self version];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -242,34 +242,34 @@
|
||||
|
||||
switch (type) {
|
||||
case MPSiteTypeGeneratedMaximum:
|
||||
return [MPElementGeneratedEntity class];
|
||||
return [MPGeneratedSiteEntity class];
|
||||
|
||||
case MPSiteTypeGeneratedLong:
|
||||
return [MPElementGeneratedEntity class];
|
||||
return [MPGeneratedSiteEntity class];
|
||||
|
||||
case MPSiteTypeGeneratedMedium:
|
||||
return [MPElementGeneratedEntity class];
|
||||
return [MPGeneratedSiteEntity class];
|
||||
|
||||
case MPSiteTypeGeneratedBasic:
|
||||
return [MPElementGeneratedEntity class];
|
||||
return [MPGeneratedSiteEntity class];
|
||||
|
||||
case MPSiteTypeGeneratedShort:
|
||||
return [MPElementGeneratedEntity class];
|
||||
return [MPGeneratedSiteEntity class];
|
||||
|
||||
case MPSiteTypeGeneratedPIN:
|
||||
return [MPElementGeneratedEntity class];
|
||||
return [MPGeneratedSiteEntity class];
|
||||
|
||||
case MPSiteTypeGeneratedName:
|
||||
return [MPElementGeneratedEntity class];
|
||||
return [MPGeneratedSiteEntity class];
|
||||
|
||||
case MPSiteTypeGeneratedPhrase:
|
||||
return [MPElementGeneratedEntity class];
|
||||
return [MPGeneratedSiteEntity class];
|
||||
|
||||
case MPSiteTypeStoredPersonal:
|
||||
return [MPSiteStoredEntity class];
|
||||
return [MPStoredSiteEntity class];
|
||||
|
||||
case MPSiteTypeStoredDevicePrivate:
|
||||
return [MPSiteStoredEntity class];
|
||||
return [MPStoredSiteEntity class];
|
||||
}
|
||||
|
||||
Throw( @"Type not supported: %lu", (long)type );
|
||||
@ -413,20 +413,20 @@
|
||||
return content;
|
||||
}
|
||||
|
||||
- (NSString *)storedLoginForSite:(MPSiteStoredEntity *)element usingKey:(MPKey *)key {
|
||||
- (NSString *)storedLoginForSite:(MPStoredSiteEntity *)site usingKey:(MPKey *)key {
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)storedPasswordForSite:(MPSiteStoredEntity *)element usingKey:(MPKey *)key {
|
||||
- (NSString *)storedPasswordForSite:(MPStoredSiteEntity *)site usingKey:(MPKey *)key {
|
||||
|
||||
return [self decryptContent:element.contentObject usingKey:key];
|
||||
return [self decryptContent:site.contentObject usingKey:key];
|
||||
}
|
||||
|
||||
- (BOOL)savePassword:(NSString *)clearContent toSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
|
||||
- (BOOL)savePassword:(NSString *)clearContent toSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
|
||||
|
||||
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
|
||||
switch (element.type) {
|
||||
NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
|
||||
switch (site.type) {
|
||||
case MPSiteTypeGeneratedMaximum:
|
||||
case MPSiteTypeGeneratedLong:
|
||||
case MPSiteTypeGeneratedMedium:
|
||||
@ -435,58 +435,58 @@
|
||||
case MPSiteTypeGeneratedPIN:
|
||||
case MPSiteTypeGeneratedName:
|
||||
case MPSiteTypeGeneratedPhrase: {
|
||||
wrn( @"Cannot save content to element with generated type %lu.", (long)element.type );
|
||||
wrn( @"Cannot save content to site with generated type %lu.", (long)site.type );
|
||||
return NO;
|
||||
}
|
||||
|
||||
case MPSiteTypeStoredPersonal: {
|
||||
if (![element isKindOfClass:[MPSiteStoredEntity class]]) {
|
||||
wrn( @"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.",
|
||||
(long)element.type, [element class] );
|
||||
if (![site isKindOfClass:[MPStoredSiteEntity class]]) {
|
||||
wrn( @"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.",
|
||||
(long)site.type, [site class] );
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
|
||||
encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
||||
if ([((MPSiteStoredEntity *)element).contentObject isEqualToData:encryptedContent])
|
||||
encryptWithSymmetricKey:[siteKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
||||
if ([((MPStoredSiteEntity *)site).contentObject isEqualToData:encryptedContent])
|
||||
return NO;
|
||||
|
||||
((MPSiteStoredEntity *)element).contentObject = encryptedContent;
|
||||
((MPStoredSiteEntity *)site).contentObject = encryptedContent;
|
||||
return YES;
|
||||
}
|
||||
case MPSiteTypeStoredDevicePrivate: {
|
||||
if (![element isKindOfClass:[MPSiteStoredEntity class]]) {
|
||||
wrn( @"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.",
|
||||
(long)element.type, [element class] );
|
||||
if (![site isKindOfClass:[MPStoredSiteEntity class]]) {
|
||||
wrn( @"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.",
|
||||
(long)site.type, [site class] );
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
|
||||
encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
||||
NSDictionary *elementQuery = [self queryForDevicePrivateElementNamed:element.name];
|
||||
encryptWithSymmetricKey:[siteKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
||||
NSDictionary *siteQuery = [self queryForDevicePrivateSiteNamed:site.name];
|
||||
if (!encryptedContent)
|
||||
[PearlKeyChain deleteItemForQuery:elementQuery];
|
||||
[PearlKeyChain deleteItemForQuery:siteQuery];
|
||||
else
|
||||
[PearlKeyChain addOrUpdateItemForQuery:elementQuery withAttributes:@{
|
||||
[PearlKeyChain addOrUpdateItemForQuery:siteQuery withAttributes:@{
|
||||
(__bridge id)kSecValueData : encryptedContent,
|
||||
#if TARGET_OS_IPHONE
|
||||
(__bridge id)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
|
||||
#endif
|
||||
}];
|
||||
((MPSiteStoredEntity *)element).contentObject = nil;
|
||||
((MPStoredSiteEntity *)site).contentObject = nil;
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
Throw( @"Unsupported type: %ld", (long)element.type );
|
||||
Throw( @"Unsupported type: %ld", (long)site.type );
|
||||
}
|
||||
|
||||
- (NSString *)resolveLoginForSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
|
||||
- (NSString *)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
|
||||
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
dispatch_group_enter( group );
|
||||
__block NSString *result = nil;
|
||||
[self resolveLoginForSite:element usingKey:elementKey result:^(NSString *result_) {
|
||||
[self resolveLoginForSite:site usingKey:siteKey result:^(NSString *result_) {
|
||||
result = result_;
|
||||
dispatch_group_leave( group );
|
||||
}];
|
||||
@ -495,12 +495,12 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSString *)resolvePasswordForSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
|
||||
- (NSString *)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
|
||||
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
dispatch_group_enter( group );
|
||||
__block NSString *result = nil;
|
||||
[self resolvePasswordForSite:element usingKey:elementKey result:^(NSString *result_) {
|
||||
[self resolvePasswordForSite:site usingKey:siteKey result:^(NSString *result_) {
|
||||
result = result_;
|
||||
dispatch_group_leave( group );
|
||||
}];
|
||||
@ -509,32 +509,32 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)resolveLoginForSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey result:(void ( ^ )(NSString *result))resultBlock {
|
||||
- (void)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock {
|
||||
|
||||
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
|
||||
NSString *name = element.name;
|
||||
BOOL loginGenerated = element.loginGenerated && [[MPAppDelegate_Shared get] isPurchased:MPProductGenerateLogins];
|
||||
NSString *loginName = loginGenerated? nil: element.loginName;
|
||||
NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
|
||||
NSString *name = site.name;
|
||||
BOOL loginGenerated = site.loginGenerated && [[MPAppDelegate_Shared get] isPurchased:MPProductGenerateLogins];
|
||||
NSString *loginName = loginGenerated? nil: site.loginName;
|
||||
id<MPAlgorithm> algorithm = nil;
|
||||
if (!name.length)
|
||||
err( @"Missing name." );
|
||||
else if (!elementKey.keyData.length)
|
||||
else if (!siteKey.keyData.length)
|
||||
err( @"Missing key." );
|
||||
else
|
||||
algorithm = element.algorithm;
|
||||
algorithm = site.algorithm;
|
||||
|
||||
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
|
||||
if (loginGenerated)
|
||||
resultBlock( [algorithm generateLoginForSiteNamed:name usingKey:elementKey] );
|
||||
resultBlock( [algorithm generateLoginForSiteNamed:name usingKey:siteKey] );
|
||||
else
|
||||
resultBlock( loginName );
|
||||
} );
|
||||
}
|
||||
|
||||
- (void)resolvePasswordForSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey result:(void ( ^ )(NSString *result))resultBlock {
|
||||
- (void)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock {
|
||||
|
||||
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
|
||||
switch (element.type) {
|
||||
NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
|
||||
switch (site.type) {
|
||||
case MPSiteTypeGeneratedMaximum:
|
||||
case MPSiteTypeGeneratedLong:
|
||||
case MPSiteTypeGeneratedMedium:
|
||||
@ -543,55 +543,55 @@
|
||||
case MPSiteTypeGeneratedPIN:
|
||||
case MPSiteTypeGeneratedName:
|
||||
case MPSiteTypeGeneratedPhrase: {
|
||||
if (![element isKindOfClass:[MPElementGeneratedEntity class]]) {
|
||||
wrn( @"Element with generated type %lu is not an MPSiteGeneratedEntity, but a %@.",
|
||||
(long)element.type, [element class] );
|
||||
if (![site isKindOfClass:[MPGeneratedSiteEntity class]]) {
|
||||
wrn( @"Site with generated type %lu is not an MPGeneratedSiteEntity, but a %@.",
|
||||
(long)site.type, [site class] );
|
||||
break;
|
||||
}
|
||||
|
||||
NSString *name = element.name;
|
||||
MPSiteType type = element.type;
|
||||
NSUInteger counter = ((MPElementGeneratedEntity *)element).counter;
|
||||
NSString *name = site.name;
|
||||
MPSiteType type = site.type;
|
||||
NSUInteger counter = ((MPGeneratedSiteEntity *)site).counter;
|
||||
id<MPAlgorithm> algorithm = nil;
|
||||
if (!element.name.length)
|
||||
if (!site.name.length)
|
||||
err( @"Missing name." );
|
||||
else if (!elementKey.keyData.length)
|
||||
else if (!siteKey.keyData.length)
|
||||
err( @"Missing key." );
|
||||
else
|
||||
algorithm = element.algorithm;
|
||||
algorithm = site.algorithm;
|
||||
|
||||
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
|
||||
NSString *result = [algorithm generatePasswordForSiteNamed:name ofType:type withCounter:counter usingKey:elementKey];
|
||||
NSString *result = [algorithm generatePasswordForSiteNamed:name ofType:type withCounter:counter usingKey:siteKey];
|
||||
resultBlock( result );
|
||||
} );
|
||||
break;
|
||||
}
|
||||
|
||||
case MPSiteTypeStoredPersonal: {
|
||||
if (![element isKindOfClass:[MPSiteStoredEntity class]]) {
|
||||
wrn( @"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.",
|
||||
(long)element.type, [element class] );
|
||||
if (![site isKindOfClass:[MPStoredSiteEntity class]]) {
|
||||
wrn( @"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.",
|
||||
(long)site.type, [site class] );
|
||||
break;
|
||||
}
|
||||
|
||||
NSData *encryptedContent = ((MPSiteStoredEntity *)element).contentObject;
|
||||
NSData *encryptedContent = ((MPStoredSiteEntity *)site).contentObject;
|
||||
|
||||
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
|
||||
NSString *result = [self decryptContent:encryptedContent usingKey:elementKey];
|
||||
NSString *result = [self decryptContent:encryptedContent usingKey:siteKey];
|
||||
resultBlock( result );
|
||||
} );
|
||||
break;
|
||||
}
|
||||
case MPSiteTypeStoredDevicePrivate: {
|
||||
NSAssert( [element isKindOfClass:[MPSiteStoredEntity class]],
|
||||
@"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.", (long)element.type,
|
||||
[element class] );
|
||||
NSAssert( [site isKindOfClass:[MPStoredSiteEntity class]],
|
||||
@"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.", (long)site.type,
|
||||
[site class] );
|
||||
|
||||
NSDictionary *elementQuery = [self queryForDevicePrivateElementNamed:element.name];
|
||||
NSData *encryptedContent = [PearlKeyChain dataOfItemForQuery:elementQuery];
|
||||
NSDictionary *siteQuery = [self queryForDevicePrivateSiteNamed:site.name];
|
||||
NSData *encryptedContent = [PearlKeyChain dataOfItemForQuery:siteQuery];
|
||||
|
||||
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
|
||||
NSString *result = [self decryptContent:encryptedContent usingKey:elementKey];
|
||||
NSString *result = [self decryptContent:encryptedContent usingKey:siteKey];
|
||||
resultBlock( result );
|
||||
} );
|
||||
break;
|
||||
@ -600,10 +600,10 @@
|
||||
}
|
||||
|
||||
- (void)importProtectedPassword:(NSString *)protectedContent protectedByKey:(MPKey *)importKey
|
||||
intoSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
|
||||
intoSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
|
||||
|
||||
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
|
||||
switch (element.type) {
|
||||
NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
|
||||
switch (site.type) {
|
||||
case MPSiteTypeGeneratedMaximum:
|
||||
case MPSiteTypeGeneratedLong:
|
||||
case MPSiteTypeGeneratedMedium:
|
||||
@ -615,17 +615,17 @@
|
||||
break;
|
||||
|
||||
case MPSiteTypeStoredPersonal: {
|
||||
if (![element isKindOfClass:[MPSiteStoredEntity class]]) {
|
||||
wrn( @"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.",
|
||||
(long)element.type, [element class] );
|
||||
if (![site isKindOfClass:[MPStoredSiteEntity class]]) {
|
||||
wrn( @"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.",
|
||||
(long)site.type, [site class] );
|
||||
break;
|
||||
}
|
||||
if ([importKey.keyID isEqualToData:elementKey.keyID])
|
||||
((MPSiteStoredEntity *)element).contentObject = [protectedContent decodeBase64];
|
||||
if ([importKey.keyID isEqualToData:siteKey.keyID])
|
||||
((MPStoredSiteEntity *)site).contentObject = [protectedContent decodeBase64];
|
||||
|
||||
else {
|
||||
NSString *clearContent = [self decryptContent:[protectedContent decodeBase64] usingKey:importKey];
|
||||
[self importClearTextPassword:clearContent intoSite:element usingKey:elementKey];
|
||||
[self importClearTextPassword:clearContent intoSite:site usingKey:siteKey];
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -635,10 +635,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)importClearTextPassword:(NSString *)clearContent intoSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
|
||||
- (void)importClearTextPassword:(NSString *)clearContent intoSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
|
||||
|
||||
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
|
||||
switch (element.type) {
|
||||
NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
|
||||
switch (site.type) {
|
||||
case MPSiteTypeGeneratedMaximum:
|
||||
case MPSiteTypeGeneratedLong:
|
||||
case MPSiteTypeGeneratedMedium:
|
||||
@ -650,7 +650,7 @@
|
||||
break;
|
||||
|
||||
case MPSiteTypeStoredPersonal: {
|
||||
[self savePassword:clearContent toSite:element usingKey:elementKey];
|
||||
[self savePassword:clearContent toSite:site usingKey:siteKey];
|
||||
break;
|
||||
}
|
||||
|
||||
@ -659,14 +659,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)exportPasswordForSite:(MPSiteEntity *)element usingKey:(MPKey *)elementKey {
|
||||
- (NSString *)exportPasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
|
||||
|
||||
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
|
||||
if (!(element.type & MPSiteFeatureExportContent))
|
||||
NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
|
||||
if (!(site.type & MPSiteFeatureExportContent))
|
||||
return nil;
|
||||
|
||||
NSString *result = nil;
|
||||
switch (element.type) {
|
||||
switch (site.type) {
|
||||
case MPSiteTypeGeneratedMaximum:
|
||||
case MPSiteTypeGeneratedLong:
|
||||
case MPSiteTypeGeneratedMedium:
|
||||
@ -680,12 +680,12 @@
|
||||
}
|
||||
|
||||
case MPSiteTypeStoredPersonal: {
|
||||
if (![element isKindOfClass:[MPSiteStoredEntity class]]) {
|
||||
wrn( @"Element with stored type %lu is not an MPSiteStoredEntity, but a %@.",
|
||||
(long)element.type, [element class] );
|
||||
if (![site isKindOfClass:[MPStoredSiteEntity class]]) {
|
||||
wrn( @"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.",
|
||||
(long)site.type, [site class] );
|
||||
break;
|
||||
}
|
||||
result = [((MPSiteStoredEntity *)element).contentObject encodeBase64];
|
||||
result = [((MPStoredSiteEntity *)site).contentObject encodeBase64];
|
||||
break;
|
||||
}
|
||||
|
||||
@ -703,7 +703,7 @@
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSDictionary *)queryForDevicePrivateElementNamed:(NSString *)name {
|
||||
- (NSDictionary *)queryForDevicePrivateSiteNamed:(NSString *)name {
|
||||
|
||||
return [PearlKeyChain createQueryForClass:kSecClassGenericPassword
|
||||
attributes:@{
|
||||
|
@ -25,23 +25,23 @@
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (BOOL)migrateSite:(MPSiteEntity *)element explicit:(BOOL)explicit {
|
||||
- (BOOL)migrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit {
|
||||
|
||||
if (element.version != [self version] - 1)
|
||||
if (site.version != [self version] - 1)
|
||||
// Only migrate from previous version.
|
||||
return NO;
|
||||
|
||||
if (!explicit) {
|
||||
if (element.type & MPSiteTypeClassGenerated) {
|
||||
if (site.type & MPSiteTypeClassGenerated) {
|
||||
// This migration requires explicit permission for types of the generated class.
|
||||
element.requiresExplicitMigration = YES;
|
||||
site.requiresExplicitMigration = YES;
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply migration.
|
||||
element.requiresExplicitMigration = NO;
|
||||
element.version = [self version];
|
||||
site.requiresExplicitMigration = NO;
|
||||
site.version = [self version];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -91,8 +91,8 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
||||
if ([password length] && (tryKey = [MPAlgorithmDefault keyForPassword:password ofUserNamed:user.name])) {
|
||||
user.keyID = tryKey.keyID;
|
||||
|
||||
// Migrate existing elements.
|
||||
[self migrateElementsForUser:user saveInContext:moc toKey:tryKey];
|
||||
// Migrate existing sites.
|
||||
[self migrateSitesForUser:user saveInContext:moc toKey:tryKey];
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,23 +164,23 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)migrateElementsForUser:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc toKey:(MPKey *)newKey {
|
||||
- (void)migrateSitesForUser:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc toKey:(MPKey *)newKey {
|
||||
|
||||
if (![user.elements count])
|
||||
if (![user.sites count])
|
||||
// Nothing to migrate.
|
||||
return;
|
||||
|
||||
MPKey *recoverKey = newKey;
|
||||
#ifdef PEARL_UIKIT
|
||||
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:PearlString( @"Migrating %ld sites...",
|
||||
(long)[user.elements count] )];
|
||||
(long)[user.sites count] )];
|
||||
#endif
|
||||
|
||||
for (MPSiteEntity *element in user.elements) {
|
||||
if (element.type & MPSiteTypeClassStored) {
|
||||
for (MPSiteEntity *site in user.sites) {
|
||||
if (site.type & MPSiteTypeClassStored) {
|
||||
NSString *content;
|
||||
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.
|
||||
while (!(content = [site.algorithm storedPasswordForSite:(MPStoredSiteEntity *)site usingKey:recoverKey])) {
|
||||
// Failed to decrypt site with the current recoveryKey. Ask user for a new one to use.
|
||||
__block NSString *masterPassword = nil;
|
||||
|
||||
#ifdef PEARL_UIKIT
|
||||
@ -188,7 +188,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
||||
dispatch_group_enter( recoverPasswordGroup );
|
||||
[PearlAlert showAlertWithTitle:@"Enter Old Master Password"
|
||||
message:PearlString( @"Your old master password is required to migrate the stored password for %@",
|
||||
element.name )
|
||||
site.name )
|
||||
viewStyle:UIAlertViewStyleSecureTextInput
|
||||
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
||||
@try {
|
||||
@ -208,7 +208,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
||||
// Don't Migrate
|
||||
break;
|
||||
|
||||
recoverKey = [element.algorithm keyForPassword:masterPassword ofUserNamed:user.name];
|
||||
recoverKey = [site.algorithm keyForPassword:masterPassword ofUserNamed:user.name];
|
||||
}
|
||||
|
||||
if (!content)
|
||||
@ -216,7 +216,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
||||
break;
|
||||
|
||||
if (![recoverKey isEqualToKey:newKey])
|
||||
[element.algorithm savePassword:content toSite:element usingKey:newKey];
|
||||
[site.algorithm savePassword:content toSite:site usingKey:newKey];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,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)addSiteNamed:(NSString *)siteName completion:(void ( ^ )(MPSiteEntity *element, NSManagedObjectContext *context))completion;
|
||||
/** @param completion The block to execute after adding the site, executed from the main thread with the new site in the main MOC. */
|
||||
- (void)addSiteNamed:(NSString *)siteName completion:(void ( ^ )(MPSiteEntity *site, NSManagedObjectContext *context))completion;
|
||||
- (MPSiteEntity *)changeSite:(MPSiteEntity *)site saveInContext:(NSManagedObjectContext *)context toType:(MPSiteType)type;
|
||||
- (MPImportResult)importSites:(NSString *)importedSitesString
|
||||
askImportPassword:(NSString *(^)(NSString *userName))importPassword
|
||||
|
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "MPGeneratedSiteEntity.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#define STORE_OPTIONS NSPersistentStoreFileProtectionKey : NSFileProtectionComplete,
|
||||
@ -656,24 +657,24 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
|
||||
|
||||
// Create new site.
|
||||
NSString *typeEntityName = [MPAlgorithmForVersion( version ) classNameOfType:type];
|
||||
MPSiteEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
|
||||
element.name = siteName;
|
||||
element.loginName = loginName;
|
||||
element.user = user;
|
||||
element.type = type;
|
||||
element.uses = uses;
|
||||
element.lastUsed = lastUsed;
|
||||
element.version = version;
|
||||
MPSiteEntity *site = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
|
||||
site.name = siteName;
|
||||
site.loginName = loginName;
|
||||
site.user = user;
|
||||
site.type = type;
|
||||
site.uses = uses;
|
||||
site.lastUsed = lastUsed;
|
||||
site.version = version;
|
||||
if ([exportContent length]) {
|
||||
if (clearText)
|
||||
[element.algorithm importClearTextPassword:exportContent intoSite:element usingKey:userKey];
|
||||
[site.algorithm importClearTextPassword:exportContent intoSite:site usingKey:userKey];
|
||||
else
|
||||
[element.algorithm importProtectedPassword:exportContent protectedByKey:importKey intoSite:element usingKey:userKey];
|
||||
[site.algorithm importProtectedPassword:exportContent protectedByKey:importKey intoSite:site usingKey:userKey];
|
||||
}
|
||||
if ([element isKindOfClass:[MPElementGeneratedEntity class]] && counter != NSNotFound)
|
||||
((MPElementGeneratedEntity *)element).counter = counter;
|
||||
if ([site isKindOfClass:[MPGeneratedSiteEntity class]] && counter != NSNotFound)
|
||||
((MPGeneratedSiteEntity *)site).counter = counter;
|
||||
|
||||
dbg( @"Created Element: %@", [element debugDescription] );
|
||||
dbg( @"Created Site: %@", [site debugDescription] );
|
||||
}
|
||||
|
||||
if (![context saveToStore])
|
||||
@ -719,27 +720,27 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
|
||||
[export appendFormat:@"# used used type name\t name\tpassword\n"];
|
||||
|
||||
// Sites.
|
||||
for (MPSiteEntity *element in activeUser.elements) {
|
||||
NSDate *lastUsed = element.lastUsed;
|
||||
NSUInteger uses = element.uses;
|
||||
MPSiteType type = element.type;
|
||||
NSUInteger version = element.version;
|
||||
for (MPSiteEntity *site in activeUser.sites) {
|
||||
NSDate *lastUsed = site.lastUsed;
|
||||
NSUInteger uses = site.uses;
|
||||
MPSiteType type = site.type;
|
||||
NSUInteger version = site.version;
|
||||
NSUInteger counter = 0;
|
||||
NSString *loginName = element.loginName;
|
||||
NSString *siteName = element.name;
|
||||
NSString *loginName = site.loginName;
|
||||
NSString *siteName = site.name;
|
||||
NSString *content = nil;
|
||||
|
||||
// Generated-specific
|
||||
if ([element isKindOfClass:[MPElementGeneratedEntity class]])
|
||||
counter = ((MPElementGeneratedEntity *)element).counter;
|
||||
if ([site isKindOfClass:[MPGeneratedSiteEntity class]])
|
||||
counter = ((MPGeneratedSiteEntity *)site).counter;
|
||||
|
||||
|
||||
// Determine the content to export.
|
||||
if (!(type & MPSiteFeatureDevicePrivate)) {
|
||||
if (revealPasswords)
|
||||
content = [element.algorithm resolvePasswordForSite:element usingKey:self.key];
|
||||
content = [site.algorithm resolvePasswordForSite:site usingKey:self.key];
|
||||
else if (type & MPSiteFeatureExportContent)
|
||||
content = [element.algorithm exportPasswordForSite:element usingKey:self.key];
|
||||
content = [site.algorithm exportPasswordForSite:site usingKey:self.key];
|
||||
}
|
||||
|
||||
[export appendFormat:@"%@ %8ld %8s %25s\t%25s\t%@\n",
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPSiteEntity.h"
|
||||
#import "MPSiteStoredEntity.h"
|
||||
#import "MPSiteGeneratedEntity.h"
|
||||
#import "MPStoredSiteEntity.h"
|
||||
#import "MPGeneratedSiteEntity.h"
|
||||
#import "MPUserEntity.h"
|
||||
#import "MPAlgorithm.h"
|
||||
#import "MPFixable.h"
|
||||
@ -44,7 +44,7 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface MPSiteGeneratedEntity(MP)
|
||||
@interface MPGeneratedSiteEntity(MP)
|
||||
|
||||
@property(assign) NSUInteger counter;
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#import "MPEntities.h"
|
||||
#import "MPAppDelegate_Shared.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
|
||||
@implementation NSManagedObjectContext(MP)
|
||||
|
||||
@ -172,7 +171,7 @@
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPSiteGeneratedEntity(MP)
|
||||
@implementation MPGeneratedSiteEntity(MP)
|
||||
|
||||
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
@ -225,7 +224,7 @@
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPSiteStoredEntity(MP)
|
||||
@implementation MPStoredSiteEntity(MP)
|
||||
|
||||
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
|
@ -17,26 +17,26 @@
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "MPElementModel.h"
|
||||
#import "MPElementsTableView.h"
|
||||
#import "MPSiteModel.h"
|
||||
#import "MPSitesTableView.h"
|
||||
|
||||
@class MPMacAppDelegate;
|
||||
|
||||
@interface MPPasswordWindowController : NSWindowController<NSTextViewDelegate, NSTextFieldDelegate, NSTableViewDataSource, NSTableViewDelegate>
|
||||
|
||||
@property(nonatomic) NSMutableArray *elements;
|
||||
@property(nonatomic) NSMutableArray *sites;
|
||||
@property(nonatomic) NSString *masterPassword;
|
||||
@property(nonatomic) BOOL alternatePressed;
|
||||
@property(nonatomic) BOOL locked;
|
||||
@property(nonatomic) BOOL newUser;
|
||||
|
||||
@property(nonatomic, weak) IBOutlet NSArrayController *elementsController;
|
||||
@property(nonatomic, weak) IBOutlet NSArrayController *sitesController;
|
||||
@property(nonatomic, weak) IBOutlet NSImageView *blurView;
|
||||
@property(nonatomic, weak) IBOutlet NSTextField *inputLabel;
|
||||
@property(nonatomic, weak) IBOutlet NSTextField *securePasswordField;
|
||||
@property(nonatomic, weak) IBOutlet NSTextField *revealPasswordField;
|
||||
@property(nonatomic, weak) IBOutlet NSSearchField *siteField;
|
||||
@property(nonatomic, weak) IBOutlet MPElementsTableView *siteTable;
|
||||
@property(nonatomic, weak) IBOutlet MPSitesTableView *siteTable;
|
||||
@property(nonatomic, weak) IBOutlet NSProgressIndicator *progressView;
|
||||
|
||||
@property(nonatomic, strong) IBOutlet NSBox *passwordTypesBox;
|
||||
|
@ -20,7 +20,7 @@
|
||||
#import "MPPasswordWindowController.h"
|
||||
#import "MPMacAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "MPElementModel.h"
|
||||
#import "MPSiteModel.h"
|
||||
#import "MPAppDelegate_Key.h"
|
||||
#import "PearlProfiler.h"
|
||||
|
||||
@ -77,7 +77,7 @@
|
||||
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
[self updateUser];
|
||||
}];
|
||||
[self observeKeyPath:@"elementsController.selection"
|
||||
[self observeKeyPath:@"sitesController.selection"
|
||||
withBlock:^(id from, id to, NSKeyValueChange cause, id _self) {
|
||||
[_self updateSelection];
|
||||
}];
|
||||
@ -100,7 +100,7 @@
|
||||
BOOL alternatePressed = (theEvent.modifierFlags & NSAlternateKeyMask) != 0;
|
||||
if (alternatePressed != self.alternatePressed) {
|
||||
self.alternatePressed = alternatePressed;
|
||||
[self.selectedElement updateContent];
|
||||
[self.selectedSite updateContent];
|
||||
|
||||
if (self.locked) {
|
||||
NSTextField *passwordField = self.securePasswordField;
|
||||
@ -169,9 +169,9 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (IBAction)doSearchElements:(id)sender {
|
||||
- (IBAction)doSearchSites:(id)sender {
|
||||
|
||||
[self updateElements];
|
||||
[self updateSites];
|
||||
}
|
||||
|
||||
#pragma mark - NSTextViewDelegate
|
||||
@ -186,7 +186,7 @@
|
||||
|
||||
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
|
||||
|
||||
return (NSInteger)[self.elements count];
|
||||
return (NSInteger)[self.sites count];
|
||||
}
|
||||
|
||||
#pragma mark - NSTableViewDelegate
|
||||
@ -229,10 +229,10 @@
|
||||
switch (returnCode) {
|
||||
case NSAlertFirstButtonReturn: {
|
||||
// "Create" button.
|
||||
[[MPMacAppDelegate get]
|
||||
addSiteNamed:[self.siteField stringValue] completion:^(MPSiteEntity *element, NSManagedObjectContext *context) {
|
||||
if (element)
|
||||
PearlMainQueue( ^{ [self updateElements]; } );
|
||||
[[MPMacAppDelegate get] addSiteNamed:[self.siteField stringValue] completion:
|
||||
^(MPSiteEntity *site, NSManagedObjectContext *context) {
|
||||
if (site)
|
||||
PearlMainQueue( ^{ [self updateSites]; } );
|
||||
}];
|
||||
break;
|
||||
}
|
||||
@ -246,9 +246,9 @@
|
||||
// "Save" button.
|
||||
MPSiteType type = (MPSiteType)[self.passwordTypesMatrix.selectedCell tag];
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *entity = [[MPMacAppDelegate get] changeSite:[self.selectedElement entityInContext:context]
|
||||
MPSiteEntity *entity = [[MPMacAppDelegate get] changeSite:[self.selectedSite entityInContext:context]
|
||||
saveInContext:context toType:type];
|
||||
if ([entity isKindOfClass:[MPElementStoredEntity class]] && ![(MPElementStoredEntity *)entity contentObject].length)
|
||||
if ([entity isKindOfClass:[MPStoredSiteEntity class]] && ![(MPStoredSiteEntity *)entity contentObject].length)
|
||||
PearlMainQueue( ^{
|
||||
[self changePassword:nil];
|
||||
} );
|
||||
@ -265,7 +265,7 @@
|
||||
// "Save" button.
|
||||
NSString *loginName = [(NSSecureTextField *)alert.accessoryView stringValue];
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *entity = [self.selectedElement entityInContext:context];
|
||||
MPSiteEntity *entity = [self.selectedSite entityInContext:context];
|
||||
entity.loginName = loginName;
|
||||
[context saveToStore];
|
||||
}];
|
||||
@ -281,7 +281,7 @@
|
||||
// "Save" button.
|
||||
NSString *password = [(NSSecureTextField *)alert.accessoryView stringValue];
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *entity = [self.selectedElement entityInContext:context];
|
||||
MPSiteEntity *entity = [self.selectedSite entityInContext:context];
|
||||
[entity.algorithm savePassword:password toSite:entity usingKey:[MPMacAppDelegate get].key];
|
||||
[context saveToStore];
|
||||
}];
|
||||
@ -296,7 +296,7 @@
|
||||
case NSAlertFirstButtonReturn: {
|
||||
// "Delete" button.
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
[context deleteObject:[self.selectedElement entityInContext:context]];
|
||||
[context deleteObject:[self.selectedSite entityInContext:context]];
|
||||
[context saveToStore];
|
||||
}];
|
||||
break;
|
||||
@ -314,19 +314,19 @@
|
||||
return [self.siteField.stringValue stringByReplacingCharactersInRange:self.siteField.currentEditor.selectedRange withString:@""]?: @"";
|
||||
}
|
||||
|
||||
- (void)insertObject:(MPElementModel *)model inElementsAtIndex:(NSUInteger)index {
|
||||
- (void)insertObject:(MPSiteModel *)model inSitesAtIndex:(NSUInteger)index {
|
||||
|
||||
[self.elements insertObject:model atIndex:index];
|
||||
[self.sites insertObject:model atIndex:index];
|
||||
}
|
||||
|
||||
- (void)removeObjectFromElementsAtIndex:(NSUInteger)index {
|
||||
- (void)removeObjectFromSitesAtIndex:(NSUInteger)index {
|
||||
|
||||
[self.elements removeObjectAtIndex:index];
|
||||
[self.sites removeObjectAtIndex:index];
|
||||
}
|
||||
|
||||
- (MPElementModel *)selectedElement {
|
||||
- (MPSiteModel *)selectedSite {
|
||||
|
||||
return [self.elementsController.selectedObjects firstObject];
|
||||
return [self.sitesController.selectedObjects firstObject];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
@ -337,13 +337,13 @@
|
||||
[[MPMacAppDelegate get] showPopup:sender];
|
||||
}
|
||||
|
||||
- (IBAction)deleteElement:(id)sender {
|
||||
- (IBAction)deleteSite:(id)sender {
|
||||
|
||||
NSAlert *alert = [NSAlert new];
|
||||
[alert addButtonWithTitle:@"Delete"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
[alert setMessageText:@"Delete Site?"];
|
||||
[alert setInformativeText:strf( @"Do you want to delete the site named:\n\n%@", self.selectedElement.siteName )];
|
||||
[alert setInformativeText:strf( @"Do you want to delete the site named:\n\n%@", self.selectedSite.siteName )];
|
||||
[alert beginSheetModalForWindow:self.window modalDelegate:self
|
||||
didEndSelector:@selector( alertDidEnd:returnCode:contextInfo: ) contextInfo:MPAlertDeleteSite];
|
||||
}
|
||||
@ -354,9 +354,9 @@
|
||||
[alert addButtonWithTitle:@"Save"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
[alert setMessageText:@"Change Login Name"];
|
||||
[alert setInformativeText:strf( @"Enter the login name for: %@", self.selectedElement.siteName )];
|
||||
[alert setInformativeText:strf( @"Enter the login name for: %@", self.selectedSite.siteName )];
|
||||
NSTextField *loginField = [[NSTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
||||
loginField.stringValue = self.selectedElement.loginName?: @"";
|
||||
loginField.stringValue = self.selectedSite.loginName?: @"";
|
||||
[loginField selectText:self];
|
||||
[alert setAccessoryView:loginField];
|
||||
[alert layout];
|
||||
@ -381,14 +381,14 @@
|
||||
|
||||
- (IBAction)changePassword:(id)sender {
|
||||
|
||||
if (!self.selectedElement.stored)
|
||||
if (!self.selectedSite.stored)
|
||||
return;
|
||||
|
||||
NSAlert *alert = [NSAlert new];
|
||||
[alert addButtonWithTitle:@"Save"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
[alert setMessageText:@"Change Password"];
|
||||
[alert setInformativeText:strf( @"Enter the new password for: %@", self.selectedElement.siteName )];
|
||||
[alert setInformativeText:strf( @"Enter the new password for: %@", self.selectedSite.siteName )];
|
||||
[alert setAccessoryView:[[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )]];
|
||||
[alert layout];
|
||||
[alert beginSheetModalForWindow:self.window modalDelegate:self
|
||||
@ -397,19 +397,19 @@
|
||||
|
||||
- (IBAction)changeType:(id)sender {
|
||||
|
||||
MPElementModel *element = self.selectedElement;
|
||||
NSArray *types = [element.algorithm allTypesStartingWith:MPSiteTypeGeneratedPIN];
|
||||
MPSiteModel *site = self.selectedSite;
|
||||
NSArray *types = [site.algorithm allTypesStartingWith:MPSiteTypeGeneratedPIN];
|
||||
[self.passwordTypesMatrix renewRows:(NSInteger)[types count] columns:1];
|
||||
for (NSUInteger t = 0; t < [types count]; ++t) {
|
||||
MPSiteType type = [types[t] unsignedIntegerValue];
|
||||
NSString *title = [element.algorithm nameOfType:type];
|
||||
NSString *title = [site.algorithm nameOfType:type];
|
||||
if (type & MPSiteTypeClassGenerated)
|
||||
title = [element.algorithm generatePasswordForSiteNamed:element.siteName ofType:type
|
||||
withCounter:element.counter usingKey:[MPMacAppDelegate get].key];
|
||||
title = [site.algorithm generatePasswordForSiteNamed:site.siteName ofType:type
|
||||
withCounter:site.counter usingKey:[MPMacAppDelegate get].key];
|
||||
|
||||
NSButtonCell *cell = [self.passwordTypesMatrix cellAtRow:(NSInteger)t column:0];
|
||||
cell.tag = type;
|
||||
cell.state = type == element.type? NSOnState: NSOffState;
|
||||
cell.state = type == site.type? NSOnState: NSOffState;
|
||||
cell.title = title;
|
||||
}
|
||||
|
||||
@ -417,7 +417,7 @@
|
||||
[alert addButtonWithTitle:@"Save"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
[alert setMessageText:@"Change Password Type"];
|
||||
[alert setInformativeText:strf( @"Choose a new password type for: %@", element.siteName )];
|
||||
[alert setInformativeText:strf( @"Choose a new password type for: %@", site.siteName )];
|
||||
[alert setAccessoryView:self.passwordTypesBox];
|
||||
[alert layout];
|
||||
[alert beginSheetModalForWindow:self.window modalDelegate:self
|
||||
@ -429,11 +429,11 @@
|
||||
- (BOOL)handleCommand:(SEL)commandSelector {
|
||||
|
||||
if (commandSelector == @selector( moveUp: )) {
|
||||
[self.elementsController selectPrevious:self];
|
||||
[self.sitesController selectPrevious:self];
|
||||
return YES;
|
||||
}
|
||||
if (commandSelector == @selector( moveDown: )) {
|
||||
[self.elementsController selectNext:self];
|
||||
[self.sitesController selectNext:self];
|
||||
return YES;
|
||||
}
|
||||
if (commandSelector == @selector( insertNewline: )) {
|
||||
@ -450,19 +450,19 @@
|
||||
|
||||
- (void)useSite {
|
||||
|
||||
MPElementModel *selectedElement = [self selectedElement];
|
||||
if (selectedElement) {
|
||||
MPSiteModel *selectedSite = [self selectedSite];
|
||||
if (selectedSite) {
|
||||
// Performing action while content is available. Copy it.
|
||||
[self copyContent:selectedElement.content];
|
||||
[self copyContent:selectedSite.content];
|
||||
|
||||
[self fadeOut];
|
||||
|
||||
NSUserNotification *notification = [NSUserNotification new];
|
||||
notification.title = @"Password Copied";
|
||||
if (selectedElement.loginName.length)
|
||||
notification.subtitle = strf( @"%@ at %@", selectedElement.loginName, selectedElement.siteName );
|
||||
if (selectedSite.loginName.length)
|
||||
notification.subtitle = strf( @"%@ at %@", selectedSite.loginName, selectedSite.siteName );
|
||||
else
|
||||
notification.subtitle = selectedElement.siteName;
|
||||
notification.subtitle = selectedSite.siteName;
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
|
||||
}
|
||||
else {
|
||||
@ -500,18 +500,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
[self updateElements];
|
||||
[self updateSites];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateElements {
|
||||
- (void)updateSites {
|
||||
|
||||
if (![MPMacAppDelegate get].key) {
|
||||
self.elements = nil;
|
||||
self.sites = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
PearlProfiler *profiler = [PearlProfiler profilerForTask:@"updateElements"];
|
||||
PearlProfiler *profiler = [PearlProfiler profilerForTask:@"updateSites"];
|
||||
NSString *query = [self query];
|
||||
[profiler finishJob:@"query"];
|
||||
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
|
||||
@ -524,17 +524,17 @@
|
||||
NSError *error = nil;
|
||||
NSArray *siteResults = [context executeFetchRequest:fetchRequest error:&error];
|
||||
if (!siteResults) {
|
||||
err( @"While fetching elements for completion: %@", error );
|
||||
err( @"While fetching sites for completion: %@", error );
|
||||
return;
|
||||
}
|
||||
[profiler finishJob:@"do fetch"];
|
||||
|
||||
NSMutableArray *newElements = [NSMutableArray arrayWithCapacity:[siteResults count]];
|
||||
for (MPSiteEntity *element in siteResults)
|
||||
[newElements addObject:[[MPElementModel alloc] initWithEntity:element]];
|
||||
NSMutableArray *newSites = [NSMutableArray arrayWithCapacity:[siteResults count]];
|
||||
for (MPSiteEntity *site in siteResults)
|
||||
[newSites addObject:[[MPSiteModel alloc] initWithEntity:site]];
|
||||
[profiler finishJob:@"make models"];
|
||||
self.elements = newElements;
|
||||
[profiler finishJob:@"update elements"];
|
||||
self.sites = newSites;
|
||||
[profiler finishJob:@"update sites"];
|
||||
}];
|
||||
[profiler finishJob:@"done"];
|
||||
}
|
||||
@ -546,7 +546,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *siteName = self.selectedElement.siteName;
|
||||
NSString *siteName = self.selectedSite.siteName;
|
||||
if (!siteName)
|
||||
return;
|
||||
|
||||
@ -559,14 +559,14 @@
|
||||
NSMakeRange( siteNameQueryRange.length, siteName.length - siteNameQueryRange.length );
|
||||
}
|
||||
|
||||
[self.siteTable scrollRowToVisible:(NSInteger)self.elementsController.selectionIndex];
|
||||
[self.siteTable scrollRowToVisible:(NSInteger)self.sitesController.selectionIndex];
|
||||
[self updateGradient];
|
||||
}
|
||||
|
||||
- (void)updateGradient {
|
||||
|
||||
NSView *siteScrollView = self.siteTable.superview.superview;
|
||||
NSRect selectedCellFrame = [self.siteTable frameOfCellAtColumn:0 row:((NSInteger)self.elementsController.selectionIndex)];
|
||||
NSRect selectedCellFrame = [self.siteTable frameOfCellAtColumn:0 row:((NSInteger)self.sitesController.selectionIndex)];
|
||||
CGFloat selectedOffset = [siteScrollView convertPoint:selectedCellFrame.origin fromView:self.siteTable].y;
|
||||
CGFloat gradientOpacity = selectedOffset / siteScrollView.bounds.size.height;
|
||||
self.siteGradient.colors = @[
|
||||
@ -597,7 +597,7 @@
|
||||
}
|
||||
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
||||
[[self.selectedElement entityInContext:moc] use];
|
||||
[[self.selectedSite entityInContext:moc] use];
|
||||
[moc saveToStore];
|
||||
}];
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="MPPasswordWindowController">
|
||||
<connections>
|
||||
<outlet property="blurView" destination="Bwc-sd-6gm" id="wNV-0x-LJn"/>
|
||||
<outlet property="elementsController" destination="mcS-ik-b0n" id="cdF-BL-lfg"/>
|
||||
<outlet property="sitesController" destination="mcS-ik-b0n" id="cdF-BL-lfg"/>
|
||||
<outlet property="inputLabel" destination="OnR-s6-d4P" id="p6G-Ut-cdu"/>
|
||||
<outlet property="passwordTypesBox" destination="bZe-7q-i6q" id="Ai3-pt-i6K"/>
|
||||
<outlet property="passwordTypesMatrix" destination="3fr-Fd-pxx" id="T8g-mS-lxP"/>
|
||||
@ -144,7 +144,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="147"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" selectionHighlightStyle="sourceList" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="33" rowSizeStyle="automatic" viewBased="YES" floatsGroupRows="NO" id="xvJ-5c-vDp" customClass="MPElementsTableView">
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" selectionHighlightStyle="sourceList" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="33" rowSizeStyle="automatic" viewBased="YES" floatsGroupRows="NO" id="xvJ-5c-vDp" customClass="MPSitesTableView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="147"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
@ -262,7 +262,7 @@
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.0" colorSpace="calibratedRGB"/>
|
||||
</searchFieldCell>
|
||||
<connections>
|
||||
<action selector="doSearchElements:" target="-2" id="NJO-iR-OXt"/>
|
||||
<action selector="doSearchSites:" target="-2" id="NJO-iR-OXt"/>
|
||||
<binding destination="-2" name="hidden" keyPath="locked" id="fAX-uK-cgn"/>
|
||||
<outlet property="delegate" destination="-2" id="2WA-uI-asx"/>
|
||||
</connections>
|
||||
@ -371,7 +371,7 @@
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="deleteElement:" target="-2" id="mVT-O6-KfN"/>
|
||||
<action selector="deleteSite:" target="-2" id="mVT-O6-KfN"/>
|
||||
<binding destination="mcS-ik-b0n" name="hidden" keyPath="canRemove" id="eqU-d2-XhQ">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
@ -869,9 +869,9 @@
|
||||
</view>
|
||||
</window>
|
||||
<userDefaultsController representsSharedInstance="YES" id="yy2-3W-Ocj"/>
|
||||
<arrayController objectClassName="MPElementModel" id="mcS-ik-b0n">
|
||||
<arrayController objectClassName="MPSiteModel" id="mcS-ik-b0n">
|
||||
<connections>
|
||||
<binding destination="-2" name="contentArray" keyPath="elements" id="c96-Dv-HK1"/>
|
||||
<binding destination="-2" name="contentArray" keyPath="sites" id="c96-Dv-HK1"/>
|
||||
</connections>
|
||||
</arrayController>
|
||||
<box autoresizesSubviews="NO" title="Password Types" borderType="line" titlePosition="noTitle" id="bZe-7q-i6q">
|
||||
|
@ -9,8 +9,8 @@
|
||||
*/
|
||||
|
||||
//
|
||||
// MPElementModel.h
|
||||
// MPElementModel
|
||||
// MPSiteModel.h
|
||||
// MPSiteModel
|
||||
//
|
||||
// Created by lhunath on 2/11/2014.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
@ -19,7 +19,7 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
@class MPSiteEntity;
|
||||
|
||||
@interface MPElementModel : NSObject
|
||||
@interface MPSiteModel : NSObject
|
||||
|
||||
@property (nonatomic) NSString *siteName;
|
||||
@property (nonatomic) MPSiteType type;
|
@ -9,21 +9,21 @@
|
||||
*/
|
||||
|
||||
//
|
||||
// MPElementModel.h
|
||||
// MPElementModel
|
||||
// MPSiteModel.h
|
||||
// MPSiteModel
|
||||
//
|
||||
// Created by lhunath on 2/11/2014.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPElementModel.h"
|
||||
#import "MPSiteModel.h"
|
||||
#import "MPSiteEntity.h"
|
||||
#import "MPEntities.h"
|
||||
#import "MPAppDelegate_Shared.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "MPMacAppDelegate.h"
|
||||
|
||||
@implementation MPElementModel {
|
||||
@implementation MPSiteModel {
|
||||
NSManagedObjectID *_entityOID;
|
||||
BOOL _initialized;
|
||||
}
|
||||
@ -52,7 +52,7 @@
|
||||
self.type = entity.type;
|
||||
self.typeName = entity.typeName;
|
||||
self.uses = entity.uses_;
|
||||
self.counter = [entity isKindOfClass:[MPElementGeneratedEntity class]]? [(MPElementGeneratedEntity *)entity counter]: 0;
|
||||
self.counter = [entity isKindOfClass:[MPGeneratedSiteEntity class]]? [(MPGeneratedSiteEntity *)entity counter]: 0;
|
||||
|
||||
// Find all password types and the index of the current type amongst them.
|
||||
[self updateContent:entity];
|
||||
@ -66,7 +66,7 @@
|
||||
NSError *error;
|
||||
MPSiteEntity *entity = (MPSiteEntity *)[moc existingObjectWithID:_entityOID error:&error];
|
||||
if (!entity)
|
||||
err( @"Couldn't retrieve active element: %@", error );
|
||||
err( @"Couldn't retrieve active site: %@", error );
|
||||
|
||||
return entity;
|
||||
}
|
||||
@ -83,8 +83,8 @@
|
||||
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *entity = [self entityInContext:context];
|
||||
if ([entity isKindOfClass:[MPElementGeneratedEntity class]]) {
|
||||
((MPElementGeneratedEntity *)entity).counter = counter;
|
||||
if ([entity isKindOfClass:[MPGeneratedSiteEntity class]]) {
|
||||
((MPGeneratedSiteEntity *)entity).counter = counter;
|
||||
[context saveToStore];
|
||||
|
||||
[self updateContent:entity];
|
@ -9,8 +9,8 @@
|
||||
*/
|
||||
|
||||
//
|
||||
// MPElementsTableView.h
|
||||
// MPElementsTableView
|
||||
// MPSitesTableView.h
|
||||
// MPSitesTableView
|
||||
//
|
||||
// Created by lhunath on 2014-06-30.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
@ -20,7 +20,7 @@
|
||||
|
||||
@class MPPasswordWindowController;
|
||||
|
||||
@interface MPElementsTableView : NSTableView
|
||||
@interface MPSitesTableView : NSTableView
|
||||
|
||||
@property(nonatomic, weak) MPPasswordWindowController *controller;
|
||||
|
@ -9,17 +9,17 @@
|
||||
*/
|
||||
|
||||
//
|
||||
// MPElementsTableView.h
|
||||
// MPElementsTableView
|
||||
// MPSitesTableView.h
|
||||
// MPSitesTableView
|
||||
//
|
||||
// Created by lhunath on 2014-06-30.
|
||||
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPElementsTableView.h"
|
||||
#import "MPSitesTableView.h"
|
||||
#import "MPPasswordWindowController.h"
|
||||
|
||||
@implementation MPElementsTableView
|
||||
@implementation MPSitesTableView
|
||||
|
||||
- (void)doCommandBySelector:(SEL)aSelector {
|
||||
|
@ -9,12 +9,12 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
93D390C676DF52DA7E459F19 /* MPPasswordWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D9D0061FF1159998F06 /* MPPasswordWindow.m */; };
|
||||
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */; };
|
||||
93D394C4254EEB45FB335AFB /* MPElementsTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39423D7BF4FD31FE6D27C /* MPElementsTableView.m */; };
|
||||
93D394C4254EEB45FB335AFB /* MPSitesTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39423D7BF4FD31FE6D27C /* MPSitesTableView.m */; };
|
||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
|
||||
93D3970BCF85F7902E611168 /* PearlProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DB3A8ADED08C39A6228 /* PearlProfiler.m */; };
|
||||
93D39784E725A34D1EE3FB3B /* MPInitialWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D3CB30874147D9A9E1B /* MPInitialWindowController.m */; };
|
||||
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
|
||||
93D39C5789EFA607CF788082 /* MPElementModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */; };
|
||||
93D39C5789EFA607CF788082 /* MPSiteModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E73BF5CBF8E5B005CD3 /* MPSiteModel.m */; };
|
||||
93D39D304F73B3BBA031522A /* PearlProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D394EEFF5BF555A55AF361 /* PearlProfiler.h */; };
|
||||
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
|
||||
93D39F833DEC1C89B2F795AC /* MPPasswordWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A57A7823DE98A0FF83C /* MPPasswordWindowController.m */; };
|
||||
@ -230,21 +230,21 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; };
|
||||
93D39240B5143E01F0B75E96 /* MPElementModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementModel.h; sourceTree = "<group>"; };
|
||||
93D39240B5143E01F0B75E96 /* MPSiteModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteModel.h; sourceTree = "<group>"; };
|
||||
93D392C3918763B3B72CF366 /* MPPasswordWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordWindowController.h; sourceTree = "<group>"; };
|
||||
93D39368EF3CBFEF2AFCA15A /* MPInitialWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPInitialWindowController.h; sourceTree = "<group>"; };
|
||||
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
|
||||
93D39423D7BF4FD31FE6D27C /* MPElementsTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementsTableView.m; sourceTree = "<group>"; };
|
||||
93D39423D7BF4FD31FE6D27C /* MPSitesTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesTableView.m; sourceTree = "<group>"; };
|
||||
93D394EEFF5BF555A55AF361 /* PearlProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PearlProfiler.h; path = ../../../External/Pearl/Pearl/PearlProfiler.h; sourceTree = "<group>"; };
|
||||
93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = "<group>"; };
|
||||
93D3977484534E99F9BA579D /* MPPasswordWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordWindow.h; sourceTree = "<group>"; };
|
||||
93D39A57A7823DE98A0FF83C /* MPPasswordWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordWindowController.m; sourceTree = "<group>"; };
|
||||
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = "<group>"; };
|
||||
93D39AC6360DDC16AEAA4119 /* MPElementsTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementsTableView.h; sourceTree = "<group>"; };
|
||||
93D39AC6360DDC16AEAA4119 /* MPSitesTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSitesTableView.h; sourceTree = "<group>"; };
|
||||
93D39D3CB30874147D9A9E1B /* MPInitialWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPInitialWindowController.m; sourceTree = "<group>"; };
|
||||
93D39D9D0061FF1159998F06 /* MPPasswordWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordWindow.m; sourceTree = "<group>"; };
|
||||
93D39DB3A8ADED08C39A6228 /* PearlProfiler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PearlProfiler.m; path = ../../../External/Pearl/Pearl/PearlProfiler.m; sourceTree = "<group>"; };
|
||||
93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementModel.m; sourceTree = "<group>"; };
|
||||
93D39E73BF5CBF8E5B005CD3 /* MPSiteModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteModel.m; sourceTree = "<group>"; };
|
||||
DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPInitialWindow.xib; sourceTree = "<group>"; };
|
||||
DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "shot-laptop-leaning-iphone.png"; sourceTree = "<group>"; };
|
||||
DA0933CF1747B91B00DE1CEF /* appstore.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = appstore.png; sourceTree = "<group>"; };
|
||||
@ -1051,8 +1051,8 @@
|
||||
DA5E5CC41724A667003798D8 /* MainMenu.xib */,
|
||||
DA5E5CC61724A667003798D8 /* main.m */,
|
||||
DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */,
|
||||
93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */,
|
||||
93D39240B5143E01F0B75E96 /* MPElementModel.h */,
|
||||
93D39E73BF5CBF8E5B005CD3 /* MPSiteModel.m */,
|
||||
93D39240B5143E01F0B75E96 /* MPSiteModel.h */,
|
||||
DA2508F019511D3600AC23F1 /* MPPasswordWindowController.xib */,
|
||||
93D39A57A7823DE98A0FF83C /* MPPasswordWindowController.m */,
|
||||
93D392C3918763B3B72CF366 /* MPPasswordWindowController.h */,
|
||||
@ -1060,8 +1060,8 @@
|
||||
93D3977484534E99F9BA579D /* MPPasswordWindow.h */,
|
||||
93D39D3CB30874147D9A9E1B /* MPInitialWindowController.m */,
|
||||
93D39368EF3CBFEF2AFCA15A /* MPInitialWindowController.h */,
|
||||
93D39423D7BF4FD31FE6D27C /* MPElementsTableView.m */,
|
||||
93D39AC6360DDC16AEAA4119 /* MPElementsTableView.h */,
|
||||
93D39423D7BF4FD31FE6D27C /* MPSitesTableView.m */,
|
||||
93D39AC6360DDC16AEAA4119 /* MPSitesTableView.h */,
|
||||
);
|
||||
path = Mac;
|
||||
sourceTree = "<group>";
|
||||
@ -2159,13 +2159,13 @@
|
||||
DA5E5D031724A667003798D8 /* MPMacAppDelegate.m in Sources */,
|
||||
DA5E5D041724A667003798D8 /* MPMacConfig.m in Sources */,
|
||||
DA5E5D0C1724A667003798D8 /* main.m in Sources */,
|
||||
93D39C5789EFA607CF788082 /* MPElementModel.m in Sources */,
|
||||
93D39C5789EFA607CF788082 /* MPSiteModel.m in Sources */,
|
||||
93D39F833DEC1C89B2F795AC /* MPPasswordWindowController.m in Sources */,
|
||||
DA32CFD919CF1C70004F3F0E /* MPGeneratedSiteEntity.m in Sources */,
|
||||
93D390C676DF52DA7E459F19 /* MPPasswordWindow.m in Sources */,
|
||||
93D39784E725A34D1EE3FB3B /* MPInitialWindowController.m in Sources */,
|
||||
DA32CFDF19CF1C70004F3F0E /* MPSiteEntity.m in Sources */,
|
||||
93D394C4254EEB45FB335AFB /* MPElementsTableView.m in Sources */,
|
||||
93D394C4254EEB45FB335AFB /* MPSitesTableView.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -8,10 +8,10 @@
|
||||
<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" elementID="FC8AE32E-7BE3-4FA6-8611-B7DC0DB063EF" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="MPElementGeneratedEntity" representedClassName="MPSiteGeneratedEntity" parentEntity="MPElementEntity" elementID="789304EA-070D-4982-8C20-54EECFC20CB6" syncable="YES">
|
||||
<entity name="MPElementGeneratedEntity" representedClassName="MPGeneratedSiteEntity" 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="MPSiteStoredEntity" parentEntity="MPElementEntity" elementID="BEEF1688-0CCD-4699-A86A-4D860FE2CEB8" syncable="YES">
|
||||
<entity name="MPElementStoredEntity" representedClassName="MPStoredSiteEntity" 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" elementID="D18D6772-040E-4CFE-8F32-A34B08E9E9BC" syncable="YES">
|
||||
|
@ -13,10 +13,10 @@
|
||||
<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" elementID="FC8AE32E-7BE3-4FA6-8611-B7DC0DB063EF" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="MPElementGeneratedEntity" representedClassName="MPSiteGeneratedEntity" parentEntity="MPElementEntity" elementID="789304EA-070D-4982-8C20-54EECFC20CB6" syncable="YES">
|
||||
<entity name="MPElementGeneratedEntity" representedClassName="MPGeneratedSiteEntity" 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="MPSiteStoredEntity" parentEntity="MPElementEntity" elementID="BEEF1688-0CCD-4699-A86A-4D860FE2CEB8" syncable="YES">
|
||||
<entity name="MPElementStoredEntity" representedClassName="MPStoredSiteEntity" 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" elementID="D18D6772-040E-4CFE-8F32-A34B08E9E9BC" syncable="YES">
|
||||
|
@ -13,10 +13,10 @@
|
||||
<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" elementID="FC8AE32E-7BE3-4FA6-8611-B7DC0DB063EF" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="MPElementGeneratedEntity" representedClassName="MPSiteGeneratedEntity" parentEntity="MPElementEntity" elementID="789304EA-070D-4982-8C20-54EECFC20CB6" syncable="YES">
|
||||
<entity name="MPElementGeneratedEntity" representedClassName="MPGeneratedSiteEntity" 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="MPSiteStoredEntity" parentEntity="MPElementEntity" elementID="BEEF1688-0CCD-4699-A86A-4D860FE2CEB8" syncable="YES">
|
||||
<entity name="MPElementStoredEntity" representedClassName="MPStoredSiteEntity" 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">
|
||||
|
@ -13,10 +13,10 @@
|
||||
<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" elementID="FC8AE32E-7BE3-4FA6-8611-B7DC0DB063EF" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="MPElementGeneratedEntity" representedClassName="MPSiteGeneratedEntity" parentEntity="MPElementEntity" elementID="789304EA-070D-4982-8C20-54EECFC20CB6" syncable="YES">
|
||||
<entity name="MPElementGeneratedEntity" representedClassName="MPGeneratedSiteEntity" 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="MPSiteStoredEntity" parentEntity="MPElementEntity" elementID="BEEF1688-0CCD-4699-A86A-4D860FE2CEB8" syncable="YES">
|
||||
<entity name="MPElementStoredEntity" representedClassName="MPStoredSiteEntity" 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">
|
||||
|
@ -27,7 +27,7 @@ typedef NS_ENUM ( NSUInteger, MPPasswordCellMode ) {
|
||||
|
||||
@interface MPPasswordCell : MPCell <UIScrollViewDelegate, UITextFieldDelegate>
|
||||
|
||||
- (void)setElement:(MPSiteEntity *)element animated:(BOOL)animated;
|
||||
- (void)setSite:(MPSiteEntity *)site animated:(BOOL)animated;
|
||||
- (void)setTransientSite:(NSString *)siteName animated:(BOOL)animated;
|
||||
- (void)setMode:(MPPasswordCellMode)mode animated:(BOOL)animated;
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
||||
@end
|
||||
|
||||
@implementation MPPasswordCell {
|
||||
NSManagedObjectID *_elementOID;
|
||||
NSManagedObjectID *_siteOID;
|
||||
}
|
||||
|
||||
#pragma mark - Life cycle
|
||||
@ -132,7 +132,7 @@
|
||||
|
||||
[super prepareForReuse];
|
||||
|
||||
_elementOID = nil;
|
||||
_siteOID = nil;
|
||||
self.transientSite = nil;
|
||||
self.mode = MPPasswordCellModePassword;
|
||||
[self updateAnimated:NO];
|
||||
@ -155,9 +155,9 @@
|
||||
[self updateAnimated:animated];
|
||||
}
|
||||
|
||||
- (void)setElement:(MPSiteEntity *)element animated:(BOOL)animated {
|
||||
- (void)setSite:(MPSiteEntity *)site animated:(BOOL)animated {
|
||||
|
||||
_elementOID = [element objectID];
|
||||
_siteOID = [site objectID];
|
||||
[self updateAnimated:animated];
|
||||
}
|
||||
|
||||
@ -195,10 +195,10 @@
|
||||
NSString *password = self.passwordField.text;
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
TimeToCrack timeToCrack;
|
||||
MPSiteEntity *element = [self elementInContext:context];
|
||||
id<MPAlgorithm> algorithm = element.algorithm?: MPAlgorithmDefault;
|
||||
MPSiteEntity *site = [self siteInContext:context];
|
||||
id<MPAlgorithm> algorithm = site.algorithm?: MPAlgorithmDefault;
|
||||
MPAttacker attackHardware = [[MPConfig get].siteAttacker unsignedIntegerValue];
|
||||
if ([algorithm timeToCrack:&timeToCrack passwordOfType:[self elementInContext:context].type byAttacker:attackHardware] ||
|
||||
if ([algorithm timeToCrack:&timeToCrack passwordOfType:[self siteInContext:context].type byAttacker:attackHardware] ||
|
||||
[algorithm timeToCrack:&timeToCrack passwordString:password byAttacker:attackHardware])
|
||||
PearlMainQueue( ^{
|
||||
self.strengthLabel.text = NSStringFromTimeToCrack( timeToCrack );
|
||||
@ -214,19 +214,19 @@
|
||||
NSString *text = textField.text;
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *element = [self elementInContext:context];
|
||||
if (!element)
|
||||
MPSiteEntity *site = [self siteInContext:context];
|
||||
if (!site)
|
||||
return;
|
||||
|
||||
if (textField == self.passwordField) {
|
||||
if ([element.algorithm savePassword:text toSite:element usingKey:[MPiOSAppDelegate get].key])
|
||||
if ([site.algorithm savePassword:text toSite:site usingKey:[MPiOSAppDelegate get].key])
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2];
|
||||
}
|
||||
else if (textField == self.loginNameField &&
|
||||
((element.loginGenerated && ![text length]) ||
|
||||
(!element.loginGenerated && ![text isEqualToString:element.loginName]))) {
|
||||
element.loginName = text;
|
||||
element.loginGenerated = NO;
|
||||
((site.loginGenerated && ![text length]) ||
|
||||
(!site.loginGenerated && ![text isEqualToString:site.loginName]))) {
|
||||
site.loginName = text;
|
||||
site.loginGenerated = NO;
|
||||
if ([text length])
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Login Name Saved" dismissAfter:2];
|
||||
else
|
||||
@ -243,17 +243,17 @@
|
||||
|
||||
- (IBAction)doDelete:(UIButton *)sender {
|
||||
|
||||
MPSiteEntity *element = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||
if (!element)
|
||||
MPSiteEntity *site = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||
if (!site)
|
||||
return;
|
||||
|
||||
[PearlSheet showSheetWithTitle:strf( @"Delete %@?", element.name ) viewStyle:UIActionSheetStyleAutomatic
|
||||
[PearlSheet showSheetWithTitle:strf( @"Delete %@?", site.name ) viewStyle:UIActionSheetStyleAutomatic
|
||||
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
|
||||
if (buttonIndex == [sheet cancelButtonIndex])
|
||||
return;
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
[context deleteObject:[self elementInContext:context]];
|
||||
[context deleteObject:[self siteInContext:context]];
|
||||
[context saveToStore];
|
||||
}];
|
||||
} cancelTitle:@"Cancel" destructiveTitle:@"Delete Site" otherTitles:nil];
|
||||
@ -265,12 +265,11 @@
|
||||
|
||||
[PearlSheet showSheetWithTitle:@"Change Password Type" viewStyle:UIActionSheetStyleAutomatic
|
||||
initSheet:^(UIActionSheet *sheet) {
|
||||
MPSiteEntity
|
||||
*mainElement = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||
for (NSNumber *typeNumber in [MPAlgorithmDefault allTypes]) {
|
||||
MPSiteType type = [typeNumber unsignedIntegerValue];
|
||||
NSString *typeName = [MPAlgorithmDefault nameOfType:type];
|
||||
if (type == mainElement.type)
|
||||
if (type == mainSite.type)
|
||||
[sheet addButtonWithTitle:strf( @"● %@", typeName )];
|
||||
else
|
||||
[sheet addButtonWithTitle:typeName];
|
||||
@ -282,9 +281,9 @@
|
||||
MPSiteType type = [[MPAlgorithmDefault allTypes][buttonIndex] unsignedIntegerValue]?: MPSiteTypeGeneratedLong;
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *element = [self elementInContext:context];
|
||||
element = [[MPiOSAppDelegate get] changeSite:element saveInContext:context toType:type];
|
||||
[self setElement:element animated:YES];
|
||||
MPSiteEntity *site = [self siteInContext:context];
|
||||
site = [[MPiOSAppDelegate get] changeSite:site saveInContext:context toType:type];
|
||||
[self setSite:site animated:YES];
|
||||
}];
|
||||
} cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:nil];
|
||||
}
|
||||
@ -294,7 +293,7 @@
|
||||
self.loginNameField.enabled = YES;
|
||||
self.passwordField.enabled = YES;
|
||||
|
||||
if ([self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].type & MPSiteTypeClassStored)
|
||||
if ([self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].type & MPSiteTypeClassStored)
|
||||
[self.passwordField becomeFirstResponder];
|
||||
else
|
||||
[self.loginNameField becomeFirstResponder];
|
||||
@ -317,7 +316,7 @@
|
||||
- (IBAction)doUpgrade:(UIButton *)sender {
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
if (![[self elementInContext:context] migrateExplicitly:YES]) {
|
||||
if (![[self siteInContext:context] migrateExplicitly:YES]) {
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Couldn't Upgrade Site" dismissAfter:2];
|
||||
return;
|
||||
}
|
||||
@ -331,11 +330,11 @@
|
||||
- (IBAction)doIncrementCounter:(UIButton *)sender {
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *element = [self elementInContext:context];
|
||||
if (!element || ![element isKindOfClass:[MPElementGeneratedEntity class]])
|
||||
MPSiteEntity *site = [self siteInContext:context];
|
||||
if (!site || ![site isKindOfClass:[MPGeneratedSiteEntity class]])
|
||||
return;
|
||||
|
||||
++((MPElementGeneratedEntity *)element).counter;
|
||||
++((MPGeneratedSiteEntity *)site).counter;
|
||||
[context saveToStore];
|
||||
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Generating New Password" dismissAfter:2];
|
||||
@ -363,11 +362,11 @@
|
||||
return;
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *element = [self elementInContext:context];
|
||||
if (!element || ![element isKindOfClass:[MPElementGeneratedEntity class]])
|
||||
MPSiteEntity *site = [self siteInContext:context];
|
||||
if (!site || ![site isKindOfClass:[MPGeneratedSiteEntity class]])
|
||||
return;
|
||||
|
||||
((MPElementGeneratedEntity *)element).counter = 1;
|
||||
((MPGeneratedSiteEntity *)site).counter = 1;
|
||||
[context saveToStore];
|
||||
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Counter Reset" dismissAfter:2];
|
||||
@ -393,8 +392,8 @@
|
||||
}
|
||||
|
||||
[[MPiOSAppDelegate get]
|
||||
addSiteNamed:self.transientSite completion:^(MPSiteEntity *element, NSManagedObjectContext *context) {
|
||||
[self copyContentOfElement:element saveInContext:context];
|
||||
addSiteNamed:self.transientSite completion:^(MPSiteEntity *site, NSManagedObjectContext *context) {
|
||||
[self copyContentOfSite:site saveInContext:context];
|
||||
|
||||
PearlMainQueueAfter( .3f, ^{
|
||||
[UIView animateWithDuration:.2f animations:^{
|
||||
@ -407,7 +406,7 @@
|
||||
}
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
[self copyContentOfElement:[self elementInContext:context] saveInContext:context];
|
||||
[self copyContentOfSite:[self siteInContext:context] saveInContext:context];
|
||||
|
||||
PearlMainQueueAfter( .3f, ^{
|
||||
[UIView animateWithDuration:.2f animations:^{
|
||||
@ -424,9 +423,9 @@
|
||||
}];
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *element = [self elementInContext:context];
|
||||
if (![self copyLoginOfElement:element saveInContext:context]) {
|
||||
element.loginGenerated = YES;
|
||||
MPSiteEntity *site = [self siteInContext:context];
|
||||
if (![self copyLoginOfSite:site saveInContext:context]) {
|
||||
site.loginGenerated = YES;
|
||||
[context saveToStore];
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Login Name Generated" dismissAfter:2];
|
||||
[self updateAnimated:YES];
|
||||
@ -462,15 +461,15 @@
|
||||
}
|
||||
|
||||
[UIView animateWithDuration:animated? .3f: 0 animations:^{
|
||||
MPSiteEntity *mainElement = [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||
|
||||
// UI
|
||||
self.upgradeButton.alpha = mainElement.requiresExplicitMigration? 1: 0;
|
||||
self.upgradeButton.alpha = mainSite.requiresExplicitMigration? 1: 0;
|
||||
BOOL settingsMode = self.mode == MPPasswordCellModeSettings;
|
||||
self.loginNameContainer.alpha = settingsMode || mainElement.loginGenerated || [mainElement.loginName length]? 0.7f: 0;
|
||||
self.loginNameField.textColor = [UIColor colorWithHexString:mainElement.loginGenerated? @"5E636D": @"6D5E63"];
|
||||
self.loginNameContainer.alpha = settingsMode || mainSite.loginGenerated || [mainSite.loginName length]? 0.7f: 0;
|
||||
self.loginNameField.textColor = [UIColor colorWithHexString:mainSite.loginGenerated? @"5E636D": @"6D5E63"];
|
||||
self.modeButton.alpha = self.transientSite? 0: settingsMode? 0.5f: 0.1f;
|
||||
self.counterLabel.alpha = self.counterButton.alpha = mainElement.type & MPSiteTypeClassGenerated? 0.5f: 0;
|
||||
self.counterLabel.alpha = self.counterButton.alpha = mainSite.type & MPSiteTypeClassGenerated? 0.5f: 0;
|
||||
self.modeButton.selected = settingsMode;
|
||||
self.strengthLabel.gone = !settingsMode;
|
||||
self.modeScrollView.scrollEnabled = !self.transientSite;
|
||||
@ -485,34 +484,34 @@
|
||||
[self.loginNameButton setTitle:@"Tap the pencil to save a username" forState:UIControlStateNormal];
|
||||
|
||||
// Site Name
|
||||
self.siteNameLabel.text = strl( @"%@ - %@", self.transientSite?: mainElement.name,
|
||||
self.transientSite? @"Tap to create": [mainElement.algorithm shortNameOfType:mainElement.type] );
|
||||
self.siteNameLabel.text = strl( @"%@ - %@", self.transientSite?: mainSite.name,
|
||||
self.transientSite? @"Tap to create": [mainSite.algorithm shortNameOfType:mainSite.type] );
|
||||
|
||||
// Site Password
|
||||
self.passwordField.secureTextEntry = [[MPiOSConfig get].hidePasswords boolValue];
|
||||
self.passwordField.attributedPlaceholder = stra(
|
||||
mainElement.type & MPSiteTypeClassStored? strl( @"No password" ):
|
||||
mainElement.type & MPSiteTypeClassGenerated? strl( @"..." ): @"", @{
|
||||
mainSite.type & MPSiteTypeClassStored? strl( @"No password" ):
|
||||
mainSite.type & MPSiteTypeClassGenerated? strl( @"..." ): @"", @{
|
||||
NSForegroundColorAttributeName : [UIColor whiteColor]
|
||||
} );
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *element = [self elementInContext:context];
|
||||
MPSiteEntity *site = [self siteInContext:context];
|
||||
MPKey *key = [MPiOSAppDelegate get].key;
|
||||
NSString *password, *loginName = [element resolveLoginUsingKey:key];
|
||||
NSString *password, *loginName = [site resolveLoginUsingKey:key];
|
||||
if (self.transientSite)
|
||||
password = [MPAlgorithmDefault generatePasswordForSiteNamed:self.transientSite ofType:
|
||||
[[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPSiteTypeGeneratedLong
|
||||
withCounter:1 usingKey:key];
|
||||
else if (element)
|
||||
password = [element resolvePasswordUsingKey:key];
|
||||
else if (site)
|
||||
password = [site resolvePasswordUsingKey:key];
|
||||
else
|
||||
return;
|
||||
|
||||
TimeToCrack timeToCrack;
|
||||
NSString *timeToCrackString = nil;
|
||||
id<MPAlgorithm> algorithm = element.algorithm?: MPAlgorithmDefault;
|
||||
id<MPAlgorithm> algorithm = site.algorithm?: MPAlgorithmDefault;
|
||||
MPAttacker attackHardware = [[MPConfig get].siteAttacker unsignedIntegerValue];
|
||||
if ([algorithm timeToCrack:&timeToCrack passwordOfType:element.type byAttacker:attackHardware] ||
|
||||
if ([algorithm timeToCrack:&timeToCrack passwordOfType:site.type byAttacker:attackHardware] ||
|
||||
[algorithm timeToCrack:&timeToCrack passwordString:password byAttacker:attackHardware])
|
||||
timeToCrackString = NSStringFromTimeToCrack( timeToCrack );
|
||||
|
||||
@ -538,8 +537,8 @@
|
||||
}];
|
||||
|
||||
// Site Counter
|
||||
if ([mainElement isKindOfClass:[MPElementGeneratedEntity class]])
|
||||
self.counterLabel.text = strf( @"%lu", (unsigned long)((MPElementGeneratedEntity *)mainElement).counter );
|
||||
if ([mainSite isKindOfClass:[MPGeneratedSiteEntity class]])
|
||||
self.counterLabel.text = strf( @"%lu", (unsigned long)((MPGeneratedSiteEntity *)mainSite).counter );
|
||||
|
||||
// Site Login Name
|
||||
self.loginNameField.enabled = self.passwordField.enabled = //
|
||||
@ -549,10 +548,10 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (BOOL)copyContentOfElement:(MPSiteEntity *)element saveInContext:(NSManagedObjectContext *)context {
|
||||
- (BOOL)copyContentOfSite:(MPSiteEntity *)site saveInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
inf( @"Copying password for: %@", element.name );
|
||||
NSString *password = [element resolvePasswordUsingKey:[MPAppDelegate_Shared get].key];
|
||||
inf( @"Copying password for: %@", site.name );
|
||||
NSString *password = [site resolvePasswordUsingKey:[MPAppDelegate_Shared get].key];
|
||||
if (![password length])
|
||||
return NO;
|
||||
|
||||
@ -561,15 +560,15 @@
|
||||
[UIPasteboard generalPasteboard].string = password;
|
||||
} );
|
||||
|
||||
[element use];
|
||||
[site use];
|
||||
[context saveToStore];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)copyLoginOfElement:(MPSiteEntity *)element saveInContext:(NSManagedObjectContext *)context {
|
||||
- (BOOL)copyLoginOfSite:(MPSiteEntity *)site saveInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
inf( @"Copying login for: %@", element.name );
|
||||
NSString *loginName = [element.algorithm resolveLoginForSite:element usingKey:[MPiOSAppDelegate get].key];
|
||||
inf( @"Copying login for: %@", site.name );
|
||||
NSString *loginName = [site.algorithm resolveLoginForSite:site usingKey:[MPiOSAppDelegate get].key];
|
||||
if (![loginName length])
|
||||
return NO;
|
||||
|
||||
@ -578,14 +577,14 @@
|
||||
[UIPasteboard generalPasteboard].string = loginName;
|
||||
} );
|
||||
|
||||
[element use];
|
||||
[site use];
|
||||
[context saveToStore];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (MPSiteEntity *)elementInContext:(NSManagedObjectContext *)context {
|
||||
- (MPSiteEntity *)siteInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
return [MPSiteEntity existingObjectWithID:_elementOID inContext:context];
|
||||
return [MPSiteEntity existingObjectWithID:_siteOID inContext:context];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -131,7 +131,7 @@ referenceSizeForHeaderInSection:(NSInteger)section {
|
||||
|
||||
MPPasswordCell *cell = [MPPasswordCell dequeueCellFromCollectionView:collectionView indexPath:indexPath];
|
||||
if (indexPath.item < ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[indexPath.section]).numberOfObjects)
|
||||
[cell setElement:[self.fetchedResultsController objectAtIndexPath:indexPath] animated:NO];
|
||||
[cell setSite:[self.fetchedResultsController objectAtIndexPath:indexPath] animated:NO];
|
||||
else
|
||||
[cell setTransientSite:self.query animated:NO];
|
||||
|
||||
@ -384,7 +384,7 @@ referenceSizeForHeaderInSection:(NSInteger)section {
|
||||
[NSPredicate predicateWithFormat:@"user == %@ AND name BEGINSWITH[cd] %@", activeUserOID, query]:
|
||||
[NSPredicate predicateWithFormat:@"user == %@", activeUserOID];
|
||||
if (![self.fetchedResultsController performFetch:&error])
|
||||
err( @"Couldn't fetch elements: %@", error );
|
||||
err( @"Couldn't fetch sites: %@", error );
|
||||
|
||||
[self.passwordCollectionView performBatchUpdates:^{
|
||||
[self fetchedItemsDidUpdate];
|
||||
|
@ -17,7 +17,7 @@
|
||||
- (MPSiteType)selectedType;
|
||||
|
||||
@optional
|
||||
- (MPSiteEntity *)selectedElement;
|
||||
- (MPSiteEntity *)selectedSite;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -63,21 +63,21 @@
|
||||
|
||||
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||
|
||||
MPSiteEntity *selectedElement = nil;
|
||||
if ([self.delegate respondsToSelector:@selector(selectedElement)])
|
||||
selectedElement = [self.delegate selectedElement];
|
||||
MPSiteEntity *selectedSite = nil;
|
||||
if ([self.delegate respondsToSelector:@selector( selectedSite )])
|
||||
selectedSite = [self.delegate selectedSite];
|
||||
|
||||
MPSiteType cellType = [self typeAtIndexPath:indexPath];
|
||||
MPSiteType selectedType = selectedElement? selectedElement.type: [self.delegate selectedType];
|
||||
MPSiteType selectedType = selectedSite? selectedSite.type: [self.delegate selectedType];
|
||||
cell.selected = (selectedType == cellType);
|
||||
|
||||
if (cellType != (MPSiteType)NSNotFound && cellType & MPSiteTypeClassGenerated) {
|
||||
[(UITextField *)[cell viewWithTag:2] setText:@"..."];
|
||||
|
||||
NSString *name = selectedElement.name;
|
||||
NSString *name = selectedSite.name;
|
||||
NSUInteger counter = 0;
|
||||
if ([selectedElement isKindOfClass:[MPElementGeneratedEntity class]])
|
||||
counter = ((MPElementGeneratedEntity *)selectedElement).counter;
|
||||
if ([selectedSite isKindOfClass:[MPGeneratedSiteEntity class]])
|
||||
counter = ((MPGeneratedSiteEntity *)selectedSite).counter;
|
||||
|
||||
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{
|
||||
NSString *typeContent = [MPAlgorithmDefault generatePasswordForSiteNamed:name ofType:cellType
|
||||
@ -129,7 +129,7 @@
|
||||
return (MPSiteType)NSNotFound;
|
||||
|
||||
default: {
|
||||
Throw(@"Unsupported row: %ld, when selecting generated element type.", (long)indexPath.row);
|
||||
Throw(@"Unsupported row: %ld, when selecting generated site type.", (long)indexPath.row);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,13 +147,13 @@
|
||||
return (MPSiteType)NSNotFound;
|
||||
|
||||
default: {
|
||||
Throw(@"Unsupported row: %ld, when selecting stored element type.", (long)indexPath.row);
|
||||
Throw(@"Unsupported row: %ld, when selecting stored site type.", (long)indexPath.row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
Throw(@"Unsupported section: %ld, when selecting element type.", (long)indexPath.section);
|
||||
Throw(@"Unsupported section: %ld, when selecting site type.", (long)indexPath.section);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user