compare safety numbers with clipboard (#1475)

* Compare safety numbers with clipboard

// FREEBIE
pull/1/head
Michael Kirk 8 years ago committed by GitHub
parent de7752ab20
commit 584118a9fc

@ -65,6 +65,8 @@
45CD81F21DC03A22004C9430 /* OWSLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 45CD81F11DC03A22004C9430 /* OWSLogger.m */; };
45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */; };
45D231781DC7E8F10034FA89 /* SessionResetJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */; };
45DF5DF21DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */; };
45DF5DF31DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */; };
45EB32CF1D7465C900735B2E /* OWSLinkedDevicesTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 45EB32CE1D7465C900735B2E /* OWSLinkedDevicesTableViewController.m */; };
45F2B1941D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 45F2B1931D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m */; };
45F2B1971D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45F2B1951D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib */; };
@ -614,6 +616,7 @@
45CD81F01DC03A22004C9430 /* OWSLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLogger.h; sourceTree = "<group>"; };
45CD81F11DC03A22004C9430 /* OWSLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSLogger.m; sourceTree = "<group>"; };
45D231761DC7E8F10034FA89 /* SessionResetJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SessionResetJob.swift; path = Jobs/SessionResetJob.swift; sourceTree = "<group>"; };
45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompareSafetyNumbersActivity.swift; sourceTree = "<group>"; };
45E282DE1D08E67800ADD4C8 /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = translations/gl.lproj/Localizable.strings; sourceTree = "<group>"; };
45E282DF1D08E6CC00ADD4C8 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = translations/id.lproj/Localizable.strings; sourceTree = "<group>"; };
45EB32CD1D7465C900735B2E /* OWSLinkedDevicesTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLinkedDevicesTableViewController.h; sourceTree = "<group>"; };
@ -1232,6 +1235,7 @@
45666EC71D994C0D008FE134 /* OWSGroupAvatarBuilder.h */,
45666EC81D994C0D008FE134 /* OWSGroupAvatarBuilder.m */,
45CD81EE1DC030E7004C9430 /* AccountManager.swift */,
45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */,
);
path = Models;
sourceTree = "<group>";
@ -2845,6 +2849,7 @@
76EB05E018170B33006006FC /* NetworkStream.m in Sources */,
FCFA64B71A24F6730007FB87 /* UIFont+OWS.m in Sources */,
B6B9ECFC198B31BA00C620D3 /* PushManager.m in Sources */,
45DF5DF21DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift in Sources */,
76EB05D618170B33006006FC /* ZrtpResponder.m in Sources */,
B62D53F71A23CCAD009AAF82 /* TSMessageAdapter.m in Sources */,
FCD274EB1A5AFDDB00202277 /* AboutTableViewController.m in Sources */,
@ -3144,6 +3149,7 @@
B660F76A1C29988E00687D6E /* EventWindow.m in Sources */,
B660F76B1C29988E00687D6E /* LoggingUtil.m in Sources */,
B660F76C1C29988E00687D6E /* AnonymousConditionLogger.m in Sources */,
45DF5DF31DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift in Sources */,
B660F76D1C29988E00687D6E /* AnonymousOccurrenceLogger.m in Sources */,
B660F76E1C29988E00687D6E /* AnonymousValueLogger.m in Sources */,
B660F76F1C29988E00687D6E /* DiscardingLog.m in Sources */,

@ -0,0 +1,101 @@
// Created by Michael Kirk on 11/15/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
import Foundation
let CompareSafetyNumbersActivityType = "org.whispersystems.signal.activity.CompareSafetyNumbers"
@objc(OWSCompareSafetyNumbersActivityDelegate)
protocol CompareSafetyNumbersActivityDelegate {
func compareSafetyNumbersActivitySucceeded(activity: CompareSafetyNumbersActivity) -> Void;
func compareSafetyNumbersActivity(_ activity: CompareSafetyNumbersActivity, failedWithError error: Error) -> Void;
}
@objc (OWSCompareSafetyNumbersActivity)
class CompareSafetyNumbersActivity: UIActivity {
let TAG = "[CompareSafetyNumbersActivity]"
var mySafetyNumbers: String?
let delegate: CompareSafetyNumbersActivityDelegate
required init(delegate:CompareSafetyNumbersActivityDelegate) {
self.delegate = delegate
super.init()
}
// MARK: UIActivity
override class var activityCategory: UIActivityCategory {
get { return .action }
}
override var activityType: UIActivityType? {
get { return UIActivityType(rawValue: CompareSafetyNumbersActivityType) }
}
override var activityTitle: String? {
get {
return NSLocalizedString("COMPARE_SAFETY_NUMBER_ACTION", comment: "Activity Sheet label")
}
}
override var activityImage: UIImage? {
get {
return #imageLiteral(resourceName: "ic_lock_outline")
}
}
override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
return stringsFrom(activityItems:activityItems).count > 0
}
override func prepare(withActivityItems activityItems: [Any]) {
let myFormattedSafetyNumbers = stringsFrom(activityItems: activityItems).first
mySafetyNumbers = numericOnly(string: myFormattedSafetyNumbers)
}
override func perform() {
defer { activityDidFinish(true) }
let pasteboardString = numericOnly(string: UIPasteboard.general.string)
guard (pasteboardString != nil && pasteboardString!.characters.count == 60) else {
Logger.warn("\(TAG) no valid safety numbers found in pasteboard: \(pasteboardString)")
let error = OWSErrorWithCodeDescription(OWSErrorCode.userError,
NSLocalizedString("PRIVACY_VERIFICATION_FAILED_NO_SAFETY_NUMBERS_IN_CLIPBOARD", comment: "Alert body for user error"))
delegate.compareSafetyNumbersActivity(self, failedWithError: error)
return
}
let pasteboardSafetyNumbers = pasteboardString!
if pasteboardSafetyNumbers == mySafetyNumbers {
Logger.info("\(TAG) successfully matched safety numbers. local numbers: \(mySafetyNumbers) pasteboard:\(pasteboardSafetyNumbers)")
delegate.compareSafetyNumbersActivitySucceeded(activity:self)
} else {
Logger.warn("\(TAG) local numbers: \(mySafetyNumbers) didn't match pasteboard:\(pasteboardSafetyNumbers)")
let error = OWSErrorWithCodeDescription(OWSErrorCode.privacyVerificationFailure,
NSLocalizedString("PRIVACY_VERIFICATION_FAILED_MISMATCHED_SAFETY_NUMBERS_IN_CLIPBOARD", comment: "Alert body"))
delegate.compareSafetyNumbersActivity(self, failedWithError: error)
}
}
// MARK: Helpers
func numericOnly(string: String?) -> String? {
guard (string != nil) else {
return nil
}
var numericOnly: String?
if let regex = try? NSRegularExpression(pattern: "\\D", options: .caseInsensitive) {
numericOnly = regex.stringByReplacingMatches(in: string!, options: .withTransparentBounds, range: NSMakeRange(0, string!.characters.count), withTemplate: "")
}
return numericOnly
}
func stringsFrom(activityItems: [Any]) -> [String] {
return activityItems.map { $0 as? String }.filter { $0 != nil }.map { $0! }
}
}

@ -14,6 +14,7 @@
#import "UIUtil.h"
#import "UIViewController+CameraPermissions.h"
#import <SignalServiceKit/NSDate+millisecondTimeStamp.h>
#import <SignalServiceKit/OWSError.h>
#import <SignalServiceKit/OWSFingerprint.h>
#import <SignalServiceKit/TSInfoMessage.h>
#import <SignalServiceKit/TSStorageManager+IdentityKeyStore.h>
@ -23,7 +24,7 @@
NS_ASSUME_NONNULL_BEGIN
@interface FingerprintViewController () <OWSHighlightableLabelDelegate>
@interface FingerprintViewController () <OWSHighlightableLabelDelegate, OWSCompareSafetyNumbersActivityDelegate>
@property (strong, nonatomic) TSStorageManager *storageManager;
@property (strong, nonatomic) TSThread *thread;
@ -141,7 +142,7 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - HilightableLableDelegate
- (void)didHighlightLabelWithLabel:(OWSHighlightableLabel *)label completion:(nullable void (^)(void))completionHandler
- (void)didHighlightLabel:(OWSHighlightableLabel *)label completion:(nullable void (^)(void))completionHandler
{
[self showSharingActivityWithCompletion:completionHandler];
}
@ -150,32 +151,48 @@ NS_ASSUME_NONNULL_BEGIN
{
DDLogDebug(@"%@ Sharing safety numbers", self.tag);
OWSCompareSafetyNumbersActivity *compareActivity = [[OWSCompareSafetyNumbersActivity alloc] initWithDelegate:self];
NSString *shareFormat = NSLocalizedString(@"SAFETY_NUMBER_SHARE_FORMAT", @"Snippet to share {{safety numbers}} with a friend. sent e.g. via sms");
NSString *shareString = [NSString stringWithFormat:shareFormat, self.fingerprint.displayableText];
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:@[shareString]
applicationActivities:nil];
UIActivityViewController *activityController =
[[UIActivityViewController alloc] initWithActivityItems:@[ shareString ]
applicationActivities:@[ compareActivity ]];
void (^activityControllerCompletionHandler)(UIActivityType __nullable activityType, BOOL completed, NSArray * __nullable returnedItems, NSError * __nullable activityError) = ^void(UIActivityType __nullable activityType, BOOL completed, NSArray * __nullable returnedItems, NSError * __nullable activityError){
activityController.completionWithItemsHandler = ^void(UIActivityType __nullable activityType, BOOL completed, NSArray * __nullable returnedItems, NSError * __nullable activityError){
if (completionHandler) {
completionHandler();
}
[UIUtil applySignalAppearence];
};
activityController.completionWithItemsHandler = activityControllerCompletionHandler;
// This value was extracted by inspecting `activityType` in the activityController.completionHandler
NSString *const iCloudActivityType = @"com.apple.CloudDocsUI.AddToiCloudDrive";
activityController.excludedActivityTypes = @[
UIActivityTypePostToFacebook,
UIActivityTypePostToWeibo,
UIActivityTypeAirDrop,
UIActivityTypePostToTwitter
UIActivityTypePostToTwitter,
iCloudActivityType // This isn't being excluded. RADAR https://openradar.appspot.com/27493621
];
[UIUtil applyDefaultSystemAppearence];
[self presentViewController:activityController animated:YES completion:nil];
}
#pragma mark - OWSCompareSafetyNumbersActivityDelegate
- (void)compareSafetyNumbersActivitySucceededWithActivity:(OWSCompareSafetyNumbersActivity *)activity
{
[self showVerificationSucceeded];
}
- (void)compareSafetyNumbersActivity:(OWSCompareSafetyNumbersActivity *)activity failedWithError:(NSError *)error
{
[self showVerificationFailedWithError:error];
}
#pragma mark - Action
- (IBAction)closeButtonAction:(id)sender
@ -230,45 +247,46 @@ NS_ASSUME_NONNULL_BEGIN
{
NSError *error;
if ([self.fingerprint matchesLogicalFingerprintsData:combinedFingerprintData error:&error]) {
DDLogInfo(@"%@ Successfully verified privacy.", self.tag);
NSString *successTitle = NSLocalizedString(@"SUCCESSFUL_VERIFICATION_TITLE", nil);
NSString *dismissText = NSLocalizedString(@"DISMISS_BUTTON_TEXT", nil);
NSString *descriptionFormat = NSLocalizedString(
@"SUCCESSFUL_VERIFICATION_DESCRIPTION", @"Alert body after verifying privacy with {{other user's name}}");
NSString *successDescription = [NSString stringWithFormat:descriptionFormat, self.contactName];
UIAlertController *successAlertController =
[UIAlertController alertControllerWithTitle:successTitle
message:successDescription
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *dismissAction =
[UIAlertAction actionWithTitle:dismissText
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[self dismissViewControllerAnimated:YES completion:nil];
}];
[successAlertController addAction:dismissAction];
[self presentViewController:successAlertController animated:YES completion:nil];
[self showVerificationSucceeded];
} else {
[self failVerificationWithError:error];
[self showVerificationFailedWithError:error];
}
}
- (void)failVerificationWithError:(NSError *)error
- (void)showVerificationSucceeded
{
NSString *failureTitle = NSLocalizedString(@"FAILED_VERIFICATION_TITLE", @"alert title");
DDLogInfo(@"%@ Successfully verified privacy.", self.tag);
NSString *successTitle = NSLocalizedString(@"SUCCESSFUL_VERIFICATION_TITLE", nil);
NSString *dismissText = NSLocalizedString(@"DISMISS_BUTTON_TEXT", nil);
NSString *descriptionFormat = NSLocalizedString(
@"SUCCESSFUL_VERIFICATION_DESCRIPTION", @"Alert body after verifying privacy with {{other user's name}}");
NSString *successDescription = [NSString stringWithFormat:descriptionFormat, self.contactName];
UIAlertController *successAlertController =
[UIAlertController alertControllerWithTitle:successTitle
message:successDescription
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *dismissAction =
[UIAlertAction actionWithTitle:dismissText style:UIAlertActionStyleDefault handler:nil];
[successAlertController addAction:dismissAction];
[self presentViewController:successAlertController animated:YES completion:nil];
}
- (void)showVerificationFailedWithError:(NSError *)error
{
NSString *_Nullable failureTitle;
if (error.code != OWSErrorCodeUserError) {
failureTitle = NSLocalizedString(@"FAILED_VERIFICATION_TITLE", @"alert title");
} // else no title. We don't want to show a big scary "VERIFICATION FAILED" when it's just user error.
UIAlertController *failureAlertController =
[UIAlertController alertControllerWithTitle:failureTitle
message:error.localizedDescription
preferredStyle:UIAlertControllerStyleAlert];
NSString *cancelText = NSLocalizedString(@"TXT_CANCEL_TITLE", nil);
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelText
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[self dismissViewControllerAnimated:YES completion:nil];
}];
[failureAlertController addAction:cancelAction];
NSString *dismissText = NSLocalizedString(@"DISMISS_BUTTON_TEXT", nil);
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:dismissText style:UIAlertActionStyleCancel handler:nil];
[failureAlertController addAction:dismissAction];
// TODO
// NSString retryText = NSLocalizedString(@"RETRY_BUTTON_TEXT", nil);

@ -5,7 +5,7 @@ import UIKit
@objc(OWSHighlightableLabelDelegate)
protocol HighlightableLabelDelegate {
func didHighlightLabel(label:HighlightableLabel, completion: (()->())?) -> ()
func didHighlightLabel(_ label:HighlightableLabel, completion: (()->())?) -> ()
}
@objc(OWSHighlightableLabel)
@ -60,6 +60,6 @@ class HighlightableLabel : UILabel {
becomeFirstResponder();
showBorder()
self.delegate?.didHighlightLabel(label: self, completion:{ self.hideBorder() })
self.delegate?.didHighlightLabel(self, completion:{ self.hideBorder() })
}
}

Loading…
Cancel
Save