Merge branch 'dev' into light-mode

pull/107/head
Niels Andriesse 5 years ago
commit a85875e4df

@ -1 +1 @@
Subproject commit 67dbced37481e0011a3df1397ed57711384a4957 Subproject commit 2870e676deec6a7ddb931edb6f0284f1f5b36085

@ -11,6 +11,8 @@ extern NSString *const AppDelegateStoryboardMain;
- (void)startLongPollerIfNeeded; - (void)startLongPollerIfNeeded;
- (void)stopLongPollerIfNeeded; - (void)stopLongPollerIfNeeded;
- (void)setUpDefaultPublicChatsIfNeeded; - (void)setUpDefaultPublicChatsIfNeeded;
- (void)startOpenGroupPollersIfNeeded;
- (void)stopOpenGroupPollersIfNeeded;
- (void)createRSSFeedsIfNeeded; - (void)createRSSFeedsIfNeeded;
- (void)startRSSFeedPollersIfNeeded; - (void)startRSSFeedPollersIfNeeded;

@ -177,7 +177,9 @@ static NSTimeInterval launchStartedAt;
[DDLog flushLog]; [DDLog flushLog];
// Loki: Stop pollers
[self stopLongPollerIfNeeded]; [self stopLongPollerIfNeeded];
[self stopOpenGroupPollersIfNeeded];
} }
- (void)applicationWillEnterForeground:(UIApplication *)application - (void)applicationWillEnterForeground:(UIApplication *)application
@ -196,7 +198,9 @@ static NSTimeInterval launchStartedAt;
[DDLog flushLog]; [DDLog flushLog];
// Loki: Stop pollers
[self stopLongPollerIfNeeded]; [self stopLongPollerIfNeeded];
[self stopOpenGroupPollersIfNeeded];
if (self.lokiP2PServer) { [self.lokiP2PServer stop]; } if (self.lokiP2PServer) { [self.lokiP2PServer stop]; }
} }
@ -316,9 +320,6 @@ static NSTimeInterval launchStartedAt;
name:NSNotificationName_2FAStateDidChange name:NSNotificationName_2FAStateDidChange
object:nil]; object:nil];
// Loki - Observe new messages received notifications
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleNewMessagesReceived:) name:NSNotification.newMessagesReceived object:nil];
// Loki - Observe thread deleted notifications // Loki - Observe thread deleted notifications
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleThreadDeleted:) name:NSNotification.threadDeleted object:nil]; [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleThreadDeleted:) name:NSNotification.threadDeleted object:nil];
@ -770,14 +771,32 @@ static NSTimeInterval launchStartedAt;
[self.socketManager requestSocketOpen]; [self.socketManager requestSocketOpen];
[Environment.shared.contactsManager fetchSystemContactsOnceIfAlreadyAuthorized]; [Environment.shared.contactsManager fetchSystemContactsOnceIfAlreadyAuthorized];
NSString *userHexEncodedPublicKey = self.tsAccountManager.localNumber;
// Loki: Tell our friends that we are online // Loki: Tell our friends that we are online
[LKP2PAPI broadcastOnlineStatus]; [LKP2PAPI broadcastOnlineStatus];
// Loki: Start long polling // Loki: Start pollers
[self startLongPollerIfNeeded]; [self startLongPollerIfNeeded];
[self startOpenGroupPollersIfNeeded];
// Loki: Get device links // Loki: Get device links
[LKFileServerAPI getDeviceLinksAssociatedWith:self.tsAccountManager.localNumber]; [[LKFileServerAPI getDeviceLinksAssociatedWith:userHexEncodedPublicKey] retainUntilComplete];
// Loki: Update profile picture if needed
NSUserDefaults *userDefaults = NSUserDefaults.standardUserDefaults;
NSDate *now = [NSDate new];
NSDate *lastProfilePictureUpload = (NSDate *)[userDefaults objectForKey:@"lastProfilePictureUpload"];
if (lastProfilePictureUpload != nil && [now timeIntervalSinceDate:lastProfilePictureUpload] > 14 * 24 * 60 * 60) {
OWSProfileManager *profileManager = OWSProfileManager.sharedManager;
NSString *displayName = [profileManager profileNameForRecipientId:userHexEncodedPublicKey];
UIImage *profilePicture = [profileManager profileAvatarForRecipientId:userHexEncodedPublicKey];
[profileManager updateLocalProfileName:displayName avatarImage:profilePicture success:^{
// Do nothing; the user defaults flag is updated in LokiFileServerAPI
} failure:^(NSError *error) {
// Do nothing
} requiresSync:YES];
}
if (![UIApplication sharedApplication].isRegisteredForRemoteNotifications) { if (![UIApplication sharedApplication].isRegisteredForRemoteNotifications) {
OWSLogInfo(@"Retrying to register for remote notifications since user hasn't registered yet."); OWSLogInfo(@"Retrying to register for remote notifications since user hasn't registered yet.");
@ -1119,6 +1138,8 @@ static NSTimeInterval launchStartedAt;
return; return;
} }
CurrentAppContext().wasWokenUpBySilentPushNotification = true;
[LKLogger print:@"[Loki] Silent push notification received; fetching messages."]; [LKLogger print:@"[Loki] Silent push notification received; fetching messages."];
NSMutableArray *promises = [NSMutableArray new]; NSMutableArray *promises = [NSMutableArray new];
@ -1135,7 +1156,7 @@ static NSTimeInterval launchStartedAt;
[OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
publicChats = [LKDatabaseUtilities getAllPublicChats:transaction]; publicChats = [LKDatabaseUtilities getAllPublicChats:transaction];
}]; }];
for (LKPublicChat *publicChat in publicChats) { for (LKPublicChat *publicChat in publicChats.allValues) {
if (![publicChat isKindOfClass:LKPublicChat.class]) { continue; } // For some reason publicChat is sometimes a base 64 encoded string... if (![publicChat isKindOfClass:LKPublicChat.class]) { continue; } // For some reason publicChat is sometimes a base 64 encoded string...
LKPublicChatPoller *poller = [[LKPublicChatPoller alloc] initForPublicChat:publicChat]; LKPublicChatPoller *poller = [[LKPublicChatPoller alloc] initForPublicChat:publicChat];
[poller stop]; [poller stop];
@ -1146,8 +1167,12 @@ static NSTimeInterval launchStartedAt;
PMKJoin(promises).then(^(id results) { PMKJoin(promises).then(^(id results) {
completionHandler(UIBackgroundFetchResultNewData); completionHandler(UIBackgroundFetchResultNewData);
CurrentAppContext().wasWokenUpBySilentPushNotification = false;
[LKLogger print:@"[Loki] UIBackgroundFetchResultNewData"];
}).catch(^(id error) { }).catch(^(id error) {
completionHandler(UIBackgroundFetchResultFailed); completionHandler(UIBackgroundFetchResultFailed);
CurrentAppContext().wasWokenUpBySilentPushNotification = false;
[LKLogger print:@"[Loki] UIBackgroundFetchResultFailed"];
}); });
} }
@ -1444,11 +1469,12 @@ static NSTimeInterval launchStartedAt;
// Loki: Start friend request expiration job // Loki: Start friend request expiration job
[self.lokiFriendRequestExpirationJob startIfNecessary]; [self.lokiFriendRequestExpirationJob startIfNecessary];
// Loki: Start long polling // Loki: Start pollers
[self startLongPollerIfNeeded]; [self startLongPollerIfNeeded];
[self startOpenGroupPollersIfNeeded];
// Loki: Get device links // Loki: Get device links
[LKFileServerAPI getDeviceLinksAssociatedWith:self.tsAccountManager.localNumber]; [[LKFileServerAPI getDeviceLinksAssociatedWith:self.tsAccountManager.localNumber] retainUntilComplete]; // TODO: Is this even needed?
} }
} }
@ -1586,16 +1612,6 @@ static NSTimeInterval launchStartedAt;
[self.lokiLongPoller stopIfNeeded]; [self.lokiLongPoller stopIfNeeded];
} }
- (LKRSSFeed *)lokiNewsFeed
{
return [[LKRSSFeed alloc] initWithId:@"loki.network.feed" server:@"https://loki.network/feed/" displayName:@"Loki News" isDeletable:true];
}
- (LKRSSFeed *)lokiMessengerUpdatesFeed
{
return [[LKRSSFeed alloc] initWithId:@"loki.network.messenger-updates.feed" server:@"https://loki.network/category/messenger-updates/feed/" displayName:@"Session Updates" isDeletable:false];
}
- (void)setUpDefaultPublicChatsIfNeeded - (void)setUpDefaultPublicChatsIfNeeded
{ {
for (LKPublicChat *chat in LKPublicChatAPI.defaultChats) { for (LKPublicChat *chat in LKPublicChatAPI.defaultChats) {
@ -1612,6 +1628,27 @@ static NSTimeInterval launchStartedAt;
} }
} }
- (void)startOpenGroupPollersIfNeeded
{
[LKPublicChatManager.shared startPollersIfNeeded];
[SSKEnvironment.shared.attachmentDownloads continueDownloadIfPossible];
}
- (void)stopOpenGroupPollersIfNeeded
{
[LKPublicChatManager.shared stopPollers];
}
- (LKRSSFeed *)lokiNewsFeed
{
return [[LKRSSFeed alloc] initWithId:@"loki.network.feed" server:@"https://loki.network/feed/" displayName:@"Loki News" isDeletable:true];
}
- (LKRSSFeed *)lokiMessengerUpdatesFeed
{
return [[LKRSSFeed alloc] initWithId:@"loki.network.messenger-updates.feed" server:@"https://loki.network/category/messenger-updates/feed/" displayName:@"Session Updates" isDeletable:false];
}
- (void)createRSSFeedsIfNeeded - (void)createRSSFeedsIfNeeded
{ {
NSArray *feeds = @[ /*self.lokiNewsFeed,*/ self.lokiMessengerUpdatesFeed ]; NSArray *feeds = @[ /*self.lokiNewsFeed,*/ self.lokiMessengerUpdatesFeed ];
@ -1670,6 +1707,7 @@ static NSTimeInterval launchStartedAt;
[SSKEnvironment.shared.identityManager clearIdentityKey]; [SSKEnvironment.shared.identityManager clearIdentityKey];
[LKAPI clearRandomSnodePool]; [LKAPI clearRandomSnodePool];
[self stopLongPollerIfNeeded]; [self stopLongPollerIfNeeded];
[self stopOpenGroupPollersIfNeeded];
[self.lokiNewsFeedPoller stop]; [self.lokiNewsFeedPoller stop];
[self.lokiMessengerUpdatesFeedPoller stop]; [self.lokiMessengerUpdatesFeedPoller stop];
[LKPublicChatManager.shared stopPollers]; [LKPublicChatManager.shared stopPollers];

@ -7,8 +7,8 @@ final class ConversationTitleView : UIView {
// MARK: Types // MARK: Types
private enum Status : Int { private enum Status : Int {
case calculatingPoW = 1 case calculatingPoW = 1
case contactingNetwork = 2 case routing = 2
case sendingMessage = 3 case messageSending = 3
case messageSent = 4 case messageSent = 4
case messageFailed = 5 case messageFailed = 5
} }
@ -40,8 +40,8 @@ final class ConversationTitleView : UIView {
let notificationCenter = NotificationCenter.default let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(handleProfileChangedNotification(_:)), name: NSNotification.Name(rawValue: kNSNotificationName_OtherUsersProfileDidChange), object: nil) notificationCenter.addObserver(self, selector: #selector(handleProfileChangedNotification(_:)), name: NSNotification.Name(rawValue: kNSNotificationName_OtherUsersProfileDidChange), object: nil)
notificationCenter.addObserver(self, selector: #selector(handleCalculatingPoWNotification(_:)), name: .calculatingPoW, object: nil) notificationCenter.addObserver(self, selector: #selector(handleCalculatingPoWNotification(_:)), name: .calculatingPoW, object: nil)
notificationCenter.addObserver(self, selector: #selector(handleContactingNetworkNotification(_:)), name: .contactingNetwork, object: nil) notificationCenter.addObserver(self, selector: #selector(handleRoutingNotification(_:)), name: .routing, object: nil)
notificationCenter.addObserver(self, selector: #selector(handleSendingMessageNotification(_:)), name: .sendingMessage, object: nil) notificationCenter.addObserver(self, selector: #selector(handleMessageSendingNotification(_:)), name: .messageSending, object: nil)
notificationCenter.addObserver(self, selector: #selector(handleMessageSentNotification(_:)), name: .messageSent, object: nil) notificationCenter.addObserver(self, selector: #selector(handleMessageSentNotification(_:)), name: .messageSent, object: nil)
notificationCenter.addObserver(self, selector: #selector(handleMessageFailedNotification(_:)), name: .messageFailed, object: nil) notificationCenter.addObserver(self, selector: #selector(handleMessageFailedNotification(_:)), name: .messageFailed, object: nil)
} }
@ -99,14 +99,14 @@ final class ConversationTitleView : UIView {
setStatusIfNeeded(to: .calculatingPoW, forMessageWithTimestamp: timestamp) setStatusIfNeeded(to: .calculatingPoW, forMessageWithTimestamp: timestamp)
} }
@objc private func handleContactingNetworkNotification(_ notification: Notification) { @objc private func handleRoutingNotification(_ notification: Notification) {
guard let timestamp = notification.object as? NSNumber else { return } guard let timestamp = notification.object as? NSNumber else { return }
setStatusIfNeeded(to: .contactingNetwork, forMessageWithTimestamp: timestamp) setStatusIfNeeded(to: .routing, forMessageWithTimestamp: timestamp)
} }
@objc private func handleSendingMessageNotification(_ notification: Notification) { @objc private func handleMessageSendingNotification(_ notification: Notification) {
guard let timestamp = notification.object as? NSNumber else { return } guard let timestamp = notification.object as? NSNumber else { return }
setStatusIfNeeded(to: .sendingMessage, forMessageWithTimestamp: timestamp) setStatusIfNeeded(to: .messageSending, forMessageWithTimestamp: timestamp)
} }
@objc private func handleMessageSentNotification(_ notification: Notification) { @objc private func handleMessageSentNotification(_ notification: Notification) {
@ -147,8 +147,8 @@ final class ConversationTitleView : UIView {
self.subtitleLabel.isHidden = false self.subtitleLabel.isHidden = false
switch self.currentStatus { switch self.currentStatus {
case .calculatingPoW: self.subtitleLabel.text = NSLocalizedString("Encrypting message", comment: "") case .calculatingPoW: self.subtitleLabel.text = NSLocalizedString("Encrypting message", comment: "")
case .contactingNetwork: self.subtitleLabel.text = NSLocalizedString("Tracing a path", comment: "") case .routing: self.subtitleLabel.text = NSLocalizedString("Tracing a path", comment: "")
case .sendingMessage: self.subtitleLabel.text = NSLocalizedString("Sending message", comment: "") case .messageSending: self.subtitleLabel.text = NSLocalizedString("Sending message", comment: "")
case .messageSent: self.subtitleLabel.text = NSLocalizedString("Message sent securely", comment: "") case .messageSent: self.subtitleLabel.text = NSLocalizedString("Message sent securely", comment: "")
case .messageFailed: self.subtitleLabel.text = NSLocalizedString("Message failed to send", comment: "") case .messageFailed: self.subtitleLabel.text = NSLocalizedString("Message failed to send", comment: "")
case nil: case nil:

@ -22,7 +22,11 @@ final class LokiPushNotificationManager : NSObject {
} }
// Send token to Loki server // Send token to Loki server
let parameters = [ "token" : hexEncodedToken ] let parameters = [ "token" : hexEncodedToken ]
#if DEBUG
let url = URL(string: "https://dev.apns.getsession.org/register")!
#else
let url = URL(string: "https://live.apns.getsession.org/register")! let url = URL(string: "https://live.apns.getsession.org/register")!
#endif
let request = TSRequest(url: url, method: "POST", parameters: parameters) let request = TSRequest(url: url, method: "POST", parameters: parameters)
request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ] request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ]
TSNetworkManager.shared().makeRequest(request, success: { _, response in TSNetworkManager.shared().makeRequest(request, success: { _, response in

@ -134,8 +134,8 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol
if OWSIdentityManager.shared().identityKeyPair() != nil { if OWSIdentityManager.shared().identityKeyPair() != nil {
let appDelegate = UIApplication.shared.delegate as! AppDelegate let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.setUpDefaultPublicChatsIfNeeded() appDelegate.setUpDefaultPublicChatsIfNeeded()
appDelegate.startOpenGroupPollersIfNeeded()
appDelegate.createRSSFeedsIfNeeded() appDelegate.createRSSFeedsIfNeeded()
LokiPublicChatManager.shared.startPollersIfNeeded()
appDelegate.startRSSFeedPollersIfNeeded() appDelegate.startRSSFeedPollersIfNeeded()
} }
// Do initial update // Do initial update

@ -429,12 +429,12 @@ typedef enum : NSUInteger {
name:NSNotification.calculatingPoW name:NSNotification.calculatingPoW
object:nil]; object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleContactingNetworkNotification:) selector:@selector(handleRoutingNotification:)
name:NSNotification.contactingNetwork name:NSNotification.routing
object:nil]; object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleSendingMessageNotification:) selector:@selector(handleMessageSendingNotification:)
name:NSNotification.sendingMessage name:NSNotification.messageSending
object:nil]; object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleMessageSentNotification:) selector:@selector(handleMessageSentNotification:)
@ -5419,13 +5419,13 @@ typedef enum : NSUInteger {
[self setProgressIfNeededTo:0.25f forMessageWithTimestamp:timestamp]; [self setProgressIfNeededTo:0.25f forMessageWithTimestamp:timestamp];
} }
- (void)handleContactingNetworkNotification:(NSNotification *)notification - (void)handleRoutingNotification:(NSNotification *)notification
{ {
NSNumber *timestamp = (NSNumber *)notification.object; NSNumber *timestamp = (NSNumber *)notification.object;
[self setProgressIfNeededTo:0.50f forMessageWithTimestamp:timestamp]; [self setProgressIfNeededTo:0.50f forMessageWithTimestamp:timestamp];
} }
- (void)handleSendingMessageNotification:(NSNotification *)notification - (void)handleMessageSendingNotification:(NSNotification *)notification
{ {
NSNumber *timestamp = (NSNumber *)notification.object; NSNumber *timestamp = (NSNumber *)notification.object;
[self setProgressIfNeededTo:0.75f forMessageWithTimestamp:timestamp]; [self setProgressIfNeededTo:0.75f forMessageWithTimestamp:timestamp];

@ -682,6 +682,7 @@ typedef NS_ENUM(NSInteger, HomeViewControllerSection) {
[LKAPI clearRandomSnodePool]; [LKAPI clearRandomSnodePool];
AppDelegate *appDelegate = (AppDelegate *)UIApplication.sharedApplication.delegate; AppDelegate *appDelegate = (AppDelegate *)UIApplication.sharedApplication.delegate;
[appDelegate stopLongPollerIfNeeded]; [appDelegate stopLongPollerIfNeeded];
[appDelegate stopOpenGroupPollersIfNeeded];
[SSKEnvironment.shared.tsAccountManager resetForReregistration]; [SSKEnvironment.shared.tsAccountManager resetForReregistration];
UIViewController *rootViewController = [[OnboardingController new] initialViewController]; UIViewController *rootViewController = [[OnboardingController new] initialViewController];
OWSNavigationController *navigationController = [[OWSNavigationController alloc] initWithRootViewController:rootViewController]; OWSNavigationController *navigationController = [[OWSNavigationController alloc] initWithRootViewController:rootViewController];

@ -28,6 +28,7 @@ NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplic
@synthesize mainWindow = _mainWindow; @synthesize mainWindow = _mainWindow;
@synthesize appLaunchTime = _appLaunchTime; @synthesize appLaunchTime = _appLaunchTime;
@synthesize wasWokenUpBySilentPushNotification = _wasWokenUpBySilentPushNotification;
- (instancetype)init - (instancetype)init
{ {
@ -40,6 +41,7 @@ NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplic
self.reportedApplicationState = UIApplicationStateInactive; self.reportedApplicationState = UIApplicationStateInactive;
_appLaunchTime = [NSDate new]; _appLaunchTime = [NSDate new];
_wasWokenUpBySilentPushNotification = false;
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterForeground:) selector:@selector(applicationWillEnterForeground:)

@ -416,10 +416,10 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
NSData *encryptedAvatarData = [self encryptProfileData:avatarData profileKey:newProfileKey]; NSData *encryptedAvatarData = [self encryptProfileData:avatarData profileKey:newProfileKey];
OWSAssertDebug(encryptedAvatarData.length > 0); OWSAssertDebug(encryptedAvatarData.length > 0);
[[LKFileServerAPI setProfilePicture:encryptedAvatarData] [[LKFileServerAPI uploadProfilePicture:encryptedAvatarData]
.thenOn(dispatch_get_main_queue(), ^(NSString *url) { .thenOn(dispatch_get_main_queue(), ^(NSString *downloadURL) {
[self.localUserProfile updateWithProfileKey:newProfileKey dbConnection:self.dbConnection completion:^{ [self.localUserProfile updateWithProfileKey:newProfileKey dbConnection:self.dbConnection completion:^{
successBlock(url); successBlock(downloadURL);
}]; }];
}) })
.catchOn(dispatch_get_main_queue(), ^(id result) { .catchOn(dispatch_get_main_queue(), ^(id result) {

@ -2,6 +2,7 @@ import PromiseKit
public extension LokiAPI { public extension LokiAPI {
/// Only ever accessed from `LokiAPI.errorHandlingQueue` to avoid race conditions.
fileprivate static var failureCount: [LokiAPITarget:UInt] = [:] fileprivate static var failureCount: [LokiAPITarget:UInt] = [:]
// MARK: Settings // MARK: Settings

@ -187,10 +187,10 @@ public final class LokiAPI : NSObject {
func sendLokiMessageUsingSwarmAPI() -> Promise<Set<RawResponsePromise>> { func sendLokiMessageUsingSwarmAPI() -> Promise<Set<RawResponsePromise>> {
notificationCenter.post(name: .calculatingPoW, object: NSNumber(value: signalMessage.timestamp)) notificationCenter.post(name: .calculatingPoW, object: NSNumber(value: signalMessage.timestamp))
return lokiMessage.calculatePoW().then { lokiMessageWithPoW -> Promise<Set<RawResponsePromise>> in return lokiMessage.calculatePoW().then { lokiMessageWithPoW -> Promise<Set<RawResponsePromise>> in
notificationCenter.post(name: .contactingNetwork, object: NSNumber(value: signalMessage.timestamp)) notificationCenter.post(name: .routing, object: NSNumber(value: signalMessage.timestamp))
return getTargetSnodes(for: destination).map { swarm in return getTargetSnodes(for: destination).map { swarm in
return Set(swarm.map { target in return Set(swarm.map { target in
notificationCenter.post(name: .sendingMessage, object: NSNumber(value: signalMessage.timestamp)) notificationCenter.post(name: .messageSending, object: NSNumber(value: signalMessage.timestamp))
return sendLokiMessage(lokiMessageWithPoW, to: target).map { rawResponse in return sendLokiMessage(lokiMessageWithPoW, to: target).map { rawResponse in
if let json = rawResponse as? JSON, let powDifficulty = json["difficulty"] as? Int { if let json = rawResponse as? JSON, let powDifficulty = json["difficulty"] as? Int {
guard powDifficulty != LokiAPI.powDifficulty else { return rawResponse } guard powDifficulty != LokiAPI.powDifficulty else { return rawResponse }

@ -137,40 +137,33 @@ public final class LokiFileServerAPI : LokiDotNetAPI {
} }
// MARK: Profile Pictures (Public API) // MARK: Profile Pictures (Public API)
public static func setProfilePicture(_ profilePicture: Data) -> Promise<String> { public static func uploadProfilePicture(_ profilePicture: Data) -> Promise<String> {
return Promise<String>() { seal in guard profilePicture.count < maxFileSize else { return Promise(error: LokiDotNetAPIError.maxFileSizeExceeded) }
guard profilePicture.count < maxFileSize else { return seal.reject(LokiDotNetAPIError.maxFileSizeExceeded) } let url = "\(server)/files"
getAuthToken(for: server).done { token in let parameters: JSON = [ "type" : attachmentType, "Content-Type" : "application/binary" ]
let url = "\(server)/users/me/avatar" var error: NSError?
let parameters: JSON = [ "type" : attachmentType, "Content-Type" : "application/binary" ] var request = AFHTTPRequestSerializer().multipartFormRequest(withMethod: "POST", urlString: url, parameters: parameters, constructingBodyWith: { formData in
var error: NSError? formData.appendPart(withFileData: profilePicture, name: "content", fileName: UUID().uuidString, mimeType: "application/binary")
var request = AFHTTPRequestSerializer().multipartFormRequest(withMethod: "POST", urlString: url, parameters: parameters, constructingBodyWith: { formData in }, error: &error)
formData.appendPart(withFileData: profilePicture, name: "avatar", fileName: UUID().uuidString, mimeType: "application/binary") // Uploads to the Loki File Server shouldn't include any personally identifiable information so use a dummy auth token
}, error: &error) request.addValue("Bearer loki", forHTTPHeaderField: "Authorization")
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization") if let error = error {
if let error = error { print("[Loki] Couldn't upload profile picture due to error: \(error).")
print("[Loki] Couldn't upload profile picture due to error: \(error).") return Promise(error: error)
throw error }
} return LokiFileServerProxy(for: server).performLokiFileServerNSURLRequest(request as NSURLRequest).map { responseObject in
let _ = LokiFileServerProxy(for: server).performLokiFileServerNSURLRequest(request as NSURLRequest).done { responseObject in guard let json = responseObject as? JSON, let data = json["data"] as? JSON, let downloadURL = data["url"] as? String else {
guard let json = responseObject as? JSON, let data = json["data"] as? JSON, let profilePicture = data["avatar_image"] as? JSON, let downloadURL = profilePicture["url"] as? String else { print("[Loki] Couldn't parse profile picture from: \(responseObject).")
print("[Loki] Couldn't parse profile picture from: \(responseObject).") throw LokiDotNetAPIError.parsingFailed
return seal.reject(LokiDotNetAPIError.parsingFailed)
}
return seal.fulfill(downloadURL)
}.catch { error in
seal.reject(error)
}
}.catch { error in
print("[Loki] Couldn't upload profile picture due to error: \(error).")
seal.reject(error)
} }
UserDefaults.standard[.lastProfilePictureUpload] = Date()
return downloadURL
} }
} }
// MARK: Profile Pictures (Public Obj-C API) // MARK: Profile Pictures (Public Obj-C API)
@objc(setProfilePicture:) @objc(uploadProfilePicture:)
public static func objc_setProfilePicture(_ profilePicture: Data) -> AnyPromise { public static func objc_uploadProfilePicture(_ profilePicture: Data) -> AnyPromise {
return AnyPromise.from(setProfilePicture(profilePicture)) return AnyPromise.from(uploadProfilePicture(profilePicture))
} }
} }

@ -10,6 +10,10 @@ public enum LKUserDefaults {
case wasUnlinked case wasUnlinked
} }
public enum Date : Swift.String {
case lastProfilePictureUpload
}
public enum Double : Swift.String { public enum Double : Swift.String {
case lastDeviceTokenUpload = "lastDeviceTokenUploadTime" case lastDeviceTokenUpload = "lastDeviceTokenUploadTime"
} }
@ -37,6 +41,11 @@ public extension UserDefaults {
set { set(newValue, forKey: bool.rawValue) } set { set(newValue, forKey: bool.rawValue) }
} }
public subscript(date: LKUserDefaults.Date) -> Date? {
get { return self.object(forKey: date.rawValue) as? Date }
set { set(newValue, forKey: date.rawValue) }
}
public subscript(double: LKUserDefaults.Double) -> Double { public subscript(double: LKUserDefaults.Double) -> Double {
get { return self.double(forKey: double.rawValue) } get { return self.double(forKey: double.rawValue) }
set { set(newValue, forKey: double.rawValue) } set { set(newValue, forKey: double.rawValue) }

@ -1,36 +1,40 @@
public extension Notification.Name { public extension Notification.Name {
// State changes
public static let contactOnlineStatusChanged = Notification.Name("contactOnlineStatusChanged") public static let contactOnlineStatusChanged = Notification.Name("contactOnlineStatusChanged")
public static let newMessagesReceived = Notification.Name("newMessagesReceived")
public static let threadFriendRequestStatusChanged = Notification.Name("threadFriendRequestStatusChanged") public static let threadFriendRequestStatusChanged = Notification.Name("threadFriendRequestStatusChanged")
public static let messageFriendRequestStatusChanged = Notification.Name("messageFriendRequestStatusChanged") public static let messageFriendRequestStatusChanged = Notification.Name("messageFriendRequestStatusChanged")
public static let threadDeleted = Notification.Name("threadDeleted") public static let threadDeleted = Notification.Name("threadDeleted")
public static let dataNukeRequested = Notification.Name("dataNukeRequested")
public static let threadSessionRestoreDevicesChanged = Notification.Name("threadSessionRestoreDevicesChanged") public static let threadSessionRestoreDevicesChanged = Notification.Name("threadSessionRestoreDevicesChanged")
// Message statuses // Message status changes
public static let calculatingPoW = Notification.Name("calculatingPoW") public static let calculatingPoW = Notification.Name("calculatingPoW")
public static let contactingNetwork = Notification.Name("contactingNetwork") public static let routing = Notification.Name("routing")
public static let sendingMessage = Notification.Name("sendingMessage") public static let messageSending = Notification.Name("messageSending")
public static let messageSent = Notification.Name("messageSent") public static let messageSent = Notification.Name("messageSent")
public static let messageFailed = Notification.Name("messageFailed") public static let messageFailed = Notification.Name("messageFailed")
// Onboarding // Onboarding
public static let seedViewed = Notification.Name("seedViewed") public static let seedViewed = Notification.Name("seedViewed")
// Interaction
public static let dataNukeRequested = Notification.Name("dataNukeRequested")
} }
@objc public extension NSNotification { @objc public extension NSNotification {
// State changes
@objc public static let contactOnlineStatusChanged = Notification.Name.contactOnlineStatusChanged.rawValue as NSString @objc public static let contactOnlineStatusChanged = Notification.Name.contactOnlineStatusChanged.rawValue as NSString
@objc public static let newMessagesReceived = Notification.Name.newMessagesReceived.rawValue as NSString
@objc public static let threadFriendRequestStatusChanged = Notification.Name.threadFriendRequestStatusChanged.rawValue as NSString @objc public static let threadFriendRequestStatusChanged = Notification.Name.threadFriendRequestStatusChanged.rawValue as NSString
@objc public static let messageFriendRequestStatusChanged = Notification.Name.messageFriendRequestStatusChanged.rawValue as NSString @objc public static let messageFriendRequestStatusChanged = Notification.Name.messageFriendRequestStatusChanged.rawValue as NSString
@objc public static let threadDeleted = Notification.Name.threadDeleted.rawValue as NSString @objc public static let threadDeleted = Notification.Name.threadDeleted.rawValue as NSString
@objc public static let dataNukeRequested = Notification.Name.dataNukeRequested.rawValue as NSString
@objc public static let threadSessionRestoreDevicesChanged = Notification.Name.threadSessionRestoreDevicesChanged.rawValue as NSString @objc public static let threadSessionRestoreDevicesChanged = Notification.Name.threadSessionRestoreDevicesChanged.rawValue as NSString
// Message statuses // Message statuses
@objc public static let calculatingPoW = Notification.Name.calculatingPoW.rawValue as NSString @objc public static let calculatingPoW = Notification.Name.calculatingPoW.rawValue as NSString
@objc public static let contactingNetwork = Notification.Name.contactingNetwork.rawValue as NSString @objc public static let routing = Notification.Name.routing.rawValue as NSString
@objc public static let sendingMessage = Notification.Name.sendingMessage.rawValue as NSString @objc public static let messageSending = Notification.Name.messageSending.rawValue as NSString
@objc public static let messageSent = Notification.Name.messageSent.rawValue as NSString @objc public static let messageSent = Notification.Name.messageSent.rawValue as NSString
@objc public static let messageFailed = Notification.Name.messageFailed.rawValue as NSString @objc public static let messageFailed = Notification.Name.messageFailed.rawValue as NSString
// Onboarding // Onboarding
@objc public static let seedViewed = Notification.Name.seedViewed.rawValue as NSString @objc public static let seedViewed = Notification.Name.seedViewed.rawValue as NSString
// Interaction
@objc public static let dataNukeRequested = Notification.Name.dataNukeRequested.rawValue as NSString
} }

@ -43,6 +43,8 @@ extern NSString *const kAttachmentDownloadAttachmentIDKey;
success:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))success success:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))success
failure:(void (^)(NSError *error))failure; failure:(void (^)(NSError *error))failure;
- (void)continueDownloadIfPossible;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

@ -264,6 +264,8 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
- (void)startDownloadIfPossible - (void)startDownloadIfPossible
{ {
if (CurrentAppContext().wasWokenUpBySilentPushNotification) { return; }
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
OWSAttachmentDownloadJob *_Nullable job; OWSAttachmentDownloadJob *_Nullable job;
@ -342,6 +344,16 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
#pragma mark - #pragma mark -
- (void)continueDownloadIfPossible
{
if (self.attachmentDownloadJobQueue.count > 0) {
[LKLogger print:@"[Loki] Continuing unfinished attachment download tasks."];
[self startDownloadIfPossible];
}
}
#pragma mark -
- (void)retrieveAttachmentForJob:(OWSAttachmentDownloadJob *)job - (void)retrieveAttachmentForJob:(OWSAttachmentDownloadJob *)job
success:(void (^)(TSAttachmentStream *attachmentStream))successHandler success:(void (^)(TSAttachmentStream *attachmentStream))successHandler
failure:(void (^)(NSError *error))failureHandler failure:(void (^)(NSError *error))failureHandler

@ -37,6 +37,9 @@ NSString *NSStringForUIApplicationState(UIApplicationState value);
@property (nonatomic, readonly) BOOL isMainApp; @property (nonatomic, readonly) BOOL isMainApp;
@property (nonatomic, readonly) BOOL isMainAppAndActive; @property (nonatomic, readonly) BOOL isMainAppAndActive;
/// Whether the app was woken up by a silent push notification. This is important for
/// determining whether attachments should be downloaded or not.
@property (nonatomic) BOOL wasWokenUpBySilentPushNotification;
// Whether the user is using a right-to-left language like Arabic. // Whether the user is using a right-to-left language like Arabic.
@property (nonatomic, readonly) BOOL isRTL; @property (nonatomic, readonly) BOOL isRTL;

Loading…
Cancel
Save