2011-11-30 21:42:40 +00:00
|
|
|
|
//
|
2013-04-25 01:26:04 +00:00
|
|
|
|
// MPiOSAppDelegate.m
|
2012-02-03 07:45:09 +00:00
|
|
|
|
// MasterPassword
|
2011-11-30 21:42:40 +00:00
|
|
|
|
//
|
|
|
|
|
// Created by Maarten Billemont on 24/11/11.
|
|
|
|
|
// Copyright (c) 2011 Lyndir. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
2013-04-25 01:26:04 +00:00
|
|
|
|
#import "MPiOSAppDelegate.h"
|
2012-05-11 20:45:05 +00:00
|
|
|
|
#import "MPAppDelegate_Key.h"
|
|
|
|
|
#import "MPAppDelegate_Store.h"
|
2012-02-05 21:01:37 +00:00
|
|
|
|
#import "IASKSettingsReader.h"
|
2014-09-29 02:15:55 +00:00
|
|
|
|
#import "MPStoreViewController.h"
|
2012-05-03 14:49:15 +00:00
|
|
|
|
|
2014-09-21 14:29:18 +00:00
|
|
|
|
@interface MPiOSAppDelegate()<UIDocumentInteractionControllerDelegate>
|
2013-05-11 12:54:49 +00:00
|
|
|
|
|
2014-09-21 14:29:18 +00:00
|
|
|
|
@property(nonatomic, strong) UIDocumentInteractionController *interactionController;
|
2014-09-22 02:45:21 +00:00
|
|
|
|
|
2013-05-11 12:54:49 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2013-04-25 01:26:04 +00:00
|
|
|
|
@implementation MPiOSAppDelegate
|
2011-11-30 21:42:40 +00:00
|
|
|
|
|
2012-01-05 00:44:15 +00:00
|
|
|
|
+ (void)initialize {
|
2012-06-08 21:46:13 +00:00
|
|
|
|
|
2014-09-17 05:34:58 +00:00
|
|
|
|
static dispatch_once_t once = 0;
|
|
|
|
|
dispatch_once( &once, ^{
|
2014-04-12 18:43:41 +00:00
|
|
|
|
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
|
2012-01-24 23:30:43 +00:00
|
|
|
|
#ifdef DEBUG
|
2014-09-16 04:34:22 +00:00
|
|
|
|
[PearlLogger get].printLevel = PearlLogLevelDebug; //Trace;
|
2013-08-28 03:28:10 +00:00
|
|
|
|
#else
|
2014-04-12 18:43:41 +00:00
|
|
|
|
[PearlLogger get].printLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelDebug: PearlLogLevelInfo;
|
2012-01-24 23:30:43 +00:00
|
|
|
|
#endif
|
2014-09-17 05:34:58 +00:00
|
|
|
|
} );
|
2012-01-05 00:44:15 +00:00
|
|
|
|
}
|
2012-05-11 20:45:05 +00:00
|
|
|
|
|
2012-01-24 23:30:43 +00:00
|
|
|
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
2012-06-08 21:46:13 +00:00
|
|
|
|
|
2013-08-28 03:28:10 +00:00
|
|
|
|
@try {
|
2016-01-14 07:14:36 +00:00
|
|
|
|
// [[NSBundle mainBundle] mutableInfoDictionary][@"CFBundleDisplayName"] = @"Master Password";
|
|
|
|
|
// [[NSBundle mainBundle] mutableLocalizedInfoDictionary][@"CFBundleDisplayName"] = @"Master Password";
|
2012-06-08 21:46:13 +00:00
|
|
|
|
|
2013-08-25 22:49:13 +00:00
|
|
|
|
#ifdef CRASHLYTICS
|
2012-06-14 19:56:54 +00:00
|
|
|
|
NSString *crashlyticsAPIKey = [self crashlyticsAPIKey];
|
|
|
|
|
if ([crashlyticsAPIKey length]) {
|
|
|
|
|
inf(@"Initializing Crashlytics");
|
2012-06-15 09:34:53 +00:00
|
|
|
|
#if defined (DEBUG) || defined (ADHOC)
|
2012-06-14 19:56:54 +00:00
|
|
|
|
[Crashlytics sharedInstance].debugMode = YES;
|
2012-06-15 09:34:53 +00:00
|
|
|
|
#endif
|
2015-10-22 18:31:39 +00:00
|
|
|
|
[[Crashlytics sharedInstance] setUserIdentifier:[PearlKeyChain deviceIdentifier]];
|
|
|
|
|
[[Crashlytics sharedInstance] setObjectValue:[PearlKeyChain deviceIdentifier] forKey:@"deviceIdentifier"];
|
|
|
|
|
[[Crashlytics sharedInstance] setUserName:@"Anonymous"];
|
|
|
|
|
[[Crashlytics sharedInstance] setObjectValue:@"Anonymous" forKey:@"username"];
|
2012-08-24 08:12:15 +00:00
|
|
|
|
[Crashlytics startWithAPIKey:crashlyticsAPIKey];
|
2012-06-14 19:56:54 +00:00
|
|
|
|
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
2013-09-14 18:04:06 +00:00
|
|
|
|
PearlLogLevel level = PearlLogLevelInfo;
|
2014-12-31 16:28:46 +00:00
|
|
|
|
if ([[MPConfig get].sendInfo boolValue])
|
2013-09-14 18:04:06 +00:00
|
|
|
|
level = PearlLogLevelDebug;
|
2012-06-14 19:56:54 +00:00
|
|
|
|
|
|
|
|
|
if (message.level >= level)
|
2013-04-20 18:11:19 +00:00
|
|
|
|
CLSLog( @"%@", [message messageDescription] );
|
2012-06-14 19:56:54 +00:00
|
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
|
}];
|
2013-04-20 18:11:19 +00:00
|
|
|
|
CLSLog( @"Crashlytics (%@) initialized for: %@ v%@.", //
|
|
|
|
|
[Crashlytics sharedInstance].version, [PearlInfoPlist get].CFBundleName, [PearlInfoPlist get].CFBundleVersion );
|
2012-05-03 14:49:15 +00:00
|
|
|
|
}
|
2013-08-28 03:28:10 +00:00
|
|
|
|
#endif
|
2012-05-23 06:58:01 +00:00
|
|
|
|
}
|
2012-06-14 19:56:54 +00:00
|
|
|
|
@catch (id exception) {
|
2014-04-26 18:03:44 +00:00
|
|
|
|
err( @"During Analytics Setup: %@", exception );
|
2012-05-23 06:58:01 +00:00
|
|
|
|
}
|
2013-08-28 03:28:10 +00:00
|
|
|
|
@try {
|
2014-09-27 05:27:05 +00:00
|
|
|
|
PearlAddNotificationObserver( MPCheckConfigNotification, nil, [NSOperationQueue mainQueue], ^(id self, NSNotification *note) {
|
|
|
|
|
[self updateConfigKey:note.object];
|
|
|
|
|
} );
|
2015-02-28 15:01:41 +00:00
|
|
|
|
// PearlAddNotificationObserver( kIASKAppSettingChanged, nil, nil, ^(id self, NSNotification *note) {
|
|
|
|
|
// [[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:note.object];
|
|
|
|
|
// } );
|
2014-09-27 05:27:05 +00:00
|
|
|
|
PearlAddNotificationObserver( NSUserDefaultsDidChangeNotification, nil, nil, ^(id self, NSNotification *note) {
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
|
|
|
|
|
} );
|
2012-06-08 21:46:13 +00:00
|
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
|
#ifdef ADHOC
|
2013-08-28 03:28:10 +00:00
|
|
|
|
[PearlAlert showAlertWithTitle:@"Welcome, tester!" message:
|
|
|
|
|
@"Thank you for taking the time to test Master Password.\n\n"
|
|
|
|
|
@"Please provide any feedback, however minor it may seem, via the Feedback action item accessible from the top right.\n\n"
|
|
|
|
|
@"Contact me directly at:\n"
|
|
|
|
|
@"lhunath@lyndir.com\n"
|
|
|
|
|
@"Or report detailed issues at:\n"
|
|
|
|
|
@"https://youtrack.lyndir.com\n"
|
|
|
|
|
viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil
|
|
|
|
|
cancelTitle:nil otherTitles:[PearlStrings get].commonButtonOkay, nil];
|
2012-02-29 01:10:46 +00:00
|
|
|
|
#endif
|
2013-08-28 03:28:10 +00:00
|
|
|
|
}
|
|
|
|
|
@catch (id exception) {
|
2014-04-26 18:03:44 +00:00
|
|
|
|
err( @"During Config Test: %@", exception );
|
2013-08-28 03:28:10 +00:00
|
|
|
|
}
|
|
|
|
|
@try {
|
|
|
|
|
[super application:application didFinishLaunchingWithOptions:launchOptions];
|
|
|
|
|
}
|
|
|
|
|
@catch (id exception) {
|
2014-04-26 18:03:44 +00:00
|
|
|
|
err( @"During Pearl Application Launch: %@", exception );
|
2013-08-28 03:28:10 +00:00
|
|
|
|
}
|
|
|
|
|
@try {
|
2014-04-26 18:03:44 +00:00
|
|
|
|
inf( @"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier] );
|
2012-06-08 21:46:13 +00:00
|
|
|
|
|
2014-09-27 05:27:05 +00:00
|
|
|
|
PearlAddNotificationObserver( MPFoundInconsistenciesNotification, nil, nil, ^(id self, NSNotification *note) {
|
|
|
|
|
switch ((MPFixableResult)[note.userInfo[MPInconsistenciesFixResultUserKey] unsignedIntegerValue]) {
|
|
|
|
|
|
|
|
|
|
case MPFixableResultNoProblems:
|
|
|
|
|
break;
|
|
|
|
|
case MPFixableResultProblemsFixed:
|
|
|
|
|
[PearlAlert showAlertWithTitle:@"Inconsistencies Fixed" message:
|
|
|
|
|
@"Some inconsistencies were detected in your sites.\n"
|
|
|
|
|
@"All issues were fixed."
|
|
|
|
|
viewStyle:UIAlertViewStyleDefault initAlert:nil
|
|
|
|
|
tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil];
|
|
|
|
|
break;
|
|
|
|
|
case MPFixableResultProblemsNotFixed:
|
|
|
|
|
[PearlAlert showAlertWithTitle:@"Inconsistencies Found" message:
|
|
|
|
|
@"Some inconsistencies were detected in your sites.\n"
|
|
|
|
|
@"Not all issues could be fixed. Try signing in to each user or checking the logs."
|
|
|
|
|
viewStyle:UIAlertViewStyleDefault initAlert:nil
|
|
|
|
|
tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} );
|
2014-04-26 18:03:44 +00:00
|
|
|
|
|
|
|
|
|
PearlMainQueue( ^{
|
2013-08-28 03:28:10 +00:00
|
|
|
|
if ([[MPiOSConfig get].showSetup boolValue])
|
2014-04-25 01:43:47 +00:00
|
|
|
|
[self.navigationController performSegueWithIdentifier:@"setup" sender:self];
|
2013-08-28 03:28:10 +00:00
|
|
|
|
} );
|
2013-04-13 17:40:17 +00:00
|
|
|
|
|
2014-09-29 02:15:55 +00:00
|
|
|
|
NSString *latestFeatures = [MPStoreViewController latestStoreFeatures];
|
|
|
|
|
if (latestFeatures)
|
|
|
|
|
[PearlAlert showAlertWithTitle:@"New Features" message:
|
|
|
|
|
strf( @"The following features are now available in the store:\n\n%@•••\n\n"
|
|
|
|
|
@"Find the store from the user pull‑down after logging in.", latestFeatures )
|
|
|
|
|
viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil
|
|
|
|
|
cancelTitle:@"Thanks" otherTitles:nil];
|
2013-08-28 03:28:10 +00:00
|
|
|
|
}
|
|
|
|
|
@catch (id exception) {
|
2014-04-26 18:03:44 +00:00
|
|
|
|
err( @"During Post-Startup: %@", exception );
|
2013-08-28 03:28:10 +00:00
|
|
|
|
}
|
2013-05-07 15:22:01 +00:00
|
|
|
|
|
2012-06-14 19:56:54 +00:00
|
|
|
|
return YES;
|
2012-01-29 11:41:48 +00:00
|
|
|
|
}
|
2012-02-29 00:56:58 +00:00
|
|
|
|
|
2012-05-09 08:11:34 +00:00
|
|
|
|
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
|
|
|
|
|
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
|
2012-06-08 21:46:13 +00:00
|
|
|
|
|
2012-08-25 10:38:29 +00:00
|
|
|
|
// No URL?
|
|
|
|
|
if (!url)
|
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
|
|
// Arbitrary URL to mpsites data.
|
2013-04-20 18:11:19 +00:00
|
|
|
|
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
|
|
|
|
|
NSError *error;
|
2012-08-25 10:38:29 +00:00
|
|
|
|
NSURLResponse *response;
|
2013-04-20 18:11:19 +00:00
|
|
|
|
NSData *importedSitesData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url]
|
|
|
|
|
returningResponse:&response error:&error];
|
2012-08-25 10:38:29 +00:00
|
|
|
|
if (error)
|
2014-09-22 03:28:50 +00:00
|
|
|
|
err( @"While reading imported sites from %@: %@", url, [error fullDescription] );
|
2014-09-28 00:29:58 +00:00
|
|
|
|
if (!importedSitesData) {
|
|
|
|
|
[PearlAlert showError:strf( @"Master Password couldn't read the import sites.\n\n%@", [error localizedDescription]?: error )];
|
2012-08-25 10:38:29 +00:00
|
|
|
|
return;
|
2014-09-28 00:29:58 +00:00
|
|
|
|
}
|
2012-08-19 07:34:49 +00:00
|
|
|
|
|
|
|
|
|
NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
|
2014-09-28 00:29:58 +00:00
|
|
|
|
if (!importedSitesString) {
|
|
|
|
|
[PearlAlert showError:@"Master Password couldn't understand the import file."];
|
|
|
|
|
return;
|
2012-08-19 07:34:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-28 00:29:58 +00:00
|
|
|
|
[self importSites:importedSitesString];
|
2013-04-20 18:11:19 +00:00
|
|
|
|
} );
|
2012-06-08 21:46:13 +00:00
|
|
|
|
|
2012-05-09 08:11:34 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-28 00:29:58 +00:00
|
|
|
|
- (void)importSites:(NSString *)importedSitesString {
|
|
|
|
|
|
|
|
|
|
if ([NSThread isMainThread]) {
|
|
|
|
|
PearlNotMainQueue( ^{
|
|
|
|
|
[self importSites:importedSitesString];
|
|
|
|
|
} );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"];
|
|
|
|
|
MPImportResult result = [self importSites:importedSitesString askImportPassword:^NSString *(NSString *userName) {
|
|
|
|
|
__block NSString *masterPassword = nil;
|
|
|
|
|
|
|
|
|
|
dispatch_group_t importPasswordGroup = dispatch_group_create();
|
|
|
|
|
dispatch_group_enter( importPasswordGroup );
|
|
|
|
|
dispatch_async( dispatch_get_main_queue(), ^{
|
|
|
|
|
[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_) {
|
|
|
|
|
@try {
|
|
|
|
|
if (buttonIndex_ == [alert_ cancelButtonIndex])
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
masterPassword = [alert_ textFieldAtIndex:0].text;
|
|
|
|
|
}
|
|
|
|
|
@finally {
|
|
|
|
|
dispatch_group_leave( importPasswordGroup );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Unlock Import", nil];
|
|
|
|
|
} );
|
|
|
|
|
dispatch_group_wait( importPasswordGroup, DISPATCH_TIME_FOREVER );
|
|
|
|
|
|
|
|
|
|
return masterPassword;
|
|
|
|
|
} askUserPassword:^NSString *(NSString *userName, NSUInteger importCount, NSUInteger deleteCount) {
|
|
|
|
|
__block NSString *masterPassword = nil;
|
|
|
|
|
|
|
|
|
|
dispatch_group_t userPasswordGroup = dispatch_group_create();
|
|
|
|
|
dispatch_group_enter( userPasswordGroup );
|
|
|
|
|
dispatch_async( dispatch_get_main_queue(), ^{
|
|
|
|
|
[PearlAlert showAlertWithTitle:strf( @"Master Password for\n%@", userName )
|
|
|
|
|
message:strf( @"Imports %lu sites, overwriting %lu.",
|
|
|
|
|
(unsigned long)importCount, (unsigned long)deleteCount )
|
|
|
|
|
viewStyle:UIAlertViewStyleSecureTextInput
|
|
|
|
|
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
|
|
|
|
@try {
|
|
|
|
|
if (buttonIndex_ == [alert_ cancelButtonIndex])
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
masterPassword = [alert_ textFieldAtIndex:0].text;
|
|
|
|
|
}
|
|
|
|
|
@finally {
|
|
|
|
|
dispatch_group_leave( userPasswordGroup );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil];
|
|
|
|
|
} );
|
|
|
|
|
dispatch_group_wait( userPasswordGroup, DISPATCH_TIME_FOREVER );
|
|
|
|
|
|
|
|
|
|
return masterPassword;
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-29 10:32:26 +00:00
|
|
|
|
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
|
2012-08-04 21:15:50 +00:00
|
|
|
|
|
2014-04-26 18:03:44 +00:00
|
|
|
|
inf( @"Received memory warning." );
|
2012-08-04 21:15:50 +00:00
|
|
|
|
|
2012-07-29 10:32:26 +00:00
|
|
|
|
[super applicationDidReceiveMemoryWarning:application];
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-26 04:32:07 +00:00
|
|
|
|
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
2012-06-08 21:46:13 +00:00
|
|
|
|
|
2014-09-26 04:32:07 +00:00
|
|
|
|
inf( @"Will background" );
|
2012-06-07 22:40:30 +00:00
|
|
|
|
if (![[MPiOSConfig get].rememberLogin boolValue])
|
2012-06-27 22:00:41 +00:00
|
|
|
|
[self signOutAnimated:NO];
|
2012-09-12 13:58:54 +00:00
|
|
|
|
|
2014-09-26 04:32:07 +00:00
|
|
|
|
[super applicationDidEnterBackground:application];
|
2012-09-12 13:58:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
|
|
|
|
|
2014-04-26 18:03:44 +00:00
|
|
|
|
inf( @"Re-activated" );
|
2014-06-06 01:43:06 +00:00
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
|
2012-09-12 13:58:54 +00:00
|
|
|
|
|
2014-10-23 03:00:20 +00:00
|
|
|
|
PearlNotMainQueue( ^{
|
|
|
|
|
NSString *importHeader = @"# Master Password site export";
|
|
|
|
|
NSString *importedSitesString = [UIPasteboard generalPasteboard].string;
|
|
|
|
|
if ([importedSitesString length] > [importHeader length] &&
|
|
|
|
|
[[importedSitesString substringToIndex:[importHeader length]] isEqualToString:importHeader])
|
|
|
|
|
[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
|
|
|
|
|
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
|
|
|
if (buttonIndex == [alert cancelButtonIndex])
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
[self importSites:importedSitesString];
|
2014-10-23 03:32:25 +00:00
|
|
|
|
[UIPasteboard generalPasteboard].string = @"";
|
2014-10-23 03:00:20 +00:00
|
|
|
|
} cancelTitle:@"No" otherTitles:@"Import Sites", nil];
|
|
|
|
|
} );
|
2014-09-28 00:29:58 +00:00
|
|
|
|
|
2012-09-12 13:58:54 +00:00
|
|
|
|
[super applicationDidBecomeActive:application];
|
2011-11-30 21:42:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-06-15 09:16:02 +00:00
|
|
|
|
#pragma mark - Behavior
|
2012-06-14 19:56:54 +00:00
|
|
|
|
|
2012-08-26 15:40:32 +00:00
|
|
|
|
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController {
|
|
|
|
|
|
|
|
|
|
if (![PearlEMail canSendMail])
|
|
|
|
|
[PearlAlert showAlertWithTitle:@"Feedback"
|
|
|
|
|
message:
|
2013-04-20 18:11:19 +00:00
|
|
|
|
@"Have a question, comment, issue or just saying thanks?\n\n"
|
|
|
|
|
@"We'd love to hear what you think!\n"
|
|
|
|
|
@"masterpassword@lyndir.com"
|
2012-08-26 15:40:32 +00:00
|
|
|
|
viewStyle:UIAlertViewStyleDefault
|
|
|
|
|
initAlert:nil tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay
|
|
|
|
|
otherTitles:nil];
|
|
|
|
|
|
2013-04-20 18:11:19 +00:00
|
|
|
|
else if (logs)
|
|
|
|
|
[PearlAlert showAlertWithTitle:@"Feedback"
|
|
|
|
|
message:
|
|
|
|
|
@"Have a question, comment, issue or just saying thanks?\n\n"
|
|
|
|
|
@"If you're having trouble, it may help us if you can first reproduce the problem "
|
|
|
|
|
@"and then include log files in your message."
|
|
|
|
|
viewStyle:UIAlertViewStyleDefault
|
|
|
|
|
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
2014-08-21 04:30:38 +00:00
|
|
|
|
[self openFeedbackWithLogs:(buttonIndex_ == [alert_ firstOtherButtonIndex]) forVC:viewController];
|
|
|
|
|
} cancelTitle:nil otherTitles:@"Include Logs", @"No Logs", nil];
|
2012-08-26 15:40:32 +00:00
|
|
|
|
else
|
2013-04-20 18:11:19 +00:00
|
|
|
|
[self openFeedbackWithLogs:NO forVC:viewController];
|
2012-08-26 15:40:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)openFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController {
|
|
|
|
|
|
2013-06-16 16:39:52 +00:00
|
|
|
|
NSString *userName = [[MPiOSAppDelegate get] activeUserForMainThread].name;
|
2013-04-30 05:49:53 +00:00
|
|
|
|
PearlLogLevel logLevel = PearlLogLevelInfo;
|
2014-12-31 16:28:46 +00:00
|
|
|
|
if (logs && ([[MPConfig get].sendInfo boolValue] || [[MPiOSConfig get].traceMode boolValue]))
|
2013-04-30 05:49:53 +00:00
|
|
|
|
logLevel = PearlLogLevelDebug;
|
2012-08-26 15:40:32 +00:00
|
|
|
|
|
|
|
|
|
[[[PearlEMail alloc] initForEMailTo:@"Master Password Development <masterpassword@lyndir.com>"
|
2014-07-01 01:00:25 +00:00
|
|
|
|
subject:strf( @"Feedback for Master Password [%@]",
|
2014-08-21 04:30:38 +00:00
|
|
|
|
[[PearlKeyChain deviceIdentifier] stringByDeletingMatchesOf:@"-.*"] )
|
2014-07-01 01:00:25 +00:00
|
|
|
|
body:strf( @"\n\n\n"
|
2014-08-21 04:30:38 +00:00
|
|
|
|
@"--\n"
|
|
|
|
|
@"%@"
|
|
|
|
|
@"Master Password %@, build %@",
|
|
|
|
|
userName? ([userName stringByAppendingString:@"\n"]): @"",
|
|
|
|
|
[PearlInfoPlist get].CFBundleShortVersionString,
|
|
|
|
|
[PearlInfoPlist get].CFBundleVersion )
|
2012-08-26 15:40:32 +00:00
|
|
|
|
|
2012-09-20 19:37:58 +00:00
|
|
|
|
attachments:(logs
|
2013-04-20 18:11:19 +00:00
|
|
|
|
? [[PearlEMailAttachment alloc]
|
2013-10-31 03:37:12 +00:00
|
|
|
|
initWithContent:[[[PearlLogger get] formatMessagesWithLevel:logLevel]
|
|
|
|
|
dataUsingEncoding:NSUTF8StringEncoding]
|
|
|
|
|
mimeType:@"text/plain"
|
2014-07-01 01:00:25 +00:00
|
|
|
|
fileName:strf( @"%@-%@.log",
|
2014-04-26 18:03:44 +00:00
|
|
|
|
[[NSDateFormatter rfc3339DateFormatter] stringFromDate:[NSDate date]],
|
|
|
|
|
[PearlKeyChain deviceIdentifier] )]
|
2013-04-20 18:11:19 +00:00
|
|
|
|
: nil), nil]
|
|
|
|
|
showComposerForVC:viewController];
|
2012-08-26 15:40:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-22 03:11:05 +00:00
|
|
|
|
- (void)handleCoordinatorError:(NSError *)error {
|
|
|
|
|
|
|
|
|
|
static dispatch_once_t once = 0;
|
|
|
|
|
dispatch_once( &once, ^{
|
|
|
|
|
[PearlAlert showAlertWithTitle:@"Failed To Load Sites" message:
|
|
|
|
|
@"Master Password was unable to open your sites history.\n"
|
|
|
|
|
@"This may be due to corruption. You can either reset Master Password and "
|
|
|
|
|
@"recreate your user, or E-Mail us your logs and leave your corrupt store as-is for now."
|
|
|
|
|
viewStyle:UIAlertViewStyleDefault initAlert:nil
|
|
|
|
|
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
|
|
|
if (buttonIndex == [alert cancelButtonIndex])
|
|
|
|
|
return;
|
|
|
|
|
if (buttonIndex == [alert firstOtherButtonIndex])
|
|
|
|
|
[self openFeedbackWithLogs:YES forVC:nil];
|
|
|
|
|
if (buttonIndex == [alert firstOtherButtonIndex] + 1)
|
|
|
|
|
[self deleteAndResetStore];
|
|
|
|
|
} cancelTitle:@"Ignore" otherTitles:@"E-Mail Logs", @"Reset", nil];
|
|
|
|
|
} );
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-25 01:43:47 +00:00
|
|
|
|
- (void)showExportForVC:(UIViewController *)viewController {
|
2012-06-14 19:56:54 +00:00
|
|
|
|
|
2014-06-04 01:04:22 +00:00
|
|
|
|
[PearlAlert showAlertWithTitle:@"Exporting Your Sites"
|
|
|
|
|
message:@"An export is great for keeping a "
|
|
|
|
|
@"backup list of your accounts.\n\n"
|
|
|
|
|
@"When the file is ready, you will be "
|
|
|
|
|
@"able to mail it to yourself.\n"
|
|
|
|
|
@"You can open it with a text editor or "
|
|
|
|
|
@"with Master Password if you need to "
|
|
|
|
|
@"restore your list of sites."
|
|
|
|
|
viewStyle:UIAlertViewStyleDefault initAlert:nil
|
|
|
|
|
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
2014-08-21 04:30:38 +00:00
|
|
|
|
if (buttonIndex != [alert cancelButtonIndex])
|
|
|
|
|
[PearlAlert showAlertWithTitle:@"Show Passwords?"
|
|
|
|
|
message:@"Would you like to make all your passwords "
|
|
|
|
|
@"visible in the export file?\n\n"
|
|
|
|
|
@"A safe export will include all sites "
|
|
|
|
|
@"but make their passwords invisible.\n"
|
|
|
|
|
@"It is great as a backup and remains "
|
|
|
|
|
@"safe when fallen in the wrong hands."
|
|
|
|
|
viewStyle:UIAlertViewStyleDefault initAlert:nil
|
|
|
|
|
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
|
|
|
|
if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 0)
|
|
|
|
|
// Safe Export
|
|
|
|
|
[self showExportRevealPasswords:NO forVC:viewController];
|
|
|
|
|
if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 1)
|
|
|
|
|
// Show Passwords
|
|
|
|
|
[self showExportRevealPasswords:YES forVC:viewController];
|
|
|
|
|
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Safe Export", @"Show Passwords",
|
|
|
|
|
nil];
|
|
|
|
|
} cancelTitle:@"Cancel" otherTitles:@"Export Sites", nil];
|
2012-06-14 19:56:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-25 01:43:47 +00:00
|
|
|
|
- (void)showExportRevealPasswords:(BOOL)revealPasswords forVC:(UIViewController *)viewController {
|
2012-07-12 06:41:18 +00:00
|
|
|
|
|
2012-08-26 15:40:32 +00:00
|
|
|
|
if (![PearlEMail canSendMail]) {
|
2012-06-22 14:52:33 +00:00
|
|
|
|
[PearlAlert showAlertWithTitle:@"Cannot Send Mail"
|
|
|
|
|
message:
|
2013-04-20 18:11:19 +00:00
|
|
|
|
@"Your device is not yet set up for sending mail.\n"
|
|
|
|
|
@"Close Master Password, go into Settings and add a Mail account."
|
2012-06-22 14:52:33 +00:00
|
|
|
|
viewStyle:UIAlertViewStyleDefault
|
2012-08-04 21:15:50 +00:00
|
|
|
|
initAlert:nil tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay
|
2012-06-22 14:52:33 +00:00
|
|
|
|
otherTitles:nil];
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-06-14 19:56:54 +00:00
|
|
|
|
|
2014-04-25 01:43:47 +00:00
|
|
|
|
NSString *exportedSites = [self exportSitesRevealPasswords:revealPasswords];
|
2012-06-14 19:56:54 +00:00
|
|
|
|
NSString *message;
|
2012-06-22 14:52:33 +00:00
|
|
|
|
|
2014-04-25 01:43:47 +00:00
|
|
|
|
if (revealPasswords)
|
2014-07-01 01:00:25 +00:00
|
|
|
|
message = strf( @"Export of Master Password sites with passwords included.\n\n"
|
2014-08-21 04:30:38 +00:00
|
|
|
|
@"REMINDER: Make sure nobody else sees this file! Passwords are visible!\n\n\n"
|
|
|
|
|
@"--\n"
|
|
|
|
|
@"%@\n"
|
|
|
|
|
@"Master Password %@, build %@",
|
2014-04-26 18:03:44 +00:00
|
|
|
|
[self activeUserForMainThread].name,
|
|
|
|
|
[PearlInfoPlist get].CFBundleShortVersionString,
|
|
|
|
|
[PearlInfoPlist get].CFBundleVersion );
|
2012-06-14 19:56:54 +00:00
|
|
|
|
else
|
2014-07-01 01:00:25 +00:00
|
|
|
|
message = strf( @"Backup of Master Password sites.\n\n\n"
|
2014-08-21 04:30:38 +00:00
|
|
|
|
@"--\n"
|
|
|
|
|
@"%@\n"
|
|
|
|
|
@"Master Password %@, build %@",
|
2014-04-26 18:03:44 +00:00
|
|
|
|
[self activeUserForMainThread].name,
|
|
|
|
|
[PearlInfoPlist get].CFBundleShortVersionString,
|
|
|
|
|
[PearlInfoPlist get].CFBundleVersion );
|
2012-07-12 06:41:18 +00:00
|
|
|
|
|
2012-06-14 19:56:54 +00:00
|
|
|
|
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
2012-07-29 10:32:26 +00:00
|
|
|
|
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
2012-06-14 19:56:54 +00:00
|
|
|
|
|
2014-09-21 14:29:18 +00:00
|
|
|
|
NSString *exportFileName = strf( @"%@ (%@).mpsites",
|
|
|
|
|
[self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
|
2014-09-21 16:54:48 +00:00
|
|
|
|
[PearlSheet showSheetWithTitle:@"Export Destination" viewStyle:UIActionSheetStyleBlackTranslucent initSheet:nil
|
|
|
|
|
tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
|
|
|
|
|
if (buttonIndex == [sheet cancelButtonIndex])
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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])
|
2014-09-22 03:28:50 +00:00
|
|
|
|
err( @"Failed to write export data to URL %@: %@", exportURL, [error fullDescription] );
|
2014-09-21 16:54:48 +00:00
|
|
|
|
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];
|
2012-06-14 19:56:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-26 18:03:44 +00:00
|
|
|
|
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset {
|
2012-06-14 19:56:54 +00:00
|
|
|
|
|
|
|
|
|
[PearlAlert showAlertWithTitle:@"Changing Master Password"
|
|
|
|
|
message:
|
2013-04-20 18:11:19 +00:00
|
|
|
|
@"If you continue, you'll be able to set a new master password.\n\n"
|
|
|
|
|
@"Changing your master password will cause all your generated passwords to change!\n"
|
|
|
|
|
@"Changing the master password back to the old one will cause your passwords to revert as well."
|
2012-06-14 19:56:54 +00:00
|
|
|
|
viewStyle:UIAlertViewStyleDefault
|
|
|
|
|
initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
2014-08-21 04:30:38 +00:00
|
|
|
|
if (buttonIndex == [alert cancelButtonIndex])
|
|
|
|
|
return;
|
2012-06-14 19:56:54 +00:00
|
|
|
|
|
2014-08-21 04:30:38 +00:00
|
|
|
|
[moc performBlockAndWait:^{
|
2015-02-28 15:01:41 +00:00
|
|
|
|
inf( @"Clearing keyID for user: %@.", user.userID );
|
2014-08-21 04:30:38 +00:00
|
|
|
|
user.keyID = nil;
|
|
|
|
|
[self forgetSavedKeyFor:user];
|
|
|
|
|
[moc saveToStore];
|
|
|
|
|
}];
|
2012-06-14 19:56:54 +00:00
|
|
|
|
|
2014-08-21 04:30:38 +00:00
|
|
|
|
[self signOutAnimated:YES];
|
|
|
|
|
if (didReset)
|
|
|
|
|
didReset();
|
|
|
|
|
}
|
2012-08-04 21:15:50 +00:00
|
|
|
|
cancelTitle:[PearlStrings get].commonButtonAbort
|
|
|
|
|
otherTitles:[PearlStrings get].commonButtonContinue, nil];
|
2012-06-14 19:56:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 14:29:18 +00:00
|
|
|
|
#pragma mark - UIDocumentInteractionControllerDelegate
|
|
|
|
|
|
|
|
|
|
- (void)documentInteractionController:(UIDocumentInteractionController *)controller didEndSendingToApplication:(NSString *)application {
|
|
|
|
|
|
|
|
|
|
// self.interactionController = nil;
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-14 19:56:54 +00:00
|
|
|
|
#pragma mark - PearlConfigDelegate
|
|
|
|
|
|
|
|
|
|
- (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)value {
|
|
|
|
|
|
2014-04-26 18:03:44 +00:00
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:NSStringFromSelector( configKey )];
|
2013-09-06 03:52:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-06 01:43:06 +00:00
|
|
|
|
- (void)updateConfigKey:(NSString *)key {
|
2013-09-06 03:52:12 +00:00
|
|
|
|
|
|
|
|
|
// Trace mode
|
|
|
|
|
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
|
|
|
|
|
|
|
|
|
|
// Send info
|
2014-12-31 16:28:46 +00:00
|
|
|
|
if ([[MPConfig get].sendInfo boolValue]) {
|
2013-09-06 03:52:12 +00:00
|
|
|
|
if ([PearlLogger get].printLevel > PearlLogLevelInfo)
|
|
|
|
|
[PearlLogger get].printLevel = PearlLogLevelInfo;
|
|
|
|
|
|
|
|
|
|
#ifdef CRASHLYTICS
|
2014-10-23 03:00:20 +00:00
|
|
|
|
[[Crashlytics sharedInstance] setBoolValue:[[MPConfig get].rememberLogin boolValue] forKey:@"rememberLogin"];
|
2014-12-31 16:28:46 +00:00
|
|
|
|
[[Crashlytics sharedInstance] setBoolValue:[[MPConfig get].sendInfo boolValue] forKey:@"sendInfo"];
|
2014-10-23 03:00:20 +00:00
|
|
|
|
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].helpHidden boolValue] forKey:@"helpHidden"];
|
|
|
|
|
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].showSetup boolValue] forKey:@"showQuickStart"];
|
|
|
|
|
[[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].firstRun boolValue] forKey:@"firstRun"];
|
|
|
|
|
[[Crashlytics sharedInstance] setIntValue:[[PearlConfig get].launchCount intValue] forKey:@"launchCount"];
|
|
|
|
|
[[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].askForReviews boolValue] forKey:@"askForReviews"];
|
|
|
|
|
[[Crashlytics sharedInstance] setIntValue:[[PearlConfig get].reviewAfterLaunches intValue] forKey:@"reviewAfterLaunches"];
|
|
|
|
|
[[Crashlytics sharedInstance] setObjectValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"];
|
|
|
|
|
[[Crashlytics sharedInstance] setBoolValue:[PearlDeviceUtils isSimulator] forKey:@"simulator"];
|
|
|
|
|
[[Crashlytics sharedInstance] setBoolValue:[PearlDeviceUtils isAppEncrypted] forKey:@"encrypted"];
|
|
|
|
|
[[Crashlytics sharedInstance] setBoolValue:[PearlDeviceUtils isJailbroken] forKey:@"jailbroken"];
|
|
|
|
|
[[Crashlytics sharedInstance] setObjectValue:[PearlDeviceUtils platform] forKey:@"platform"];
|
|
|
|
|
#ifdef APPSTORE
|
|
|
|
|
[[Crashlytics sharedInstance] setBoolValue:[PearlDeviceUtils isAppEncrypted] forKey:@"reviewedVersion"];
|
|
|
|
|
#else
|
|
|
|
|
[[Crashlytics sharedInstance] setBoolValue:YES forKey:@"reviewedVersion"];
|
|
|
|
|
#endif
|
2013-09-06 03:52:12 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
2012-06-14 19:56:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
|
#pragma mark - Crashlytics
|
|
|
|
|
|
|
|
|
|
- (NSDictionary *)crashlyticsInfo {
|
2012-06-08 21:46:13 +00:00
|
|
|
|
|
2012-05-11 20:45:05 +00:00
|
|
|
|
static NSDictionary *crashlyticsInfo = nil;
|
2012-05-03 14:49:15 +00:00
|
|
|
|
if (crashlyticsInfo == nil)
|
|
|
|
|
crashlyticsInfo = [[NSDictionary alloc] initWithContentsOfURL:
|
2013-04-20 18:11:19 +00:00
|
|
|
|
[[NSBundle mainBundle] URLForResource:@"Crashlytics" withExtension:@"plist"]];
|
2012-06-08 21:46:13 +00:00
|
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
|
return crashlyticsInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *)crashlyticsAPIKey {
|
2012-06-08 21:46:13 +00:00
|
|
|
|
|
2014-04-26 18:03:44 +00:00
|
|
|
|
NSString *crashlyticsAPIKey = NSNullToNil( [[self crashlyticsInfo] valueForKeyPath:@"API Key"] );
|
2013-04-27 21:39:31 +00:00
|
|
|
|
if (![crashlyticsAPIKey length])
|
2014-04-26 18:03:44 +00:00
|
|
|
|
wrn( @"Crashlytics API key not set. Crash logs won't be recorded." );
|
2013-04-27 21:39:31 +00:00
|
|
|
|
|
|
|
|
|
return crashlyticsAPIKey;
|
2012-05-03 14:49:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-30 21:42:40 +00:00
|
|
|
|
@end
|