Add marshalling metadata lookup & adapt iOS for new APIs.
This commit is contained in:
@@ -137,7 +137,7 @@
|
||||
- (void)updatePassword {
|
||||
|
||||
NSString *siteName = self.siteField.text;
|
||||
MPSiteType siteType = [self siteType];
|
||||
MPResultType siteType = [self siteType];
|
||||
NSUInteger siteCounter = (NSUInteger)self.counterStepper.value;
|
||||
self.counterLabel.text = strf( @"%lu", (unsigned long)siteCounter );
|
||||
|
||||
@@ -147,8 +147,8 @@
|
||||
[self.emergencyPasswordQueue addOperationWithBlock:^{
|
||||
NSString *sitePassword = nil;
|
||||
if (self.key && [siteName length])
|
||||
sitePassword = [MPAlgorithmDefault generatePasswordForSiteNamed:siteName ofType:siteType withCounter:siteCounter
|
||||
usingKey:self.key];
|
||||
sitePassword = [MPAlgorithmDefault mpwTemplateForSiteNamed:siteName ofType:siteType withCounter:siteCounter
|
||||
usingKey:self.key];
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[self.activity stopAnimating];
|
||||
@@ -157,21 +157,21 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (enum MPSiteType)siteType {
|
||||
- (MPResultType)siteType {
|
||||
|
||||
switch (self.typeControl.selectedSegmentIndex) {
|
||||
case 0:
|
||||
return MPSiteTypeGeneratedMaximum;
|
||||
return MPResultTypeTemplateMaximum;
|
||||
case 1:
|
||||
return MPSiteTypeGeneratedLong;
|
||||
return MPResultTypeTemplateLong;
|
||||
case 2:
|
||||
return MPSiteTypeGeneratedMedium;
|
||||
return MPResultTypeTemplateMedium;
|
||||
case 3:
|
||||
return MPSiteTypeGeneratedBasic;
|
||||
return MPResultTypeTemplateBasic;
|
||||
case 4:
|
||||
return MPSiteTypeGeneratedShort;
|
||||
return MPResultTypeTemplateShort;
|
||||
case 5:
|
||||
return MPSiteTypeGeneratedPIN;
|
||||
return MPResultTypeTemplatePIN;
|
||||
default:
|
||||
Throw( @"Unsupported type index: %ld", (long)self.typeControl.selectedSegmentIndex );
|
||||
}
|
||||
|
@@ -60,15 +60,15 @@
|
||||
self.touchIDSwitch.on = activeUser.touchID;
|
||||
self.touchIDSwitch.enabled = self.savePasswordSwitch.on && [[MPiOSAppDelegate get] isFeatureUnlocked:MPProductTouchID];
|
||||
|
||||
MPSiteType defaultType = activeUser.defaultType;
|
||||
MPResultType defaultType = activeUser.defaultType;
|
||||
self.generated1TypeControl.selectedSegmentIndex = [self generated1SegmentIndexForType:defaultType];
|
||||
self.generated2TypeControl.selectedSegmentIndex = [self generated2SegmentIndexForType:defaultType];
|
||||
self.storedTypeControl.selectedSegmentIndex = [self storedSegmentIndexForType:defaultType];
|
||||
PearlNotMainQueue( ^{
|
||||
NSString *examplePassword = nil;
|
||||
if (defaultType & MPSiteTypeClassGenerated)
|
||||
examplePassword = [MPAlgorithmDefault generatePasswordForSiteNamed:@"test" ofType:defaultType
|
||||
withCounter:1 usingKey:[MPiOSAppDelegate get].key];
|
||||
if (defaultType & MPResultTypeClassTemplate)
|
||||
examplePassword = [MPAlgorithmDefault mpwTemplateForSiteNamed:@"test" ofType:defaultType
|
||||
withCounter:1 usingKey:[MPiOSAppDelegate get].key];
|
||||
PearlMainQueue( ^{
|
||||
self.typeSamplePassword.text = [examplePassword length]? [NSString stringWithFormat:@"eg. %@", examplePassword]: nil;
|
||||
} );
|
||||
@@ -164,7 +164,7 @@
|
||||
if (sender != self.storedTypeControl)
|
||||
self.storedTypeControl.selectedSegmentIndex = -1;
|
||||
|
||||
MPSiteType defaultType = [self typeForSelectedSegment];
|
||||
MPResultType defaultType = [self typeForSelectedSegment];
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
[[MPiOSAppDelegate get] activeUserInContext:context].defaultType = defaultType;
|
||||
[context saveToStore];
|
||||
@@ -242,7 +242,7 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (MPSiteType)typeForSelectedSegment {
|
||||
- (MPResultType)typeForSelectedSegment {
|
||||
|
||||
NSInteger selectedGenerated1Index = self.generated1TypeControl.selectedSegmentIndex;
|
||||
NSInteger selectedGenerated2Index = self.generated2TypeControl.selectedSegmentIndex;
|
||||
@@ -250,30 +250,30 @@
|
||||
|
||||
switch (selectedGenerated1Index) {
|
||||
case 0:
|
||||
return MPSiteTypeGeneratedPhrase;
|
||||
return MPResultTypeTemplatePhrase;
|
||||
case 1:
|
||||
return MPSiteTypeGeneratedName;
|
||||
return MPResultTypeTemplateName;
|
||||
default:
|
||||
switch (selectedGenerated2Index) {
|
||||
case 0:
|
||||
return MPSiteTypeGeneratedMaximum;
|
||||
return MPResultTypeTemplateMaximum;
|
||||
case 1:
|
||||
return MPSiteTypeGeneratedLong;
|
||||
return MPResultTypeTemplateLong;
|
||||
case 2:
|
||||
return MPSiteTypeGeneratedMedium;
|
||||
return MPResultTypeTemplateMedium;
|
||||
case 3:
|
||||
return MPSiteTypeGeneratedBasic;
|
||||
return MPResultTypeTemplateBasic;
|
||||
case 4:
|
||||
return MPSiteTypeGeneratedShort;
|
||||
return MPResultTypeTemplateShort;
|
||||
case 5:
|
||||
return MPSiteTypeGeneratedPIN;
|
||||
return MPResultTypeTemplatePIN;
|
||||
default:
|
||||
|
||||
switch (selectedStoredIndex) {
|
||||
case 0:
|
||||
return MPSiteTypeStoredPersonal;
|
||||
return MPResultTypeStatefulPersonal;
|
||||
case 1:
|
||||
return MPSiteTypeStoredDevicePrivate;
|
||||
return MPResultTypeStatefulDevice;
|
||||
default:
|
||||
Throw( @"unsupported selected type index: generated1=%ld, generated2=%ld, stored=%ld",
|
||||
(long)selectedGenerated1Index, (long)selectedGenerated2Index, (long)selectedStoredIndex );
|
||||
@@ -282,44 +282,44 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)generated1SegmentIndexForType:(MPSiteType)type {
|
||||
- (NSInteger)generated1SegmentIndexForType:(MPResultType)type {
|
||||
|
||||
switch (type) {
|
||||
case MPSiteTypeGeneratedPhrase:
|
||||
case MPResultTypeTemplatePhrase:
|
||||
return 0;
|
||||
case MPSiteTypeGeneratedName:
|
||||
case MPResultTypeTemplateName:
|
||||
return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)generated2SegmentIndexForType:(MPSiteType)type {
|
||||
- (NSInteger)generated2SegmentIndexForType:(MPResultType)type {
|
||||
|
||||
switch (type) {
|
||||
case MPSiteTypeGeneratedMaximum:
|
||||
case MPResultTypeTemplateMaximum:
|
||||
return 0;
|
||||
case MPSiteTypeGeneratedLong:
|
||||
case MPResultTypeTemplateLong:
|
||||
return 1;
|
||||
case MPSiteTypeGeneratedMedium:
|
||||
case MPResultTypeTemplateMedium:
|
||||
return 2;
|
||||
case MPSiteTypeGeneratedBasic:
|
||||
case MPResultTypeTemplateBasic:
|
||||
return 3;
|
||||
case MPSiteTypeGeneratedShort:
|
||||
case MPResultTypeTemplateShort:
|
||||
return 4;
|
||||
case MPSiteTypeGeneratedPIN:
|
||||
case MPResultTypeTemplatePIN:
|
||||
return 5;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)storedSegmentIndexForType:(MPSiteType)type {
|
||||
- (NSInteger)storedSegmentIndexForType:(MPResultType)type {
|
||||
|
||||
switch (type) {
|
||||
case MPSiteTypeStoredPersonal:
|
||||
case MPResultTypeStatefulPersonal:
|
||||
return 0;
|
||||
case MPSiteTypeStoredDevicePrivate:
|
||||
case MPResultTypeStatefulDevice:
|
||||
return 1;
|
||||
default:
|
||||
return -1;
|
||||
|
@@ -284,7 +284,7 @@
|
||||
[PearlSheet showSheetWithTitle:@"Change Password Type" viewStyle:UIActionSheetStyleAutomatic
|
||||
initSheet:^(UIActionSheet *sheet) {
|
||||
for (NSNumber *typeNumber in [mainSite.algorithm allTypes]) {
|
||||
MPSiteType type = (MPSiteType)[typeNumber unsignedIntegerValue];
|
||||
MPResultType type = (MPResultType)[typeNumber unsignedIntegerValue];
|
||||
NSString *typeName = [mainSite.algorithm nameOfType:type];
|
||||
if (type == mainSite.type)
|
||||
[sheet addButtonWithTitle:strf( @"● %@", typeName )];
|
||||
@@ -295,7 +295,7 @@
|
||||
if (buttonIndex == [sheet cancelButtonIndex])
|
||||
return;
|
||||
|
||||
MPSiteType type = (MPSiteType)[[mainSite.algorithm allTypes][buttonIndex] unsignedIntegerValue]?:
|
||||
MPResultType type = (MPResultType)[[mainSite.algorithm allTypes][buttonIndex] unsignedIntegerValue]?:
|
||||
mainSite.user.defaultType?: mainSite.algorithm.defaultType;
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
@@ -311,7 +311,7 @@
|
||||
self.loginNameField.enabled = YES;
|
||||
self.passwordField.enabled = YES;
|
||||
|
||||
if ([self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].type & MPSiteTypeClassStored)
|
||||
if ([self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].type & MPResultTypeClassStateful)
|
||||
[self.passwordField becomeFirstResponder];
|
||||
else
|
||||
[self.loginNameField becomeFirstResponder];
|
||||
@@ -537,7 +537,7 @@
|
||||
self.loginNameContainer.visible = settingsMode || mainSite.loginGenerated || [mainSite.loginName length];
|
||||
self.modeButton.visible = !self.transientSite;
|
||||
self.modeButton.alpha = settingsMode? 0.5f: 0.1f;
|
||||
self.counterLabel.visible = self.counterButton.visible = mainSite.type & MPSiteTypeClassGenerated;
|
||||
self.counterLabel.visible = self.counterButton.visible = mainSite.type & MPResultTypeClassTemplate;
|
||||
self.modeButton.selected = settingsMode;
|
||||
self.strengthLabel.gone = !settingsMode;
|
||||
self.modeScrollView.scrollEnabled = !self.transientSite;
|
||||
@@ -565,8 +565,8 @@
|
||||
// Site Password
|
||||
self.passwordField.secureTextEntry = [[MPiOSConfig get].hidePasswords boolValue];
|
||||
self.passwordField.attributedPlaceholder = stra(
|
||||
mainSite.type & MPSiteTypeClassStored? strl( @"No password" ):
|
||||
mainSite.type & MPSiteTypeClassGenerated? strl( @"..." ): @"", @{
|
||||
mainSite.type & MPResultTypeClassStateful? strl( @"No password" ):
|
||||
mainSite.type & MPResultTypeClassTemplate? strl( @"..." ): @"", @{
|
||||
NSForegroundColorAttributeName: [UIColor whiteColor]
|
||||
} );
|
||||
|
||||
@@ -585,10 +585,10 @@
|
||||
|
||||
BOOL loginGenerated = site.loginGenerated;
|
||||
NSString *password = nil, *loginName = [site resolveLoginUsingKey:key];
|
||||
MPSiteType transientType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPAlgorithmDefault.defaultType;
|
||||
if (self.transientSite && transientType & MPSiteTypeClassGenerated)
|
||||
password = [MPAlgorithmDefault generatePasswordForSiteNamed:self.transientSite ofType:transientType
|
||||
withCounter:1 usingKey:key];
|
||||
MPResultType transientType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPAlgorithmDefault.defaultType;
|
||||
if (self.transientSite && transientType & MPResultTypeClassTemplate)
|
||||
password = [MPAlgorithmDefault mpwTemplateForSiteNamed:self.transientSite ofType:transientType
|
||||
withCounter:1 usingKey:key];
|
||||
else if (site)
|
||||
password = [site resolvePasswordUsingKey:key];
|
||||
|
||||
|
@@ -23,8 +23,8 @@
|
||||
@protocol MPTypeDelegate<NSObject>
|
||||
|
||||
@required
|
||||
- (void)didSelectType:(MPSiteType)type;
|
||||
- (MPSiteType)selectedType;
|
||||
- (void)didSelectType:(MPResultType)type;
|
||||
- (MPResultType)selectedType;
|
||||
|
||||
@optional
|
||||
- (MPSiteEntity *)selectedSite;
|
||||
|
@@ -22,7 +22,7 @@
|
||||
|
||||
@interface MPTypeViewController()
|
||||
|
||||
- (MPSiteType)typeAtIndexPath:(NSIndexPath *)indexPath;
|
||||
- (MPResultType)typeAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
@end
|
||||
|
||||
@@ -75,11 +75,11 @@
|
||||
if ([self.delegate respondsToSelector:@selector( selectedSite )])
|
||||
selectedSite = [self.delegate selectedSite];
|
||||
|
||||
MPSiteType cellType = [self typeAtIndexPath:indexPath];
|
||||
MPSiteType selectedType = selectedSite? selectedSite.type: [self.delegate selectedType];
|
||||
MPResultType cellType = [self typeAtIndexPath:indexPath];
|
||||
MPResultType selectedType = selectedSite? selectedSite.type: [self.delegate selectedType];
|
||||
cell.selected = (selectedType == cellType);
|
||||
|
||||
if (cellType != (MPSiteType)NSNotFound && cellType & MPSiteTypeClassGenerated) {
|
||||
if (cellType != (MPResultType)NSNotFound && cellType & MPResultTypeClassTemplate) {
|
||||
[(UITextField *)[cell viewWithTag:2] setText:@"..."];
|
||||
|
||||
NSString *name = selectedSite.name;
|
||||
@@ -88,8 +88,8 @@
|
||||
counter = ((MPGeneratedSiteEntity *)selectedSite).counter;
|
||||
|
||||
PearlNotMainQueue( ^{
|
||||
NSString *typeContent = [MPAlgorithmDefault generatePasswordForSiteNamed:name ofType:cellType
|
||||
withCounter:counter usingKey:[MPiOSAppDelegate get].key];
|
||||
NSString *typeContent = [MPAlgorithmDefault mpwTemplateForSiteNamed:name ofType:cellType
|
||||
withCounter:counter usingKey:[MPiOSAppDelegate get].key];
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[(UITextField *)[[tableView cellForRowAtIndexPath:indexPath] viewWithTag:2] setText:typeContent];
|
||||
@@ -104,8 +104,8 @@
|
||||
|
||||
NSAssert( self.navigationController.topViewController == self, @"Not the currently active navigation item." );
|
||||
|
||||
MPSiteType type = [self typeAtIndexPath:indexPath];
|
||||
if (type == (MPSiteType)NSNotFound)
|
||||
MPResultType type = [self typeAtIndexPath:indexPath];
|
||||
if (type == (MPResultType)NSNotFound)
|
||||
// Selected a non-type row.
|
||||
return;
|
||||
|
||||
@@ -113,28 +113,28 @@
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (MPSiteType)typeAtIndexPath:(NSIndexPath *)indexPath {
|
||||
- (MPResultType)typeAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
switch (indexPath.section) {
|
||||
case 0: {
|
||||
// Generated
|
||||
switch (indexPath.row) {
|
||||
case 0:
|
||||
return (MPSiteType)NSNotFound;
|
||||
return (MPResultType)NSNotFound;
|
||||
case 1:
|
||||
return MPSiteTypeGeneratedMaximum;
|
||||
return MPResultTypeTemplateMaximum;
|
||||
case 2:
|
||||
return MPSiteTypeGeneratedLong;
|
||||
return MPResultTypeTemplateLong;
|
||||
case 3:
|
||||
return MPSiteTypeGeneratedMedium;
|
||||
return MPResultTypeTemplateMedium;
|
||||
case 4:
|
||||
return MPSiteTypeGeneratedBasic;
|
||||
return MPResultTypeTemplateBasic;
|
||||
case 5:
|
||||
return MPSiteTypeGeneratedShort;
|
||||
return MPResultTypeTemplateShort;
|
||||
case 6:
|
||||
return MPSiteTypeGeneratedPIN;
|
||||
return MPResultTypeTemplatePIN;
|
||||
case 7:
|
||||
return (MPSiteType)NSNotFound;
|
||||
return (MPResultType)NSNotFound;
|
||||
|
||||
default: {
|
||||
Throw( @"Unsupported row: %ld, when selecting generated site type.", (long)indexPath.row );
|
||||
@@ -146,13 +146,13 @@
|
||||
// Stored
|
||||
switch (indexPath.row) {
|
||||
case 0:
|
||||
return (MPSiteType)NSNotFound;
|
||||
return (MPResultType)NSNotFound;
|
||||
case 1:
|
||||
return MPSiteTypeStoredPersonal;
|
||||
return MPResultTypeStatefulPersonal;
|
||||
case 2:
|
||||
return MPSiteTypeStoredDevicePrivate;
|
||||
return MPResultTypeStatefulDevice;
|
||||
case 3:
|
||||
return (MPSiteType)NSNotFound;
|
||||
return (MPResultType)NSNotFound;
|
||||
|
||||
default: {
|
||||
Throw( @"Unsupported row: %ld, when selecting stored site type.", (long)indexPath.row );
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#import "MPAppDelegate_Key.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "MPStoreViewController.h"
|
||||
#import "mpw-marshall.h"
|
||||
|
||||
@interface MPiOSAppDelegate()<UIDocumentInteractionControllerDelegate>
|
||||
|
||||
@@ -177,62 +178,46 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)importSites:(NSString *)importedSitesString {
|
||||
- (void)importSites:(NSString *)importData {
|
||||
|
||||
if ([NSThread isMainThread]) {
|
||||
PearlNotMainQueue( ^{
|
||||
[self importSites:importedSitesString];
|
||||
[self importSites:importData];
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"];
|
||||
MPImportResult result = [self importSites:importedSitesString askImportPassword:^NSString *(NSString *userName) {
|
||||
[self importSites:importData askImportPassword:^NSString *(NSString *userName) {
|
||||
return PearlAwait( ^(void (^setResult)(id)) {
|
||||
[PearlAlert showAlertWithTitle:@"Import File's Master Password"
|
||||
message:strf( @"%@'s export was done using a different master password.\n"
|
||||
@"Enter that master password to unlock the exported data.", userName )
|
||||
[PearlAlert showAlertWithTitle:strf( @"Importing Sites For\n%@", userName )
|
||||
message:@"Enter the master password used to create this export file."
|
||||
viewStyle:UIAlertViewStyleSecureTextInput
|
||||
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
||||
if (buttonIndex_ == [alert_ cancelButtonIndex])
|
||||
setResult( nil );
|
||||
else
|
||||
setResult( [alert_ textFieldAtIndex:0].text );
|
||||
}
|
||||
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Unlock Import", nil];
|
||||
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil];
|
||||
} );
|
||||
} askUserPassword:^NSString *(NSString *userName, NSUInteger importCount, NSUInteger deleteCount) {
|
||||
} askUserPassword:^NSString *(NSString *userName) {
|
||||
return PearlAwait( (id)^(void (^setResult)(id)) {
|
||||
[PearlAlert showAlertWithTitle:strf( @"Master Password for\n%@", userName )
|
||||
message:strf( @"Imports %lu sites, overwriting %lu.",
|
||||
(unsigned long)importCount, (unsigned long)deleteCount )
|
||||
[PearlAlert showAlertWithTitle:strf( @"Master Password For\n%@", userName )
|
||||
message:@"Enter the current master password for this user."
|
||||
viewStyle:UIAlertViewStyleSecureTextInput
|
||||
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
||||
if (buttonIndex_ == [alert_ cancelButtonIndex])
|
||||
setResult( nil );
|
||||
else
|
||||
setResult( [alert_ textFieldAtIndex:0].text );
|
||||
}
|
||||
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil];
|
||||
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil];
|
||||
} );
|
||||
} result:^(NSError *error) {
|
||||
[activityOverlay cancelOverlayAnimated:YES];
|
||||
|
||||
if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError))
|
||||
[PearlAlert showError:error.localizedDescription];
|
||||
}];
|
||||
|
||||
switch (result) {
|
||||
case MPImportResultSuccess:
|
||||
case MPImportResultCancelled:
|
||||
break;
|
||||
case MPImportResultInternalError:
|
||||
[PearlAlert showError:@"Import failed because of an internal error."];
|
||||
break;
|
||||
case MPImportResultMalformedInput:
|
||||
[PearlAlert showError:@"The import doesn't look like a Master Password export."];
|
||||
break;
|
||||
case MPImportResultInvalidPassword:
|
||||
[PearlAlert showError:@"Incorrect master password for the import sites."];
|
||||
break;
|
||||
}
|
||||
|
||||
[activityOverlay cancelOverlayAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
||||
@@ -250,10 +235,9 @@
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
|
||||
|
||||
PearlNotMainQueue( ^{
|
||||
NSString *importHeader = @"# Master Password site export";
|
||||
NSString *importedSitesString = [UIPasteboard generalPasteboard].string;
|
||||
if ([importedSitesString length] > [importHeader length] &&
|
||||
[[importedSitesString substringToIndex:[importHeader length]] isEqualToString:importHeader])
|
||||
NSString *importData = [UIPasteboard generalPasteboard].string;
|
||||
MPMarshallInfo *importInfo = mpw_marshall_read_info( importData.UTF8String );
|
||||
if (importInfo->format != MPMarshallFormatNone)
|
||||
[PearlAlert showAlertWithTitle:@"Import Sites?" message:
|
||||
@"We've detected Master Password import sites on your pasteboard, would you like to import them?"
|
||||
viewStyle:UIAlertViewStyleDefault initAlert:nil
|
||||
@@ -261,9 +245,10 @@
|
||||
if (buttonIndex == [alert cancelButtonIndex])
|
||||
return;
|
||||
|
||||
[self importSites:importedSitesString];
|
||||
[self importSites:importData];
|
||||
[UIPasteboard generalPasteboard].string = @"";
|
||||
} cancelTitle:@"No" otherTitles:@"Import Sites", nil];
|
||||
mpw_marshal_info_free( importInfo );
|
||||
} );
|
||||
|
||||
[super applicationDidBecomeActive:application];
|
||||
@@ -449,62 +434,86 @@
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *exportedSites = [self exportSitesRevealPasswords:revealPasswords];
|
||||
NSString *message;
|
||||
[self exportSitesRevealPasswords:revealPasswords askExportPassword:^NSString *(NSString *userName) {
|
||||
return PearlAwait( ^(void (^setResult)(id)) {
|
||||
[PearlAlert showAlertWithTitle:@"Import File's Master Password"
|
||||
message:strf( @"%@'s export was done using a different master password.\n"
|
||||
@"Enter that master password to unlock the exported data.", userName )
|
||||
viewStyle:UIAlertViewStyleSecureTextInput
|
||||
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
||||
if (buttonIndex_ == [alert_ cancelButtonIndex])
|
||||
setResult( nil );
|
||||
else
|
||||
setResult( [alert_ textFieldAtIndex:0].text );
|
||||
}
|
||||
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Unlock Import", nil];
|
||||
} );
|
||||
} result:^(NSString *mpsites, NSError *error) {
|
||||
if (!mpsites || error) {
|
||||
MPError( error, @"Failed to export mpsites." );
|
||||
[PearlAlert showAlertWithTitle:@"Export Error"
|
||||
message:error.localizedDescription
|
||||
viewStyle:UIAlertViewStyleDefault
|
||||
initAlert:nil tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay
|
||||
otherTitles:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
if (revealPasswords)
|
||||
message = strf( @"Export of Master Password sites with passwords included.\n\n"
|
||||
@"REMINDER: Make sure nobody else sees this file! Passwords are visible!\n\n\n"
|
||||
@"--\n"
|
||||
@"%@\n"
|
||||
@"Master Password %@, build %@",
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
else
|
||||
message = strf( @"Backup of Master Password sites.\n\n\n"
|
||||
@"--\n"
|
||||
@"%@\n"
|
||||
@"Master Password %@, build %@",
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
[PearlSheet showSheetWithTitle:@"Export Destination" viewStyle:UIActionSheetStyleBlackTranslucent initSheet:nil
|
||||
tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
|
||||
if (buttonIndex == [sheet cancelButtonIndex])
|
||||
return;
|
||||
|
||||
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
||||
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
||||
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
||||
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
||||
NSString *exportFileName = strf( @"%@ (%@).mpsites",
|
||||
[self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
|
||||
|
||||
NSString *exportFileName = strf( @"%@ (%@).mpsites",
|
||||
[self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
|
||||
[PearlSheet showSheetWithTitle:@"Export Destination" viewStyle:UIActionSheetStyleBlackTranslucent initSheet:nil
|
||||
tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
|
||||
if (buttonIndex == [sheet cancelButtonIndex])
|
||||
return;
|
||||
if (buttonIndex == [sheet firstOtherButtonIndex]) {
|
||||
NSString *message;
|
||||
if (revealPasswords)
|
||||
message = strf( @"Export of Master Password sites with passwords included.\n\n"
|
||||
@"REMINDER: Make sure nobody else sees this file! Passwords are visible!\n\n\n"
|
||||
@"--\n"
|
||||
@"%@\n"
|
||||
@"Master Password %@, build %@",
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
else
|
||||
message = strf( @"Backup of Master Password sites.\n\n\n"
|
||||
@"--\n"
|
||||
@"%@\n"
|
||||
@"Master Password %@, build %@",
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
|
||||
if (buttonIndex == [sheet firstOtherButtonIndex]) {
|
||||
[PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
|
||||
attachments:[[PearlEMailAttachment alloc]
|
||||
initWithContent:[exportedSites dataUsingEncoding:NSUTF8StringEncoding]
|
||||
mimeType:@"text/plain" fileName:exportFileName],
|
||||
nil];
|
||||
return;
|
||||
}
|
||||
[PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
|
||||
attachments:[[PearlEMailAttachment alloc]
|
||||
initWithContent:[mpsites dataUsingEncoding:NSUTF8StringEncoding]
|
||||
mimeType:@"text/plain" fileName:exportFileName],
|
||||
nil];
|
||||
return;
|
||||
}
|
||||
|
||||
NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
|
||||
inDomains:NSUserDomainMask] lastObject];
|
||||
NSURL *exportURL = [[applicationSupportURL
|
||||
URLByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier isDirectory:YES]
|
||||
URLByAppendingPathComponent:exportFileName isDirectory:NO];
|
||||
NSError *error = nil;
|
||||
if (![[exportedSites dataUsingEncoding:NSUTF8StringEncoding]
|
||||
writeToURL:exportURL options:NSDataWritingFileProtectionComplete error:&error])
|
||||
MPError( error, @"Failed to write export data to URL %@.", exportURL );
|
||||
else {
|
||||
self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:exportURL];
|
||||
self.interactionController.UTI = @"com.lyndir.masterpassword.sites";
|
||||
self.interactionController.delegate = self;
|
||||
[self.interactionController presentOpenInMenuFromRect:CGRectZero inView:viewController.view animated:YES];
|
||||
}
|
||||
} cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:@"Send As E-Mail", @"Share / Airdrop", nil];
|
||||
NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
|
||||
inDomains:NSUserDomainMask] lastObject];
|
||||
NSURL *exportURL = [[applicationSupportURL
|
||||
URLByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier isDirectory:YES]
|
||||
URLByAppendingPathComponent:exportFileName isDirectory:NO];
|
||||
NSError *writeError = nil;
|
||||
if (![[mpsites dataUsingEncoding:NSUTF8StringEncoding]
|
||||
writeToURL:exportURL options:NSDataWritingFileProtectionComplete error:&writeError])
|
||||
MPError( writeError, @"Failed to write export data to URL %@.", exportURL );
|
||||
else {
|
||||
self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:exportURL];
|
||||
self.interactionController.UTI = @"com.lyndir.masterpassword.sites";
|
||||
self.interactionController.delegate = self;
|
||||
[self.interactionController presentOpenInMenuFromRect:CGRectZero inView:viewController.view animated:YES];
|
||||
}
|
||||
} cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:@"Send As E-Mail", @"Share / Airdrop", nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset {
|
||||
|
Reference in New Issue
Block a user