Ensure alerts are triggered on main thread.
This commit is contained in:
parent
9c3e272849
commit
ee16c4a66d
@ -161,13 +161,14 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
|
||||
MPError( error, @"StoreKit request (%@) failed.", request );
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Purchase Failed" message:
|
||||
strf( @"%@\n\n%@", error.localizedDescription,
|
||||
@"Ensure you are online and try logging out and back into iTunes from your device's Settings." )
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:controller animated:YES completion:nil];
|
||||
#else
|
||||
} );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -248,8 +248,7 @@
|
||||
|
||||
MPKey *recoverKey = newKey;
|
||||
#ifdef PEARL_UIKIT
|
||||
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:PearlString( @"Migrating %ld sites...",
|
||||
(long)[user.sites count] )];
|
||||
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:strf( @"Migrating %ld sites...", (long)[user.sites count] )];
|
||||
#endif
|
||||
|
||||
for (MPSiteEntity *site in user.sites) {
|
||||
@ -261,8 +260,9 @@
|
||||
|
||||
#ifdef PEARL_UIKIT
|
||||
masterPassword = PearlAwait( ^(void (^setResult)(id)) {
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Enter Old Master Password" message:
|
||||
PearlString( @"Your old master password is required to migrate the stored password for %@", site.name )
|
||||
strf( @"Your old master password is required to migrate the stored password for %@", site.name )
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[controller addTextFieldWithConfigurationHandler:nil];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Migrate" style:UIAlertActionStyleDefault handler:
|
||||
@ -275,6 +275,7 @@
|
||||
}]];
|
||||
[self.navigationController presentViewController:controller animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
#endif
|
||||
if (!masterPassword)
|
||||
// Don't Migrate
|
||||
|
@ -548,11 +548,8 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
|
||||
do {
|
||||
if ([MPAppDelegate_Shared managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
|
||||
NSError *error = [self importSites:importData askImportPassword:importPassword askUserPassword:userPassword
|
||||
saveInContext:context];
|
||||
PearlMainQueue( ^{
|
||||
resultBlock( error );
|
||||
} );
|
||||
resultBlock( [self importSites:importData askImportPassword:importPassword askUserPassword:userPassword
|
||||
saveInContext:context] );
|
||||
}])
|
||||
break;
|
||||
usleep( (useconds_t)(USEC_PER_SEC * 0.2) );
|
||||
|
@ -113,7 +113,7 @@
|
||||
}
|
||||
|
||||
if (cell == self.checkInconsistencies)
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlock:^(NSManagedObjectContext *context) {
|
||||
if ([[MPiOSAppDelegate get] findAndFixInconsistenciesSaveInContext:context] == MPFixableResultNoProblems) {
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"No Inconsistencies" message:
|
||||
@"No inconsistencies were detected in your sites."
|
||||
@ -215,7 +215,7 @@
|
||||
- (IBAction)securityButton:(id)sender {
|
||||
|
||||
[[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender:
|
||||
[NSURL URLWithString:@"https://masterpassword.app/security.html"]];
|
||||
[NSURL URLWithString:@"https://masterpassword.app/masterpassword-algorithm.pdf"]];
|
||||
}
|
||||
|
||||
- (IBAction)sourceButton:(id)sender {
|
||||
|
@ -40,7 +40,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
|
||||
NSMutableString *features = [NSMutableString string];
|
||||
NSArray *storeVersions = @[
|
||||
@"Generated Usernames\nSecurity Question Answers",
|
||||
@"TouchID Support"
|
||||
@"Biometrics Support",
|
||||
];
|
||||
NSInteger storeVersion = [[NSUserDefaults standardUserDefaults] integerForKey:@"storeVersion"];
|
||||
for (; storeVersion < [storeVersions count]; ++storeVersion)
|
||||
|
@ -431,22 +431,22 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
NSManagedObjectID *userID = user.permanentObjectID;
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:user.name message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Deleting User" message:
|
||||
UIAlertController *controller_ = [UIAlertController alertControllerWithTitle:@"Deleting User" message:
|
||||
@"The user and its sites will be deleted." preferredStyle:UIAlertControllerStyleAlert];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
|
||||
[controller_ addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
|
||||
[self deleteUser:userID];
|
||||
}]];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:controller animated:YES completion:nil];
|
||||
[controller_ addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:controller_ animated:YES completion:nil];
|
||||
}]];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Reset Password" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Resetting User" message:
|
||||
UIAlertController *controller_ = [UIAlertController alertControllerWithTitle:@"Resetting User" message:
|
||||
@"The user's master password will be reset." preferredStyle:UIAlertControllerStyleAlert];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Reset User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
|
||||
[controller_ addAction:[UIAlertAction actionWithTitle:@"Reset User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
|
||||
[self resetUser:userID avatar:avatarCell];
|
||||
}]];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:controller animated:YES completion:nil];
|
||||
[controller_ addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:controller_ animated:YES completion:nil];
|
||||
}]];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:controller animated:YES completion:nil];
|
||||
|
@ -182,7 +182,8 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
@try {
|
||||
inf( @"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier] );
|
||||
|
||||
PearlAddNotificationObserver( MPFoundInconsistenciesNotification, nil, nil, ^(id self, NSNotification *note) {
|
||||
PearlAddNotificationObserver(
|
||||
MPFoundInconsistenciesNotification, nil, [NSOperationQueue mainQueue], ^(id self, NSNotification *note) {
|
||||
switch ((MPFixableResult)[note.userInfo[MPInconsistenciesFixResultUserKey] unsignedIntegerValue]) {
|
||||
|
||||
case MPFixableResultNoProblems:
|
||||
@ -244,22 +245,26 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
MPError( error, @"While reading imported sites from %@.", url );
|
||||
|
||||
if (!importedSitesData) {
|
||||
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];
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
|
||||
if (!importedSitesString) {
|
||||
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];
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -281,6 +286,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"];
|
||||
[self importSites:importData askImportPassword:^NSString *(NSString *userName) {
|
||||
return PearlAwait( ^(void (^setResult)(id)) {
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Importing Sites For\n%@", userName ) message:
|
||||
@"Enter the master password used to create this export file."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
@ -295,8 +301,10 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
}]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
} askUserPassword:^NSString *(NSString *userName) {
|
||||
return PearlAwait( (id)^(void (^setResult)(id)) {
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Master Password For\n%@", userName ) message:
|
||||
@"Enter the current master password for this user."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
@ -311,14 +319,17 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
}]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
} result:^(NSError *error) {
|
||||
[activityOverlay cancelOverlayAnimated:YES];
|
||||
|
||||
if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError)) {
|
||||
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];
|
||||
} );
|
||||
}
|
||||
}];
|
||||
}
|
||||
@ -341,6 +352,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
NSString *importData = [UIPasteboard generalPasteboard].string;
|
||||
MPMarshalledFile *importFile = mpw_marshal_read( NULL, importData.UTF8String );
|
||||
if (importFile && importFile->error.type == MPMarshalSuccess && importFile->info->format != MPMarshalFormatNone) {
|
||||
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];
|
||||
@ -351,6 +363,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
}
|
||||
mpw_marshal_file_free( &importFile );
|
||||
} );
|
||||
@ -422,7 +435,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Feedback" message:
|
||||
@"Have a question, comment, issue or just saying thanks?\n\n"
|
||||
@"We'd love to hear what you think!\n"
|
||||
@"masterpassword@lyndir.com"
|
||||
@"help@masterpassword.app"
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
@ -452,7 +465,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
if (logs && ([[MPConfig get].sendInfo boolValue] || [[MPiOSConfig get].traceMode boolValue]))
|
||||
logLevel = PearlLogLevelDebug;
|
||||
|
||||
[[[PearlEMail alloc] initForEMailTo:@"Master Password Development <masterpassword@lyndir.com>"
|
||||
[[[PearlEMail alloc] initForEMailTo:@"Master Password Development <help@masterpassword.app"
|
||||
subject:strf( @"Feedback for Master Password [%@]",
|
||||
[[PearlKeyChain deviceIdentifier] stringByDeletingMatchesOf:@"-.*"] )
|
||||
body:strf( @"\n\n\n"
|
||||
@ -479,12 +492,14 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
|
||||
static dispatch_once_t once = 0;
|
||||
dispatch_once( &once, ^{
|
||||
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) {
|
||||
[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) {
|
||||
@ -493,6 +508,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Ignore" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
- (void)showExportForVC:(UIViewController *)viewController {
|
||||
@ -620,6 +636,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
|
||||
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset {
|
||||
|
||||
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"
|
||||
@ -639,6 +656,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
}
|
||||
|
||||
#pragma mark - UIDocumentInteractionControllerDelegate
|
||||
|
@ -37,10 +37,6 @@
|
||||
<string>[auto]</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>[auto]</string>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>volto</string>
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
@ -69,7 +69,7 @@
|
||||
</collectionViewFlowLayout>
|
||||
<cells>
|
||||
<collectionViewCell opaque="NO" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPAvatarCell" id="Zab-uQ-uk9" customClass="MPAvatarCell">
|
||||
<rect key="frame" x="80" y="114.5" width="215" height="667"/>
|
||||
<rect key="frame" x="80" y="115" width="215" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="215" height="667"/>
|
||||
@ -898,15 +898,15 @@
|
||||
<action selector="valueChanged:" destination="JFc-sj-awD" eventType="valueChanged" id="KmT-CO-GZh"/>
|
||||
</connections>
|
||||
</switch>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="TouchID" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6xf-vt-aXd">
|
||||
<rect key="frame" x="20" y="20" width="374" height="20"/>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Biometrics" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6xf-vt-aXd">
|
||||
<rect key="frame" x="20" y="20" width="374" height="21"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="URR-yZ-QuC">
|
||||
<rect key="frame" x="20" y="48" width="374" height="143"/>
|
||||
<string key="text">When enabled on a TouchID-enabled device, your fingerprint will be required to load your saved password. Note that this feature requires that the Save Password option is enabled and TouchID support has been purchased from the in-app store.</string>
|
||||
<rect key="frame" x="20" y="49" width="374" height="142"/>
|
||||
<string key="text">When enabled on a biometrics-enabled device, your fingerprint or face scan will be required to load your saved password. Note that this feature requires that the Save Password option is enabled and Biometrics support has been purchased from the in-app store.</string>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="12"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@ -1030,7 +1030,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="250"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="999" verticalCompressionResistancePriority="1000" text="© 2011-2017, Maarten Billemont (lhunath)" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sPw-mV-mFF">
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="999" verticalCompressionResistancePriority="1000" text="© 2011-2020, Maarten Billemont (lhunath)" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sPw-mV-mFF">
|
||||
<rect key="frame" x="20" y="4" width="374" height="106"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="11"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
Loading…
Reference in New Issue
Block a user