2
0

Element -> Site

This commit is contained in:
Maarten Billemont 2014-09-21 11:47:53 -04:00
parent b3a0b6a7c0
commit 5b85ba3a4b
25 changed files with 337 additions and 338 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,7 +17,7 @@
- (MPSiteType)selectedType;
@optional
- (MPSiteEntity *)selectedElement;
- (MPSiteEntity *)selectedSite;
@end

View File

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