2011-11-30 21:42:40 +00:00
|
|
|
//
|
2012-02-05 21:18:38 +00:00
|
|
|
// MPAppDelegate.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.
|
|
|
|
//
|
|
|
|
|
2012-05-11 20:45:05 +00:00
|
|
|
#import "MPAppDelegate.h"
|
|
|
|
#import "MPAppDelegate_Key.h"
|
|
|
|
#import "MPAppDelegate_Store.h"
|
2011-11-30 21:42:40 +00:00
|
|
|
|
2012-02-05 21:18:38 +00:00
|
|
|
#import "MPMainViewController.h"
|
2012-02-05 21:01:37 +00:00
|
|
|
#import "IASKSettingsReader.h"
|
2012-05-03 14:49:15 +00:00
|
|
|
#import "LocalyticsSession.h"
|
|
|
|
#import "TestFlight.h"
|
|
|
|
#import <Crashlytics/Crashlytics.h>
|
2012-05-23 06:58:01 +00:00
|
|
|
#import "ATConnect.h"
|
|
|
|
#import "ATAppRatingFlow.h"
|
2012-05-03 14:49:15 +00:00
|
|
|
|
|
|
|
@interface MPAppDelegate ()
|
|
|
|
|
|
|
|
- (NSString *)testFlightInfo;
|
|
|
|
- (NSString *)testFlightToken;
|
|
|
|
|
|
|
|
- (NSString *)crashlyticsInfo;
|
|
|
|
- (NSString *)crashlyticsAPIKey;
|
|
|
|
|
2012-05-23 06:58:01 +00:00
|
|
|
- (NSString *)apptentiveInfo;
|
|
|
|
- (NSString *)apptentiveAPIKey;
|
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
- (NSString *)localyticsInfo;
|
|
|
|
- (NSString *)localyticsKey;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2011-11-30 21:42:40 +00:00
|
|
|
|
2012-02-05 21:18:38 +00:00
|
|
|
@implementation MPAppDelegate
|
2011-11-30 21:42:40 +00:00
|
|
|
|
2012-01-05 00:44:15 +00:00
|
|
|
+ (void)initialize {
|
2012-05-04 16:54:58 +00:00
|
|
|
|
2012-03-05 21:19:05 +00:00
|
|
|
[MPiOSConfig get];
|
2012-05-04 16:54:58 +00:00
|
|
|
|
2012-01-24 23:30:43 +00:00
|
|
|
#ifdef DEBUG
|
2012-03-11 10:14:28 +00:00
|
|
|
[PearlLogger get].autoprintLevel = PearlLogLevelDebug;
|
2012-05-06 23:15:19 +00:00
|
|
|
//[NSClassFromString(@"WebView") performSelector:NSSelectorFromString(@"_enableRemoteInspector")];
|
2012-01-24 23:30:43 +00:00
|
|
|
#endif
|
2012-01-05 00:44:15 +00:00
|
|
|
}
|
2012-05-11 20:45:05 +00:00
|
|
|
|
|
|
|
+ (MPAppDelegate *)get {
|
|
|
|
|
|
|
|
return (MPAppDelegate *)[super get];
|
|
|
|
}
|
|
|
|
|
2012-05-09 08:11:34 +00:00
|
|
|
- (void)showGuide {
|
|
|
|
|
|
|
|
[self.navigationController performSegueWithIdentifier:@"MP_Guide" sender:self];
|
|
|
|
|
|
|
|
[TestFlight passCheckpoint:MPTestFlightCheckpointShowGuide];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)loadKey:(BOOL)animated {
|
|
|
|
|
|
|
|
if (!self.key)
|
|
|
|
// Try and load the key from the keychain.
|
|
|
|
[self loadStoredKey];
|
|
|
|
|
|
|
|
if (!self.key)
|
|
|
|
// Ask the user to set the key through his master password.
|
2012-05-20 17:17:22 +00:00
|
|
|
if ([NSThread isMainThread])
|
2012-05-09 08:11:34 +00:00
|
|
|
[self.navigationController presentViewController:
|
|
|
|
[self.navigationController.storyboard instantiateViewControllerWithIdentifier:@"MPUnlockViewController"]
|
|
|
|
animated:animated completion:nil];
|
2012-05-20 17:17:22 +00:00
|
|
|
else
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
[self.navigationController presentViewController:
|
|
|
|
[self.navigationController.storyboard instantiateViewControllerWithIdentifier:@"MPUnlockViewController"]
|
|
|
|
animated:animated completion:nil];
|
|
|
|
});
|
2012-05-09 08:11:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)export {
|
|
|
|
|
|
|
|
[PearlAlert showNotice:
|
|
|
|
@"This will export all your site names.\n\n"
|
|
|
|
@"You can open the export with a text editor to get an overview of all your sites.\n\n"
|
|
|
|
@"The file also acts as a personal backup of your site list in case you don't sync with iCloud/iTunes."
|
|
|
|
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
|
|
[PearlAlert showAlertWithTitle:@"Reveal Passwords?" message:
|
|
|
|
@"Would you like to make all your passwords visible in the export?\n\n"
|
|
|
|
@"A safe export will only include your stored passwords, in an encrypted manner, "
|
|
|
|
@"making the result safe from falling in the wrong hands.\n\n"
|
|
|
|
@"If all your passwords are shown and somebody else finds the export, "
|
|
|
|
@"they could gain access to all your sites!"
|
|
|
|
viewStyle:UIAlertViewStyleDefault tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
|
|
if (buttonIndex == [alert firstOtherButtonIndex] + 0)
|
|
|
|
// Safe Export
|
|
|
|
[self exportShowPasswords:NO];
|
|
|
|
if (buttonIndex == [alert firstOtherButtonIndex] + 1)
|
|
|
|
// Safe Export
|
|
|
|
[self exportShowPasswords:YES];
|
|
|
|
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Safe Export", @"Show Passwords", nil];
|
|
|
|
} otherTitles:nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)exportShowPasswords:(BOOL)showPasswords {
|
|
|
|
|
|
|
|
NSString *exportedSites = [self exportSitesShowingPasswords:showPasswords];
|
|
|
|
NSString *message;
|
|
|
|
if (showPasswords)
|
|
|
|
message = @"Export of my Master Password sites with passwords visible.\n\nREMINDER: Make sure nobody else sees this file!\n";
|
|
|
|
else
|
|
|
|
message = @"Backup of my Master Password sites.\n";
|
|
|
|
|
|
|
|
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
|
|
|
[exportDateFormatter setDateFormat:@"'Master Password sites ('yyyy'-'MM'-'DD').mpsites'"];
|
|
|
|
|
|
|
|
MFMailComposeViewController *composer = [[MFMailComposeViewController alloc] init];
|
|
|
|
[composer setMailComposeDelegate:self];
|
|
|
|
[composer setSubject:@"Master Password site export"];
|
|
|
|
[composer setMessageBody:message isHTML:NO];
|
|
|
|
[composer addAttachmentData:[exportedSites dataUsingEncoding:NSUTF8StringEncoding] mimeType:@"text/plain"
|
|
|
|
fileName:[exportDateFormatter stringFromDate:[NSDate date]]];
|
|
|
|
[self.window.rootViewController presentModalViewController:composer animated:YES];
|
|
|
|
}
|
|
|
|
|
2012-05-11 22:08:19 +00:00
|
|
|
#pragma mark - PearlConfigDelegate
|
|
|
|
|
|
|
|
- (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)value {
|
|
|
|
|
|
|
|
[self checkConfig];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)checkConfig {
|
|
|
|
|
|
|
|
if ([[MPConfig get].saveKey boolValue]) {
|
|
|
|
if (self.key)
|
|
|
|
[self updateKey:self.key];
|
|
|
|
} else
|
|
|
|
[self loadStoredKey];
|
|
|
|
|
|
|
|
if ([[MPConfig get].iCloud boolValue] != [self.storeManager iCloudEnabled])
|
|
|
|
[self.storeManager useiCloudStore:[[MPConfig get].iCloud boolValue] alertUser:YES];
|
|
|
|
}
|
|
|
|
|
2012-05-09 08:11:34 +00:00
|
|
|
#pragma mark - UIApplicationDelegate
|
|
|
|
|
2012-01-05 00:44:15 +00:00
|
|
|
|
2012-01-24 23:30:43 +00:00
|
|
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
|
2012-05-23 06:58:01 +00:00
|
|
|
#ifndef DEBUG
|
2012-05-03 14:49:15 +00:00
|
|
|
@try {
|
|
|
|
NSString *testFlightToken = [self testFlightToken];
|
|
|
|
if ([testFlightToken length]) {
|
|
|
|
dbg(@"Initializing TestFlight");
|
|
|
|
[TestFlight addCustomEnvironmentInformation:@"Anonymous" forKey:@"username"];
|
|
|
|
[TestFlight setOptions:[NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
[NSNumber numberWithBool:NO], @"logToConsole",
|
|
|
|
[NSNumber numberWithBool:NO], @"logToSTDERR",
|
|
|
|
nil]];
|
|
|
|
[TestFlight takeOff:testFlightToken];
|
|
|
|
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
|
|
|
if (message.level >= PearlLogLevelInfo)
|
|
|
|
TFLog(@"%@", message);
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}];
|
|
|
|
[TestFlight passCheckpoint:MPTestFlightCheckpointLaunched];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@catch (NSException *exception) {
|
|
|
|
err(@"TestFlight: %@", exception);
|
|
|
|
}
|
|
|
|
@try {
|
|
|
|
NSString *crashlyticsAPIKey = [self crashlyticsAPIKey];
|
|
|
|
if ([crashlyticsAPIKey length]) {
|
|
|
|
dbg(@"Initializing Crashlytics");
|
|
|
|
//[Crashlytics sharedInstance].debugMode = YES;
|
|
|
|
[Crashlytics startWithAPIKey:crashlyticsAPIKey afterDelay:0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@catch (NSException *exception) {
|
|
|
|
err(@"Crashlytics: %@", exception);
|
|
|
|
}
|
|
|
|
@try {
|
|
|
|
NSString *localyticsKey = [self localyticsKey];
|
|
|
|
if ([localyticsKey length]) {
|
|
|
|
dbg(@"Initializing Localytics");
|
|
|
|
[[LocalyticsSession sharedLocalyticsSession] startSession:localyticsKey];
|
|
|
|
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
|
|
|
if (message.level >= PearlLogLevelError)
|
|
|
|
[[LocalyticsSession sharedLocalyticsSession] tagEvent:@"Problem" attributes:
|
|
|
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
[message levelDescription],
|
|
|
|
@"level",
|
|
|
|
message.message,
|
|
|
|
@"message",
|
|
|
|
nil]];
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@catch (NSException *exception) {
|
|
|
|
err(@"Localytics exception: %@", exception);
|
|
|
|
}
|
2012-02-05 23:40:20 +00:00
|
|
|
#endif
|
2012-05-23 06:58:01 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
@try {
|
|
|
|
NSString *apptentiveAPIKey = [self apptentiveAPIKey];
|
|
|
|
if ([apptentiveAPIKey length]) {
|
|
|
|
dbg(@"Initializing Apptentive");
|
|
|
|
ATConnect *connection = [ATConnect sharedConnection];
|
|
|
|
connection.shouldTakeScreenshot = NO;
|
|
|
|
connection.apiKey = apptentiveAPIKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@catch (NSException *exception) {
|
|
|
|
err(@"Apptentive: %@", exception);
|
|
|
|
}
|
|
|
|
|
2012-01-24 23:30:43 +00:00
|
|
|
UIImage *navBarImage = [[UIImage imageNamed:@"ui_navbar_container"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 5)];
|
|
|
|
[[UINavigationBar appearance] setBackgroundImage:navBarImage forBarMetrics:UIBarMetricsDefault];
|
|
|
|
[[UINavigationBar appearance] setBackgroundImage:navBarImage forBarMetrics:UIBarMetricsLandscapePhone];
|
|
|
|
[[UINavigationBar appearance] setTitleTextAttributes:
|
|
|
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
2012-05-03 14:49:15 +00:00
|
|
|
[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f], UITextAttributeTextColor,
|
|
|
|
[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.8f], UITextAttributeTextShadowColor,
|
|
|
|
[NSValue valueWithUIOffset:UIOffsetMake(0, -1)], UITextAttributeTextShadowOffset,
|
2012-05-20 17:17:22 +00:00
|
|
|
[UIFont fontWithName:@"Exo-Bold" size:20.0f], UITextAttributeFont,
|
2012-01-24 23:30:43 +00:00
|
|
|
nil]];
|
|
|
|
|
|
|
|
UIImage *navBarButton = [[UIImage imageNamed:@"ui_navbar_button"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 5)];
|
|
|
|
UIImage *navBarBack = [[UIImage imageNamed:@"ui_navbar_back"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 5)];
|
|
|
|
[[UIBarButtonItem appearance] setBackgroundImage:navBarButton forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
|
|
|
|
[[UIBarButtonItem appearance] setBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
|
|
|
|
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:navBarBack forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
|
|
|
|
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
|
|
|
|
[[UIBarButtonItem appearance] setTitleTextAttributes:
|
|
|
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
2012-05-03 14:49:15 +00:00
|
|
|
[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f], UITextAttributeTextColor,
|
|
|
|
[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.5f], UITextAttributeTextShadowColor,
|
|
|
|
[NSValue valueWithUIOffset:UIOffsetMake(0, 1)], UITextAttributeTextShadowOffset,
|
|
|
|
[UIFont fontWithName:@"Helvetica-Neue" size:0.0f], UITextAttributeFont,
|
2012-01-24 23:30:43 +00:00
|
|
|
nil]
|
|
|
|
forState:UIControlStateNormal];
|
2012-01-29 11:41:48 +00:00
|
|
|
|
2012-01-24 23:30:43 +00:00
|
|
|
UIImage *toolBarImage = [[UIImage imageNamed:@"ui_toolbar_container"] resizableImageWithCapInsets:UIEdgeInsetsMake(25, 5, 5, 5)];
|
|
|
|
[[UISearchBar appearance] setBackgroundImage:toolBarImage];
|
|
|
|
[[UIToolbar appearance] setBackgroundImage:toolBarImage forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
|
|
|
|
|
|
|
|
/*
|
2012-01-29 11:41:48 +00:00
|
|
|
UIImage *minImage = [[UIImage imageNamed:@"slider-minimum.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 0)];
|
|
|
|
UIImage *maxImage = [[UIImage imageNamed:@"slider-maximum.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 0)];
|
|
|
|
UIImage *thumbImage = [UIImage imageNamed:@"slider-handle.png"];
|
|
|
|
|
|
|
|
[[UISlider appearance] setMaximumTrackImage:maxImage forState:UIControlStateNormal];
|
|
|
|
[[UISlider appearance] setMinimumTrackImage:minImage forState:UIControlStateNormal];
|
|
|
|
[[UISlider appearance] setThumbImage:thumbImage forState:UIControlStateNormal];
|
|
|
|
|
|
|
|
UIImage *segmentSelected = [[UIImage imageNamed:@"segcontrol_sel.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 4, 0, 4)];
|
|
|
|
UIImage *segmentUnselected = [[UIImage imageNamed:@"segcontrol_uns.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 15)];
|
|
|
|
UIImage *segmentSelectedUnselected = [UIImage imageNamed:@"segcontrol_sel-uns.png"];
|
|
|
|
UIImage *segUnselectedSelected = [UIImage imageNamed:@"segcontrol_uns-sel.png"];
|
|
|
|
UIImage *segmentUnselectedUnselected = [UIImage imageNamed:@"segcontrol_uns-uns.png"];
|
|
|
|
|
|
|
|
[[UISegmentedControl appearance] setBackgroundImage:segmentUnselected forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
|
|
|
|
[[UISegmentedControl appearance] setBackgroundImage:segmentSelected forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
|
|
|
|
|
|
|
|
[[UISegmentedControl appearance] setDividerImage:segmentUnselectedUnselected forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
|
|
|
|
[[UISegmentedControl appearance] setDividerImage:segmentSelectedUnselected forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
|
|
|
|
[[UISegmentedControl appearance] setDividerImage:segUnselectedSelected forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];*/
|
2012-01-24 23:30:43 +00:00
|
|
|
|
2012-02-05 21:01:37 +00:00
|
|
|
[[NSNotificationCenter defaultCenter] addObserverForName:kIASKAppSettingChanged object:nil queue:nil
|
|
|
|
usingBlock:^(NSNotification *note) {
|
2012-05-11 20:45:05 +00:00
|
|
|
[self checkConfig];
|
2012-02-05 21:01:37 +00:00
|
|
|
}];
|
2012-02-29 01:10:46 +00:00
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
#ifdef ADHOC
|
2012-02-29 01:10:46 +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 tappedButtonBlock:nil
|
|
|
|
cancelTitle:nil otherTitles:[PearlStrings get].commonButtonOkay, nil];
|
2012-05-23 06:58:01 +00:00
|
|
|
#else
|
|
|
|
@try {
|
|
|
|
ATAppRatingFlow *sharedFlow = [ATAppRatingFlow sharedRatingFlowWithAppID:[PearlConfig get].iTunesID];
|
|
|
|
[sharedFlow appDidLaunch:YES viewController:self.navigationController];
|
|
|
|
}
|
|
|
|
@catch (NSException *exception) {
|
|
|
|
err(@"Apptentive: %@", exception);
|
|
|
|
}
|
2012-02-29 01:10:46 +00:00
|
|
|
#endif
|
2012-05-04 16:54:58 +00:00
|
|
|
|
2012-02-29 00:56:58 +00:00
|
|
|
[[UIApplication sharedApplication] setStatusBarHidden:NO
|
|
|
|
withAnimation:UIStatusBarAnimationSlide];
|
2012-05-23 06:58:01 +00:00
|
|
|
|
2012-01-29 11:41:48 +00:00
|
|
|
return [super application:application didFinishLaunchingWithOptions:launchOptions];
|
|
|
|
}
|
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 {
|
|
|
|
|
|
|
|
__autoreleasing NSError *error;
|
|
|
|
__autoreleasing NSURLResponse *response;
|
|
|
|
NSData *importedSitesData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url]
|
|
|
|
returningResponse:&response error:&error];
|
|
|
|
if (error)
|
|
|
|
err(@"While reading imported sites from %@: %@", url, error);
|
|
|
|
if (!importedSitesData)
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
|
|
|
|
[PearlAlert showAlertWithTitle:@"Import Password" message:
|
|
|
|
@"Enter the master password for this export:"
|
|
|
|
viewStyle:UIAlertViewStyleSecureTextInput tappedButtonBlock:
|
|
|
|
^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
|
|
MPImportResult result = [self importSites:importedSitesString withPassword:[alert textFieldAtIndex:0].text
|
|
|
|
askConfirmation:^BOOL(NSUInteger importCount, NSUInteger deleteCount) {
|
|
|
|
__block BOOL confirmation = NO;
|
|
|
|
|
|
|
|
dispatch_group_t confirmationGroup = dispatch_group_create();
|
|
|
|
dispatch_group_enter(confirmationGroup);
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
[PearlAlert showAlertWithTitle:@"Import Sites?"
|
2012-05-15 21:27:05 +00:00
|
|
|
message:PearlLocalize(@"Import %d sites, overwriting %d existing sites?", importCount, deleteCount)
|
2012-05-09 08:11:34 +00:00
|
|
|
viewStyle:UIAlertViewStyleDefault
|
|
|
|
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
|
|
if (buttonIndex != [alert cancelButtonIndex])
|
|
|
|
confirmation = YES;
|
|
|
|
|
|
|
|
dispatch_group_leave(confirmationGroup);
|
|
|
|
}
|
|
|
|
cancelTitle:[PearlStrings get].commonButtonCancel
|
|
|
|
otherTitles:@"Import", nil];
|
|
|
|
});
|
|
|
|
dispatch_group_wait(confirmationGroup, DISPATCH_TIME_FOREVER);
|
|
|
|
|
|
|
|
return confirmation;
|
|
|
|
}];
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Unlock File", nil];
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2012-01-29 11:41:48 +00:00
|
|
|
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
2012-01-24 23:30:43 +00:00
|
|
|
|
2012-03-05 21:19:05 +00:00
|
|
|
if ([[MPiOSConfig get].showQuickStart boolValue])
|
2012-02-02 13:56:09 +00:00
|
|
|
[self showGuide];
|
2012-05-11 20:45:05 +00:00
|
|
|
else {
|
2012-03-05 21:19:05 +00:00
|
|
|
[self loadKey:NO];
|
2012-05-11 20:45:05 +00:00
|
|
|
[self checkConfig];
|
|
|
|
}
|
2012-02-13 09:27:08 +00:00
|
|
|
|
2012-02-05 23:40:20 +00:00
|
|
|
[TestFlight passCheckpoint:MPTestFlightCheckpointActivated];
|
2012-05-23 06:58:01 +00:00
|
|
|
|
|
|
|
ATAppRatingFlow *sharedFlow = [ATAppRatingFlow sharedRatingFlowWithAppID:[PearlConfig get].iTunesID];
|
|
|
|
[sharedFlow appDidEnterForeground:YES viewController:self.navigationController];
|
|
|
|
|
|
|
|
[super applicationDidBecomeActive:application];
|
2012-02-02 13:56:09 +00:00
|
|
|
}
|
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
2012-01-19 16:40:39 +00:00
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
[[LocalyticsSession sharedLocalyticsSession] close];
|
|
|
|
[[LocalyticsSession sharedLocalyticsSession] upload];
|
2012-02-04 23:36:19 +00:00
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
[super applicationDidEnterBackground:application];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
2012-02-13 09:27:08 +00:00
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
[[LocalyticsSession sharedLocalyticsSession] resume];
|
|
|
|
[[LocalyticsSession sharedLocalyticsSession] upload];
|
|
|
|
|
|
|
|
[super applicationWillEnterForeground:application];
|
2011-11-30 21:42:40 +00:00
|
|
|
}
|
|
|
|
|
2012-02-04 23:36:19 +00:00
|
|
|
- (void)applicationWillTerminate:(UIApplication *)application {
|
|
|
|
|
2011-11-30 21:42:40 +00:00
|
|
|
[self saveContext];
|
2012-02-05 23:40:20 +00:00
|
|
|
|
|
|
|
[TestFlight passCheckpoint:MPTestFlightCheckpointTerminated];
|
2012-05-04 16:54:58 +00:00
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
[[LocalyticsSession sharedLocalyticsSession] close];
|
|
|
|
[[LocalyticsSession sharedLocalyticsSession] upload];
|
|
|
|
|
|
|
|
[super applicationWillTerminate:application];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applicationWillResignActive:(UIApplication *)application {
|
|
|
|
|
|
|
|
[self saveContext];
|
|
|
|
|
2012-05-20 17:17:22 +00:00
|
|
|
if (![[MPiOSConfig get].rememberKey boolValue]) {
|
2012-05-03 14:49:15 +00:00
|
|
|
[self updateKey:nil];
|
2012-05-20 17:17:22 +00:00
|
|
|
[self loadKey:NO];
|
|
|
|
}
|
2012-05-03 14:49:15 +00:00
|
|
|
|
|
|
|
[TestFlight passCheckpoint:MPTestFlightCheckpointDeactivated];
|
2011-11-30 21:42:40 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 13:57:11 +00:00
|
|
|
#pragma mark - MFMailComposeViewControllerDelegate
|
|
|
|
|
|
|
|
- (void)mailComposeController:(MFMailComposeViewController *)controller
|
|
|
|
didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
err(@"Error composing mail message: %@", error);
|
|
|
|
|
|
|
|
switch (result) {
|
|
|
|
case MFMailComposeResultSaved:
|
|
|
|
case MFMailComposeResultSent:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MFMailComposeResultFailed:
|
2012-05-09 08:11:34 +00:00
|
|
|
[PearlAlert showError:@"A problem occurred while sending the message." tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
|
|
if (buttonIndex == [alert firstOtherButtonIndex])
|
|
|
|
return;
|
|
|
|
} otherTitles:@"Retry", nil];
|
|
|
|
return;
|
2012-05-08 13:57:11 +00:00
|
|
|
case MFMailComposeResultCancelled:
|
|
|
|
break;
|
|
|
|
}
|
2012-05-09 08:11:34 +00:00
|
|
|
|
|
|
|
[controller dismissModalViewControllerAnimated:YES];
|
2012-05-08 13:57:11 +00:00
|
|
|
}
|
|
|
|
|
2012-05-09 17:34:00 +00:00
|
|
|
#pragma mark - UbiquityStoreManagerDelegate
|
|
|
|
|
2012-05-11 20:45:05 +00:00
|
|
|
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didSwitchToiCloud:(BOOL)iCloudEnabled {
|
|
|
|
|
|
|
|
[super ubiquityStoreManager:manager didSwitchToiCloud:iCloudEnabled];
|
|
|
|
|
|
|
|
if (![[MPConfig get].iCloudDecided boolValue]) {
|
|
|
|
if (!iCloudEnabled) {
|
|
|
|
[PearlAlert showAlertWithTitle:@"iCloud"
|
|
|
|
message:
|
|
|
|
@"iCloud is now disabled.\n\n"
|
|
|
|
@"It is highly recommended you enable iCloud."
|
|
|
|
viewStyle:UIAlertViewStyleDefault tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
2012-05-20 18:52:13 +00:00
|
|
|
if (buttonIndex == [alert firstOtherButtonIndex] + 0) {
|
2012-05-11 20:45:05 +00:00
|
|
|
[PearlAlert showAlertWithTitle:@"About iCloud"
|
|
|
|
message:
|
|
|
|
@"iCloud is Apple's solution for saving your data in \"the cloud\" "
|
|
|
|
@"and making sure your other iPhones, iPads and Macs are in sync.\n\n"
|
|
|
|
@"For Master Password, that means your sites are available on all your "
|
|
|
|
@"Apple devices, and you always have a backup of them in case "
|
|
|
|
@"you loose one or need to restore.\n\n"
|
|
|
|
@"Because of the way Master Password works, it doesn't need to send your "
|
|
|
|
@"site's passwords to Apple. Only their names are saved to make it easier "
|
|
|
|
@"for you to find the site you need. For some sites you may have set "
|
|
|
|
@"a user-specified password: these are sent to iCloud after being encrypted "
|
|
|
|
@"with your master password.\n\n"
|
|
|
|
@"Apple can never see any of your passwords."
|
|
|
|
viewStyle:UIAlertViewStyleDefault
|
|
|
|
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
|
|
[self ubiquityStoreManager:manager didSwitchToiCloud:iCloudEnabled];
|
|
|
|
}
|
|
|
|
cancelTitle:[PearlStrings get].commonButtonThanks otherTitles:nil];
|
2012-05-20 18:52:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
[MPConfig get].iCloudDecided = [NSNumber numberWithBool:YES];
|
|
|
|
if (buttonIndex == [alert cancelButtonIndex])
|
|
|
|
return;
|
2012-05-11 20:45:05 +00:00
|
|
|
if (buttonIndex == [alert firstOtherButtonIndex] + 1)
|
|
|
|
[manager useiCloudStore:YES alertUser:NO];
|
|
|
|
} cancelTitle:@"Leave iCloud Off" otherTitles:@"Explain?", @"Enable iCloud", nil];
|
|
|
|
}
|
2012-05-11 15:04:51 +00:00
|
|
|
}
|
2012-05-09 21:36:45 +00:00
|
|
|
}
|
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
#pragma mark - TestFlight
|
|
|
|
|
|
|
|
|
|
|
|
- (NSDictionary *)testFlightInfo {
|
|
|
|
|
2012-05-11 20:45:05 +00:00
|
|
|
static NSDictionary *testFlightInfo = nil;
|
2012-05-03 14:49:15 +00:00
|
|
|
if (testFlightInfo == nil)
|
|
|
|
testFlightInfo = [[NSDictionary alloc] initWithContentsOfURL:
|
|
|
|
[[NSBundle mainBundle] URLForResource:@"TestFlight" withExtension:@"plist"]];
|
|
|
|
|
|
|
|
return testFlightInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)testFlightToken {
|
|
|
|
|
2012-05-15 21:27:05 +00:00
|
|
|
return NullToNil([[self testFlightInfo] valueForKeyPath:@"Team Token"]);
|
2012-05-03 14:49:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Crashlytics
|
|
|
|
|
|
|
|
|
|
|
|
- (NSDictionary *)crashlyticsInfo {
|
|
|
|
|
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:
|
|
|
|
[[NSBundle mainBundle] URLForResource:@"Crashlytics" withExtension:@"plist"]];
|
|
|
|
|
|
|
|
return crashlyticsInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)crashlyticsAPIKey {
|
|
|
|
|
2012-05-15 21:27:05 +00:00
|
|
|
return NullToNil([[self crashlyticsInfo] valueForKeyPath:@"API Key"]);
|
2012-05-03 14:49:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-23 06:58:01 +00:00
|
|
|
#pragma mark - Apptentive
|
|
|
|
|
|
|
|
|
|
|
|
- (NSDictionary *)apptentiveInfo {
|
|
|
|
|
|
|
|
static NSDictionary *apptentiveInfo = nil;
|
|
|
|
if (apptentiveInfo == nil)
|
|
|
|
apptentiveInfo = [[NSDictionary alloc] initWithContentsOfURL:
|
|
|
|
[[NSBundle mainBundle] URLForResource:@"Apptentive" withExtension:@"plist"]];
|
|
|
|
|
|
|
|
return apptentiveInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)apptentiveAPIKey {
|
|
|
|
|
|
|
|
return NullToNil([[self apptentiveInfo] valueForKeyPath:@"API Key"]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-03 14:49:15 +00:00
|
|
|
#pragma mark - Localytics
|
|
|
|
|
|
|
|
|
|
|
|
- (NSDictionary *)localyticsInfo {
|
|
|
|
|
2012-05-11 20:45:05 +00:00
|
|
|
static NSDictionary *localyticsInfo = nil;
|
2012-05-03 14:49:15 +00:00
|
|
|
if (localyticsInfo == nil)
|
|
|
|
localyticsInfo = [[NSDictionary alloc] initWithContentsOfURL:
|
|
|
|
[[NSBundle mainBundle] URLForResource:@"Localytics" withExtension:@"plist"]];
|
|
|
|
|
|
|
|
return localyticsInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)localyticsKey {
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2012-05-15 21:27:05 +00:00
|
|
|
return NullToNil([[self localyticsInfo] valueForKeyPath:@"Key.development"]);
|
2012-05-03 14:49:15 +00:00
|
|
|
#elif defined(LITE)
|
2012-05-15 21:27:05 +00:00
|
|
|
return NullToNil([[self localyticsInfo] valueForKeyPath:@"Key.distribution.lite"]);
|
2012-05-03 14:49:15 +00:00
|
|
|
#else
|
2012-05-15 21:27:05 +00:00
|
|
|
return NullToNil([[self localyticsInfo] valueForKeyPath:@"Key.distribution"]);
|
2012-05-03 14:49:15 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-11-30 21:42:40 +00:00
|
|
|
@end
|