2017-04-05 20:56:22 +00:00
|
|
|
//==============================================================================
|
|
|
|
// This file is part of Master Password.
|
|
|
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
2011-11-30 21:42:40 +00:00
|
|
|
//
|
2017-04-05 20:56:22 +00:00
|
|
|
// Master Password is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
2011-11-30 21:42:40 +00:00
|
|
|
//
|
2017-04-05 20:56:22 +00:00
|
|
|
// Master Password is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
2011-11-30 21:42:40 +00:00
|
|
|
//
|
2017-04-05 20:56:22 +00:00
|
|
|
// You can find a copy of the GNU General Public License in the
|
|
|
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
|
|
|
//==============================================================================
|
2011-11-30 21:42:40 +00:00
|
|
|
|
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"
|
2014-09-29 02:15:55 +00:00
|
|
|
#import "MPStoreViewController.h"
|
2017-09-20 16:43:03 +00:00
|
|
|
#import "mpw-marshal.h"
|
2020-01-27 18:27:10 +00:00
|
|
|
#import "MPSecrets.h"
|
|
|
|
|
|
|
|
#import <Sentry/Sentry.h>
|
|
|
|
#import <Countly/Countly.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;
|
2017-06-07 02:10:02 +00:00
|
|
|
@property(nonatomic, strong) PearlHangDetector *hangDetector;
|
2014-09-22 02:45:21 +00:00
|
|
|
|
2013-05-11 12:54:49 +00:00
|
|
|
@end
|
|
|
|
|
2020-02-28 22:33:38 +00:00
|
|
|
MPLogSink mpw_log_sink_pearl;
|
|
|
|
void mpw_log_sink_pearl(const MPLogEvent *record) {
|
|
|
|
|
|
|
|
PearlLogLevel level = PearlLogLevelInfo;
|
|
|
|
switch (record->level) {
|
|
|
|
case LogLevelTrace:
|
|
|
|
level = PearlLogLevelDebug;
|
|
|
|
break;
|
|
|
|
case LogLevelDebug:
|
|
|
|
level = PearlLogLevelDebug;
|
|
|
|
break;
|
|
|
|
case LogLevelInfo:
|
|
|
|
level = PearlLogLevelInfo;
|
|
|
|
break;
|
|
|
|
case LogLevelWarning:
|
|
|
|
level = PearlLogLevelWarn;
|
|
|
|
break;
|
|
|
|
case LogLevelError:
|
|
|
|
level = PearlLogLevelError;
|
|
|
|
break;
|
|
|
|
case LogLevelFatal:
|
|
|
|
level = PearlLogLevelFatal;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[PearlLogger get] inFile:[@(record->file) lastPathComponent] atLine:record->line fromFunction:@(record->function)
|
|
|
|
withLevel:level text:@(record->message)];
|
|
|
|
}
|
|
|
|
|
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, ^{
|
2020-01-27 18:27:10 +00:00
|
|
|
[PearlLogger get].printLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelDebug: PearlLogLevelInfo;
|
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
|
2020-02-17 00:49:06 +00:00
|
|
|
[PearlLogger get].printLevel = PearlLogLevelDebug;
|
2012-01-24 23:30:43 +00:00
|
|
|
#endif
|
2020-02-28 22:33:38 +00:00
|
|
|
|
|
|
|
mpw_verbosity = LogLevelTrace;
|
|
|
|
mpw_log_sink_register( &mpw_log_sink_pearl );
|
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 {
|
2020-01-27 18:27:10 +00:00
|
|
|
// Sentry
|
|
|
|
SentryClient.sharedClient = [[SentryClient alloc] initWithDsn:decrypt( sentryDSN ) didFailWithError:nil];
|
|
|
|
#ifdef DEBUG
|
|
|
|
SentryClient.sharedClient.environment = @"Development";
|
|
|
|
#elif PUBLIC
|
|
|
|
SentryClient.sharedClient.environment = @"Public";
|
|
|
|
#else
|
|
|
|
SentryClient.sharedClient.environment = @"Private";
|
2012-06-15 09:34:53 +00:00
|
|
|
#endif
|
2020-01-27 18:27:10 +00:00
|
|
|
SentryClient.sharedClient.enabled = [MPiOSConfig get].sendInfo;
|
|
|
|
[SentryClient.sharedClient enableAutomaticBreadcrumbTracking];
|
|
|
|
[SentryClient.sharedClient startCrashHandlerWithError:nil];
|
|
|
|
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
|
|
|
PearlLogLevel level = PearlLogLevelWarn;
|
|
|
|
if ([[MPConfig get].sendInfo boolValue])
|
|
|
|
level = PearlLogLevelDebug;
|
|
|
|
|
|
|
|
if (message.level >= level) {
|
|
|
|
SentrySeverity sentryLevel = kSentrySeverityInfo;
|
|
|
|
switch (message.level) {
|
|
|
|
case PearlLogLevelTrace:
|
|
|
|
sentryLevel = kSentrySeverityDebug;
|
|
|
|
break;
|
|
|
|
case PearlLogLevelDebug:
|
|
|
|
sentryLevel = kSentrySeverityDebug;
|
|
|
|
break;
|
|
|
|
case PearlLogLevelInfo:
|
|
|
|
sentryLevel = kSentrySeverityInfo;
|
|
|
|
break;
|
|
|
|
case PearlLogLevelWarn:
|
|
|
|
sentryLevel = kSentrySeverityWarning;
|
|
|
|
break;
|
|
|
|
case PearlLogLevelError:
|
|
|
|
sentryLevel = kSentrySeverityError;
|
|
|
|
break;
|
|
|
|
case PearlLogLevelFatal:
|
|
|
|
sentryLevel = kSentrySeverityFatal;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SentryBreadcrumb *breadcrumb = [[SentryBreadcrumb alloc] initWithLevel:sentryLevel category:@"Pearl"];
|
|
|
|
breadcrumb.type = @"log";
|
|
|
|
breadcrumb.message = message.message;
|
|
|
|
breadcrumb.timestamp = message.occurrence;
|
|
|
|
breadcrumb.data = @{ @"file": message.fileName, @"line": @(message.lineNumber), @"function": message.function };
|
|
|
|
[SentryClient.sharedClient.breadcrumbs addBreadcrumb:breadcrumb];
|
|
|
|
}
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}];
|
|
|
|
|
|
|
|
// Countly
|
|
|
|
CountlyConfig *countlyConfig = [CountlyConfig new];
|
2020-02-27 04:01:44 +00:00
|
|
|
countlyConfig.host = @"https://countly.lyndir.com";
|
2020-01-27 18:27:10 +00:00
|
|
|
countlyConfig.appKey = decrypt( countlyKey );
|
2020-02-13 17:59:15 +00:00
|
|
|
countlyConfig.features = @[ CLYPushNotifications, CLYAutoViewTracking ];
|
|
|
|
countlyConfig.requiresConsent = YES;
|
2020-01-27 18:27:10 +00:00
|
|
|
#if PUBLIC
|
|
|
|
countlyConfig.pushTestMode = nil;
|
|
|
|
#elif DEBUG
|
|
|
|
countlyConfig.pushTestMode = CLYPushTestModeDevelopment;
|
|
|
|
#else
|
|
|
|
countlyConfig.pushTestMode = CLYPushTestModeTestFlightOrAdHoc;
|
2013-08-28 03:28:10 +00:00
|
|
|
#endif
|
2020-02-13 17:59:15 +00:00
|
|
|
countlyConfig.alwaysUsePOST = YES;
|
2020-01-27 18:27:10 +00:00
|
|
|
countlyConfig.deviceID = [PearlKeyChain deviceIdentifier];
|
|
|
|
countlyConfig.secretSalt = decrypt( countlySalt );
|
2020-02-13 17:59:15 +00:00
|
|
|
countlyConfig.enableDebug = YES;
|
2020-01-27 18:27:10 +00:00
|
|
|
[Countly.sharedInstance startWithConfig:countlyConfig];
|
2017-05-04 17:57:12 +00:00
|
|
|
|
2020-02-17 00:49:06 +00:00
|
|
|
#if ! DEBUG
|
2017-06-07 02:10:02 +00:00
|
|
|
[self.hangDetector = [[PearlHangDetector alloc] initWithHangAction:^(NSTimeInterval hangTime) {
|
|
|
|
MPError( [NSError errorWithDomain:MPErrorDomain code:MPErrorHangCode userInfo:@{
|
|
|
|
@"time": @(hangTime)
|
|
|
|
}], @"Timeout waiting for main thread after %fs.", hangTime );
|
|
|
|
}] start];
|
2020-02-17 00:49:06 +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];
|
|
|
|
} );
|
|
|
|
PearlAddNotificationObserver( NSUserDefaultsDidChangeNotification, nil, nil, ^(id self, NSNotification *note) {
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
|
|
|
|
} );
|
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
|
|
|
|
2020-03-05 16:29:10 +00:00
|
|
|
PearlAddNotificationObserver(
|
|
|
|
MPFoundInconsistenciesNotification, nil, [NSOperationQueue mainQueue], ^(id self, NSNotification *note) {
|
2014-09-27 05:27:05 +00:00
|
|
|
switch ((MPFixableResult)[note.userInfo[MPInconsistenciesFixResultUserKey] unsignedIntegerValue]) {
|
|
|
|
|
|
|
|
case MPFixableResultNoProblems:
|
|
|
|
break;
|
2020-01-14 18:59:32 +00:00
|
|
|
case MPFixableResultProblemsFixed: {
|
2020-01-27 18:27:10 +00:00
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Inconsistencies Fixed" message:
|
2014-09-27 05:27:05 +00:00
|
|
|
@"Some inconsistencies were detected in your sites.\n"
|
2020-01-14 18:59:32 +00:00
|
|
|
@"All issues were fixed."
|
2020-01-27 18:27:10 +00:00
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self presentViewController:alert animated:YES completion:nil];
|
2014-09-27 05:27:05 +00:00
|
|
|
break;
|
2020-01-14 18:59:32 +00:00
|
|
|
}
|
|
|
|
case MPFixableResultProblemsNotFixed: {
|
2020-01-27 18:27:10 +00:00
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Inconsistencies Found" message:
|
2014-09-27 05:27:05 +00:00
|
|
|
@"Some inconsistencies were detected in your sites.\n"
|
2020-01-14 18:59:32 +00:00
|
|
|
@"Not all issues could be fixed. Try signing in to each user or checking the logs."
|
2020-01-27 18:27:10 +00:00
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self presentViewController:alert animated:YES completion:nil];
|
2014-09-27 05:27:05 +00:00
|
|
|
break;
|
2020-01-14 18:59:32 +00:00
|
|
|
}
|
2014-09-27 05:27:05 +00:00
|
|
|
}
|
|
|
|
} );
|
2014-04-26 18:03:44 +00:00
|
|
|
|
2020-03-13 16:15:24 +00:00
|
|
|
if (@available( iOS 12, * )) {
|
|
|
|
[Countly.sharedInstance askForNotificationPermissionWithOptions:UNAuthorizationOptionProvisional completionHandler:
|
|
|
|
^(BOOL granted, NSError *error) {
|
|
|
|
inf( @"provisional: %d: %@", granted, error );
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PearlMainQueueOperation( ^{
|
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-04-13 17:40:17 +00:00
|
|
|
|
2020-03-13 16:15:24 +00:00
|
|
|
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"notificationsDecided"]) {
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Coming Soon" message:
|
|
|
|
@"Master Password is rolling out a new modern personal security platform and we're excited to bring you along.\n\n"
|
|
|
|
@"When it's time, we'll send you a notification to help you make an effortless transition."
|
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Thanks" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
|
|
|
[Countly.sharedInstance askForNotificationPermission];
|
|
|
|
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"notificationsDecided"];
|
|
|
|
}]];
|
|
|
|
[(self.navigationController.presentedViewController?: (UIViewController *)self.navigationController)
|
|
|
|
presentViewController:alert animated:YES completion: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.
|
2017-04-15 14:57:52 +00:00
|
|
|
[[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:
|
|
|
|
^(NSData *importedSitesData, NSURLResponse *response, NSError *error) {
|
|
|
|
if (error)
|
2017-04-30 03:03:50 +00:00
|
|
|
MPError( error, @"While reading imported sites from %@.", url );
|
|
|
|
|
2017-04-15 14:57:52 +00:00
|
|
|
if (!importedSitesData) {
|
2020-03-05 16:29:10 +00:00
|
|
|
PearlMainQueue( ^{
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error" message:
|
|
|
|
strf( @"Master Password couldn't read the import sites.\n\n%@",
|
|
|
|
(id)[error localizedDescription]?: error )
|
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
|
|
|
} );
|
2017-04-15 14:57:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
|
|
|
|
if (!importedSitesString) {
|
2020-03-05 16:29:10 +00:00
|
|
|
PearlMainQueue( ^{
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error" message:
|
|
|
|
@"Master Password couldn't understand the import file."
|
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
|
|
|
} );
|
2017-04-15 14:57:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
[self importSites:importedSitesString];
|
|
|
|
}] resume];
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2012-05-09 08:11:34 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2017-08-13 01:57:47 +00:00
|
|
|
- (void)importSites:(NSString *)importData {
|
2014-09-28 00:29:58 +00:00
|
|
|
|
|
|
|
if ([NSThread isMainThread]) {
|
|
|
|
PearlNotMainQueue( ^{
|
2017-08-13 01:57:47 +00:00
|
|
|
[self importSites:importData];
|
2014-09-28 00:29:58 +00:00
|
|
|
} );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"];
|
2017-08-13 01:57:47 +00:00
|
|
|
[self importSites:importData askImportPassword:^NSString *(NSString *userName) {
|
2017-04-15 06:28:11 +00:00
|
|
|
return PearlAwait( ^(void (^setResult)(id)) {
|
2020-03-05 16:29:10 +00:00
|
|
|
PearlMainQueue( ^{
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Importing Sites For\n%@", userName ) message:
|
|
|
|
@"Enter the master password used to create this export file."
|
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
|
|
|
textField.secureTextEntry = YES;
|
|
|
|
}];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Import" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
|
|
|
setResult( alert.textFields.firstObject.text );
|
|
|
|
}]];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
|
|
|
setResult( nil );
|
|
|
|
}]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
|
|
|
} );
|
2014-09-28 00:29:58 +00:00
|
|
|
} );
|
2017-08-13 01:57:47 +00:00
|
|
|
} askUserPassword:^NSString *(NSString *userName) {
|
2017-04-15 06:28:11 +00:00
|
|
|
return PearlAwait( (id)^(void (^setResult)(id)) {
|
2020-03-05 16:29:10 +00:00
|
|
|
PearlMainQueue( ^{
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Master Password For\n%@", userName ) message:
|
|
|
|
@"Enter the current master password for this user."
|
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
|
|
|
textField.secureTextEntry = YES;
|
|
|
|
}];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Import" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
|
|
|
setResult( alert.textFields.firstObject.text );
|
|
|
|
}]];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
|
|
|
setResult( nil );
|
|
|
|
}]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
|
|
|
} );
|
2014-09-28 00:29:58 +00:00
|
|
|
} );
|
2017-08-13 01:57:47 +00:00
|
|
|
} result:^(NSError *error) {
|
|
|
|
[activityOverlay cancelOverlayAnimated:YES];
|
2014-09-28 00:29:58 +00:00
|
|
|
|
2020-01-14 18:59:32 +00:00
|
|
|
if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError)) {
|
2020-03-05 16:29:10 +00:00
|
|
|
PearlMainQueue( ^{
|
|
|
|
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:[error localizedDescription]
|
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:controller animated:YES completion:nil];
|
|
|
|
} );
|
2020-01-14 18:59:32 +00:00
|
|
|
}
|
2017-08-13 01:57:47 +00:00
|
|
|
}];
|
2014-09-28 00:29:58 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 02:10:02 +00:00
|
|
|
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
|
|
|
|
|
|
|
inf( @"Will foreground" );
|
|
|
|
|
|
|
|
[super applicationWillEnterForeground:application];
|
|
|
|
|
|
|
|
[self.hangDetector start];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
|
|
|
|
|
|
|
inf( @"Re-activated" );
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
|
|
|
|
|
|
|
|
PearlNotMainQueue( ^{
|
2017-08-13 01:57:47 +00:00
|
|
|
NSString *importData = [UIPasteboard generalPasteboard].string;
|
2020-01-27 18:27:10 +00:00
|
|
|
MPMarshalledFile *importFile = mpw_marshal_read( NULL, importData.UTF8String );
|
|
|
|
if (importFile && importFile->error.type == MPMarshalSuccess && importFile->info->format != MPMarshalFormatNone) {
|
2020-03-05 16:29:10 +00:00
|
|
|
PearlMainQueue( ^{
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Import Sites?" message:
|
|
|
|
@"We've detected Master Password import sites on your pasteboard, would you like to import them?"
|
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Import Sites" style:UIAlertActionStyleDefault handler:
|
|
|
|
^(UIAlertAction *action) {
|
|
|
|
[self importSites:importData];
|
|
|
|
[UIPasteboard generalPasteboard].string = @"";
|
|
|
|
}]];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
|
|
|
} );
|
2020-01-14 18:59:32 +00:00
|
|
|
}
|
2020-01-27 18:27:10 +00:00
|
|
|
mpw_marshal_file_free( &importFile );
|
2017-06-07 02:10:02 +00:00
|
|
|
} );
|
|
|
|
|
|
|
|
[super applicationDidBecomeActive:application];
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2017-06-07 02:10:02 +00:00
|
|
|
inf( @"Did 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
|
|
|
|
2017-06-07 02:10:02 +00:00
|
|
|
[self.hangDetector stop];
|
|
|
|
|
2017-04-27 06:20:49 +00:00
|
|
|
// self.task = [application beginBackgroundTaskWithExpirationHandler:^{
|
|
|
|
// [application endBackgroundTask:self.task];
|
|
|
|
// dbg( @"background expiring" );
|
|
|
|
// }];
|
|
|
|
// PearlNotMainQueueOperation( ^{
|
|
|
|
// NSString *pbstring = [UIPasteboard generalPasteboard].string;
|
|
|
|
// while (YES) {
|
|
|
|
// NSString *newString = [UIPasteboard generalPasteboard].string;
|
|
|
|
// if (![newString isEqualToString:pbstring]) {
|
|
|
|
// dbg( @"pasteboard changed to: %@", newString );
|
|
|
|
// pbstring = newString;
|
|
|
|
// NSURL *url = [NSURL URLWithString:pbstring];
|
|
|
|
// if (url) {
|
|
|
|
// NSString *siteName = [url host];
|
|
|
|
// }
|
|
|
|
// MPKey *key = [MPiOSAppDelegate get].key;
|
|
|
|
// if (key)
|
|
|
|
// [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
|
|
|
// NSFetchRequest<MPSiteEntity *>
|
|
|
|
// *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
|
|
|
|
// fetchRequest.sortDescriptors = @[
|
|
|
|
// [[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO]
|
|
|
|
// ];
|
|
|
|
// fetchRequest.fetchBatchSize = 2;
|
|
|
|
// fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(name LIKE[cd] %@) AND user == %@", siteName,
|
|
|
|
// [[MPiOSAppDelegate get] activeUserOID]];
|
|
|
|
// NSError *error = nil;
|
|
|
|
// NSArray<MPSiteEntity *> *results = [fetchRequest execute:&error];
|
|
|
|
// dbg( @"site search, error: %@, results:\n%@", error, results );
|
|
|
|
// if ([results count]) {
|
|
|
|
// [UIPasteboard generalPasteboard].string = [[results firstObject] resolvePasswordUsingKey:key];
|
|
|
|
// }
|
|
|
|
// }];
|
|
|
|
// }
|
|
|
|
// [NSThread sleepForTimeInterval:5];
|
|
|
|
// }
|
|
|
|
// } );
|
|
|
|
|
2014-09-26 04:32:07 +00:00
|
|
|
[super applicationDidEnterBackground: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 {
|
|
|
|
|
2020-01-14 18:59:32 +00:00
|
|
|
if (![PearlEMail canSendMail]) {
|
2020-01-27 18:27:10 +00:00
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Feedback" message:
|
2020-01-14 18:59:32 +00:00
|
|
|
@"Have a question, comment, issue or just saying thanks?\n\n"
|
|
|
|
@"We'd love to hear what you think!\n"
|
2020-03-05 16:29:10 +00:00
|
|
|
@"help@masterpassword.app"
|
2020-01-27 18:27:10 +00:00
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
2020-01-14 18:59:32 +00:00
|
|
|
}
|
|
|
|
else if (logs) {
|
2020-01-27 18:27:10 +00:00
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Feedback" message:
|
2020-01-14 18:59:32 +00:00
|
|
|
@"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."
|
2020-01-27 18:27:10 +00:00
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Include Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
2020-01-14 18:59:32 +00:00
|
|
|
[self openFeedbackWithLogs:YES forVC:viewController];
|
|
|
|
}]];
|
2020-01-27 18:27:10 +00:00
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"No Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
2020-01-14 18:59:32 +00:00
|
|
|
[self openFeedbackWithLogs:NO forVC:viewController];
|
|
|
|
}]];
|
2020-01-27 18:27:10 +00:00
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
2020-01-14 18:59:32 +00:00
|
|
|
}
|
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
|
|
|
|
2020-03-05 16:29:10 +00:00
|
|
|
[[[PearlEMail alloc] initForEMailTo:@"Master Password Development <help@masterpassword.app"
|
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"
|
2020-01-14 18:59:32 +00:00
|
|
|
@"--\n"
|
|
|
|
@"%@"
|
|
|
|
@"Master Password %@, build %@",
|
2014-08-21 04:30:38 +00:00
|
|
|
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, ^{
|
2020-03-05 16:29:10 +00:00
|
|
|
PearlMainQueue( ^{
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"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."
|
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"E-Mail Logs" style:UIAlertActionStyleDefault
|
|
|
|
handler:^(UIAlertAction *action) {
|
|
|
|
[self openFeedbackWithLogs:YES forVC:nil];
|
|
|
|
}]];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
|
|
|
[self deleteAndResetStore];
|
|
|
|
}]];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Ignore" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
|
|
|
} );
|
2014-09-22 03:11:05 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2014-04-25 01:43:47 +00:00
|
|
|
- (void)showExportForVC:(UIViewController *)viewController {
|
2012-06-14 19:56:54 +00:00
|
|
|
|
2020-01-27 18:27:10 +00:00
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Exporting Your Sites" message:
|
2020-01-14 18:59:32 +00:00
|
|
|
@"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."
|
2020-01-27 18:27:10 +00:00
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Export Sites" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
|
|
|
UIAlertController *sheet = [UIAlertController alertControllerWithTitle:@"Show Passwords?" message:
|
2020-01-14 18:59:32 +00:00
|
|
|
@"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."
|
2020-01-27 18:27:10 +00:00
|
|
|
preferredStyle:UIAlertControllerStyleActionSheet];
|
|
|
|
[sheet addAction:[UIAlertAction actionWithTitle:@"Safe Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
|
|
|
[self showExportRevealPasswords:NO forVC:viewController];
|
2020-01-14 18:59:32 +00:00
|
|
|
}]];
|
2020-01-27 18:27:10 +00:00
|
|
|
[sheet addAction:[UIAlertAction actionWithTitle:@"Show Passwords" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
|
|
|
[self showExportRevealPasswords:YES forVC:viewController];
|
2020-01-14 18:59:32 +00:00
|
|
|
}]];
|
2020-01-27 18:27:10 +00:00
|
|
|
[sheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:sheet animated:YES completion:nil];
|
2020-01-14 18:59:32 +00:00
|
|
|
}]];
|
2020-01-27 18:27:10 +00:00
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion: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]) {
|
2020-01-27 18:27:10 +00:00
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Cannot Send Mail" message:
|
2020-01-14 18:59:32 +00:00
|
|
|
@"Your device is not yet set up for sending mail.\n"
|
|
|
|
@"Close Master Password, go into Settings and add a Mail account."
|
2020-01-27 18:27:10 +00:00
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
2012-06-22 14:52:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-06-14 19:56:54 +00:00
|
|
|
|
2017-08-13 01:57:47 +00:00
|
|
|
[self exportSitesRevealPasswords:revealPasswords askExportPassword:^NSString *(NSString *userName) {
|
|
|
|
return PearlAwait( ^(void (^setResult)(id)) {
|
2020-02-28 22:33:38 +00:00
|
|
|
PearlMainQueue( ^{
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Master Password For:\n%@", userName )
|
|
|
|
message:@"Enter your master password to export the user."
|
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
|
|
|
textField.secureTextEntry = YES;
|
|
|
|
}];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
|
|
|
setResult( alert.textFields.firstObject.text );
|
|
|
|
}]];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
|
|
|
setResult( nil );
|
|
|
|
}]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
|
|
|
} );
|
2017-08-13 01:57:47 +00:00
|
|
|
} );
|
2020-02-28 22:33:38 +00:00
|
|
|
} result:^(NSString *exportedUser, NSError *error) {
|
|
|
|
if (!exportedUser || error) {
|
2017-08-13 01:57:47 +00:00
|
|
|
MPError( error, @"Failed to export mpsites." );
|
2020-02-28 22:33:38 +00:00
|
|
|
PearlMainQueue( ^{
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Error" message:[error localizedDescription]
|
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
|
|
|
} );
|
2017-08-13 01:57:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-14 18:59:32 +00:00
|
|
|
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
|
|
|
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
|
|
|
NSString *exportFileName = strf( @"%@ (%@).mpsites",
|
|
|
|
[self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
|
|
|
|
|
2020-01-27 18:27:10 +00:00
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Destination" message:nil
|
|
|
|
preferredStyle:UIAlertControllerStyleActionSheet];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Send As E-Mail" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
2020-01-14 18:59:32 +00:00
|
|
|
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 );
|
|
|
|
|
|
|
|
[PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
|
2020-02-28 22:33:38 +00:00
|
|
|
attachments:[[PearlEMailAttachment alloc] initWithContent:[exportedUser dataUsingEncoding:NSUTF8StringEncoding]
|
|
|
|
mimeType:@"text/plain"
|
|
|
|
fileName:exportFileName], nil];
|
2020-01-14 18:59:32 +00:00
|
|
|
return;
|
|
|
|
}]];
|
2020-01-27 18:27:10 +00:00
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Share / Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
2020-01-14 18:59:32 +00:00
|
|
|
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;
|
2020-02-28 22:33:38 +00:00
|
|
|
if (![[exportedUser dataUsingEncoding:NSUTF8StringEncoding]
|
2020-01-14 18:59:32 +00:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
}]];
|
2020-01-27 18:27:10 +00:00
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
2017-08-13 01:57:47 +00:00
|
|
|
}];
|
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
|
|
|
|
2020-03-05 16:29:10 +00:00
|
|
|
PearlMainQueue( ^{
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Changing Master Password" message:
|
|
|
|
@"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."
|
|
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
|
|
|
[moc performBlockAndWait:^{
|
|
|
|
inf( @"Clearing keyID for user: %@.", user.userID );
|
|
|
|
user.keyID = nil;
|
|
|
|
[self forgetSavedKeyFor:user];
|
|
|
|
[moc saveToStore];
|
|
|
|
}];
|
2020-01-14 18:59:32 +00:00
|
|
|
|
2020-03-05 16:29:10 +00:00
|
|
|
[self signOutAnimated:YES];
|
|
|
|
if (didReset)
|
|
|
|
didReset();
|
|
|
|
}]];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleCancel handler:nil]];
|
|
|
|
[self.navigationController presentViewController:alert animated:YES completion: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]) {
|
2020-01-27 18:27:10 +00:00
|
|
|
[Countly.sharedInstance giveConsentForAllFeatures];
|
|
|
|
|
2013-09-06 03:52:12 +00:00
|
|
|
if ([PearlLogger get].printLevel > PearlLogLevelInfo)
|
|
|
|
[PearlLogger get].printLevel = PearlLogLevelInfo;
|
|
|
|
|
2020-01-27 18:27:10 +00:00
|
|
|
NSMutableDictionary *prefs = [NSMutableDictionary new];
|
|
|
|
prefs[@"rememberLogin"] = [MPConfig get].rememberLogin;
|
|
|
|
prefs[@"sendInfo"] = [MPConfig get].sendInfo;
|
|
|
|
prefs[@"helpHidden"] = [MPiOSConfig get].helpHidden;
|
|
|
|
prefs[@"showQuickStart"] = [MPiOSConfig get].showSetup;
|
|
|
|
prefs[@"firstRun"] = [PearlConfig get].firstRun;
|
|
|
|
prefs[@"launchCount"] = [PearlConfig get].launchCount;
|
|
|
|
prefs[@"askForReviews"] = [PearlConfig get].askForReviews;
|
|
|
|
prefs[@"reviewAfterLaunches"] = [PearlConfig get].reviewAfterLaunches;
|
|
|
|
prefs[@"reviewedVersion"] = [PearlConfig get].reviewedVersion;
|
|
|
|
prefs[@"simulator"] = @([PearlDeviceUtils isSimulator]);
|
|
|
|
prefs[@"encrypted"] = @([PearlDeviceUtils isAppEncrypted]);
|
|
|
|
prefs[@"jailbroken"] = @([PearlDeviceUtils isJailbroken]);
|
|
|
|
prefs[@"platform"] = [PearlDeviceUtils platform];
|
2014-10-23 03:00:20 +00:00
|
|
|
#ifdef APPSTORE
|
2020-01-27 18:27:10 +00:00
|
|
|
prefs[@"reviewedVersion"] = @([PearlDeviceUtils isAppEncrypted]);
|
2014-10-23 03:00:20 +00:00
|
|
|
#else
|
2020-01-27 18:27:10 +00:00
|
|
|
prefs[@"reviewedVersion"] = @(YES);
|
2013-09-06 03:52:12 +00:00
|
|
|
#endif
|
2020-01-27 18:27:10 +00:00
|
|
|
PearlMainQueueOperation( ^{
|
|
|
|
if (![[SentryClient.sharedClient.extra dictionaryWithValuesForKeys:prefs.allKeys] isEqualToDictionary:prefs]) {
|
|
|
|
NSMutableDictionary *extra = [SentryClient.sharedClient.extra mutableCopy]?: [NSMutableDictionary dictionary];
|
|
|
|
[extra addEntriesFromDictionary:prefs];
|
|
|
|
SentryClient.sharedClient.extra = extra;
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
[Countly.sharedInstance cancelConsentForAllFeatures];
|
2013-09-06 03:52:12 +00:00
|
|
|
}
|
2012-05-03 14:49:15 +00:00
|
|
|
}
|
|
|
|
|
2011-11-30 21:42:40 +00:00
|
|
|
@end
|