diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 92e685fb0..b9be951d2 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -288,6 +288,9 @@ B6019E971A2492AB001118DF /* NSDate+millisecondTimeStamp.mm in Sources */ = {isa = PBXBuildFile; fileRef = B6019E961A2492AB001118DF /* NSDate+millisecondTimeStamp.mm */; }; B60C16651988999D00E97A6C /* VersionMigrations.m in Sources */ = {isa = PBXBuildFile; fileRef = B60C16641988999D00E97A6C /* VersionMigrations.m */; }; B60EDE041A05A01700D73516 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B60EDE031A05A01700D73516 /* AudioToolbox.framework */; }; + B60FB9A71A46F099006A5A66 /* TSAllocAttachmentRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = B60FB9A61A46F099006A5A66 /* TSAllocAttachmentRequest.m */; }; + B60FB9AD1A46F831006A5A66 /* UIImage+contentTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = B60FB9AC1A46F831006A5A66 /* UIImage+contentTypes.m */; }; + B60FB9B01A4711D4006A5A66 /* TSAttachmentEncryptionResult.m in Sources */ = {isa = PBXBuildFile; fileRef = B60FB9AF1A4711D4006A5A66 /* TSAttachmentEncryptionResult.m */; }; B62D53F71A23CCAD009AAF82 /* TSMessageAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */; }; B633C5801A1D190B0059AC12 /* archive@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B633C4FE1A1D190B0059AC12 /* archive@2x.png */; }; B633C5831A1D190B0059AC12 /* backspace.png in Resources */ = {isa = PBXBuildFile; fileRef = B633C5011A1D190B0059AC12 /* backspace.png */; }; @@ -336,10 +339,10 @@ B63AF5CD1A1F757900D01AAD /* TSRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = B63AF5B91A1F757900D01AAD /* TSRequest.m */; }; B63AF5CE1A1F757900D01AAD /* TSAttachmentRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = B63AF5BB1A1F757900D01AAD /* TSAttachmentRequest.m */; }; B63AF5D01A1F757900D01AAD /* TSSubmitMessageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = B63AF5BF1A1F757900D01AAD /* TSSubmitMessageRequest.m */; }; - B63AF5D11A1F757900D01AAD /* TSUploadAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = B63AF5C11A1F757900D01AAD /* TSUploadAttachment.m */; }; B63AF5D21A1F757900D01AAD /* TSNetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B63AF5C31A1F757900D01AAD /* TSNetworkManager.m */; }; B63AF5D31A1F757900D01AAD /* TSSocketManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B63AF5C61A1F757900D01AAD /* TSSocketManager.m */; }; B63AF5D81A1F889500D01AAD /* SubProtocol.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = B63AF5D71A1F889500D01AAD /* SubProtocol.pb.m */; settings = {COMPILER_FLAGS = "-w"; }; }; + B640C4771A477B0F005C7C8A /* TSAttachementsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B640C4761A477B0F005C7C8A /* TSAttachementsTest.m */; }; B6416FB8199A0478003C5699 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6416F57199A0478003C5699 /* Localizable.strings */; }; B65EDA1219E1BE6400AAA7CB /* RPAPICall.m in Sources */ = {isa = PBXBuildFile; fileRef = B65EDA1119E1BE6400AAA7CB /* RPAPICall.m */; }; B66DBF4A19D5BBC8006EA940 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B66DBF4919D5BBC8006EA940 /* Images.xcassets */; }; @@ -884,6 +887,12 @@ B60C16631988999D00E97A6C /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VersionMigrations.h; sourceTree = ""; }; B60C16641988999D00E97A6C /* VersionMigrations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VersionMigrations.m; sourceTree = ""; }; B60EDE031A05A01700D73516 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; + B60FB9A51A46F099006A5A66 /* TSAllocAttachmentRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAllocAttachmentRequest.h; sourceTree = ""; }; + B60FB9A61A46F099006A5A66 /* TSAllocAttachmentRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAllocAttachmentRequest.m; sourceTree = ""; }; + B60FB9AB1A46F831006A5A66 /* UIImage+contentTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+contentTypes.h"; sourceTree = ""; }; + B60FB9AC1A46F831006A5A66 /* UIImage+contentTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+contentTypes.m"; sourceTree = ""; }; + B60FB9AE1A4711D4006A5A66 /* TSAttachmentEncryptionResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAttachmentEncryptionResult.h; sourceTree = ""; }; + B60FB9AF1A4711D4006A5A66 /* TSAttachmentEncryptionResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentEncryptionResult.m; sourceTree = ""; }; B62D53F51A23CCAD009AAF82 /* TSMessageAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSMessageAdapter.h; sourceTree = ""; }; B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSMessageAdapter.m; sourceTree = ""; }; B633C4FE1A1D190B0059AC12 /* archive@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "archive@2x.png"; sourceTree = ""; }; @@ -949,14 +958,13 @@ B63AF5BB1A1F757900D01AAD /* TSAttachmentRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentRequest.m; sourceTree = ""; }; B63AF5BE1A1F757900D01AAD /* TSSubmitMessageRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSSubmitMessageRequest.h; sourceTree = ""; }; B63AF5BF1A1F757900D01AAD /* TSSubmitMessageRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSSubmitMessageRequest.m; sourceTree = ""; }; - B63AF5C01A1F757900D01AAD /* TSUploadAttachment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSUploadAttachment.h; sourceTree = ""; }; - B63AF5C11A1F757900D01AAD /* TSUploadAttachment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSUploadAttachment.m; sourceTree = ""; }; B63AF5C21A1F757900D01AAD /* TSNetworkManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSNetworkManager.h; sourceTree = ""; }; B63AF5C31A1F757900D01AAD /* TSNetworkManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSNetworkManager.m; sourceTree = ""; }; B63AF5C51A1F757900D01AAD /* TSSocketManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSSocketManager.h; sourceTree = ""; }; B63AF5C61A1F757900D01AAD /* TSSocketManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSSocketManager.m; sourceTree = ""; }; B63AF5D61A1F889500D01AAD /* SubProtocol.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SubProtocol.pb.h; sourceTree = ""; }; B63AF5D71A1F889500D01AAD /* SubProtocol.pb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SubProtocol.pb.m; sourceTree = ""; }; + B640C4761A477B0F005C7C8A /* TSAttachementsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachementsTest.m; sourceTree = ""; }; B6416F58199A0478003C5699 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Localizable.strings; sourceTree = ""; }; B657DDC91911A40500F45B0C /* Signal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Signal.entitlements; sourceTree = ""; }; B65EDA1019E1BE6400AAA7CB /* RPAPICall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RPAPICall.h; sourceTree = ""; }; @@ -2221,6 +2229,8 @@ B63AF5AB1A1F757900D01AAD /* Requests */ = { isa = PBXGroup; children = ( + B60FB9A51A46F099006A5A66 /* TSAllocAttachmentRequest.h */, + B60FB9A61A46F099006A5A66 /* TSAllocAttachmentRequest.m */, B63AF5AC1A1F757900D01AAD /* TSContactsIntersectionRequest.h */, B63AF5AD1A1F757900D01AAD /* TSContactsIntersectionRequest.m */, B63AF5AE1A1F757900D01AAD /* TSUnregisterAccountRequest.h */, @@ -2239,8 +2249,6 @@ B63AF5BB1A1F757900D01AAD /* TSAttachmentRequest.m */, B63AF5BE1A1F757900D01AAD /* TSSubmitMessageRequest.h */, B63AF5BF1A1F757900D01AAD /* TSSubmitMessageRequest.m */, - B63AF5C01A1F757900D01AAD /* TSUploadAttachment.h */, - B63AF5C11A1F757900D01AAD /* TSUploadAttachment.m */, ); path = Requests; sourceTree = ""; @@ -2292,6 +2300,7 @@ B6B095E11A1D25C5008BFAA6 /* TSStorageIdentityKeyStoreTests.m */, B6B095E21A1D25C5008BFAA6 /* TSStoragePreKeyStoreTests.m */, B6B095E31A1D25C5008BFAA6 /* TSStorageSignedPreKeyStore.m */, + B640C4761A477B0F005C7C8A /* TSAttachementsTest.m */, ); path = textsecure; sourceTree = ""; @@ -2367,14 +2376,14 @@ B6B096101A1D25ED008BFAA6 /* TSInteraction.m */, B6B096111A1D25ED008BFAA6 /* TSMessage.h */, B6B096121A1D25ED008BFAA6 /* TSMessage.m */, + B6B50AA91A4192C500F8F607 /* TSMessagesManager+attachments.h */, + B6B50AAA1A4192C500F8F607 /* TSMessagesManager+attachments.m */, B63885CB1A26772D00A226A6 /* TSMessagesManager+callRecorder.h */, B63885CC1A26772D00A226A6 /* TSMessagesManager+callRecorder.m */, B6B096131A1D25ED008BFAA6 /* TSMessagesManager+sendMessages.h */, B6B096141A1D25ED008BFAA6 /* TSMessagesManager+sendMessages.m */, B6B096151A1D25ED008BFAA6 /* TSMessagesManager.h */, B6B096161A1D25ED008BFAA6 /* TSMessagesManager.m */, - B6B50AA91A4192C500F8F607 /* TSMessagesManager+attachments.h */, - B6B50AAA1A4192C500F8F607 /* TSMessagesManager+attachments.m */, B6B096171A1D25ED008BFAA6 /* TSOutgoingMessage.h */, B6B096181A1D25ED008BFAA6 /* TSOutgoingMessage.m */, B6B096191A1D25ED008BFAA6 /* TSServerMessage.h */, @@ -2445,6 +2454,10 @@ B6B096601A1D25ED008BFAA6 /* NSURLSessionDataTask+StatusCode.m */, B6019E951A2492AB001118DF /* NSDate+millisecondTimeStamp.h */, B6019E961A2492AB001118DF /* NSDate+millisecondTimeStamp.mm */, + B60FB9AB1A46F831006A5A66 /* UIImage+contentTypes.h */, + B60FB9AC1A46F831006A5A66 /* UIImage+contentTypes.m */, + B60FB9AE1A4711D4006A5A66 /* TSAttachmentEncryptionResult.h */, + B60FB9AF1A4711D4006A5A66 /* TSAttachmentEncryptionResult.m */, ); path = Util; sourceTree = ""; @@ -3082,6 +3095,7 @@ buildActionMask = 2147483647; files = ( 76EB063E18170B33006006FC /* Operation.m in Sources */, + B60FB9AD1A46F831006A5A66 /* UIImage+contentTypes.m in Sources */, 76EB05F618170B33006006FC /* CallConnectUtil.m in Sources */, 76EB061218170B33006006FC /* LoggingUtil.m in Sources */, A56977921A351BC400173BF2 /* PresentIdentityQRCodeViewController.m in Sources */, @@ -3225,6 +3239,7 @@ FC31962A1A067D8F0094C78E /* MessageComposeTableViewController.m in Sources */, E16E5BEE18AAC40200B7C403 /* EC25KeyAgreementParticipant.m in Sources */, 76EB057418170B33006006FC /* RecentCallManager.m in Sources */, + B60FB9A71A46F099006A5A66 /* TSAllocAttachmentRequest.m in Sources */, 76EB061C18170B33006006FC /* ArrayUtil.m in Sources */, 76EB05C418170B33006006FC /* HandshakePacket.m in Sources */, 76EB05AA18170B33006006FC /* SequenceCounter.m in Sources */, @@ -3235,13 +3250,13 @@ B6B096881A1D25ED008BFAA6 /* TSStorageManager+keyFromIntLong.m in Sources */, B6B50AAB1A4192C500F8F607 /* TSMessagesManager+attachments.m in Sources */, 76EB059018170B33006006FC /* IgnoredPacketFailure.m in Sources */, + B60FB9B01A4711D4006A5A66 /* TSAttachmentEncryptionResult.m in Sources */, 765052AF182AC9B5008313E1 /* DialerButtonView.m in Sources */, 76EB05D418170B33006006FC /* ZrtpManager.m in Sources */, B63AF5CD1A1F757900D01AAD /* TSRequest.m in Sources */, 76EB058E18170B33006006FC /* HostNameEndPoint.m in Sources */, E19167A418A9687800B7A468 /* DH3KKeyAgreementParticipant.m in Sources */, E16E5BF018AAC40200B7C403 /* EvpKeyAgreement.m in Sources */, - B63AF5D11A1F757900D01AAD /* TSUploadAttachment.m in Sources */, FCFD25821A154B3800F4C644 /* CodeVerificationViewController.m in Sources */, FCF72A131A02D27F006BC849 /* ContactDetailTableViewController.m in Sources */, B65EDA1219E1BE6400AAA7CB /* RPAPICall.m in Sources */, @@ -3379,6 +3394,7 @@ A157076117F0CD6D007C2BD6 /* RtpPacketTests.m in Sources */, 76EB05C518170B33006006FC /* HandshakePacket.m in Sources */, 76EB058F18170B33006006FC /* HostNameEndPoint.m in Sources */, + B640C4771A477B0F005C7C8A /* TSAttachementsTest.m in Sources */, 76EB062118170B33006006FC /* BloomFilter.m in Sources */, 76EB064518170B33006006FC /* ThreadManager.m in Sources */, 76EB068718170B34006006FC /* ContactTableViewCell.m in Sources */, diff --git a/Signal/src/Storyboard/Storyboard.storyboard b/Signal/src/Storyboard/Storyboard.storyboard index f4587b8e0..f718d6e54 100755 --- a/Signal/src/Storyboard/Storyboard.storyboard +++ b/Signal/src/Storyboard/Storyboard.storyboard @@ -1,5 +1,5 @@ - + diff --git a/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.h b/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.h index b8876801e..837a7dc9b 100644 --- a/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.h +++ b/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.h @@ -15,7 +15,7 @@ - (instancetype)initWithIdentifier:(uint64_t)identifier key:(NSData*)key contentType:(NSString*)contentType - relay:(NSString*)relay; + relay:(NSString*)relay NS_DESIGNATED_INITIALIZER;; @property NSString *relay; diff --git a/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.h b/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.h index 040cdc378..2ef09e91e 100644 --- a/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.h +++ b/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.h @@ -13,13 +13,11 @@ - (instancetype)initWithIdentifier:(NSString*)identifier data:(NSData*)data key:(NSData*)key - contentType:(NSString*)contentType; + contentType:(NSString*)contentType NS_DESIGNATED_INITIALIZER;; -- (NSString*)path; +- (UIImage *)image; - (BOOL)isImage; -- (UIImage*)image; - - (BOOL)isVideo; @end diff --git a/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m b/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m index a59d66354..0b9e548f6 100644 --- a/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m +++ b/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m @@ -62,6 +62,14 @@ } } +- (BOOL)isVideo{ + if ([self.contentType containsString:@"video/"]) { + return YES; + } else{ + return NO; + } +} + - (UIImage*)image{ if (![self isImage]) { return nil; diff --git a/Signal/src/textsecure/Messages/TSAttachment.h b/Signal/src/textsecure/Messages/TSAttachment.h index 0e2644b3f..50270cb4f 100644 --- a/Signal/src/textsecure/Messages/TSAttachment.h +++ b/Signal/src/textsecure/Messages/TSAttachment.h @@ -22,5 +22,4 @@ encryptionKey:(NSData*)encryptionKey contentType:(NSString*)contentType; - @end diff --git a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.h b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.h index 5e75c7d94..bdc0772a4 100644 --- a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.h +++ b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.h @@ -13,5 +13,6 @@ - (void)handleReceivedMediaMessage:(IncomingPushMessageSignal*)message withContent:(PushMessageContent*)content; - (void)retrieveAttachment:(TSAttachment*)attachment; +- (void)sendAttachment:(NSData*)attachmentData contentType:(NSString*)contentType thread:(TSThread*)thread; @end diff --git a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m index dd390580f..45d129fdd 100644 --- a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m +++ b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m @@ -11,12 +11,15 @@ #import "Cryptography.h" -#import "TSConstants.h" -#import "TSMessagesManager+attachments.h" +#import "TSAllocAttachmentRequest.h" +#import "TSAttachmentEncryptionResult.h" +#import "TSAttachmentPointer.h" +#import "TSAttachmentStream.h" #import "TSAttachmentRequest.h" -#import "TSUploadAttachment.h" +#import "TSConstants.h" #import "TSInfoMessage.h" -#import "TSattachmentPointer.h" +#import "TSMessagesManager+attachments.h" +#import "TSMessagesManager+sendMessages.h" #import "TSNetworkManager.h" @interface TSMessagesManager () @@ -53,6 +56,39 @@ dispatch_queue_t attachmentsQueue() { [self handleReceivedMessage:message withContent:content attachments:attachments]; } +- (void)sendAttachment:(NSData*)attachmentData contentType:(NSString*)contentType thread:(TSThread*)thread { + + TSRequest *allocateAttachment = [[TSAllocAttachmentRequest alloc] init]; + [[TSNetworkManager sharedManager] queueAuthenticatedRequest:allocateAttachment success:^(NSURLSessionDataTask *task, id responseObject) { + dispatch_async(attachmentsQueue(), ^{ + if ([responseObject isKindOfClass:[NSDictionary class]]){ + NSDictionary *responseDict = (NSDictionary*)responseObject; + NSString *attachementId = [[responseDict objectForKey:@"id"] stringValue]; + NSString *location = [responseDict objectForKey:@"location"]; + + TSAttachmentEncryptionResult *result = + [Cryptography encryptAttachment:attachmentData contentType:contentType identifier:attachementId]; + + BOOL success = [self uploadData:result.body location:location]; + + if (success) { + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [result.pointer saveWithTransaction:transaction]; + }]; + TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:thread messageBody:nil attachments:@[attachementId]]; + [self sendMessage:message inThread:thread]; + } else{ + DDLogWarn(@"Failed to upload attachment"); + } + } else{ + DDLogError(@"The server didn't returned an empty responseObject"); + } + }); + } failure:^(NSURLSessionDataTask *task, NSError *error) { + DDLogError(@"Failed to get attachment allocated: %@", error); + }]; +} + - (void)retrieveAttachment:(TSAttachmentPointer*)attachment { TSAttachmentRequest *attachmentRequest = [[TSAttachmentRequest alloc] initWithId:[attachment identifier] @@ -74,6 +110,21 @@ dispatch_queue_t attachmentsQueue() { }]; } +- (void)decryptedAndSaveAttachment:(TSAttachmentPointer*)attachment data:(NSData*)cipherText { + NSData *plaintext = [Cryptography decryptAttachment:cipherText withKey:attachment.encryptionKey]; + + if (!plaintext) { + DDLogError(@"Failed to get attachment decrypted ..."); + } else { + TSAttachmentStream *stream = [[TSAttachmentStream alloc] initWithIdentifier:attachment.uniqueId + data:plaintext key:attachment.encryptionKey + contentType:attachment.contentType]; + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [stream saveWithTransaction:transaction]; + }]; + } +} + - (NSData*)downloadFromLocation:(NSString*)location { __block NSData *data; @@ -96,21 +147,31 @@ dispatch_queue_t attachmentsQueue() { return data; } -- (void)decryptedAndSaveAttachment:(TSAttachmentPointer*)attachment data:(NSData*)cipherText { - NSData *plaintext = [Cryptography decryptAttachment:cipherText withKey:attachment.encryptionKey]; +- (BOOL)uploadData:(NSData*)cipherText location:(NSString*)location { + AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; + manager.responseSerializer = [AFHTTPResponseSerializer serializer]; + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + __block BOOL success = NO; - if (!plaintext) { - DDLogError(@"Failed to get attachment decrypted ..."); - } else { - TSAttachmentStream *stream = [[TSAttachmentStream alloc] initWithIdentifier:attachment.uniqueId - data:plaintext key:attachment.encryptionKey - contentType:attachment.contentType]; - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [stream saveWithTransaction:transaction]; - }]; - NSLog(@"We got %@ of type %@", plaintext, attachment.contentType); - } + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:location]]; + request.HTTPMethod = @"PUT"; + request.HTTPBody = cipherText; + [request setValue:@"application/octet-stream" forHTTPHeaderField:@"Content-Type"]; + + AFHTTPRequestOperation *httpOperation = [manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) { + success = YES; + dispatch_semaphore_signal(sema); + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + DDLogError(@"Failed uploading attachment with error: %@", error.description); + success = NO; + dispatch_semaphore_signal(sema); + }]; + + [httpOperation start]; + + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + return success; } @end diff --git a/Signal/src/textsecure/Messages/TSMessagesManager+sendMessages.m b/Signal/src/textsecure/Messages/TSMessagesManager+sendMessages.m index bde3d99ef..be2b5dba7 100644 --- a/Signal/src/textsecure/Messages/TSMessagesManager+sendMessages.m +++ b/Signal/src/textsecure/Messages/TSMessagesManager+sendMessages.m @@ -21,8 +21,8 @@ #import "TSStorageManager+SignedPreKeyStore.h" #import "PreKeyBundle+jsonDict.h" -#import "TSErrorMessage.h" +#import "TSAttachmentStream.h" #import "TSNetworkManager.h" #import "TSServerMessage.h" #import "TSSubmitMessageRequest.h" @@ -219,9 +219,27 @@ dispatch_queue_t sendingQueue() { PushMessageContentBuilder *builder = [PushMessageContentBuilder new]; [builder setBody:message.body]; - return [builder.build data]; - //TO-DO: DEAL WITH ATTACHEMENTS AND GROUPS STUFF + NSMutableArray *attachmentsArray = [NSMutableArray array]; + + for (NSString *attachmentId in message.attachments){ + id dbObject = [TSAttachmentStream fetchObjectWithUniqueID:attachmentId]; + + if ([dbObject isKindOfClass:[TSAttachmentStream class]]) { + TSAttachmentStream *attachment = (TSAttachmentStream*)dbObject; + + PushMessageContentAttachmentPointerBuilder *attachmentbuilder = [PushMessageContentAttachmentPointerBuilder new]; + [attachmentbuilder setId:[attachment.identifier unsignedLongLongValue]]; + [attachmentbuilder setContentType:attachment.contentType]; + [attachmentbuilder setKey:attachment.encryptionKey]; + + [attachmentsArray addObject:[attachmentbuilder build]]; + } + } + + [builder setAttachmentsArray:attachmentsArray]; + + return [builder.build data]; } @end diff --git a/Signal/src/textsecure/Network/API/Requests/TSAllocAttachmentRequest.h b/Signal/src/textsecure/Network/API/Requests/TSAllocAttachmentRequest.h new file mode 100644 index 000000000..3864ab2af --- /dev/null +++ b/Signal/src/textsecure/Network/API/Requests/TSAllocAttachmentRequest.h @@ -0,0 +1,13 @@ +// +// TSAllocAttachmentRequest.h +// Signal +// +// Created by Frederic Jacobs on 21/12/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import "TSRequest.h" + +@interface TSAllocAttachmentRequest : TSRequest + +@end diff --git a/Signal/src/textsecure/Network/API/Requests/TSAllocAttachmentRequest.m b/Signal/src/textsecure/Network/API/Requests/TSAllocAttachmentRequest.m new file mode 100644 index 000000000..78d32d6c4 --- /dev/null +++ b/Signal/src/textsecure/Network/API/Requests/TSAllocAttachmentRequest.m @@ -0,0 +1,26 @@ +// +// TSAllocAttachmentRequest.m +// Signal +// +// Created by Frederic Jacobs on 21/12/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import "TSAllocAttachmentRequest.h" +#import "TSConstants.h" + +@implementation TSAllocAttachmentRequest + +-(instancetype)init { + NSString *path = [NSString stringWithFormat:@"%@", textSecureAttachmentsAPI]; + + self = [super initWithURL:[NSURL URLWithString:path]]; + + if (self) { + [self setHTTPMethod:@"GET"]; + } + + return self; +} + +@end diff --git a/Signal/src/textsecure/Network/API/Requests/TSUploadAttachment.h b/Signal/src/textsecure/Network/API/Requests/TSUploadAttachment.h deleted file mode 100644 index ed3644b5e..000000000 --- a/Signal/src/textsecure/Network/API/Requests/TSUploadAttachment.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// TSUploadAttachment.h -// TextSecureiOS -// -// Created by Christine Corbett Moran on 12/3/13. -// Copyright (c) 2013 Open Whisper Systems. All rights reserved. -// - -#import "TSRequest.h" -#import "TSAttachmentStream.h" - -@interface TSUploadAttachment : TSRequest - --(TSRequest*) initWithAttachment:(TSAttachmentStream*)attachment; - -@end diff --git a/Signal/src/textsecure/Network/API/Requests/TSUploadAttachment.m b/Signal/src/textsecure/Network/API/Requests/TSUploadAttachment.m deleted file mode 100644 index 27d2973bc..000000000 --- a/Signal/src/textsecure/Network/API/Requests/TSUploadAttachment.m +++ /dev/null @@ -1,32 +0,0 @@ -// -// TSUploadAttachment.m -// TextSecureiOS -// -// Created by Christine Corbett Moran on 12/3/13. -// Copyright (c) 2013 Open Whisper Systems. All rights reserved. -// - -#import "TSUploadAttachment.h" -#import "TSAttachmentStream.h" -#import - -@interface TSUploadAttachment () -@property(nonatomic,strong) TSAttachment* attachment; -@end - -@implementation TSUploadAttachment - --(TSRequest*) initWithAttachment:(TSAttachmentStream*)attachment{ - -// self = [super initWithURL:attachment.attachmentURL]; -// self.HTTPMethod = @"PUT"; -// self.attachment = attachment; -// -// [self setHTTPBody:[self.attachment getData]]; -// [self setAllHTTPHeaderFields: @{@"Content-Type": @"application/octet-stream"}]; -// -// return self; - -} - -@end diff --git a/Signal/src/textsecure/Network/API/TSNetworkManager.m b/Signal/src/textsecure/Network/API/TSNetworkManager.m index 6254e3b3d..3d686bada 100644 --- a/Signal/src/textsecure/Network/API/TSNetworkManager.m +++ b/Signal/src/textsecure/Network/API/TSNetworkManager.m @@ -14,7 +14,6 @@ #import "TSRequest.h" #import "TSRegisterWithTokenRequest.h" #import "TSStorageManager+keyingMaterial.h" -#import "TSUploadAttachment.h" @interface TSNetworkManager () diff --git a/Signal/src/textsecure/Util/Cryptography.h b/Signal/src/textsecure/Util/Cryptography.h index 89ec15879..3ddfd731c 100755 --- a/Signal/src/textsecure/Util/Cryptography.h +++ b/Signal/src/textsecure/Util/Cryptography.h @@ -7,6 +7,7 @@ // #import +#import "TSAttachmentEncryptionResult.h" @interface Cryptography : NSObject @@ -32,7 +33,6 @@ typedef NS_ENUM(NSInteger, TSMACType) { #pragma mark encrypt and decrypt attachment data +(NSData*) decryptAttachment:(NSData*)dataToDecrypt withKey:(NSData*)key ; -+(NSData*) encryptAttachment:(NSData*)attachment withRandomKey:(NSData**)key; - ++(TSAttachmentEncryptionResult*)encryptAttachment:(NSData*)attachment contentType:(NSString*)contentType identifier:(NSString*)identifier; @end diff --git a/Signal/src/textsecure/Util/Cryptography.m b/Signal/src/textsecure/Util/Cryptography.m index 6774ed141..b5ff5cc77 100755 --- a/Signal/src/textsecure/Util/Cryptography.m +++ b/Signal/src/textsecure/Util/Cryptography.m @@ -6,13 +6,15 @@ // Copyright (c) 2013 Open Whisper Systems. All rights reserved. // -#import "Cryptography.h" -#import "Constraints.h" #import #import #import -#include "NSData+Base64.h" +#import "Cryptography.h" +#import "Constraints.h" +#import "TSAttachmentStream.h" + +#import "NSData+Base64.h" #define HMAC256_KEY_LENGTH 32 #define HMAC256_OUTPUT_LENGTH 32 @@ -138,9 +140,10 @@ if(hmacType == TSHMACSHA1Truncated10Bytes) { *hmac = [Cryptography truncatedSHA1HMAC:dataToHmac withHMACKey:hmacKey truncation:10]; - } - else if (hmacType == TSHMACSHA256Truncated10Bytes) { + } else if (hmacType == TSHMACSHA256Truncated10Bytes) { *hmac = [Cryptography truncatedSHA256HMAC:dataToHmac withHMACKey:hmacKey truncation:10]; + } else if (hmacType == TSHMACSHA256AttachementType) { + *hmac = [Cryptography truncatedSHA256HMAC:dataToHmac withHMACKey:hmacKey truncation:HMAC256_OUTPUT_LENGTH]; } return encryptedData; @@ -240,7 +243,7 @@ } -+(NSData*) decryptAttachment:(NSData*) dataToDecrypt withKey:(NSData*) key { ++ (NSData*)decryptAttachment:(NSData*)dataToDecrypt withKey:(NSData*)key { if (([dataToDecrypt length] < AES_CBC_IV_LENGTH + HMAC256_OUTPUT_LENGTH) || ([key length] < AES_KEY_SIZE + HMAC256_KEY_LENGTH)) { DDLogError(@"Message shorter than crypto overhead!"); return nil; @@ -254,35 +257,39 @@ NSData *iv = [dataToDecrypt subdataWithRange:NSMakeRange(0, AES_CBC_IV_LENGTH)]; NSData *encryptedAttachment = [dataToDecrypt subdataWithRange:NSMakeRange(AES_CBC_IV_LENGTH, [dataToDecrypt length]-AES_CBC_IV_LENGTH-HMAC256_OUTPUT_LENGTH)]; NSData *hmac = [dataToDecrypt subdataWithRange:NSMakeRange([dataToDecrypt length]-HMAC256_OUTPUT_LENGTH, HMAC256_OUTPUT_LENGTH)]; - return [Cryptography decryptCBCMode:encryptedAttachment key:encryptionKey IV:iv version:nil HMACKey:hmacKey HMACType:TSHMACSHA256AttachementType matchingHMAC:hmac]; + + return [Cryptography decryptCBCMode:encryptedAttachment + key:encryptionKey + IV:iv version:nil + HMACKey:hmacKey + HMACType:TSHMACSHA256AttachementType + matchingHMAC:hmac]; } - - - -+(NSData*) encryptAttachment:(NSData*) attachment withRandomKey:(NSData**)key{ - // generate - // random 10 byte IV - // key: 32 byte AES key || 32 byte Hmac-SHA256 key. - // returns: IV || Ciphertext || truncated MAC(IV||Ciphertext) - NSData* iv = [Cryptography generateRandomBytes:10]; - NSData* encryptionKey = [Cryptography generateRandomBytes:32]; - NSData* hmacKey = [Cryptography generateRandomBytes:32]; ++ (TSAttachmentEncryptionResult*)encryptAttachment:(NSData*)attachment contentType:(NSString*)contentType identifier:(NSString*)identifier { + + NSData* iv = [Cryptography generateRandomBytes:AES_CBC_IV_LENGTH]; + NSData* encryptionKey = [Cryptography generateRandomBytes:AES_KEY_SIZE]; + NSData* hmacKey = [Cryptography generateRandomBytes:HMAC256_KEY_LENGTH]; // The concatenated key for storage NSMutableData *outKey = [NSMutableData data]; [outKey appendData:encryptionKey]; [outKey appendData:hmacKey]; - *key = [NSData dataWithData:outKey]; NSData* computedHMAC; - NSData* ciphertext = [Cryptography encryptCBCMode:attachment withKey:encryptionKey withIV:iv withVersion:nil withHMACKey:hmacKey withHMACType:TSHMACSHA256Truncated10Bytes computedHMAC:&computedHMAC]; + NSData* ciphertext = [Cryptography encryptCBCMode:attachment withKey:encryptionKey withIV:iv withVersion:nil withHMACKey:hmacKey withHMACType:TSHMACSHA256AttachementType computedHMAC:&computedHMAC]; NSMutableData* encryptedAttachment = [NSMutableData data]; [encryptedAttachment appendData:iv]; [encryptedAttachment appendData:ciphertext]; [encryptedAttachment appendData:computedHMAC]; - return encryptedAttachment; + + NSLog(@"Resulting IV: %@ cipherText: %@ hmac: %@", iv, ciphertext, computedHMAC); + + TSAttachmentStream *pointer = [[TSAttachmentStream alloc] initWithIdentifier:identifier data:attachment key:outKey contentType:contentType]; + + return [[TSAttachmentEncryptionResult alloc] initWithPointer:pointer body:encryptedAttachment]; } @end diff --git a/Signal/src/textsecure/Util/TSAttachmentEncryptionResult.h b/Signal/src/textsecure/Util/TSAttachmentEncryptionResult.h new file mode 100644 index 000000000..a5597e894 --- /dev/null +++ b/Signal/src/textsecure/Util/TSAttachmentEncryptionResult.h @@ -0,0 +1,20 @@ +// +// TSAttachmentEncryptionResult.h +// Signal +// +// Created by Frederic Jacobs on 21/12/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import +#import "TSAttachmentStream.h" + +@interface TSAttachmentEncryptionResult : NSData + +@property (readonly) TSAttachmentStream *pointer; +@property (readonly) NSData *body; + +- (instancetype)initWithPointer:(TSAttachmentStream*)pointer + body:(NSData*)cipherText; + +@end diff --git a/Signal/src/textsecure/Util/TSAttachmentEncryptionResult.m b/Signal/src/textsecure/Util/TSAttachmentEncryptionResult.m new file mode 100644 index 000000000..0e1535063 --- /dev/null +++ b/Signal/src/textsecure/Util/TSAttachmentEncryptionResult.m @@ -0,0 +1,25 @@ +// +// TSAttachmentEncryptionResult.m +// Signal +// +// Created by Frederic Jacobs on 21/12/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import "TSAttachmentEncryptionResult.h" + +@implementation TSAttachmentEncryptionResult + +- (instancetype)initWithPointer:(TSAttachmentStream*)pointer + body:(NSData*)cipherText { + self = [super init]; + + if (self) { + _body = cipherText; + _pointer = pointer; + } + + return self; +} + +@end diff --git a/Signal/src/textsecure/Util/UIImage+contentTypes.h b/Signal/src/textsecure/Util/UIImage+contentTypes.h new file mode 100644 index 000000000..61a330cc9 --- /dev/null +++ b/Signal/src/textsecure/Util/UIImage+contentTypes.h @@ -0,0 +1,16 @@ +// +// UIImage+contentTypes.h +// Signal +// +// Created by Frederic Jacobs on 21/12/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import + +@interface UIImage (contentTypes) + +- (NSString*)contentType; +- (BOOL)isSupportedImageType; + +@end diff --git a/Signal/src/textsecure/Util/UIImage+contentTypes.m b/Signal/src/textsecure/Util/UIImage+contentTypes.m new file mode 100644 index 000000000..93feb6af9 --- /dev/null +++ b/Signal/src/textsecure/Util/UIImage+contentTypes.m @@ -0,0 +1,38 @@ +// +// UIImage+contentTypes.m +// Signal +// +// Created by Frederic Jacobs on 21/12/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import "UIImage+contentTypes.h" + +@implementation UIImage (contentTypes) + +- (NSString*)contentType { + uint8_t c; + [UIImagePNGRepresentation(self) getBytes:&c length:1]; + + switch (c) { + case 0xFF: + return @"image/jpeg"; + case 0x89: + return @"image/png"; + case 0x47: + return @"image/gif"; + case 0x49: + break; + case 0x42: + return @"image/bmp"; + case 0x4D: + return @"image/tiff"; + } + return nil; +} + +- (BOOL)isSupportedImageType { + return ([self contentType]?YES:NO); +} + +@end diff --git a/Signal/src/view controllers/InitialViewController.m b/Signal/src/view controllers/InitialViewController.m index c16b2536e..9e5a4c167 100644 --- a/Signal/src/view controllers/InitialViewController.m +++ b/Signal/src/view controllers/InitialViewController.m @@ -17,7 +17,6 @@ - (void)viewDidLoad { [super viewDidLoad]; - NSLog(@"%@",self.navigationController); [[Environment getCurrent]setSignUpFlowNavigationController:self.navigationController]; } diff --git a/Signal/src/view controllers/MessagesViewController.m b/Signal/src/view controllers/MessagesViewController.m index 5725d2146..2a2e75316 100644 --- a/Signal/src/view controllers/MessagesViewController.m +++ b/Signal/src/view controllers/MessagesViewController.m @@ -40,6 +40,7 @@ #import "TSAttachmentAdapter.h" #import "TSMessagesManager+sendMessages.h" +#import "TSMessagesManager+attachments.h" #import "NSDate+millisecondTimeStamp.h" #import "PhoneNumber.h" @@ -614,35 +615,10 @@ typedef enum : NSUInteger { NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType]; if (CFStringCompare ((__bridge_retained CFStringRef)mediaType, kUTTypeMovie, 0) == kCFCompareEqualTo) { - //Is a video - - NSURL* videoURL = [info objectForKey:UIImagePickerControllerMediaURL]; - AVURLAsset *asset1 = [[AVURLAsset alloc] initWithURL:videoURL options:nil]; - AVAssetImageGenerator *generate1 = [[AVAssetImageGenerator alloc] initWithAsset:asset1]; - generate1.appliesPreferredTrackTransform = YES; - NSError *err = NULL; - CMTime time = CMTimeMake(2, 1); - CGImageRef snapshotRef = [generate1 copyCGImageAtTime:time actualTime:NULL error:&err]; - __unused UIImage *snapshot = [[UIImage alloc] initWithCGImage:snapshotRef]; - - JSQVideoMediaItem * videoItem = [[JSQVideoMediaItem alloc] initWithFileURL:videoURL isReadyToPlay:YES]; - JSQMessage * videoMessage = [JSQMessage messageWithSenderId:self.senderId - displayName:self.senderDisplayName - media:videoItem]; - - self. - - [self finishSendingMessage]; - + DDLogWarn(@"Video formats not supported, yet"); } else if (picture_camera) { - //Is a photo - - JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] initWithImage:picture_camera]; - JSQMessage *photoMessage = [JSQMessage messageWithSenderId:self.senderId - displayName:self.senderDisplayName - media:photoItem]; - [self finishSendingMessage]; - + DDLogVerbose(@"Sending picture attachement ..."); + [[TSMessagesManager sharedManager] sendAttachment:UIImagePNGRepresentation(picture_camera) contentType:@"image/png" thread:self.thread]; } [self dismissViewControllerAnimated:YES completion:nil]; diff --git a/Signal/src/view controllers/TSMessageAdapter.m b/Signal/src/view controllers/TSMessageAdapter.m index 06f4905da..8c661dd41 100644 --- a/Signal/src/view controllers/TSMessageAdapter.m +++ b/Signal/src/view controllers/TSMessageAdapter.m @@ -88,8 +88,7 @@ TSMessage *message = (TSMessage*)interaction; adapter.messageBody = message.body; - if (message.attachments > 0) { - + if ([message.attachments count] > 0) { for (NSString *attachmentID in message.attachments) { TSAttachment *attachment = [TSAttachment fetchObjectWithUniqueID:attachmentID]; diff --git a/Signal/test/textsecure/TSAttachementsTest.m b/Signal/test/textsecure/TSAttachementsTest.m new file mode 100644 index 000000000..bf7a19996 --- /dev/null +++ b/Signal/test/textsecure/TSAttachementsTest.m @@ -0,0 +1,43 @@ +// +// TSAttachementsTest.m +// Signal +// +// Created by Frederic Jacobs on 21/12/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import + +#import "TSAttachmentStream.h" +#import "Cryptography.h" + +@interface TSAttachementsTest : XCTestCase + +@end + +@implementation TSAttachementsTest + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testAttachementEncryptionDecryption { + NSData *plaintext = [Cryptography generateRandomBytes:100]; + NSString *contentType = @"img/jpg"; + uint64_t identifier = 3063578577793591963; + NSNumber *number = [NSNumber numberWithUnsignedLongLong:identifier]; + + TSAttachmentEncryptionResult *encryptionResult = [Cryptography encryptAttachment:plaintext contentType:contentType identifier:[number stringValue]]; + + NSData *plaintextBis = [Cryptography decryptAttachment:encryptionResult.body withKey:encryptionResult.pointer.encryptionKey]; + + XCTAssert([plaintext isEqualToData:plaintextBis], @"Attachements encryption failed"); +} + +@end