2
0

Improve support for import/export headers on iOS/Mac.

[ADDED]     iOS/macOS support for Full Name, Algorithm and Default Type mpsites headers.
This commit is contained in:
Maarten Billemont 2017-04-19 21:58:10 -04:00
parent c99252809d
commit d9bd604436
6 changed files with 46 additions and 29 deletions

View File

@ -58,6 +58,7 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack);
- (Class)classOfType:(MPSiteType)type; - (Class)classOfType:(MPSiteType)type;
- (NSArray *)allTypes; - (NSArray *)allTypes;
- (NSArray *)allTypesStartingWith:(MPSiteType)startingType; - (NSArray *)allTypesStartingWith:(MPSiteType)startingType;
- (MPSiteType)defaultType;
- (MPSiteType)nextType:(MPSiteType)type; - (MPSiteType)nextType:(MPSiteType)type;
- (MPSiteType)previousType:(MPSiteType)type; - (MPSiteType)previousType:(MPSiteType)type;

View File

@ -286,6 +286,11 @@ NSOperationQueue *_mpwQueue = nil;
return allTypes; return allTypes;
} }
- (MPSiteType)defaultType {
return MPSiteTypeGeneratedLong;
}
- (MPSiteType)nextType:(MPSiteType)type { - (MPSiteType)nextType:(MPSiteType)type {
switch (type) { switch (type) {
@ -309,9 +314,9 @@ NSOperationQueue *_mpwQueue = nil;
return MPSiteTypeStoredDevicePrivate; return MPSiteTypeStoredDevicePrivate;
case MPSiteTypeStoredDevicePrivate: case MPSiteTypeStoredDevicePrivate:
return MPSiteTypeGeneratedPhrase; return MPSiteTypeGeneratedPhrase;
default:
return MPSiteTypeGeneratedLong;
} }
return [self defaultType];
} }
- (MPSiteType)previousType:(MPSiteType)type { - (MPSiteType)previousType:(MPSiteType)type {

View File

@ -537,12 +537,13 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
// Parse import data. // Parse import data.
inf( @"Importing sites." ); inf( @"Importing sites." );
__block MPUserEntity *user = nil;
id<MPAlgorithm> importAlgorithm = nil;
NSUInteger importFormat = 0; NSUInteger importFormat = 0;
__block MPUserEntity *user = nil;
NSUInteger importAvatar = NSNotFound; NSUInteger importAvatar = NSNotFound;
NSString *importBundleVersion = nil, *importUserName = nil;
NSData *importKeyID = nil; NSData *importKeyID = nil;
NSString *importBundleVersion = nil, *importUserName = nil;
id<MPAlgorithm> importAlgorithm = nil;
MPSiteType importDefaultType = (MPSiteType)0;
BOOL headerStarted = NO, headerEnded = NO, clearText = NO; BOOL headerStarted = NO, headerEnded = NO, clearText = NO;
NSArray *importedSiteLines = [importedSitesString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; NSArray *importedSiteLines = [importedSitesString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSMutableSet *sitesToDelete = [NSMutableSet set]; NSMutableSet *sitesToDelete = [NSMutableSet set];
@ -573,7 +574,15 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
range:NSMakeRange( 0, [importedSiteLine length] )] lastObject]; range:NSMakeRange( 0, [importedSiteLine length] )] lastObject];
NSString *headerName = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:1]]; NSString *headerName = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:1]];
NSString *headerValue = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:2]]; NSString *headerValue = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:2]];
if ([headerName isEqualToString:@"User Name"]) {
if ([headerName isEqualToString:@"Format"]) {
importFormat = (NSUInteger)[headerValue integerValue];
if (importFormat >= [sitePatterns count]) {
err( @"Unsupported import format: %lu", (unsigned long)importFormat );
return MPImportResultInternalError;
}
}
if (([headerName isEqualToString:@"User Name"] || [headerName isEqualToString:@"Full Name"]) && !importUserName) {
importUserName = headerValue; importUserName = headerValue;
NSFetchRequest *userFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )]; NSFetchRequest *userFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
@ -591,21 +600,18 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
user = [users lastObject]; user = [users lastObject];
dbg( @"Existing user? %@", [user debugDescription] ); dbg( @"Existing user? %@", [user debugDescription] );
} }
if ([headerName isEqualToString:@"Avatar"])
importAvatar = (NSUInteger)[headerValue integerValue];
if ([headerName isEqualToString:@"Key ID"]) if ([headerName isEqualToString:@"Key ID"])
importKeyID = [headerValue decodeHex]; importKeyID = [headerValue decodeHex];
if ([headerName isEqualToString:@"Version"]) { if ([headerName isEqualToString:@"Version"]) {
importBundleVersion = headerValue; importBundleVersion = headerValue;
importAlgorithm = MPAlgorithmDefaultForBundleVersion( importBundleVersion ); importAlgorithm = MPAlgorithmDefaultForBundleVersion( importBundleVersion );
} }
if ([headerName isEqualToString:@"Format"]) { if ([headerName isEqualToString:@"Algorithm"])
importFormat = (NSUInteger)[headerValue integerValue]; importAlgorithm = MPAlgorithmForVersion( (MPAlgorithmVersion)[headerValue integerValue] );
if (importFormat >= [sitePatterns count]) { if ([headerName isEqualToString:@"Default Type"])
err( @"Unsupported import format: %lu", (unsigned long)importFormat ); importDefaultType = (MPSiteType)[headerValue integerValue];
return MPImportResultInternalError;
}
}
if ([headerName isEqualToString:@"Avatar"])
importAvatar = (NSUInteger)[headerValue integerValue];
if ([headerName isEqualToString:@"Passwords"]) { if ([headerName isEqualToString:@"Passwords"]) {
if ([headerValue isEqualToString:@"VISIBLE"]) if ([headerValue isEqualToString:@"VISIBLE"])
clearText = YES; clearText = YES;
@ -709,6 +715,8 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
if (user) { if (user) {
if (importAvatar != NSNotFound) if (importAvatar != NSNotFound)
user.avatar = importAvatar; user.avatar = importAvatar;
if (importDefaultType)
user.defaultType = importDefaultType;
dbg( @"Updating User: %@", [user debugDescription] ); dbg( @"Updating User: %@", [user debugDescription] );
} }
else { else {
@ -716,6 +724,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
user.name = importUserName; user.name = importUserName;
user.algorithm = MPAlgorithmDefault; user.algorithm = MPAlgorithmDefault;
user.keyID = [userKey keyIDForAlgorithm:user.algorithm]; user.keyID = [userKey keyIDForAlgorithm:user.algorithm];
user.defaultType = importDefaultType?: user.algorithm.defaultType;
if (importAvatar != NSNotFound) if (importAvatar != NSNotFound)
user.avatar = importAvatar; user.avatar = importAvatar;
dbg( @"Created User: %@", [user debugDescription] ); dbg( @"Created User: %@", [user debugDescription] );
@ -785,16 +794,16 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
[export appendFormat:@"# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n"]; [export appendFormat:@"# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n"];
[export appendFormat:@"# \n"]; [export appendFormat:@"# \n"];
[export appendFormat:@"##\n"]; [export appendFormat:@"##\n"];
[export appendFormat:@"# Format: 1\n"];
[export appendFormat:@"# Date: %@\n", [[NSDateFormatter rfc3339DateFormatter] stringFromDate:[NSDate date]]];
[export appendFormat:@"# User Name: %@\n", activeUser.name]; [export appendFormat:@"# User Name: %@\n", activeUser.name];
[export appendFormat:@"# Full Name: %@\n", activeUser.name];
[export appendFormat:@"# Avatar: %lu\n", (unsigned long)activeUser.avatar]; [export appendFormat:@"# Avatar: %lu\n", (unsigned long)activeUser.avatar];
[export appendFormat:@"# Key ID: %@\n", [activeUser.keyID encodeHex]]; [export appendFormat:@"# Key ID: %@\n", [activeUser.keyID encodeHex]];
[export appendFormat:@"# Date: %@\n", [[NSDateFormatter rfc3339DateFormatter] stringFromDate:[NSDate date]]];
[export appendFormat:@"# Version: %@\n", [PearlInfoPlist get].CFBundleVersion]; [export appendFormat:@"# Version: %@\n", [PearlInfoPlist get].CFBundleVersion];
[export appendFormat:@"# Format: 1\n"]; [export appendFormat:@"# Algorithm: %d\n", activeUser.algorithm.version];
if (revealPasswords) [export appendFormat:@"# Default Type: %d\n", activeUser.defaultType];
[export appendFormat:@"# Passwords: VISIBLE\n"]; [export appendFormat:@"# Passwords: %@\n", revealPasswords? @"VISIBLE": @"PROTECTED"];
else
[export appendFormat:@"# Passwords: PROTECTED\n"];
[export appendFormat:@"##\n"]; [export appendFormat:@"##\n"];
[export appendFormat:@"#\n"]; [export appendFormat:@"#\n"];
[export appendFormat:@"# Last Times Password Login\t Site\tSite\n"]; [export appendFormat:@"# Last Times Password Login\t Site\tSite\n"];

View File

@ -237,8 +237,8 @@
// Invalid self.user.defaultType // Invalid self.user.defaultType
result = MPApplyFix( result, ^MPFixableResult { result = MPApplyFix( result, ^MPFixableResult {
wrn( @"Invalid type for: %@ of %@, type: %ld. Will use %ld instead.", wrn( @"Invalid type for: %@ of %@, type: %ld. Will use %ld instead.",
self.name, self.user.name, (long)self.type, (long)MPSiteTypeGeneratedLong ); self.name, self.user.name, (long)self.type, (long)[self.algorithm defaultType] );
self.type = MPSiteTypeGeneratedLong; self.type = [self.algorithm defaultType];
return MPFixableResultProblemsFixed; return MPFixableResultProblemsFixed;
} ); } );
if (![self isKindOfClass:[self.algorithm classOfType:self.type]]) if (![self isKindOfClass:[self.algorithm classOfType:self.type]])
@ -330,7 +330,7 @@
- (MPSiteType)defaultType { - (MPSiteType)defaultType {
return (MPSiteType)[self.defaultType_ unsignedIntegerValue]?: MPSiteTypeGeneratedLong; return (MPSiteType)[self.defaultType_ unsignedIntegerValue]?: self.algorithm.defaultType;
} }
- (void)setDefaultType:(MPSiteType)aDefaultType { - (void)setDefaultType:(MPSiteType)aDefaultType {

View File

@ -281,12 +281,12 @@
[self setMode:MPPasswordCellModePassword animated:YES]; [self setMode:MPPasswordCellModePassword animated:YES];
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
[PearlSheet showSheetWithTitle:@"Change Password Type" viewStyle:UIActionSheetStyleAutomatic [PearlSheet showSheetWithTitle:@"Change Password Type" viewStyle:UIActionSheetStyleAutomatic
initSheet:^(UIActionSheet *sheet) { initSheet:^(UIActionSheet *sheet) {
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]; for (NSNumber *typeNumber in [mainSite.algorithm allTypes]) {
for (NSNumber *typeNumber in [MPAlgorithmDefault allTypes]) {
MPSiteType type = (MPSiteType)[typeNumber unsignedIntegerValue]; MPSiteType type = (MPSiteType)[typeNumber unsignedIntegerValue];
NSString *typeName = [MPAlgorithmDefault nameOfType:type]; NSString *typeName = [mainSite.algorithm nameOfType:type];
if (type == mainSite.type) if (type == mainSite.type)
[sheet addButtonWithTitle:strf( @"● %@", typeName )]; [sheet addButtonWithTitle:strf( @"● %@", typeName )];
else else
@ -296,7 +296,8 @@
if (buttonIndex == [sheet cancelButtonIndex]) if (buttonIndex == [sheet cancelButtonIndex])
return; return;
MPSiteType type = (MPSiteType)[[MPAlgorithmDefault allTypes][buttonIndex] unsignedIntegerValue]?: MPSiteTypeGeneratedLong; MPSiteType type = (MPSiteType)[[mainSite.algorithm allTypes][buttonIndex] unsignedIntegerValue]?:
mainSite.user.defaultType?: mainSite.algorithm.defaultType;
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPSiteEntity *site = [self siteInContext:context]; MPSiteEntity *site = [self siteInContext:context];
@ -550,7 +551,7 @@
BOOL loginGenerated = site.loginGenerated; BOOL loginGenerated = site.loginGenerated;
NSString *password = nil, *loginName = [site resolveLoginUsingKey:key]; NSString *password = nil, *loginName = [site resolveLoginUsingKey:key];
MPSiteType transientType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPSiteTypeGeneratedLong; MPSiteType transientType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPAlgorithmDefault.defaultType;
if (self.transientSite && transientType & MPSiteTypeClassGenerated) if (self.transientSite && transientType & MPSiteTypeClassGenerated)
password = [MPAlgorithmDefault generatePasswordForSiteNamed:self.transientSite ofType:transientType password = [MPAlgorithmDefault generatePasswordForSiteNamed:self.transientSite ofType:transientType
withCounter:1 usingKey:key]; withCounter:1 usingKey:key];

View File

@ -220,6 +220,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
if (isNew) { if (isNew) {
user = [MPUserEntity insertNewObjectInContext:context]; user = [MPUserEntity insertNewObjectInContext:context];
user.algorithm = MPAlgorithmDefault; user.algorithm = MPAlgorithmDefault;
user.defaultType = user.algorithm.defaultType;
user.avatar = newUserAvatar; user.avatar = newUserAvatar;
user.name = newUserName; user.name = newUserName;
} }