Skip to content

Commit

Permalink
Receiving files works
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisballinger committed May 19, 2017
1 parent 098802d commit dcfd753
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 27 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@
[submodule "Carthage/Checkouts/SignalProtocol-ObjC"]
path = Carthage/Checkouts/SignalProtocol-ObjC
url = https://github.com/ChatSecure/SignalProtocol-ObjC.git
[submodule "Carthage/Checkouts/Mantle"]
path = Carthage/Checkouts/Mantle
url = https://github.com/Mantle/Mantle.git
1 change: 1 addition & 0 deletions Cartfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# github "ChatSecure/SignalProtocol-ObjC" ~> 1.0.0
github "ChatSecure/SignalProtocol-ObjC" "241f439"
github "ChatSecure/SignalProtocolC" "4335dfb"
github "Mantle/Mantle" ~> 2.1.0
1 change: 1 addition & 0 deletions Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
github "ChatSecure/SignalProtocol-ObjC" "241f439a80afd68d9199e73e95f1350ade893b53"
github "ChatSecure/SignalProtocolC" "4335dfb70f6eb036c409cea59ebc778f4d734c16"
github "Mantle/Mantle" "2.1.0"
1 change: 1 addition & 0 deletions Carthage/Checkouts/Mantle
Submodule Mantle added at d6b012
8 changes: 8 additions & 0 deletions ChatSecure.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,8 @@
D9AE3A331BA8D9AB00255537 /* OTRConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 633105EF1A16D1A300C17BAE /* OTRConstants.m */; };
D9B4B4AB1E64CB9D00B87B59 /* XMPPPushModule.h in Headers */ = {isa = PBXBuildFile; fileRef = D9B4B4A91E64CB9D00B87B59 /* XMPPPushModule.h */; settings = {ATTRIBUTES = (Public, ); }; };
D9B4B4AC1E64CB9D00B87B59 /* XMPPPushModule.m in Sources */ = {isa = PBXBuildFile; fileRef = D9B4B4AA1E64CB9D00B87B59 /* XMPPPushModule.m */; };
D9B79B951ECF951F00883963 /* OTRFileItem.h in Headers */ = {isa = PBXBuildFile; fileRef = D9B79B931ECF951F00883963 /* OTRFileItem.h */; };
D9B79B961ECF951F00883963 /* OTRFileItem.m in Sources */ = {isa = PBXBuildFile; fileRef = D9B79B941ECF951F00883963 /* OTRFileItem.m */; };
D9B7C5CE1EC3C9ED008D99E6 /* OTRAccountMigrator.m in Sources */ = {isa = PBXBuildFile; fileRef = D93718521EC267F800766D49 /* OTRAccountMigrator.m */; };
D9B7C5CF1EC3C9F2008D99E6 /* OTRAccountMigrator.h in Headers */ = {isa = PBXBuildFile; fileRef = D93718511EC267F800766D49 /* OTRAccountMigrator.h */; };
D9B9B1331DC7F3AC0007F5A7 /* UserInfoProfileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9B9B1311DC7F3AC0007F5A7 /* UserInfoProfileCell.swift */; };
Expand Down Expand Up @@ -1084,6 +1086,8 @@
D9AE3A2F1BA8D84500255537 /* OTRBranding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRBranding.m; sourceTree = "<group>"; };
D9B4B4A91E64CB9D00B87B59 /* XMPPPushModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XMPPPushModule.h; sourceTree = "<group>"; };
D9B4B4AA1E64CB9D00B87B59 /* XMPPPushModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XMPPPushModule.m; sourceTree = "<group>"; };
D9B79B931ECF951F00883963 /* OTRFileItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRFileItem.h; sourceTree = "<group>"; };
D9B79B941ECF951F00883963 /* OTRFileItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRFileItem.m; sourceTree = "<group>"; };
D9B9B1311DC7F3AC0007F5A7 /* UserInfoProfileCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserInfoProfileCell.swift; sourceTree = "<group>"; };
D9B9B1321DC7F3AC0007F5A7 /* UserInfoProfileCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = UserInfoProfileCell.xib; sourceTree = "<group>"; };
D9B9B1361DC802480007F5A7 /* OTRUserInfoProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRUserInfoProfile.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1646,6 +1650,8 @@
633620961A76E854006E8739 /* Media Items */ = {
isa = PBXGroup;
children = (
D9B79B931ECF951F00883963 /* OTRFileItem.h */,
D9B79B941ECF951F00883963 /* OTRFileItem.m */,
63D27FC31A6DC51C00EC251A /* OTRMediaItem.h */,
63D27FC41A6DC51C00EC251A /* OTRMediaItem.m */,
633620971A76E87B006E8739 /* OTRImageItem.h */,
Expand Down Expand Up @@ -2096,6 +2102,7 @@
D93DDB921BA79A9300CD8331 /* OTRXMPPBuddy.h in Headers */,
D93DDBA21BA79AA400CD8331 /* OTRWelcomeAccountTableViewDelegate.h in Headers */,
D93DDB831BA79A8800CD8331 /* OTRViewSetting.h in Headers */,
D9B79B951ECF951F00883963 /* OTRFileItem.h in Headers */,
637ABBC91DD5312200B18DD2 /* OTROutgoingMessage.h in Headers */,
D93DDB8C1BA79A8E00CD8331 /* OTRVideoItem.h in Headers */,
D93DDB821BA79A8700CD8331 /* OTRValueSetting.h in Headers */,
Expand Down Expand Up @@ -2923,6 +2930,7 @@
D91C86681E4E6DEE008BD763 /* ServerCapabilityInfo.swift in Sources */,
D93DDB001BA79A2900CD8331 /* OTRComposeViewController.m in Sources */,
63564E0D1BBB114B00EB4CA6 /* PushOTRListener.swift in Sources */,
D9B79B961ECF951F00883963 /* OTRFileItem.m in Sources */,
D93DDB011BA79A2900CD8331 /* OTRConversationViewController.m in Sources */,
D93DDB021BA79A2900CD8331 /* OTRDatabaseUnlockViewController.m in Sources */,
924F68611EA8A00D00528FB6 /* OTRServerDeprecation.swift in Sources */,
Expand Down
40 changes: 30 additions & 10 deletions ChatSecure/Classes/Controllers/FileTransferManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public class FileTransferManager: NSObject, OTRServerCapabilitiesDelegate {
// If there's a AES-GCM key, we gotta put it in the url
// and change the scheme to `aesgcm`
if var components = URLComponents(url: slot.getURL, resolvingAgainstBaseURL: true) {
components.scheme = "aesgcm"
components.scheme = URLScheme.aesgcm.rawValue
components.fragment = outKeyIv.hexString()
if let outURL = components.url {
completion(outURL, nil)
Expand Down Expand Up @@ -376,11 +376,18 @@ extension FileTransferManager {
DDLogWarn("Already downloaded media for this item")
return
}
guard let url = incomingMessage.downloadableURLs.first else {
guard var url = incomingMessage.downloadableURLs.first else {
// TODO: Only handles first URL. We cannot attach multiple media items yet.
DDLogWarn("No URLs found for media item")
return
}
// Turn aesgcm links into https links
if url.isAesGcm, var components = URLComponents(url: url, resolvingAgainstBaseURL: true) {
components.scheme = URLScheme.https.rawValue
if let rawURL = components.url {
url = rawURL
}
}

self.urlSession.getTasksWithCompletionHandler { (tasks, _, _) in
// Bail out if we've already got a task for this
Expand All @@ -390,15 +397,21 @@ extension FileTransferManager {
}

let request = URLRequest(url: url)
self.urlSession.dataTask(with: request, completionHandler: { (inData, urlResponse, error) in
DDLogVerbose("Downloading media item at URL: \(url)")
let task = self.urlSession.dataTask(with: request, completionHandler: { (inData, urlResponse, error) in
if let error = error {
DDLogError("Error downloading file \(error)")
return
}
guard var data = inData else { return }
guard var data = inData, let response = urlResponse else {
DDLogError("No data or response for URL \(url)")
return
}
DDLogVerbose("Received response \(response)")
let authTagSize = 16 // i'm not sure if this can be assumed, but how else would we know the size?
if let (key, iv) = url.aesGcmKey, data.count > authTagSize {

DDLogVerbose("Received encrypted response, attempting decryption...")

let cryptedData = data.subdata(in: 0..<data.count - authTagSize)
let authTag = data.subdata(in: data.count - authTagSize..<data.count)
let cryptoData = OTRCryptoData(data: cryptedData, authTag: authTag)
Expand All @@ -408,20 +421,27 @@ extension FileTransferManager {
DDLogError("Error decrypting data: \(error)")
return
}
DDLogVerbose("Decrpytion successful")
}
let media = OTRMediaItem(filename: url.lastPathComponent, mimeType: urlResponse?.mimeType, isIncoming: true)
incomingMessage.mediaItemUniqueId = media.uniqueId
let media = OTRMediaItem.incomingItem(withFilename: url.lastPathComponent, mimeType: urlResponse?.mimeType)
OTRMediaFileManager.sharedInstance().setData(data, for: media, buddyUniqueId: incomingMessage.buddyUniqueId, completion: { (bytesWritten, error) in
if let error = error {
DDLogError("Error copying data: \(error)")
return
}
self.connection.asyncReadWrite({ (transaction) in
media.transferProgress = 1.0
media.save(with: transaction)
incomingMessage.save(with: transaction)
if let message = incomingMessage.refetch(with: transaction) {
message.mediaItemUniqueId = media.uniqueId
message.save(with: transaction)
} else {
DDLogError("Message not found: \(incomingMessage)")
}
})
}, completionQueue: nil)
})
task.resume()
}
}
}
Expand Down Expand Up @@ -503,9 +523,9 @@ extension URL {

/** Has hex anchor with key and IV. 48 bytes w/ 16 iv + 32 key */
var anchorData: Data? {
if !isAesGcm { return nil }
guard let anchor = self.fragment else { return nil }
return anchor.dataFromHex()
let data = anchor.dataFromHex()
return data
}

var aesGcmKey: (key: Data, iv: Data)? {
Expand Down
18 changes: 1 addition & 17 deletions ChatSecure/Classes/Controllers/OTREncryptionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -597,23 +597,7 @@ - (void)dataHandler:(OTRDataHandler *)dataHandler offeredTransfer:(OTRDataIncomi
newMessage.messageSecurityInfo = [[OTRMessageEncryptionInfo alloc] initWithOTRFingerprint:fingerprint.fingerprint];
newMessage.text = nil;

NSRange imageRange = [transfer.mimeType rangeOfString:@"image"];
NSRange audioRange = [transfer.mimeType rangeOfString:@"audio"];
NSRange videoRange = [transfer.mimeType rangeOfString:@"video"];

OTRMediaItem *mediaItem = nil;
Class mediaClass = nil;
if(audioRange.location == 0) {
mediaClass = [OTRAudioItem class];
} else if (imageRange.location == 0) {
mediaClass = [OTRImageItem class];
} else if (videoRange.location == 0) {
mediaClass = [OTRVideoItem class];
}

if (mediaClass) {
mediaItem = [[mediaClass alloc] initWithFilename:transfer.fileName mimeType:transfer.mimeType isIncoming:YES];
}
OTRMediaItem *mediaItem = [OTRMediaItem incomingItemWithFilename:transfer.fileName mimeType:transfer.mimeType];

newMessage.mediaItemUniqueId = mediaItem.uniqueId;

Expand Down
14 changes: 14 additions & 0 deletions ChatSecure/Classes/Model/Yap Storage/OTRFileItem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// OTRFileItem.h
// ChatSecure
//
// Created by Chris Ballinger on 5/19/17.
// Copyright © 2017 Chris Ballinger. All rights reserved.
//

#import "OTRMediaItem.h"

/** This is a catch-all item for unknown file types */
@interface OTRFileItem : OTRMediaItem

@end
25 changes: 25 additions & 0 deletions ChatSecure/Classes/Model/Yap Storage/OTRFileItem.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// OTRFileItem.m
// ChatSecure
//
// Created by Chris Ballinger on 5/19/17.
// Copyright © 2017 Chris Ballinger. All rights reserved.
//

#import "OTRFileItem.h"

@implementation OTRFileItem

// Return empty view for now
- (UIView *)mediaView {
CGSize size = [self mediaViewDisplaySize];
CGRect frame = CGRectMake(0, 0, size.width, size.height);
return [[UIView alloc] initWithFrame:frame];
}

+ (NSString *)collection
{
return [OTRMediaItem collection];
}

@end
4 changes: 4 additions & 0 deletions ChatSecure/Classes/Model/Yap Storage/OTRMediaItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ NS_ASSUME_NONNULL_BEGIN
mimeType:(nullable NSString*)mimeType
isIncoming:(BOOL)isIncoming NS_DESIGNATED_INITIALIZER;

/** Returns the appropriate subclass (OTRImageItem, etc) for incoming file. Only image/audio/video supported at the moment. */
+ (instancetype) incomingItemWithFilename:(NSString*)filename
mimeType:(nullable NSString*)mimeType;

- (instancetype) init NS_UNAVAILABLE;

- (void)touchParentMessage DEPRECATED_MSG_ATTRIBUTE("Use touchParentMessageWithTransaction: instead.");
Expand Down
29 changes: 29 additions & 0 deletions ChatSecure/Classes/Model/Yap Storage/OTRMediaItem.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#import "OTRMediaItem.h"
#import "OTRImages.h"
#import "OTRFileItem.h"
@import JSQMessagesViewController;
@import YapDatabase;
@import OTRKit;
Expand All @@ -31,6 +32,34 @@ - (instancetype) initWithFilename:(NSString *)filename mimeType:(NSString*)mimeT
return self;
}

/** Returns the appropriate subclass (OTRImageItem, etc) for incoming file */
+ (instancetype) incomingItemWithFilename:(NSString*)filename
mimeType:(nullable NSString*)mimeType {
if (!mimeType) {
mimeType = OTRKitGetMimeTypeForExtension(filename.pathExtension);
}
NSRange imageRange = [mimeType rangeOfString:@"image"];
NSRange audioRange = [mimeType rangeOfString:@"audio"];
NSRange videoRange = [mimeType rangeOfString:@"video"];

OTRMediaItem *mediaItem = nil;
Class mediaClass = nil;
if(audioRange.location == 0) {
mediaClass = [OTRAudioItem class];
} else if (imageRange.location == 0) {
mediaClass = [OTRImageItem class];
} else if (videoRange.location == 0) {
mediaClass = [OTRVideoItem class];
} else {
mediaClass = [OTRFileItem class];
}

if (mediaClass) {
mediaItem = [[mediaClass alloc] initWithFilename:filename mimeType:mimeType isIncoming:YES];
}
return mediaItem;
}

- (NSString*) mimeType {
if (_mimeType) {
return _mimeType;
Expand Down

0 comments on commit dcfd753

Please sign in to comment.