diff --git a/Podfile b/Podfile index aefcc93b4..d61c253e0 100644 --- a/Podfile +++ b/Podfile @@ -3,7 +3,8 @@ source 'https://github.com/CocoaPods/Specs.git' target 'Signal' do pod 'SocketRocket', :git => 'https://github.com/facebook/SocketRocket.git' - pod 'SignalServiceKit', :git => 'https://github.com/WhisperSystems/SignalServiceKit.git' + #pod 'SignalServiceKit', :git => 'https://github.com/WhisperSystems/SignalServiceKit.git' + pod 'SignalServiceKit', path: '../SignalServiceKit' pod 'OpenSSL', '~> 1.0.208' pod 'PastelogKit', '~> 1.3' pod 'FFCircularProgressView', '~> 0.5' diff --git a/Podfile.lock b/Podfile.lock index db5b9dfde..59de4c003 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -119,19 +119,16 @@ DEPENDENCIES: - OpenSSL (~> 1.0.208) - PastelogKit (~> 1.3) - SCWaveformView (~> 1.0) - - SignalServiceKit (from `https://github.com/WhisperSystems/SignalServiceKit.git`) + - SignalServiceKit (from `../SignalServiceKit`) - SocketRocket (from `https://github.com/facebook/SocketRocket.git`) EXTERNAL SOURCES: SignalServiceKit: - :git: https://github.com/WhisperSystems/SignalServiceKit.git + :path: "../SignalServiceKit" SocketRocket: :git: https://github.com/facebook/SocketRocket.git CHECKOUT OPTIONS: - SignalServiceKit: - :commit: 1d0b645fc98545ba09d2828c1908689d3052ca4c - :git: https://github.com/WhisperSystems/SignalServiceKit.git SocketRocket: :commit: 8096fef47d582bff8ae3758c9ae7af1d55ea53d6 :git: https://github.com/facebook/SocketRocket.git @@ -161,6 +158,6 @@ SPEC CHECKSUMS: UnionFind: c33be5adb12983981d6e827ea94fc7f9e370f52d YapDatabase: 713d4018cfacbd6e77dd430710ca84730e450980 -PODFILE CHECKSUM: 060ff4edf8b7a110984cb2c1ffef3f6e19a6b8b6 +PODFILE CHECKSUM: fa9416a71a75bf01fde5554c0505c69f88921ab7 COCOAPODS: 1.0.1 diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 12657461c..25002fc2a 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -18,6 +18,10 @@ 45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; }; 45843D201D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; }; 45843D221D223BA10013E85A /* OWSContactsSearcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */; }; + 458E38311D6682450094BD24 /* OWSQRCodeScanningViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38301D6682450094BD24 /* OWSQRCodeScanningViewController.m */; }; + 458E38341D66873D0094BD24 /* OWSLinkDeviceViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38331D66873D0094BD24 /* OWSLinkDeviceViewController.m */; }; + 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */; }; + 458E383A1D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38391D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m */; }; 459C3F0D1C9B3A1B003ACF51 /* TSMessageAdapterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 459C3F0C1C9B3A1B003ACF51 /* TSMessageAdapterTest.m */; }; 45C681B71D305A580050903A /* OWSCall.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C681B61D305A580050903A /* OWSCall.m */; }; 45C681B81D305A580050903A /* OWSCall.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C681B61D305A580050903A /* OWSCall.m */; }; @@ -519,6 +523,13 @@ 45843D1D1D2236B30013E85A /* OWSContactsSearcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactsSearcher.h; sourceTree = ""; }; 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcher.m; sourceTree = ""; }; 45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcherTest.m; sourceTree = ""; }; + 458E382F1D6682450094BD24 /* OWSQRCodeScanningViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQRCodeScanningViewController.h; sourceTree = ""; }; + 458E38301D6682450094BD24 /* OWSQRCodeScanningViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSQRCodeScanningViewController.m; sourceTree = ""; }; + 458E38321D66873D0094BD24 /* OWSLinkDeviceViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLinkDeviceViewController.h; sourceTree = ""; }; + 458E38331D66873D0094BD24 /* OWSLinkDeviceViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSLinkDeviceViewController.m; sourceTree = ""; }; + 458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDeviceProvisioningURLParser.h; sourceTree = ""; }; + 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceProvisioningURLParser.m; sourceTree = ""; }; + 458E38391D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDeviceProvisioningURLParserTest.m; path = Models/OWSDeviceProvisioningURLParserTest.m; sourceTree = ""; }; 459C3F0C1C9B3A1B003ACF51 /* TSMessageAdapterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSMessageAdapterTest.m; path = "view controllers/Signals/TSMessageAdapters/TSMessageAdapterTest.m"; sourceTree = ""; }; 45C681B51D305A580050903A /* OWSCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSCall.h; sourceTree = ""; }; 45C681B61D305A580050903A /* OWSCall.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSCall.m; sourceTree = ""; }; @@ -1113,13 +1124,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 457F3AB01D1470CF00C51351 /* view controllers */ = { - isa = PBXGroup; - children = ( - ); - name = "view controllers"; - sourceTree = ""; - }; 457F3AC01D14A0F700C51351 /* Models */ = { isa = PBXGroup; children = ( @@ -1134,10 +1138,20 @@ 45C681B61D305A580050903A /* OWSCall.m */, 453D28B81D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.h */, 453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */, + 458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */, + 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */, ); path = Models; sourceTree = ""; }; + 458E38381D6699110094BD24 /* Models */ = { + isa = PBXGroup; + children = ( + 458E38391D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m */, + ); + name = Models; + sourceTree = ""; + }; 459C3F0E1C9B3A20003ACF51 /* TSMessageAdapters */ = { isa = PBXGroup; children = ( @@ -1678,6 +1692,8 @@ B6BADBE61B88D1AC0086A80D /* LockInteractionController.m */, 76EB050B18170B33006006FC /* InCallViewController.h */, 76EB050C18170B33006006FC /* InCallViewController.m */, + 458E382F1D6682450094BD24 /* OWSQRCodeScanningViewController.h */, + 458E38301D6682450094BD24 /* OWSQRCodeScanningViewController.m */, ); name = "View Controllers"; path = "view controllers"; @@ -1803,7 +1819,7 @@ B660F66C1C29867F00687D6E /* test */ = { isa = PBXGroup; children = ( - 457F3AB01D1470CF00C51351 /* view controllers */, + 458E38381D6699110094BD24 /* Models */, 459C3F0E1C9B3A20003ACF51 /* TSMessageAdapters */, B660F66D1C29867F00687D6E /* audio */, B660F6731C29867F00687D6E /* call */, @@ -2220,6 +2236,8 @@ B66B9F7C1AEAF40500E2E609 /* NotificationSettingsOptionsViewController.m */, FCD274E91A5AFDDB00202277 /* AboutTableViewController.h */, FCD274EA1A5AFDDB00202277 /* AboutTableViewController.m */, + 458E38321D66873D0094BD24 /* OWSLinkDeviceViewController.h */, + 458E38331D66873D0094BD24 /* OWSLinkDeviceViewController.m */, ); name = Settings; sourceTree = ""; @@ -2614,6 +2632,7 @@ 76EB060218170B33006006FC /* InitiatorSessionDescriptor.m in Sources */, 76EB05FC18170B33006006FC /* CallConnectUtil_Server.m in Sources */, B6DA6B071B8A2F9A00CA6F98 /* AppStoreRating.m in Sources */, + 458E38311D6682450094BD24 /* OWSQRCodeScanningViewController.m in Sources */, 76EB062418170B33006006FC /* PriorityQueue.m in Sources */, B6BADBE71B88D1AC0086A80D /* LockInteractionController.m in Sources */, 76EB061A18170B33006006FC /* DiscardingLog.m in Sources */, @@ -2698,12 +2717,14 @@ E197B61118BBEC1A00F073E5 /* AudioProcessor.m in Sources */, FCAC964019FEF99A0046DFC5 /* InboxTableViewCell.m in Sources */, 76EB05EA18170B33006006FC /* CallProgress.m in Sources */, + 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */, FCFA64B41A24F3880007FB87 /* UIColor+OWS.m in Sources */, 76EB05C218170B33006006FC /* DhPacketSharedSecretHashes.m in Sources */, B6C93C4E199567AD00EDF894 /* DebugLogger.m in Sources */, 76EB063218170B33006006FC /* Crc32.m in Sources */, E197B62418BBF5BB00F073E5 /* SoundPlayer.m in Sources */, E197B61018BBEC1A00F073E5 /* EncodedAudioPacket.m in Sources */, + 458E38341D66873D0094BD24 /* OWSLinkDeviceViewController.m in Sources */, 76EB063618170B33006006FC /* DataUtil.m in Sources */, E197B60C18BBEC1A00F073E5 /* AudioPacker.m in Sources */, E197B61218BBEC1A00F073E5 /* AudioStretcher.m in Sources */, @@ -2840,6 +2861,7 @@ B660F72C1C29988E00687D6E /* HttpRequestUtil.m in Sources */, B660F72D1C29988E00687D6E /* HttpResponse.m in Sources */, B660F72E1C29988E00687D6E /* HttpManager.m in Sources */, + 458E383A1D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m in Sources */, B660F72F1C29988E00687D6E /* HttpSocket.m in Sources */, B660F7301C29988E00687D6E /* IpAddress.m in Sources */, B660F7311C29988E00687D6E /* IpEndPoint.m in Sources */, diff --git a/Signal/src/Models/OWSDeviceProvisioningURLParser.h b/Signal/src/Models/OWSDeviceProvisioningURLParser.h new file mode 100644 index 000000000..319a717cd --- /dev/null +++ b/Signal/src/Models/OWSDeviceProvisioningURLParser.h @@ -0,0 +1,15 @@ +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +NS_ASSUME_NONNULL_BEGIN + +@interface OWSDeviceProvisioningURLParser : NSObject + +@property (readonly, getter=isValid) BOOL valid; +@property (nonatomic, readonly) NSString *ephemeralDeviceId; +@property (nonatomic, readonly) NSData *publicKey; + +- (instancetype)initWithProvisioningURL:(NSString *)provisioningURL; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/Models/OWSDeviceProvisioningURLParser.m b/Signal/src/Models/OWSDeviceProvisioningURLParser.m new file mode 100644 index 000000000..2fd15bce8 --- /dev/null +++ b/Signal/src/Models/OWSDeviceProvisioningURLParser.m @@ -0,0 +1,39 @@ +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import "OWSDeviceProvisioningURLParser.h" +#import "NSData+Base64.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +NSString *const OWSQueryItemNameEphemeralDeviceIdKey = @"uuid"; +NSString *const OWSQueryItemNameEncodedPublicKeyKey = @"pub_key"; + +@implementation OWSDeviceProvisioningURLParser + +- (instancetype)initWithProvisioningURL:(NSString *)provisioningURL +{ + self = [super init]; + if (!self) { + return self; + } + + NSURLComponents *components = [NSURLComponents componentsWithString:provisioningURL]; + for (NSURLQueryItem *queryItem in [components queryItems]) { + if ([queryItem.name isEqualToString:OWSQueryItemNameEphemeralDeviceIdKey]) { + _ephemeralDeviceId = queryItem.value; + } else if ([queryItem.name isEqualToString:OWSQueryItemNameEncodedPublicKeyKey]) { + NSString *encodedPublicKey = queryItem.value; + _publicKey = [[NSData dataFromBase64String:encodedPublicKey] removeKeyType]; + } else { + DDLogWarn(@"Unkown query item in provisioning string: %@", queryItem.name); + } + } + + _valid = _ephemeralDeviceId && _publicKey; + return self; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/Storyboard/Storyboard.storyboard b/Signal/src/Storyboard/Storyboard.storyboard index 2f7b6c58b..2785ec2cb 100644 --- a/Signal/src/Storyboard/Storyboard.storyboard +++ b/Signal/src/Storyboard/Storyboard.storyboard @@ -1408,8 +1408,8 @@ A0 09 9A FF A8 8A 09 99 - - + + + + + + + + + + + + + + + @@ -1492,7 +1512,7 @@ A0 09 9A FF A8 8A 09 99 - + @@ -1513,7 +1533,7 @@ A0 09 9A FF A8 8A 09 99 - + @@ -1564,6 +1584,7 @@ A0 09 9A FF A8 8A 09 99 + @@ -1577,6 +1598,25 @@ A0 09 9A FF A8 8A 09 99 + + + + + + + + + + + + + + + + + + + diff --git a/Signal/src/view controllers/OWSLinkDeviceViewController.h b/Signal/src/view controllers/OWSLinkDeviceViewController.h new file mode 100644 index 000000000..a950e6caa --- /dev/null +++ b/Signal/src/view controllers/OWSLinkDeviceViewController.h @@ -0,0 +1,7 @@ +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import "OWSQRCodeScanningViewController.h" + +@interface OWSLinkDeviceViewController : OWSQRCodeScanningViewController + +@end diff --git a/Signal/src/view controllers/OWSLinkDeviceViewController.m b/Signal/src/view controllers/OWSLinkDeviceViewController.m new file mode 100644 index 000000000..f55230595 --- /dev/null +++ b/Signal/src/view controllers/OWSLinkDeviceViewController.m @@ -0,0 +1,55 @@ +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import "OWSLinkDeviceViewController.h" +#import "OWSDeviceProvisioningURLParser.h" +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@implementation OWSLinkDeviceViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; +} + +- (void)didDetectQRCodeWithString:(NSString *)string +{ + OWSDeviceProvisioningURLParser *parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:string]; + + if (!parser.isValid) { + DDLogError(@"Unable to parse provisioning params from QRCode: %@", string); + return; + } + + NSData *myPublicKey = [[TSStorageManager sharedManager] identityKeyPair].publicKey; + NSData *myPrivateKey = [[TSStorageManager sharedManager] identityKeyPair].ows_privateKey; + NSString *accountIdentifier = [TSStorageManager localNumber]; + + OWSDeviceProvisioner *provisioner = [[OWSDeviceProvisioner alloc] initWithMyPublicKey:myPublicKey + myPrivateKey:myPrivateKey + theirPublicKey:parser.publicKey + theirEphemeralDeviceId:parser.ephemeralDeviceId + accountIdentifier:accountIdentifier]; + + [provisioner provisionWithSuccess:^{ + DDLogInfo(@"Successfully provisioned device."); + } + failure:^(NSError *error) { + DDLogError(@"Failed to provision device with error: %@", error); + }]; + + // TODO show progress. Maybe even incremental with progress callback in provisioner. +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/view controllers/OWSQRCodeScanningViewController.h b/Signal/src/view controllers/OWSQRCodeScanningViewController.h new file mode 100644 index 000000000..9c85306b3 --- /dev/null +++ b/Signal/src/view controllers/OWSQRCodeScanningViewController.h @@ -0,0 +1,16 @@ +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import +#import + +@interface OWSQRCodeScanningViewController : UIViewController + +@property (nonatomic, strong) AVCaptureSession *session; +@property (nonatomic, strong) AVCaptureDevice *device; +@property (nonatomic, strong) AVCaptureDeviceInput *input; +@property (nonatomic, strong) AVCaptureMetadataOutput *output; +@property (nonatomic, strong) AVCaptureVideoPreviewLayer *prevLayer; + +@property (nonatomic, strong) UIView *highlightView; + +@end diff --git a/Signal/src/view controllers/OWSQRCodeScanningViewController.m b/Signal/src/view controllers/OWSQRCodeScanningViewController.m new file mode 100644 index 000000000..fb37fd549 --- /dev/null +++ b/Signal/src/view controllers/OWSQRCodeScanningViewController.m @@ -0,0 +1,85 @@ +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import "OWSQRCodeScanningViewController.h" +#import "UIColor+OWS.h" + +@implementation OWSQRCodeScanningViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.title = NSLocalizedString(@"SCAN_KEY", @""); + + self.highlightView = [[UIView alloc] init]; + self.highlightView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin + | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; + self.highlightView.layer.borderColor = [UIColor ows_greenColor].CGColor; + self.highlightView.layer.borderWidth = 4; + [self.view addSubview:self.highlightView]; + + self.session = [[AVCaptureSession alloc] init]; + self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + NSError *error = nil; + + self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error]; + if (self.input) { + [self.session addInput:self.input]; + } else { + DDLogDebug(@"Error: %@", error); + } + + self.output = [[AVCaptureMetadataOutput alloc] init]; + [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; + [self.session addOutput:self.output]; + + self.output.metadataObjectTypes = [self.output availableMetadataObjectTypes]; + + self.prevLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session]; + self.prevLayer.frame = self.view.bounds; + self.prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; + [self.view.layer insertSublayer:self.prevLayer atIndex:0]; + + [self.session startRunning]; + + [self.view bringSubviewToFront:self.highlightView]; +} + + +- (void)captureOutput:(AVCaptureOutput *)captureOutput + didOutputMetadataObjects:(NSArray *)metadataObjects + fromConnection:(AVCaptureConnection *)connection +{ + CGRect highlightViewRect = CGRectZero; + AVMetadataMachineReadableCodeObject *barCodeObject; + NSString *detectionString = nil; + NSArray *barCodeTypes = @[ AVMetadataObjectTypeQRCode ]; + + for (AVMetadataObject *metadata in metadataObjects) { + for (NSString *type in barCodeTypes) { + if ([metadata.type isEqualToString:type]) { + barCodeObject = (AVMetadataMachineReadableCodeObject *)[self.prevLayer + transformedMetadataObjectForMetadataObject:(AVMetadataMachineReadableCodeObject *)metadata]; + highlightViewRect = barCodeObject.bounds; + detectionString = [(AVMetadataMachineReadableCodeObject *)metadata stringValue]; + break; + } + } + if (detectionString != nil) { + [self didDetectQRCodeWithString:detectionString]; + [self.session stopRunning]; + break; + } + } + + self.highlightView.frame = highlightViewRect; +} + +- (void)didDetectQRCodeWithString:(NSString *)string +{ + // Override in subclass. Subclass is responsible for dismissing this view controller. + DDLogInfo(@"Scanned QRCode with string value: %@", string); +} + + +@end diff --git a/Signal/src/view controllers/ScanIdentityBarcodeViewController.h b/Signal/src/view controllers/ScanIdentityBarcodeViewController.h index a1c085ead..c87d6970b 100644 --- a/Signal/src/view controllers/ScanIdentityBarcodeViewController.h +++ b/Signal/src/view controllers/ScanIdentityBarcodeViewController.h @@ -4,18 +4,11 @@ // // Created by Christine Corbett Moran on 3/29/14. // Copyright (c) 2014 Open Whisper Systems. All rights reserved. -// -#import -#import -@interface ScanIdentityBarcodeViewController : UIViewController +#import "OWSQRCodeScanningViewController.h" -@property (nonatomic, strong) AVCaptureSession *session; -@property (nonatomic, strong) AVCaptureDevice *device; -@property (nonatomic, strong) AVCaptureDeviceInput *input; -@property (nonatomic, strong) AVCaptureMetadataOutput *output; -@property (nonatomic, strong) AVCaptureVideoPreviewLayer *prevLayer; +@interface ScanIdentityBarcodeViewController : OWSQRCodeScanningViewController -@property (nonatomic, strong) UIView *highlightView; @property (nonatomic, strong) NSData *identityKey; + @end diff --git a/Signal/src/view controllers/ScanIdentityBarcodeViewController.m b/Signal/src/view controllers/ScanIdentityBarcodeViewController.m index 4f1ffd30b..2d136e54d 100644 --- a/Signal/src/view controllers/ScanIdentityBarcodeViewController.m +++ b/Signal/src/view controllers/ScanIdentityBarcodeViewController.m @@ -6,104 +6,35 @@ // Copyright (c) 2014 Open Whisper Systems. All rights reserved. // -#import "NSData+Base64.h" -#import "ScanIdentityBarcodeViewController.h" -#import "UIColor+OWS.h" +#import "ScanIdentityBarcodeViewController.h" +#import "NSData+Base64.h" @implementation ScanIdentityBarcodeViewController -- (void)viewDidLoad { - [super viewDidLoad]; +- (void)didDetectQRCodeWithString:(NSString *)string +{ + NSData *data = [NSData dataFromBase64String:string]; + NSString *dialogTitle; + NSString *dialogDescription; - self.title = NSLocalizedString(@"SCAN_KEY", @""); - - self.highlightView = [[UIView alloc] init]; - self.highlightView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | - UIViewAutoresizingFlexibleRightMargin | - UIViewAutoresizingFlexibleBottomMargin; - self.highlightView.layer.borderColor = [UIColor ows_greenColor].CGColor; - self.highlightView.layer.borderWidth = 4; - [self.view addSubview:self.highlightView]; - - self.session = [[AVCaptureSession alloc] init]; - self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; - NSError *error = nil; - - self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error]; - if (self.input) { - [self.session addInput:self.input]; + if ([data isEqualToData:self.identityKey]) { + dialogTitle = NSLocalizedString(@"SCAN_KEY_VERIFIED_TITLE", @""); + dialogDescription = NSLocalizedString(@"SCAN_KEY_VERIFIED_TEXT", @""); } else { - DDLogDebug(@"Error: %@", error); + dialogTitle = NSLocalizedString(@"SCAN_KEY_CONFLICT_TITLE", @""); + dialogDescription = NSLocalizedString(@"SCAN_KEY_CONFLICT_TEXT", @""); } - self.output = [[AVCaptureMetadataOutput alloc] init]; - [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; - [self.session addOutput:self.output]; - - self.output.metadataObjectTypes = [self.output availableMetadataObjectTypes]; - - self.prevLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session]; - self.prevLayer.frame = self.view.bounds; - self.prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; - [self.view.layer insertSublayer:self.prevLayer atIndex:0]; - - [self.session startRunning]; - - [self.view bringSubviewToFront:self.highlightView]; -} - - -- (void)captureOutput:(AVCaptureOutput *)captureOutput - didOutputMetadataObjects:(NSArray *)metadataObjects - fromConnection:(AVCaptureConnection *)connection { - CGRect highlightViewRect = CGRectZero; - AVMetadataMachineReadableCodeObject *barCodeObject; - NSString *detectionString = nil; - NSArray *barCodeTypes = @[ AVMetadataObjectTypeQRCode ]; - - for (AVMetadataObject *metadata in metadataObjects) { - for (NSString *type in barCodeTypes) { - if ([metadata.type isEqualToString:type]) { - barCodeObject = (AVMetadataMachineReadableCodeObject *)[self.prevLayer - transformedMetadataObjectForMetadataObject:(AVMetadataMachineReadableCodeObject *)metadata]; - highlightViewRect = barCodeObject.bounds; - detectionString = [(AVMetadataMachineReadableCodeObject *)metadata stringValue]; - break; - } - } - if (detectionString != nil) { - NSData *detectionData = [NSData dataFromBase64String:detectionString]; - - NSString *dialogTitle; - NSString *dialogDescription; - - if ([detectionData isEqualToData:self.identityKey]) { - dialogTitle = NSLocalizedString(@"SCAN_KEY_VERIFIED_TITLE", @""); - dialogDescription = NSLocalizedString(@"SCAN_KEY_VERIFIED_TEXT", @""); - } else { - dialogTitle = NSLocalizedString(@"SCAN_KEY_CONFLICT_TITLE", @""); - dialogDescription = NSLocalizedString(@"SCAN_KEY_CONFLICT_TEXT", @""); - } - - [self.session stopRunning]; - UIAlertController *controller = [UIAlertController alertControllerWithTitle:dialogTitle - message:dialogDescription - preferredStyle:UIAlertControllerStyleAlert]; - - [self presentViewController:controller - animated:YES - completion:^{ - [self performSelector:@selector(dismissScannerAfterSuccesfullScan) - withObject:nil - afterDelay:5]; - }]; - - break; - } - } - - self.highlightView.frame = highlightViewRect; + UIAlertController *controller = [UIAlertController alertControllerWithTitle:dialogTitle + message:dialogDescription + preferredStyle:UIAlertControllerStyleAlert]; + [self + presentViewController:controller + animated:YES + completion:^{ + [self performSelector:@selector(dismissScannerAfterSuccesfullScan) withObject:nil afterDelay:5]; + }]; } #pragma mark - Action @@ -111,7 +42,7 @@ - (void)dismissScannerAfterSuccesfullScan { [self dismissViewControllerAnimated:YES completion:^{ - [self closeButtonAction:nil]; + [self closeButtonAction:nil]; }]; } diff --git a/Signal/src/view controllers/SettingsTableViewController.h b/Signal/src/view controllers/SettingsTableViewController.h index f055fed19..acfefbeea 100644 --- a/Signal/src/view controllers/SettingsTableViewController.h +++ b/Signal/src/view controllers/SettingsTableViewController.h @@ -16,6 +16,7 @@ @property (strong, nonatomic) IBOutlet UILabel *networkStatusHeader; @property (strong, nonatomic) IBOutlet UILabel *privacyLabel; @property (strong, nonatomic) IBOutlet UILabel *notificationsLabel; +@property (strong, nonatomic) IBOutlet UILabel *linkedDevicesLabel; @property (strong, nonatomic) IBOutlet UILabel *advancedLabel; @property (strong, nonatomic) IBOutlet UILabel *aboutLabel; @property (strong, nonatomic) IBOutlet UIButton *destroyAccountButton; diff --git a/Signal/src/view controllers/SettingsTableViewController.m b/Signal/src/view controllers/SettingsTableViewController.m index 446b09451..ad0541618 100644 --- a/Signal/src/view controllers/SettingsTableViewController.m +++ b/Signal/src/view controllers/SettingsTableViewController.m @@ -33,16 +33,16 @@ #define kRegisteredNumberRow 0 #define kPrivacyRow 0 #define kNotificationRow 1 -#define kAdvancedRow 2 -#define kAboutRow 3 +#define kAdvancedRow 3 +#define kAboutRow 4 #define kNetworkRow 0 #define kUnregisterRow 0 typedef enum { - kRegisteredRows = 1, - kGeneralRows = 4, + kRegisteredRows = 1, + kGeneralRows = 5, kNetworkStatusRows = 1, - kUnregisterRows = 1, + kUnregisterRows = 1, } kRowsForSection; typedef enum { @@ -79,6 +79,8 @@ typedef enum { self.advancedLabel.text = NSLocalizedString(@"SETTINGS_ADVANCED_TITLE", @""); self.aboutLabel.text = NSLocalizedString(@"SETTINGS_ABOUT", @""); self.notificationsLabel.text = NSLocalizedString(@"SETTINGS_NOTIFICATIONS", nil); + self.linkedDevicesLabel.text = NSLocalizedString( + @"LINKED_DEVICES_LABEL", @"table cell label, when pressed takes you to manage your linked devices."); [self.destroyAccountButton setTitle:NSLocalizedString(@"SETTINGS_DELETE_ACCOUNT_BUTTON", @"") forState:UIControlStateNormal]; } diff --git a/Signal/test/Models/OWSDeviceProvisioningURLParserTest.m b/Signal/test/Models/OWSDeviceProvisioningURLParserTest.m new file mode 100644 index 000000000..12f91e3be --- /dev/null +++ b/Signal/test/Models/OWSDeviceProvisioningURLParserTest.m @@ -0,0 +1,47 @@ +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import "OWSDeviceProvisioningURLParser.h" +#import +#import + +@interface OWSDeviceProvisioningURLParserTest : XCTestCase + +@end + +@implementation OWSDeviceProvisioningURLParserTest + +- (void)testValid +{ + OWSDeviceProvisioningURLParser *parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@""]; + XCTAssertFalse(parser.isValid); + + parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/?uuid=MTIz"]; + XCTAssertFalse(parser.isValid); + + parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/?pub_key=MTIz"]; + XCTAssertFalse(parser.isValid); + + parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/uuid=asd&pub_key=MTIz"]; + XCTAssertFalse(parser.isValid); + + parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/?uuid=asd&pub_key=MTIz"]; + XCTAssert(parser.isValid); +} + +- (void)testPublicKey +{ + OWSDeviceProvisioningURLParser *parser = + [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/?uuid=asd&pub_key=MTIz"]; + + XCTAssertEqualObjects(@"MTIz", [parser.publicKey base64EncodedString]); +} + +- (void)testEphemeralDeviceId +{ + OWSDeviceProvisioningURLParser *parser = + [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/?uuid=asd&pub_key=MTIz"]; + + XCTAssertEqualObjects(@"asd", parser.ephemeralDeviceId); +} + +@end diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 70cef4f33..8a5c298e0 100644 Binary files a/Signal/translations/en.lproj/Localizable.strings and b/Signal/translations/en.lproj/Localizable.strings differ