diff --git a/Gemfile.lock b/Gemfile.lock index c58a26a6b2..d490c3783c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (2.3.5) + CFPropertyList (2.3.6) activesupport (4.2.10) i18n (~> 0.7) minitest (~> 5.1) @@ -9,32 +9,33 @@ GEM tzinfo (~> 1.1) addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) + atomos (0.1.2) babosa (1.0.2) claide (1.0.2) - cocoapods (1.3.1) + cocoapods (1.4.0) activesupport (>= 4.0.2, < 5) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.3.1) - cocoapods-deintegrate (>= 1.0.1, < 2.0) + cocoapods-core (= 1.4.0) + cocoapods-deintegrate (>= 1.0.2, < 2.0) cocoapods-downloader (>= 1.1.3, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) cocoapods-stats (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.2.0, < 2.0) + cocoapods-trunk (>= 1.3.0, < 2.0) cocoapods-try (>= 1.1.0, < 2.0) colored2 (~> 3.1) escape (~> 0.0.4) fourflusher (~> 2.0.1) gh_inspector (~> 1.0) - molinillo (~> 0.5.7) + molinillo (~> 0.6.4) nap (~> 1.0) ruby-macho (~> 1.1) - xcodeproj (>= 1.5.1, < 2.0) - cocoapods-core (1.3.1) + xcodeproj (>= 1.5.4, < 2.0) + cocoapods-core (1.4.0) activesupport (>= 4.0.2, < 6) fuzzy_match (~> 2.0.4) nap (~> 1.0) - cocoapods-deintegrate (1.0.1) + cocoapods-deintegrate (1.0.2) cocoapods-downloader (1.1.3) cocoapods-plugins (1.0.0) nap @@ -48,6 +49,7 @@ GEM colored2 (3.1.2) commander-fastlane (4.4.5) highline (~> 1.7.2) + concurrent-ruby (1.0.5) declarative (0.0.10) declarative-option (0.1.0) domain_name (0.5.20170404) @@ -98,7 +100,7 @@ GEM xcpretty-travis-formatter (>= 0.0.3) fourflusher (2.0.1) fuzzy_match (2.0.4) - gh_inspector (1.0.3) + gh_inspector (1.1.2) google-api-client (0.13.6) addressable (~> 2.5, >= 2.5.1) googleauth (~> 0.5) @@ -118,7 +120,8 @@ GEM http-cookie (1.0.3) domain_name (~> 0.5) httpclient (2.8.3) - i18n (0.8.6) + i18n (0.9.5) + concurrent-ruby (~> 1.0) json (2.1.0) jwt (1.5.6) little-plugger (1.1.4) @@ -130,8 +133,8 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) mini_magick (4.5.1) - minitest (5.10.3) - molinillo (0.5.7) + minitest (5.11.3) + molinillo (0.6.4) multi_json (1.12.2) multi_xml (0.6.0) multipart-post (2.0.0) @@ -161,7 +164,7 @@ GEM unicode-display_width (~> 1.1, >= 1.1.1) thread_safe (0.3.6) tty-screen (0.5.0) - tzinfo (1.2.3) + tzinfo (1.2.5) thread_safe (~> 0.1) uber (0.1.0) unf (0.1.4) @@ -169,8 +172,9 @@ GEM unf_ext (0.0.7.4) unicode-display_width (1.3.0) word_wrap (1.0.0) - xcodeproj (1.5.2) + xcodeproj (1.5.6) CFPropertyList (~> 2.3.3) + atomos (~> 0.1.2) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.2.3) @@ -187,4 +191,4 @@ DEPENDENCIES fastlane BUNDLED WITH - 1.14.6 + 1.16.1 diff --git a/Podfile.lock b/Podfile.lock index 793848dc7e..c63050ed21 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -211,7 +211,7 @@ SPEC CHECKSUMS: PureLayout: 4d550abe49a94f24c2808b9b95db9131685fe4cd Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c - SignalServiceKit: c639443811f2670986006f5b661cb1a862de66ab + SignalServiceKit: 5cc6e8e249f381c5eaee8693c0dff20fc1a3eee0 SocketRocket: dbb1554b8fc288ef8ef370d6285aeca7361be31e SQLCipher: f9fcf29b2e59ced7defc2a2bdd0ebe79b40d4990 SSZipArchive: 14401ade5f8e82aba1ff03e9f88e9de60937ae60 @@ -222,4 +222,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 66db99df53e7593362ebb004bea5d2215ca00e8e -COCOAPODS: 1.3.1 +COCOAPODS: 1.4.0 diff --git a/Pods b/Pods index 29babe2150..267e347b1e 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit 29babe215072d52688ea5b18592f308bfc190612 +Subproject commit 267e347b1eb97f8fd2e03a881b1a1c0c1de20e0f diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 8e444c046a..9d17a0c6d9 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -51,6 +51,7 @@ 344F249A200FD03300CFB4F4 /* MessageApprovalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344F2496200FD03200CFB4F4 /* MessageApprovalViewController.swift */; }; 344F249B200FD03300CFB4F4 /* SharingThreadPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 344F2497200FD03200CFB4F4 /* SharingThreadPickerViewController.m */; }; 344F249C200FD03300CFB4F4 /* AttachmentApprovalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344F2498200FD03200CFB4F4 /* AttachmentApprovalViewController.swift */; }; + 345BC30C2047030700257B7C /* OWS2FASettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 345BC30B2047030600257B7C /* OWS2FASettingsViewController.m */; }; 3461284B1FD0B94000532771 /* SAELoadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3461284A1FD0B93F00532771 /* SAELoadViewController.swift */; }; 346129341FD1A88700532771 /* OWSSwiftUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346129331FD1A88700532771 /* OWSSwiftUtils.swift */; }; 346129391FD1B47300532771 /* OWSPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129371FD1B47200532771 /* OWSPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -568,6 +569,8 @@ 344F2496200FD03200CFB4F4 /* MessageApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageApprovalViewController.swift; path = SignalMessaging/attachments/MessageApprovalViewController.swift; sourceTree = SOURCE_ROOT; }; 344F2497200FD03200CFB4F4 /* SharingThreadPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SharingThreadPickerViewController.m; path = SignalMessaging/attachments/SharingThreadPickerViewController.m; sourceTree = SOURCE_ROOT; }; 344F2498200FD03200CFB4F4 /* AttachmentApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentApprovalViewController.swift; path = SignalMessaging/attachments/AttachmentApprovalViewController.swift; sourceTree = SOURCE_ROOT; }; + 345BC30A2047030600257B7C /* OWS2FASettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS2FASettingsViewController.h; sourceTree = ""; }; + 345BC30B2047030600257B7C /* OWS2FASettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS2FASettingsViewController.m; sourceTree = ""; }; 3461284A1FD0B93F00532771 /* SAELoadViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAELoadViewController.swift; sourceTree = ""; }; 346129331FD1A88700532771 /* OWSSwiftUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSSwiftUtils.swift; sourceTree = ""; }; 346129371FD1B47200532771 /* OWSPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSPreferences.h; sourceTree = ""; }; @@ -1469,6 +1472,8 @@ 34B3F8571E8DF1700035BE1A /* NotificationSettingsOptionsViewController.m */, 34B3F8581E8DF1700035BE1A /* NotificationSettingsViewController.h */, 34B3F8591E8DF1700035BE1A /* NotificationSettingsViewController.m */, + 345BC30A2047030600257B7C /* OWS2FASettingsViewController.h */, + 345BC30B2047030600257B7C /* OWS2FASettingsViewController.m */, 34CCAF391F0C2748004084F4 /* OWSAddToContactViewController.h */, 34CCAF3A1F0C2748004084F4 /* OWSAddToContactViewController.m */, 347E0B772003CD7400BC2F76 /* OWSBackupExportViewController.h */, @@ -3102,6 +3107,7 @@ 4523149E1F7E916B003A428C /* SlideOffAnimatedTransition.swift in Sources */, 452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */, 45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */, + 345BC30C2047030700257B7C /* OWS2FASettingsViewController.m in Sources */, 34B3F8711E8DF1700035BE1A /* AboutTableViewController.m in Sources */, 34B3F88D1E8DF1700035BE1A /* OWSQRCodeScanningViewController.m in Sources */, 34BECE2E1F7ABCE000D7438D /* GifPickerViewController.swift in Sources */, diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index 6e4510306b..8ab64db6ca 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -24,7 +24,6 @@ #import "OWSDatabaseMigration.h" #import "OWSNavigationController.h" #import "OWSProgressView.h" -#import "OWSViewController.h" #import "OWSWebRTCDataProtos.pb.h" #import "PrivacySettingsTableViewController.h" #import "ProfileViewController.h" @@ -53,6 +52,7 @@ #import #import #import +#import #import #import #import diff --git a/Signal/src/ViewControllers/BlockListViewController.h b/Signal/src/ViewControllers/BlockListViewController.h index 71668bbc6d..b00e00dc93 100644 --- a/Signal/src/ViewControllers/BlockListViewController.h +++ b/Signal/src/ViewControllers/BlockListViewController.h @@ -1,8 +1,8 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/ViewControllers/CodeVerificationViewController.h b/Signal/src/ViewControllers/CodeVerificationViewController.h index cccbc2bd88..492aaa68be 100644 --- a/Signal/src/ViewControllers/CodeVerificationViewController.h +++ b/Signal/src/ViewControllers/CodeVerificationViewController.h @@ -1,8 +1,8 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.h b/Signal/src/ViewControllers/ConversationView/ConversationViewController.h index 1fb8fc3ffa..ec7610a4ae 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.h @@ -1,8 +1,8 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/ViewControllers/DomainFrontingCountryViewController.h b/Signal/src/ViewControllers/DomainFrontingCountryViewController.h index f0a3083c26..ab0dff699b 100644 --- a/Signal/src/ViewControllers/DomainFrontingCountryViewController.h +++ b/Signal/src/ViewControllers/DomainFrontingCountryViewController.h @@ -1,8 +1,8 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/ViewControllers/FingerprintViewController.h b/Signal/src/ViewControllers/FingerprintViewController.h index c72096104d..3d80eb8d56 100644 --- a/Signal/src/ViewControllers/FingerprintViewController.h +++ b/Signal/src/ViewControllers/FingerprintViewController.h @@ -1,8 +1,8 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/ViewControllers/FingerprintViewScanController.h b/Signal/src/ViewControllers/FingerprintViewScanController.h index 713b69bad0..e963778251 100644 --- a/Signal/src/ViewControllers/FingerprintViewScanController.h +++ b/Signal/src/ViewControllers/FingerprintViewScanController.h @@ -1,8 +1,8 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/ViewControllers/HomeViewController.h b/Signal/src/ViewControllers/HomeViewController.h index 2c32f0c9cc..26f1858c36 100644 --- a/Signal/src/ViewControllers/HomeViewController.h +++ b/Signal/src/ViewControllers/HomeViewController.h @@ -1,8 +1,8 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import #import @class TSThread; diff --git a/Signal/src/ViewControllers/MediaDetailViewController.h b/Signal/src/ViewControllers/MediaDetailViewController.h index d9dd6808a8..61f1694b71 100644 --- a/Signal/src/ViewControllers/MediaDetailViewController.h +++ b/Signal/src/ViewControllers/MediaDetailViewController.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/ViewControllers/NewContactThreadViewController.h b/Signal/src/ViewControllers/NewContactThreadViewController.h index a1f93b34b2..1fb32376b0 100644 --- a/Signal/src/ViewControllers/NewContactThreadViewController.h +++ b/Signal/src/ViewControllers/NewContactThreadViewController.h @@ -1,8 +1,8 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/ViewControllers/NewGroupViewController.h b/Signal/src/ViewControllers/NewGroupViewController.h index 9ae73fc392..b8a147dc59 100644 --- a/Signal/src/ViewControllers/NewGroupViewController.h +++ b/Signal/src/ViewControllers/NewGroupViewController.h @@ -1,9 +1,9 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "OWSConversationSettingsViewDelegate.h" -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/ViewControllers/NotificationSettingsViewController.m b/Signal/src/ViewControllers/NotificationSettingsViewController.m index f299fce923..430c2ebb95 100644 --- a/Signal/src/ViewControllers/NotificationSettingsViewController.m +++ b/Signal/src/ViewControllers/NotificationSettingsViewController.m @@ -38,21 +38,15 @@ OWSTableSection *soundsSection = [OWSTableSection new]; soundsSection.headerTitle = NSLocalizedString(@"SETTINGS_SECTION_SOUNDS", @"Header Label for the sounds section of settings views."); - - [soundsSection addItem:[OWSTableItem itemWithCustomCellBlock:^{ - UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 - reuseIdentifier:@"UITableViewCellStyleValue1"]; - cell.textLabel.text = NSLocalizedString(@"SETTINGS_ITEM_NOTIFICATION_SOUND", - @"Label for settings view that allows user to change the notification sound."); - OWSSound sound = [OWSSounds globalNotificationSound]; - cell.detailTextLabel.text = [OWSSounds displayNameForSound:sound]; - [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; - return cell; - } - actionBlock:^{ - OWSSoundSettingsViewController *vc = [OWSSoundSettingsViewController new]; - [weakSelf.navigationController pushViewController:vc animated:YES]; - }]]; + [soundsSection + addItem:[OWSTableItem disclosureItemWithText: + NSLocalizedString(@"SETTINGS_ITEM_NOTIFICATION_SOUND", + @"Label for settings view that allows user to change the notification sound.") + detailText:[OWSSounds displayNameForSound:[OWSSounds globalNotificationSound]] + actionBlock:^{ + OWSSoundSettingsViewController *vc = [OWSSoundSettingsViewController new]; + [weakSelf.navigationController pushViewController:vc animated:YES]; + }]]; NSString *inAppSoundsLabelText = NSLocalizedString(@"NOTIFICATIONS_SECTION_INAPP", @"Table cell switch label. When disabled, Signal will not play notification sounds while the app is in the " @@ -65,23 +59,15 @@ OWSTableSection *backgroundSection = [OWSTableSection new]; backgroundSection.headerTitle = NSLocalizedString(@"SETTINGS_NOTIFICATION_CONTENT_TITLE", @"table section header"); - [backgroundSection addItem:[OWSTableItem itemWithCustomCellBlock:^{ - UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 - reuseIdentifier:@"UITableViewCellStyleValue1"]; - - NotificationType notifType = [prefs notificationPreviewType]; - NSString *detailString = [prefs nameForNotificationPreviewType:notifType]; - cell.textLabel.text = NSLocalizedString(@"NOTIFICATIONS_SHOW", nil); - cell.detailTextLabel.text = detailString; - [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; - - return cell; - } - actionBlock:^{ - NotificationSettingsOptionsViewController *vc = - [NotificationSettingsOptionsViewController new]; - [weakSelf.navigationController pushViewController:vc animated:YES]; - }]]; + [backgroundSection + addItem:[OWSTableItem + disclosureItemWithText:NSLocalizedString(@"NOTIFICATIONS_SHOW", nil) + detailText:[prefs nameForNotificationPreviewType:[prefs notificationPreviewType]] + actionBlock:^{ + NotificationSettingsOptionsViewController *vc = + [NotificationSettingsOptionsViewController new]; + [weakSelf.navigationController pushViewController:vc animated:YES]; + }]]; backgroundSection.footerTitle = NSLocalizedString(@"SETTINGS_NOTIFICATION_CONTENT_DESCRIPTION", @"table section footer"); [contents addSection:backgroundSection]; diff --git a/Signal/src/ViewControllers/OWS2FASettingsViewController.h b/Signal/src/ViewControllers/OWS2FASettingsViewController.h new file mode 100644 index 0000000000..c5afc92ee3 --- /dev/null +++ b/Signal/src/ViewControllers/OWS2FASettingsViewController.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, Enable2FAMode) { + OWS2FASettingsMode_Status = 0, + OWS2FASettingsMode_SelectPIN, + OWS2FASettingsMode_ConfirmPIN, +}; + +@interface OWS2FASettingsViewController : OWSViewController + +@property (nonatomic) Enable2FAMode mode; + +// When confirming the PIN, this is the PIN that was +// initially entered by the user. +@property (nonatomic, nullable) NSString *candidatePin; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/OWS2FASettingsViewController.m b/Signal/src/ViewControllers/OWS2FASettingsViewController.m new file mode 100644 index 0000000000..5c9cd58730 --- /dev/null +++ b/Signal/src/ViewControllers/OWS2FASettingsViewController.m @@ -0,0 +1,492 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +#import "OWS2FASettingsViewController.h" +#import "OWSTableViewController.h" +#import "Signal-Swift.h" +#import "SignalMessaging.h" +#import +#import +#import +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface OWS2FASettingsViewController () + +@property (nonatomic, weak) UIViewController *root2FAViewController; + +@property (nonatomic) UITextField *pinTextfield; +@property (nonatomic) OWSTableViewController *tableViewController; + +@end + +#pragma mark - + +@implementation OWS2FASettingsViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.whiteColor; + + self.title = NSLocalizedString(@"ENABLE_2FA_VIEW_TITLE", @"Title for the 'enable two factor auth PIN' views."); + + [self createContents]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(stateDidChange:) + name:NSNotificationName_2FAStateDidChange + object:nil]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)createContents +{ + for (UIView *subview in self.view.subviews) { + [subview removeFromSuperview]; + } + + switch (self.mode) { + case OWS2FASettingsMode_Status: + [self createStatusContents]; + break; + case OWS2FASettingsMode_SelectPIN: + [self createSelectCodeContents]; + break; + case OWS2FASettingsMode_ConfirmPIN: + [self createConfirmCodeContents]; + break; + } +} + +- (void)viewWillAppear:(BOOL)animated +{ + switch (self.mode) { + case OWS2FASettingsMode_Status: + break; + case OWS2FASettingsMode_SelectPIN: + case OWS2FASettingsMode_ConfirmPIN: + OWSAssert(![OWS2FAManager.sharedManager is2FAEnabled]); + break; + } + + [super viewWillAppear:animated]; + + // If we're using a table, refresh its contents. + [self updateTableContents]; + + [self updateNavigationItems]; +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + + // If we're using a PIN textfield, select it. + [self.pinTextfield becomeFirstResponder]; +} + +- (UILabel *)createLabelWithText:(NSString *)text +{ + UILabel *label = [UILabel new]; + label.textColor = [UIColor blackColor]; + label.text = text; + label.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(14.f, 16.f)]; + label.numberOfLines = 0; + label.lineBreakMode = NSLineBreakByWordWrapping; + label.textAlignment = NSTextAlignmentCenter; + [self.view addSubview:label]; + return label; +} + +- (void)createPinTextfield +{ + self.pinTextfield = [UITextField new]; + self.pinTextfield.textColor = [UIColor blackColor]; + switch (self.mode) { + case OWS2FASettingsMode_SelectPIN: + self.pinTextfield.placeholder = NSLocalizedString(@"ENABLE_2FA_VIEW_SELECT_PIN_DEFAULT_TEXT", + @"Text field placeholder for 'two factor auth pin' when selecting a pin."); + break; + case OWS2FASettingsMode_ConfirmPIN: + self.pinTextfield.placeholder = NSLocalizedString(@"ENABLE_2FA_VIEW_CONFIRM_PIN_DEFAULT_TEXT", + @"Text field placeholder for 'two factor auth pin' when confirming a pin."); + break; + case OWS2FASettingsMode_Status: + OWSFail(@"%@ invalid mode.", self.logTag) break; + } + self.pinTextfield.font = [UIFont ows_mediumFontWithSize:ScaleFromIPhone5To7Plus(30.f, 36.f)]; + self.pinTextfield.textAlignment = NSTextAlignmentCenter; + self.pinTextfield.keyboardType = UIKeyboardTypeNumberPad; + self.pinTextfield.delegate = self; + self.pinTextfield.secureTextEntry = YES; + self.pinTextfield.textAlignment = NSTextAlignmentCenter; + [self.pinTextfield addTarget:self + action:@selector(textFieldDidChange:) + forControlEvents:UIControlEventEditingChanged]; + [self.view addSubview:self.pinTextfield]; +} + +- (void)createTableView +{ + self.tableViewController = [OWSTableViewController new]; + [self.view addSubview:self.tableViewController.view]; +} + +- (void)createStatusContents +{ + const CGFloat kVSpacing = 30.f; + + // TODO: Add hero image? + // TODO: Tweak background color? + + NSString *instructions = ([OWS2FAManager.sharedManager is2FAEnabled] + ? NSLocalizedString(@"ENABLE_2FA_VIEW_STATUS_ENABLED_INSTRUCTIONS", + @"Indicates that user has 'two factor auth pin' enabled.") + : NSLocalizedString(@"ENABLE_2FA_VIEW_STATUS_DISABLED_INSTRUCTIONS", + @"Indicates that user has 'two factor auth pin' disabled.")); + UILabel *instructionsLabel = [self createLabelWithText:instructions]; + + [self createTableView]; + + [instructionsLabel autoPinToTopLayoutGuideOfViewController:self withInset:kVSpacing]; + [instructionsLabel autoPinWidthToSuperviewWithMargin:self.hMargin]; + + [self.tableViewController.view autoPinWidthToSuperview]; + [self.tableViewController.view autoPinEdge:ALEdgeTop + toEdge:ALEdgeBottom + ofView:instructionsLabel + withOffset:kVSpacing]; + [self.tableViewController.view autoPinToBottomLayoutGuideOfViewController:self withInset:0]; + + [self updateTableContents]; +} + +- (void)createSelectCodeContents +{ + [self createEnterPINContentsWithInstructions:NSLocalizedString(@"ENABLE_2FA_VIEW_SELECT_PIN_INSTRUCTIONS", + @"Indicates that user should select a 'two factor auth pin'.")]; +} + +- (void)createConfirmCodeContents +{ + [self + createEnterPINContentsWithInstructions:NSLocalizedString(@"ENABLE_2FA_VIEW_CONFIRM_PIN_INSTRUCTIONS", + @"Indicates that user should confirm their 'two factor auth pin'.")]; +} + +- (CGFloat)hMargin +{ + return 20.f; +} + +- (void)createEnterPINContentsWithInstructions:(NSString *)instructionsText +{ + const CGFloat kVSpacing = 30.f; + + UILabel *instructionsLabel = [self createLabelWithText:instructionsText]; + + [self createPinTextfield]; + + [instructionsLabel autoPinTopToSuperviewWithMargin:kVSpacing]; + [instructionsLabel autoPinWidthToSuperviewWithMargin:self.hMargin]; + + [self.pinTextfield autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:instructionsLabel withOffset:kVSpacing]; + [self.pinTextfield autoPinWidthToSuperviewWithMargin:self.hMargin]; + [self.pinTextfield autoHCenterInSuperview]; + + UIView *underscoreView = [UIView new]; + underscoreView.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1.f]; + [self.view addSubview:underscoreView]; + [underscoreView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.pinTextfield withOffset:3]; + [underscoreView autoPinWidthToSuperviewWithMargin:self.hMargin]; + [underscoreView autoHCenterInSuperview]; + [underscoreView autoSetDimension:ALDimensionHeight toSize:1.f]; + + [self updateNavigationItems]; +} + +- (void)updateTableContents +{ + __weak OWS2FASettingsViewController *weakSelf = self; + + // Only some modes use a table. + switch (self.mode) { + case OWS2FASettingsMode_Status: { + OWSTableContents *contents = [OWSTableContents new]; + OWSTableSection *section = [OWSTableSection new]; + if ([OWS2FAManager.sharedManager is2FAEnabled]) { + [section + addItem:[OWSTableItem disclosureItemWithText: + NSLocalizedString(@"ENABLE_2FA_VIEW_DISABLE_2FA", + @"Label for the 'enable two-factor auth' item in the settings view") + actionBlock:^{ + [weakSelf tryToDisable2FA]; + }]]; + } else { + [section + addItem:[OWSTableItem disclosureItemWithText: + NSLocalizedString(@"ENABLE_2FA_VIEW_ENABLE_2FA", + @"Label for the 'enable two-factor auth' item in the settings view") + actionBlock:^{ + [weakSelf showEnable2FAWorkUI]; + }]]; + } + [contents addSection:section]; + self.tableViewController.contents = contents; + break; + } + case OWS2FASettingsMode_SelectPIN: + case OWS2FASettingsMode_ConfirmPIN: + return; + } +} + +- (BOOL)shouldHaveNextButton +{ + switch (self.mode) { + case OWS2FASettingsMode_Status: + return NO; + case OWS2FASettingsMode_SelectPIN: + case OWS2FASettingsMode_ConfirmPIN: + return [self hasValidPin]; + } +} + +- (void)updateNavigationItems +{ + // Note: This affects how the "back" button will look if another + // view is pushed on top of this one, not how the "back" + // button looks when this view is visible. + self.navigationItem.backBarButtonItem = + [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"VERIFICATION_BACK_BUTTON", + @"button text for back button on verification view") + style:UIBarButtonItemStylePlain + target:self + action:@selector(backButtonWasPressed)]; + + if (self.shouldHaveNextButton) { + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] + initWithTitle:NSLocalizedString(@"ENABLE_2FA_VIEW_NEXT_BUTTON", + @"Label for the 'next' button in the 'enable two factor auth' views.") + style:UIBarButtonItemStylePlain + target:self + action:@selector(nextButtonWasPressed)]; + } else { + self.navigationItem.rightBarButtonItem = nil; + } +} + +#pragma mark - UITextFieldDelegate + +- (BOOL)textField:(UITextField *)textField + shouldChangeCharactersInRange:(NSRange)range + replacementString:(NSString *)insertionText +{ + // TODO: ? + const NSUInteger kMaxPinLength = 14; + + // * We only want to let the user enter decimal digits. + // * The user should be able to copy and paste freely. + // * Invalid input should be simply ignored. + // + // We accomplish this by being permissive and trying to "take as much of the user + // input as possible". + // + // * Always accept deletes. + // * Ignore invalid input. + // * Take partial input if possible. + + NSString *oldText = textField.text; + // Construct the new contents of the text field by: + // 1. Determining the "left" substring: the contents of the old text _before_ the deletion range. + // Filtering will remove non-decimal digit characters. + NSString *left = [oldText substringToIndex:range.location].digitsOnly; + // 2. Determining the "right" substring: the contents of the old text _after_ the deletion range. + NSString *right = [oldText substringFromIndex:range.location + range.length].digitsOnly; + // 3. Determining the "center" substring: the contents of the new insertion text. + NSString *center = insertionText.digitsOnly; + // 4. Construct the "raw" new text by concatenating left, center and right. + NSString *textAfterChange = [[left stringByAppendingString:center] stringByAppendingString:right]; + // 5. Ensure we don't exceed the maximum length for a PIN. + if (textAfterChange.length > kMaxPinLength) { + textAfterChange = [textAfterChange substringToIndex:kMaxPinLength]; + } + // 6. Construct the final text. + textField.text = textAfterChange; + NSUInteger cursorPositionAfterChange = MIN(left.length + center.length, textAfterChange.length); + UITextPosition *pos = + [textField positionFromPosition:textField.beginningOfDocument offset:(NSInteger)cursorPositionAfterChange]; + [textField setSelectedTextRange:[textField textRangeFromPosition:pos toPosition:pos]]; + + [self updateNavigationItems]; + + return NO; +} + +- (void)textFieldDidChange:(id)sender +{ + [self updateNavigationItems]; +} + +#pragma mark - Events + +- (void)nextButtonWasPressed +{ + switch (self.mode) { + case OWS2FASettingsMode_Status: + OWSFail(@"%@ status mode should not have a next button.", self.logTag); + return; + case OWS2FASettingsMode_SelectPIN: { + OWSAssert(self.hasValidPin); + + OWS2FASettingsViewController *vc = [OWS2FASettingsViewController new]; + vc.mode = OWS2FASettingsMode_ConfirmPIN; + vc.candidatePin = self.pinTextfield.text; + OWSAssert(self.root2FAViewController); + vc.root2FAViewController = self.root2FAViewController; + [self.navigationController pushViewController:vc animated:YES]; + break; + } + case OWS2FASettingsMode_ConfirmPIN: { + OWSAssert(self.hasValidPin); + + if ([self.pinTextfield.text isEqualToString:self.candidatePin]) { + [self tryToEnable2FA]; + } else { + // Clear the PIN so that the user can try again. + self.pinTextfield.text = nil; + + [OWSAlerts + showAlertWithTitle:NSLocalizedString(@"ALERT_ERROR_TITLE", @"") + message:NSLocalizedString(@"ENABLE_2FA_VIEW_PIN_DOES_NOT_MATCH", + @"Error indicating that the entered 'two-factor auth PINs' do not match.")]; + } + break; + } + } +} + +- (BOOL)hasValidPin +{ + const NSUInteger kMinPinLength = 4; + return self.pinTextfield.text.length >= kMinPinLength; +} + +- (void)showEnable2FAWorkUI +{ + OWSAssert(![OWS2FAManager.sharedManager is2FAEnabled]); + + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + OWS2FASettingsViewController *vc = [OWS2FASettingsViewController new]; + vc.mode = OWS2FASettingsMode_SelectPIN; + vc.root2FAViewController = self; + [self.navigationController pushViewController:vc animated:YES]; +} + +- (void)tryToDisable2FA +{ + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + __weak OWS2FASettingsViewController *weakSelf = self; + + [ModalActivityIndicatorViewController + presentFromViewController:self + canCancel:NO + backgroundBlock:^(ModalActivityIndicatorViewController *modalActivityIndicator) { + [OWS2FAManager.sharedManager disable2FAWithSuccess:^{ + [modalActivityIndicator dismissWithCompletion:^{ + // TODO: Should we show an alert? + + [weakSelf updateTableContents]; + }]; + } + failure:^(NSError *error) { + [modalActivityIndicator dismissWithCompletion:^{ + [weakSelf updateTableContents]; + + [OWSAlerts + showAlertWithTitle:NSLocalizedString(@"ALERT_ERROR_TITLE", @"") + message:NSLocalizedString(@"ENABLE_2FA_VIEW_COULD_NOT_DISABLE_2FA", + @"Error indicating that attempt to disable 'two-factor " + @"auth' failed.")]; + }]; + }]; + }]; +} + +- (void)tryToEnable2FA +{ + OWSAssert(self.candidatePin.length > 0); + + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + __weak OWS2FASettingsViewController *weakSelf = self; + + [ModalActivityIndicatorViewController + presentFromViewController:self + canCancel:NO + backgroundBlock:^(ModalActivityIndicatorViewController *modalActivityIndicator) { + [OWS2FAManager.sharedManager enable2FAWithPin:self.candidatePin + success:^{ + [modalActivityIndicator dismissWithCompletion:^{ + [weakSelf showCompleteUI]; + }]; + } + failure:^(NSError *error) { + [modalActivityIndicator dismissWithCompletion:^{ + // The client may have fallen out of sync with the service. + // Try to get back to a known good state by disabling 2FA + // whenever enabling it fails. + [OWS2FAManager.sharedManager disable2FAWithSuccess:nil failure:nil]; + + [weakSelf updateTableContents]; + + [OWSAlerts + showAlertWithTitle:NSLocalizedString(@"ALERT_ERROR_TITLE", @"") + message:NSLocalizedString(@"ENABLE_2FA_VIEW_COULD_NOT_ENABLE_2FA", + @"Error indicating that attempt to enable 'two-factor " + @"auth' failed.")]; + }]; + }]; + }]; +} + +- (void)showCompleteUI +{ + OWSAssert([OWS2FAManager.sharedManager is2FAEnabled]); + OWSAssert(self.root2FAViewController); + + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + [self.navigationController popToViewController:self.root2FAViewController animated:NO]; +} + +- (void)backButtonWasPressed +{ + [self.navigationController popViewControllerAnimated:YES]; +} + +- (void)stateDidChange:(NSNotification *)notification +{ + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + if (self.mode == OWS2FASettingsMode_Status) { + [self createContents]; + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/OWSLinkDeviceViewController.h b/Signal/src/ViewControllers/OWSLinkDeviceViewController.h index 6529564b08..7cd3cfbf4e 100644 --- a/Signal/src/ViewControllers/OWSLinkDeviceViewController.h +++ b/Signal/src/ViewControllers/OWSLinkDeviceViewController.h @@ -1,9 +1,9 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "OWSQRCodeScanningViewController.h" -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/ViewControllers/OWSQRCodeScanningViewController.h b/Signal/src/ViewControllers/OWSQRCodeScanningViewController.h index 33bfe3d498..2ca5919622 100644 --- a/Signal/src/ViewControllers/OWSQRCodeScanningViewController.h +++ b/Signal/src/ViewControllers/OWSQRCodeScanningViewController.h @@ -1,9 +1,9 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" #import +#import #import #import diff --git a/Signal/src/ViewControllers/OWSQRCodeScanningViewController.m b/Signal/src/ViewControllers/OWSQRCodeScanningViewController.m index d50cd8ebcf..4cd7ba3e9d 100644 --- a/Signal/src/ViewControllers/OWSQRCodeScanningViewController.m +++ b/Signal/src/ViewControllers/OWSQRCodeScanningViewController.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "OWSQRCodeScanningViewController.h" @@ -149,16 +149,6 @@ NS_ASSUME_NONNULL_BEGIN } } -+ (NSString *)tag -{ - return [NSString stringWithFormat:@"[%@]", self.class]; -} - -- (NSString *)tag -{ - return self.class.logTag; -} - @end NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/PrivacySettingsTableViewController.h b/Signal/src/ViewControllers/PrivacySettingsTableViewController.h index 7912c0d892..fb04321864 100644 --- a/Signal/src/ViewControllers/PrivacySettingsTableViewController.h +++ b/Signal/src/ViewControllers/PrivacySettingsTableViewController.h @@ -1,9 +1,13 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "OWSTableViewController.h" +NS_ASSUME_NONNULL_BEGIN + @interface PrivacySettingsTableViewController : OWSTableViewController @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/PrivacySettingsTableViewController.m b/Signal/src/ViewControllers/PrivacySettingsTableViewController.m index f66ff97453..db706ef3e0 100644 --- a/Signal/src/ViewControllers/PrivacySettingsTableViewController.m +++ b/Signal/src/ViewControllers/PrivacySettingsTableViewController.m @@ -4,9 +4,11 @@ #import "PrivacySettingsTableViewController.h" #import "BlockListViewController.h" +#import "OWS2FASettingsViewController.h" #import "Signal-Swift.h" #import #import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -120,6 +122,25 @@ NS_ASSUME_NONNULL_BEGIN }]]; [contents addSection:historyLogsSection]; + OWSTableSection *twoFactorAuthSection = [OWSTableSection new]; + twoFactorAuthSection.headerTitle = NSLocalizedString( + @"SETTINGS_TWO_FACTOR_AUTH_TITLE", @"Title for the 'two factor auth' section of the privacy settings."); + [twoFactorAuthSection + addItem: + [OWSTableItem + disclosureItemWithText:NSLocalizedString(@"SETTINGS_TWO_FACTOR_AUTH_ITEM", + @"Label for the 'two factor auth' item of the privacy settings.") + detailText: + ([OWS2FAManager.sharedManager is2FAEnabled] + ? NSLocalizedString(@"SETTINGS_TWO_FACTOR_AUTH_ENABLED", + @"Indicates that 'two factor auth' is enabled in the privacy settings.") + : NSLocalizedString(@"SETTINGS_TWO_FACTOR_AUTH_DISABLED", + @"Indicates that 'two factor auth' is disabled in the privacy settings.")) + actionBlock:^{ + [weakSelf show2FASettings]; + }]]; + [contents addSection:twoFactorAuthSection]; + self.contents = contents; } @@ -131,7 +152,6 @@ NS_ASSUME_NONNULL_BEGIN [self.navigationController pushViewController:vc animated:YES]; } - - (void)clearHistoryLogs { UIAlertController *alertController = @@ -214,16 +234,13 @@ NS_ASSUME_NONNULL_BEGIN [SignalApp.sharedApp.callService createCallUIAdapter]; } -#pragma mark - Log util - -+ (NSString *)tag +- (void)show2FASettings { - return [NSString stringWithFormat:@"[%@]", self.class]; -} + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); -- (NSString *)tag -{ - return self.class.logTag; + OWS2FASettingsViewController *vc = [OWS2FASettingsViewController new]; + vc.mode = OWS2FASettingsMode_Status; + [self.navigationController pushViewController:vc animated:YES]; } @end diff --git a/Signal/src/ViewControllers/ProfileViewController.h b/Signal/src/ViewControllers/ProfileViewController.h index 506f654db6..eecb2bae31 100644 --- a/Signal/src/ViewControllers/ProfileViewController.h +++ b/Signal/src/ViewControllers/ProfileViewController.h @@ -1,12 +1,14 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // +#import + NS_ASSUME_NONNULL_BEGIN @class HomeViewController; -@interface ProfileViewController : UIViewController +@interface ProfileViewController : OWSViewController - (instancetype)init NS_UNAVAILABLE; diff --git a/Signal/src/ViewControllers/RegistrationViewController.h b/Signal/src/ViewControllers/RegistrationViewController.h index 0f2d68ddb5..32cbe803ce 100644 --- a/Signal/src/ViewControllers/RegistrationViewController.h +++ b/Signal/src/ViewControllers/RegistrationViewController.h @@ -1,8 +1,8 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/ViewControllers/UpdateGroupViewController.h b/Signal/src/ViewControllers/UpdateGroupViewController.h index 9a9e07f765..36583c805d 100644 --- a/Signal/src/ViewControllers/UpdateGroupViewController.h +++ b/Signal/src/ViewControllers/UpdateGroupViewController.h @@ -1,9 +1,9 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "OWSConversationSettingsViewDelegate.h" -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Signal/src/network/PushManager.m b/Signal/src/network/PushManager.m index 264b7859dd..1fb260f9e1 100644 --- a/Signal/src/network/PushManager.m +++ b/Signal/src/network/PushManager.m @@ -484,14 +484,4 @@ NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId = @"PushManager }); } -+ (NSString *)tag -{ - return [NSString stringWithFormat:@"[%@]", self.class]; -} - -- (NSString *)tag -{ - return self.class.logTag; -} - @end diff --git a/Signal/src/views/OWSBezierPathView.m b/Signal/src/views/OWSBezierPathView.m index 0155737069..323b0ed5f4 100644 --- a/Signal/src/views/OWSBezierPathView.m +++ b/Signal/src/views/OWSBezierPathView.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "OWSBezierPathView.h" @@ -93,13 +93,6 @@ NS_ASSUME_NONNULL_BEGIN [self setNeedsDisplay]; } -#pragma mark - Logging - -+ (NSString *)tag -{ - return [NSString stringWithFormat:@"[%@]", self.class]; -} - @end NS_ASSUME_NONNULL_END diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 0d37bc14c9..5299108f83 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -643,6 +643,45 @@ /* No comment provided by engineer. */ "EMPTY_INBOX_TITLE" = "Squeaky Freaking Clean."; +/* Text field placeholder for 'two factor auth pin' when confirming a pin. */ +"ENABLE_2FA_VIEW_CONFIRM_PIN_DEFAULT_TEXT" = "••••••"; + +/* Indicates that user should confirm their 'two factor auth pin'. */ +"ENABLE_2FA_VIEW_CONFIRM_PIN_INSTRUCTIONS" = "Confirm your PIN."; + +/* Error indicating that attempt to disable 'two-factor auth' failed. */ +"ENABLE_2FA_VIEW_COULD_NOT_DISABLE_2FA" = "Could not disable two-step verification."; + +/* Error indicating that attempt to enable 'two-factor auth' failed. */ +"ENABLE_2FA_VIEW_COULD_NOT_ENABLE_2FA" = "Could not enable two-step verification."; + +/* Label for the 'enable two-factor auth' item in the settings view */ +"ENABLE_2FA_VIEW_DISABLE_2FA" = "Disable"; + +/* Label for the 'enable two-factor auth' item in the settings view */ +"ENABLE_2FA_VIEW_ENABLE_2FA" = "Enable"; + +/* Label for the 'next' button in the 'enable two factor auth' views. */ +"ENABLE_2FA_VIEW_NEXT_BUTTON" = "Next"; + +/* Error indicating that the entered 'two-factor auth PINs' do not match. */ +"ENABLE_2FA_VIEW_PIN_DOES_NOT_MATCH" = "Pin does not match."; + +/* Text field placeholder for 'two factor auth pin' when selecting a pin. */ +"ENABLE_2FA_VIEW_SELECT_PIN_DEFAULT_TEXT" = "******"; + +/* Indicates that user should select a 'two factor auth pin'. */ +"ENABLE_2FA_VIEW_SELECT_PIN_INSTRUCTIONS" = "Enter a PIN which you'll be asked for when you register your phone number with Signal. Your PIN must have at least 4 digits."; + +/* Indicates that user has 'two factor auth pin' disabled. */ +"ENABLE_2FA_VIEW_STATUS_DISABLED_INSTRUCTIONS" = "For added security, enable two-step verification, which will require a PIN when registering your phone number with Signal again."; + +/* Indicates that user has 'two factor auth pin' enabled. */ +"ENABLE_2FA_VIEW_STATUS_ENABLED_INSTRUCTIONS" = "Two-step verification is enabled. You'll need to enter your PIN when registering your phone number with Signal again."; + +/* Title for the 'enable two factor auth PIN' views. */ +"ENABLE_2FA_VIEW_TITLE" = "Two-Step Verification"; + /* Call setup status label */ "END_CALL_RESPONDER_IS_BUSY" = "Busy."; @@ -1623,6 +1662,18 @@ /* No comment provided by engineer. */ "SETTINGS_SUPPORT" = "Support"; +/* Indicates that 'two factor auth' is disabled in the privacy settings. */ +"SETTINGS_TWO_FACTOR_AUTH_DISABLED" = "Disabled"; + +/* Indicates that 'two factor auth' is enabled in the privacy settings. */ +"SETTINGS_TWO_FACTOR_AUTH_ENABLED" = "Enabled"; + +/* Label for the 'two factor auth' item of the privacy settings. */ +"SETTINGS_TWO_FACTOR_AUTH_ITEM" = "Two-Step Verification"; + +/* Title for the 'two factor auth' section of the privacy settings. */ +"SETTINGS_TWO_FACTOR_AUTH_TITLE" = "Two-Step Verification"; + /* No comment provided by engineer. */ "SETTINGS_VERSION" = "Version"; diff --git a/SignalMessaging/ViewControllers/OWSTableViewController.h b/SignalMessaging/ViewControllers/OWSTableViewController.h index 12a390a90d..85d8b31dc9 100644 --- a/SignalMessaging/ViewControllers/OWSTableViewController.h +++ b/SignalMessaging/ViewControllers/OWSTableViewController.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN @@ -44,11 +44,6 @@ extern const CGFloat kOWSTable_DefaultCellHeight; #pragma mark - -typedef NS_ENUM(NSInteger, OWSTableItemType) { - OWSTableItemTypeDefault, - OWSTableItemTypeAction, -}; - typedef void (^OWSTableActionBlock)(void); typedef void (^OWSTableSubPageBlock)(UIViewController *viewController); typedef UITableViewCell *_Nonnull (^OWSTableCustomCellBlock)(void); @@ -72,6 +67,10 @@ typedef UITableViewCell *_Nonnull (^OWSTableCustomCellBlock)(void); + (OWSTableItem *)disclosureItemWithText:(NSString *)text actionBlock:(nullable OWSTableActionBlock)actionBlock; ++ (OWSTableItem *)disclosureItemWithText:(NSString *)text + detailText:(NSString *)detailText + actionBlock:(nullable OWSTableActionBlock)actionBlock; + + (OWSTableItem *)disclosureItemWithText:(NSString *)text customRowHeight:(CGFloat)customRowHeight actionBlock:(nullable OWSTableActionBlock)actionBlock; diff --git a/SignalMessaging/ViewControllers/OWSTableViewController.m b/SignalMessaging/ViewControllers/OWSTableViewController.m index 7f75932f96..f556d92849 100644 --- a/SignalMessaging/ViewControllers/OWSTableViewController.m +++ b/SignalMessaging/ViewControllers/OWSTableViewController.m @@ -83,7 +83,6 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f; @interface OWSTableItem () -@property (nonatomic) OWSTableItemType itemType; @property (nonatomic, nullable) NSString *title; @property (nonatomic, nullable) OWSTableActionBlock actionBlock; @@ -102,7 +101,6 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f; OWSAssert(title.length > 0); OWSTableItem *item = [OWSTableItem new]; - item.itemType = OWSTableItemTypeAction; item.actionBlock = actionBlock; item.title = title; return item; @@ -116,7 +114,6 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f; OWSAssert(customRowHeight > 0); OWSTableItem *item = [OWSTableItem new]; - item.itemType = (actionBlock != nil ? OWSTableItemTypeAction : OWSTableItemTypeDefault); item.actionBlock = actionBlock; item.customCell = customCell; item.customRowHeight = @(customRowHeight); @@ -140,7 +137,6 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f; OWSAssert(customCellBlock); OWSTableItem *item = [OWSTableItem new]; - item.itemType = (actionBlock != nil ? OWSTableItemTypeAction : OWSTableItemTypeDefault); item.actionBlock = actionBlock; item.customCellBlock = customCellBlock; return item; @@ -164,7 +160,6 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f; OWSAssert(actionBlock); OWSTableItem *item = [OWSTableItem new]; - item.itemType = OWSTableItemTypeAction; item.actionBlock = actionBlock; item.customCellBlock = ^{ UITableViewCell *cell = [UITableViewCell new]; @@ -188,13 +183,34 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f; return item; } ++ (OWSTableItem *)disclosureItemWithText:(NSString *)text + detailText:(NSString *)detailText + actionBlock:(nullable OWSTableActionBlock)actionBlock +{ + OWSAssert(text.length > 0); + OWSAssert(actionBlock); + + OWSTableItem *item = [OWSTableItem new]; + item.actionBlock = actionBlock; + item.customCellBlock = ^{ + UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 + reuseIdentifier:@"UITableViewCellStyleValue1"]; + cell.textLabel.text = text; + cell.textLabel.font = [UIFont ows_regularFontWithSize:18.f]; + cell.textLabel.textColor = [UIColor blackColor]; + cell.detailTextLabel.text = detailText; + [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; + return cell; + }; + return item; +} + + (OWSTableItem *)subPageItemWithText:(NSString *)text actionBlock:(nullable OWSTableSubPageBlock)actionBlock { OWSAssert(text.length > 0); OWSAssert(actionBlock); OWSTableItem *item = [OWSTableItem new]; - item.itemType = OWSTableItemTypeAction; __weak OWSTableItem *weakItem = item; item.actionBlock = ^{ OWSTableItem *strongItem = weakItem; @@ -233,7 +249,6 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f; OWSAssert(actionBlock); OWSTableItem *item = [OWSTableItem new]; - item.itemType = OWSTableItemTypeAction; item.actionBlock = actionBlock; item.customCellBlock = ^{ UITableViewCell *cell = [UITableViewCell new]; @@ -250,7 +265,6 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f; OWSAssert(text.length > 0); OWSTableItem *item = [OWSTableItem new]; - item.itemType = OWSTableItemTypeAction; item.customCellBlock = ^{ UITableViewCell *cell = [UITableViewCell new]; cell.textLabel.text = text; @@ -282,7 +296,6 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f; OWSAssert(text.length > 0); OWSTableItem *item = [OWSTableItem new]; - item.itemType = OWSTableItemTypeAction; item.customCellBlock = ^{ UITableViewCell *cell = [UITableViewCell new]; cell.textLabel.text = text; @@ -300,7 +313,6 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f; OWSAssert(accessoryText.length > 0); OWSTableItem *item = [OWSTableItem new]; - item.itemType = OWSTableItemTypeAction; item.customCellBlock = ^{ UITableViewCell *cell = [UITableViewCell new]; cell.textLabel.text = text; @@ -337,7 +349,6 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f; OWSAssert(selector); OWSTableItem *item = [OWSTableItem new]; - item.itemType = OWSTableItemTypeAction; __weak id weakTarget = target; item.customCellBlock = ^{ UITableViewCell *cell = [UITableViewCell new]; diff --git a/SignalMessaging/ViewControllers/OWSViewController.m b/SignalMessaging/ViewControllers/OWSViewController.m index 08686ff0e1..21074f6d6f 100644 --- a/SignalMessaging/ViewControllers/OWSViewController.m +++ b/SignalMessaging/ViewControllers/OWSViewController.m @@ -1,9 +1,9 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" #import "UIView+OWS.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalMessaging/contacts/SelectRecipientViewController.h b/SignalMessaging/contacts/SelectRecipientViewController.h index f6a69d8af1..7619cf38f8 100644 --- a/SignalMessaging/contacts/SelectRecipientViewController.h +++ b/SignalMessaging/contacts/SelectRecipientViewController.h @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalMessaging/contacts/SelectThreadViewController.h b/SignalMessaging/contacts/SelectThreadViewController.h index f2b11da7f7..cfa3da58dc 100644 --- a/SignalMessaging/contacts/SelectThreadViewController.h +++ b/SignalMessaging/contacts/SelectThreadViewController.h @@ -1,8 +1,8 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "OWSViewController.h" +#import @class TSThread; diff --git a/SignalMessaging/utils/OWSPreferences.m b/SignalMessaging/utils/OWSPreferences.m index afdda83948..b31a95582e 100644 --- a/SignalMessaging/utils/OWSPreferences.m +++ b/SignalMessaging/utils/OWSPreferences.m @@ -381,23 +381,11 @@ NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySyste - (void)unsetRecordedAPNSTokens { - DDLogWarn(@"%@ Forgetting recorded APNS tokens", self.tag); + DDLogWarn(@"%@ Forgetting recorded APNS tokens", self.logTag); [self setValueForKey:OWSPreferencesKeyLastRecordedPushToken toValue:nil]; [self setValueForKey:OWSPreferencesKeyLastRecordedVoipToken toValue:nil]; } -#pragma mark - Logging - -+ (NSString *)tag -{ - return [NSString stringWithFormat:@"[%@]", self.class]; -} - -- (NSString *)tag -{ - return self.class.tag; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m b/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m index 0f167a5923..73f8d32418 100644 --- a/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m +++ b/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m @@ -215,18 +215,6 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo [storage asyncRegisterExtension:[self databaseExtension] withName:OWSMessageContentJobFinderExtensionName]; } -#pragma mark Logging - -+ (NSString *)tag -{ - return [NSString stringWithFormat:@"[%@]", self.class]; -} - -- (NSString *)tag -{ - return self.class.logTag; -} - @end #pragma mark - Queue Processing @@ -365,18 +353,6 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo }]; } -#pragma mark Logging - -+ (NSString *)tag -{ - return [NSString stringWithFormat:@"[%@]", self.class]; -} - -- (NSString *)tag -{ - return self.class.logTag; -} - @end #pragma mark - OWSBatchMessageProcessor diff --git a/SignalServiceKit/src/Messages/OWSMessageReceiver.m b/SignalServiceKit/src/Messages/OWSMessageReceiver.m index a5de760182..874e42043f 100644 --- a/SignalServiceKit/src/Messages/OWSMessageReceiver.m +++ b/SignalServiceKit/src/Messages/OWSMessageReceiver.m @@ -339,18 +339,6 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin }]; } -#pragma mark Logging - -+ (NSString *)tag -{ - return [NSString stringWithFormat:@"[%@]", self.class]; -} - -- (NSString *)tag -{ - return self.class.logTag; -} - @end #pragma mark - OWSMessageReceiver diff --git a/SignalServiceKit/src/Network/API/Requests/OWSDeviceProvisioningRequest.m b/SignalServiceKit/src/Network/API/Requests/OWSDeviceProvisioningRequest.m index 21f6271835..915e511af7 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSDeviceProvisioningRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/OWSDeviceProvisioningRequest.m @@ -1,4 +1,6 @@ -// Copyright (c) 2016 Open Whisper Systems. All rights reserved. +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// #import "OWSDeviceProvisioningRequest.h" #import "TSConstants.h" @@ -17,7 +19,10 @@ NS_ASSUME_NONNULL_BEGIN } self.HTTPMethod = @"PUT"; - [self.parameters addEntriesFromDictionary:@{ @"body" : [messageBody base64EncodedString] }]; + + self.parameters = @{ + @"body" : [messageBody base64EncodedString], + }; return self; } diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h new file mode 100644 index 0000000000..0322b184ad --- /dev/null +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h @@ -0,0 +1,19 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +NS_ASSUME_NONNULL_BEGIN + +@class TSRequest; + +@interface OWSRequestFactory : NSObject + +- (instancetype)init NS_UNAVAILABLE; + ++ (TSRequest *)enable2FARequestWithPin:(NSString *)pin; + ++ (TSRequest *)disable2FARequest; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m new file mode 100644 index 0000000000..f6ec848b41 --- /dev/null +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m @@ -0,0 +1,31 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +#import "OWSRequestFactory.h" +#import "TSConstants.h" +#import "TSRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation OWSRequestFactory + ++ (TSRequest *)enable2FARequestWithPin:(NSString *)pin; +{ + OWSAssert(pin.length > 0); + + return [TSRequest requestWithUrl:[NSURL URLWithString:textSecure2FAAPI] + method:@"PUT" + parameters:@{ + @"pin" : pin, + }]; +} + ++ (TSRequest *)disable2FARequest +{ + return [TSRequest requestWithUrl:[NSURL URLWithString:textSecure2FAAPI] method:@"DELETE" parameters:@{}]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Network/API/Requests/TSContactsIntersectionRequest.m b/SignalServiceKit/src/Network/API/Requests/TSContactsIntersectionRequest.m index 9d0ac456ec..13c728238a 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSContactsIntersectionRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/TSContactsIntersectionRequest.m @@ -1,14 +1,9 @@ // -// TSContactsIntersection.m -// TextSecureiOS +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -// Created by Frederic Jacobs on 10/12/13. -// Copyright (c) 2013 Open Whisper Systems. All rights reserved. -// - -#import "TSConstants.h" #import "TSContactsIntersectionRequest.h" +#import "TSConstants.h" @implementation TSContactsIntersectionRequest @@ -16,9 +11,15 @@ self = [self initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", textSecureDirectoryAPI, @"tokens"]]]; + if (!self) { + return nil; + } + self.HTTPMethod = @"PUT"; - [self.parameters addEntriesFromDictionary:@{ @"contacts" : hashes }]; + self.parameters = @{ + @"contacts" : hashes, + }; return self; } diff --git a/SignalServiceKit/src/Network/API/Requests/TSRecipientPrekeyRequest.m b/SignalServiceKit/src/Network/API/Requests/TSRecipientPrekeyRequest.m index 0ac0184297..813956e146 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSRecipientPrekeyRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/TSRecipientPrekeyRequest.m @@ -1,23 +1,21 @@ // -// TSGetRecipientPrekey.m -// TextSecureiOS -// -// Created by Christine Corbett Moran on 11/30/13. -// Copyright (c) 2013 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "TSConstants.h" #import "TSRecipientPrekeyRequest.h" +#import "TSConstants.h" @implementation TSRecipientPrekeyRequest - (TSRequest *)initWithRecipient:(NSString *)recipientNumber deviceId:(NSString *)deviceId { - NSString *recipientInformation = recipientNumber; + self = [super + initWithURL:[NSURL + URLWithString:[NSString + stringWithFormat:@"%@/%@/%@", textSecureKeysAPI, recipientNumber, deviceId]]]; - self = [super initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/%@/%@", - textSecureKeysAPI, - recipientInformation, - deviceId]]]; + if (!self) { + return nil; + } self.HTTPMethod = @"GET"; self.parameters = nil; diff --git a/SignalServiceKit/src/Network/API/Requests/TSRegisterForPushRequest.h b/SignalServiceKit/src/Network/API/Requests/TSRegisterForPushRequest.h index 97025b4af5..5dff583b2e 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSRegisterForPushRequest.h +++ b/SignalServiceKit/src/Network/API/Requests/TSRegisterForPushRequest.h @@ -1,15 +1,15 @@ // -// TSRegisterForPushRequest.h -// TextSecureiOS -// -// Created by Frederic Jacobs on 10/13/13. -// Copyright (c) 2013 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "TSRequest.h" +NS_ASSUME_NONNULL_BEGIN + @interface TSRegisterForPushRequest : TSRequest - (id)initWithPushIdentifier:(NSString *)identifier voipIdentifier:(NSString *)voipId; @end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Network/API/Requests/TSRegisterForPushRequest.m b/SignalServiceKit/src/Network/API/Requests/TSRegisterForPushRequest.m index 4f390d4e97..14e937efbd 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSRegisterForPushRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/TSRegisterForPushRequest.m @@ -1,14 +1,11 @@ // -// TSRegisterForPushRequest.m -// TextSecureiOS +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -// Created by Frederic Jacobs on 10/13/13. -// Copyright (c) 2013 Open Whisper Systems. All rights reserved. -// - -#import "TSConstants.h" #import "TSRegisterForPushRequest.h" +#import "TSConstants.h" + +NS_ASSUME_NONNULL_BEGIN @implementation TSRegisterForPushRequest @@ -16,15 +13,21 @@ self = [super initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", textSecureAccountsAPI, @"apn"]]]; + if (!self) { + return nil; + } + self.HTTPMethod = @"PUT"; - self.parameters = [@{ @"apnRegistrationId" : identifier } mutableCopy]; - - if (voipId) { - [self.parameters setObject:voipId forKeyedSubscript:@"voipRegistrationId"]; - } + OWSAssert(voipId); + self.parameters = @{ + @"apnRegistrationId" : identifier, + @"voipRegistrationId" : voipId ?: @"", + }; return self; } @end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Network/API/Requests/TSRegisterPrekeysRequest.m b/SignalServiceKit/src/Network/API/Requests/TSRegisterPrekeysRequest.m index 8bf641b723..fec0bb9371 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSRegisterPrekeysRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/TSRegisterPrekeysRequest.m @@ -1,14 +1,13 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "TSConstants.h" #import "TSRegisterPrekeysRequest.h" - -#import +#import "TSConstants.h" #import #import #import +#import @implementation TSRegisterPrekeysRequest @@ -17,6 +16,10 @@ signedPreKeyRecord:(SignedPreKeyRecord *)signedRecord preKeyLastResort:(PreKeyRecord *)lastResort { self = [super initWithURL:[NSURL URLWithString:textSecureKeysAPI]]; + if (!self) { + return nil; + } + self.HTTPMethod = @"PUT"; NSString *publicIdentityKey = [[identityKeyPublic prependKeyType] base64EncodedStringWithOptions:0]; diff --git a/SignalServiceKit/src/Network/API/Requests/TSRegisterSignedPrekeyRequest.m b/SignalServiceKit/src/Network/API/Requests/TSRegisterSignedPrekeyRequest.m index 290aa8716a..caa41437ac 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSRegisterSignedPrekeyRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/TSRegisterSignedPrekeyRequest.m @@ -1,20 +1,23 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "TSRegisterSignedPrekeyRequest.h" #import "TSConstants.h" - -#import #import #import #import +#import @implementation TSRegisterSignedPrekeyRequest - (id)initWithSignedPreKeyRecord:(SignedPreKeyRecord *)signedRecord { self = [super initWithURL:[NSURL URLWithString:textSecureSignedKeysAPI]]; + if (!self) { + return nil; + } + self.HTTPMethod = @"PUT"; NSDictionary *serializedKeyRegistrationParameters = [self dictionaryFromSignedPreKey:signedRecord]; diff --git a/SignalServiceKit/src/Network/API/Requests/TSRequest.h b/SignalServiceKit/src/Network/API/Requests/TSRequest.h index 651ebe9e54..25a8eec278 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSRequest.h +++ b/SignalServiceKit/src/Network/API/Requests/TSRequest.h @@ -1,11 +1,13 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // @interface TSRequest : NSMutableURLRequest -@property (nonatomic, retain) NSMutableDictionary *parameters; +@property (nonatomic) NSDictionary *parameters; -- (void)makeAuthenticatedRequest; ++ (instancetype)requestWithUrl:(NSURL *)url + method:(NSString *)method + parameters:(NSDictionary *)parameters; @end diff --git a/SignalServiceKit/src/Network/API/Requests/TSRequest.m b/SignalServiceKit/src/Network/API/Requests/TSRequest.m index 5606c1a3b7..db653bd988 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/TSRequest.m @@ -13,7 +13,11 @@ self = [super initWithURL:URL cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:textSecureHTTPTimeOut]; - self.parameters = [NSMutableDictionary dictionary]; + if (!self) { + return nil; + } + + self.parameters = @{}; return self; } @@ -33,11 +37,14 @@ return nil; } -#pragma clang diagnostic pop - -- (void)makeAuthenticatedRequest { - OWSAssert([TSAccountManager serverAuthToken]); - [self.parameters addEntriesFromDictionary:@{ @"Authorization" : [TSAccountManager serverAuthToken] }]; ++ (instancetype)requestWithUrl:(NSURL *)url + method:(NSString *)method + parameters:(NSDictionary *)parameters +{ + TSRequest *request = [[TSRequest alloc] initWithURL:url]; + [request setHTTPMethod:method]; + request.parameters = parameters; + return request; } @end diff --git a/SignalServiceKit/src/Network/API/Requests/TSRequestVerificationCodeRequest.m b/SignalServiceKit/src/Network/API/Requests/TSRequestVerificationCodeRequest.m index 56812af34d..a73a1236a5 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSRequestVerificationCodeRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/TSRequestVerificationCodeRequest.m @@ -12,6 +12,9 @@ textSecureAccountsAPI, [self stringForTransport:transport], phoneNumber]]]; + if (!self) { + return nil; + } self.parameters = nil; [self setHTTPMethod:@"GET"]; @@ -30,7 +33,4 @@ } } -- (void)makeAuthenticatedRequest { -} - @end diff --git a/SignalServiceKit/src/Network/API/Requests/TSSubmitMessageRequest.m b/SignalServiceKit/src/Network/API/Requests/TSSubmitMessageRequest.m index 15f22c6809..4fa5119adf 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSSubmitMessageRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/TSSubmitMessageRequest.m @@ -1,14 +1,9 @@ // -// TSSubmitMessageRequest.m -// TextSecureiOS +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -// Created by Christine Corbett Moran on 11/30/13. -// Copyright (c) 2013 Open Whisper Systems. All rights reserved. -// - -#import "TSConstants.h" #import "TSSubmitMessageRequest.h" +#import "TSConstants.h" @implementation TSSubmitMessageRequest @@ -18,17 +13,21 @@ timeStamp:(uint64_t)timeStamp { self = [super initWithURL:[NSURL URLWithString:[textSecureMessagesAPI stringByAppendingString:contactRegisteredID]]]; + if (!self) { + return nil; + } - NSMutableDictionary *allMessages = - [@{ @"messages" : messages, - @"timestamp" : [NSNumber numberWithUnsignedLongLong:timeStamp] } mutableCopy]; + NSMutableDictionary *parameters = [@{ + @"messages" : messages, + @"timestamp" : @(timeStamp), + } mutableCopy]; if (relay) { - [allMessages setObject:relay forKey:@"relay"]; + parameters[@"relay"] = relay; } [self setHTTPMethod:@"PUT"]; - [self setParameters:allMessages]; + self.parameters = parameters; return self; } diff --git a/SignalServiceKit/src/Network/API/Requests/TSUpdateAttributesRequest.m b/SignalServiceKit/src/Network/API/Requests/TSUpdateAttributesRequest.m index caf6c4dd3e..a672ede3d0 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSUpdateAttributesRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/TSUpdateAttributesRequest.m @@ -1,10 +1,10 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // +#import "TSUpdateAttributesRequest.h" #import "TSAttributes.h" #import "TSConstants.h" -#import "TSUpdateAttributesRequest.h" NS_ASSUME_NONNULL_BEGIN @@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN if (self) { [self setHTTPMethod:@"PUT"]; - [self.parameters addEntriesFromDictionary:[TSAttributes attributesFromStorageWithManualMessageFetching:enableManualMessageFetching]]; + self.parameters = [TSAttributes attributesFromStorageWithManualMessageFetching:enableManualMessageFetching]; } return self; diff --git a/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.m b/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.m index ed7e6bdfa8..309132c74b 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.m @@ -1,11 +1,11 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // +#import "TSVerifyCodeRequest.h" #import "TSAccountManager.h" #import "TSAttributes.h" #import "TSConstants.h" -#import "TSVerifyCodeRequest.h" @implementation TSVerifyCodeRequest @@ -17,11 +17,10 @@ initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/code/%@", textSecureAccountsAPI, verificationCode]]]; - NSDictionary *attributes = - [TSAttributes attributesWithSignalingKey:signalingKey serverAuthToken:authKey manualMessageFetching:NO]; - _numberToValidate = phoneNumber; - [self.parameters addEntriesFromDictionary:attributes]; + + self.parameters = + [TSAttributes attributesWithSignalingKey:signalingKey serverAuthToken:authKey manualMessageFetching:NO]; [self setHTTPMethod:@"PUT"]; diff --git a/SignalServiceKit/src/Network/API/TSNetworkManager.m b/SignalServiceKit/src/Network/API/TSNetworkManager.m index 686fb9957f..058385c5b3 100644 --- a/SignalServiceKit/src/Network/API/TSNetworkManager.m +++ b/SignalServiceKit/src/Network/API/TSNetworkManager.m @@ -98,8 +98,9 @@ typedef void (^failureBlock)(NSURLSessionDataTask *task, NSError *error); [sessionManager.requestSerializer setAuthorizationHeaderFieldWithUsername:((TSVerifyCodeRequest *)request).numberToValidate password:[request.parameters objectForKey:@"AuthKey"]]; - [request.parameters removeObjectForKey:@"AuthKey"]; - [sessionManager PUT:request.URL.absoluteString parameters:request.parameters success:success failure:failure]; + NSMutableDictionary *parameters = [request.parameters mutableCopy]; + [parameters removeObjectForKey:@"AuthKey"]; + [sessionManager PUT:request.URL.absoluteString parameters:parameters success:success failure:failure]; } else { if (![request isKindOfClass:[TSRequestVerificationCodeRequest class]]) { [sessionManager.requestSerializer diff --git a/SignalServiceKit/src/Security/OWSFingerprint.m b/SignalServiceKit/src/Security/OWSFingerprint.m index 25cffb6938..50e2c79c98 100644 --- a/SignalServiceKit/src/Security/OWSFingerprint.m +++ b/SignalServiceKit/src/Security/OWSFingerprint.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "OWSFingerprint.h" @@ -309,16 +309,6 @@ static uint32_t const OWSFingerprintDefaultHashIterations = 5200; return qrImage; } -+ (NSString *)tag -{ - return [NSString stringWithFormat:@"[%@]", self.class]; -} - -- (NSString *)tag -{ - return self.class.logTag; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+PreKeyStore.m b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+PreKeyStore.m index dca61472bb..ba9a3e5ed8 100644 --- a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+PreKeyStore.m +++ b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+PreKeyStore.m @@ -101,16 +101,4 @@ return lastPreKeyId; } -#pragma mark - Logging - -+ (NSString *)tag -{ - return [NSString stringWithFormat:@"[%@+PreKeyStore]", self.class]; -} - -- (NSString *)tag -{ - return self.class.logTag; -} - @end diff --git a/SignalServiceKit/src/TSConstants.h b/SignalServiceKit/src/TSConstants.h index 6b9e06dc2c..d80ff8e2d7 100644 --- a/SignalServiceKit/src/TSConstants.h +++ b/SignalServiceKit/src/TSConstants.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #ifndef TextSecureKit_Constants_h @@ -51,6 +51,7 @@ typedef NS_ENUM(NSInteger, TSWhisperMessageType) { #define textSecureProfileAPIFormat @"v1/profile/%@" #define textSecureSetProfileNameAPIFormat @"v1/profile/name/%@" #define textSecureProfileAvatarFormAPI @"v1/profile/form/avatar" +#define textSecure2FAAPI @"/v1/accounts/pin" #define SignalApplicationGroup @"group.org.whispersystems.signal.group" diff --git a/SignalServiceKit/src/Util/OWS2FAManager.h b/SignalServiceKit/src/Util/OWS2FAManager.h new file mode 100644 index 0000000000..9a2828b647 --- /dev/null +++ b/SignalServiceKit/src/Util/OWS2FAManager.h @@ -0,0 +1,29 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const NSNotificationName_2FAStateDidChange; + +typedef void (^OWS2FASuccess)(void); +typedef void (^OWS2FAFailure)(NSError *error); + +// This class can be safely accessed and used from any thread. +@interface OWS2FAManager : NSObject + +- (instancetype)init NS_UNAVAILABLE; + ++ (instancetype)sharedManager; + +- (BOOL)is2FAEnabled; + +- (void)enable2FAWithPin:(NSString *)pin + success:(nullable OWS2FASuccess)success + failure:(nullable OWS2FAFailure)failure; + +- (void)disable2FAWithSuccess:(nullable OWS2FASuccess)success failure:(nullable OWS2FAFailure)failure; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Util/OWS2FAManager.m b/SignalServiceKit/src/Util/OWS2FAManager.m new file mode 100644 index 0000000000..a886f2f2a6 --- /dev/null +++ b/SignalServiceKit/src/Util/OWS2FAManager.m @@ -0,0 +1,134 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +#import "OWS2FAManager.h" +#import "NSNotificationCenter+OWS.h" +#import "OWSRequestFactory.h" +#import "TSNetworkManager.h" +#import "TSStorageManager.h" +#import "YapDatabaseConnection+OWS.h" + +NS_ASSUME_NONNULL_BEGIN + +NSString *const NSNotificationName_2FAStateDidChange = @"NSNotificationName_2FAStateDidChange"; + +NSString *const kOWS2FAManager_Collection = @"kOWS2FAManager_Collection"; +NSString *const kOWS2FAManager_IsEnabledKey = @"kOWS2FAManager_IsEnabledKey"; + +@interface OWS2FAManager () + +@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; +@property (nonatomic, readonly) TSNetworkManager *networkManager; + +@end + +#pragma mark - + +@implementation OWS2FAManager + ++ (instancetype)sharedManager +{ + static OWS2FAManager *sharedMyManager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedMyManager = [[self alloc] initDefault]; + }); + return sharedMyManager; +} + +- (instancetype)initDefault +{ + TSStorageManager *storageManager = [TSStorageManager sharedManager]; + TSNetworkManager *networkManager = [TSNetworkManager sharedManager]; + + return [self initWithStorageManager:storageManager networkManager:networkManager]; +} + +- (instancetype)initWithStorageManager:(TSStorageManager *)storageManager + networkManager:(TSNetworkManager *)networkManager +{ + self = [super init]; + + if (!self) { + return self; + } + + OWSAssert(storageManager); + OWSAssert(networkManager); + + _dbConnection = storageManager.newDatabaseConnection; + _networkManager = networkManager; + + OWSSingletonAssert(); + + return self; +} + +- (BOOL)is2FAEnabled +{ + return [self.dbConnection boolForKey:kOWS2FAManager_IsEnabledKey + inCollection:kOWS2FAManager_Collection + defaultValue:NO]; +} + +- (void)setIs2FAEnabled:(BOOL)value +{ + [self.dbConnection setBool:value forKey:kOWS2FAManager_IsEnabledKey inCollection:kOWS2FAManager_Collection]; + + [[NSNotificationCenter defaultCenter] postNotificationNameAsync:NSNotificationName_2FAStateDidChange + object:nil + userInfo:nil]; +} + +- (void)enable2FAWithPin:(NSString *)pin success:(nullable OWS2FASuccess)success failure:(nullable OWS2FAFailure)failure +{ + OWSAssert(pin.length > 0); + OWSAssert(success); + OWSAssert(failure); + + TSRequest *request = [OWSRequestFactory enable2FARequestWithPin:pin]; + [self.networkManager makeRequest:request + success:^(NSURLSessionDataTask *task, id responseObject) { + OWSAssertIsOnMainThread(); + + [self setIs2FAEnabled:YES]; + + if (success) { + success(); + } + } + failure:^(NSURLSessionDataTask *task, NSError *error) { + OWSAssertIsOnMainThread(); + + if (failure) { + failure(error); + } + }]; +} + +- (void)disable2FAWithSuccess:(nullable OWS2FASuccess)success failure:(nullable OWS2FAFailure)failure +{ + TSRequest *request = [OWSRequestFactory disable2FARequest]; + [self.networkManager makeRequest:request + success:^(NSURLSessionDataTask *task, id responseObject) { + OWSAssertIsOnMainThread(); + + [self setIs2FAEnabled:NO]; + + if (success) { + success(); + } + } + failure:^(NSURLSessionDataTask *task, NSError *error) { + OWSAssertIsOnMainThread(); + + if (failure) { + failure(error); + } + }]; +} + +@end + +NS_ASSUME_NONNULL_END