diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist
index 342d37adb..378a5f3ca 100644
--- a/Signal/Signal-Info.plist
+++ b/Signal/Signal-Info.plist
@@ -5,7 +5,7 @@
BuildDetails
CarthageVersion
- 0.34.0
+ 0.33.0
OSXVersion
10.15.3
WebRTCCommit
diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m
index 3039232bf..c3e764c2a 100644
--- a/Signal/src/AppDelegate.m
+++ b/Signal/src/AppDelegate.m
@@ -770,6 +770,8 @@ static NSTimeInterval launchStartedAt;
[self.socketManager requestSocketOpen];
[Environment.shared.contactsManager fetchSystemContactsOnceIfAlreadyAuthorized];
+ NSString *userHexEncodedPublicKey = self.tsAccountManager.localNumber;
+
// Loki: Tell our friends that we are online
[LKP2PAPI broadcastOnlineStatus];
@@ -777,7 +779,22 @@ static NSTimeInterval launchStartedAt;
[self startLongPollerIfNeeded];
// 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 ([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:^{
+ [userDefaults setObject:now forKey:@"lastProfilePictureUpload"];
+ } failure:^(NSError *error) {
+ // Do nothing
+ } requiresSync:YES];
+ }
if (![UIApplication sharedApplication].isRegisteredForRemoteNotifications) {
OWSLogInfo(@"Retrying to register for remote notifications since user hasn't registered yet.");
@@ -1448,7 +1465,7 @@ static NSTimeInterval launchStartedAt;
[self startLongPollerIfNeeded];
// Loki: Get device links
- [LKFileServerAPI getDeviceLinksAssociatedWith:self.tsAccountManager.localNumber];
+ [[LKFileServerAPI getDeviceLinksAssociatedWith:self.tsAccountManager.localNumber] retainUntilComplete]; // TODO: Is this even needed?
}
}
diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m
index bd2b6887e..1bbea7d6e 100644
--- a/SignalMessaging/profiles/OWSProfileManager.m
+++ b/SignalMessaging/profiles/OWSProfileManager.m
@@ -416,10 +416,10 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
NSData *encryptedAvatarData = [self encryptProfileData:avatarData profileKey:newProfileKey];
OWSAssertDebug(encryptedAvatarData.length > 0);
- [[LKFileServerAPI setProfilePicture:encryptedAvatarData]
- .thenOn(dispatch_get_main_queue(), ^(NSString *url) {
+ [[LKFileServerAPI uploadProfilePicture:encryptedAvatarData]
+ .thenOn(dispatch_get_main_queue(), ^(NSString *downloadURL) {
[self.localUserProfile updateWithProfileKey:newProfileKey dbConnection:self.dbConnection completion:^{
- successBlock(url);
+ successBlock(downloadURL);
}];
})
.catchOn(dispatch_get_main_queue(), ^(id result) {
diff --git a/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift b/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift
index 7dcac5e9f..9bde68e93 100644
--- a/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift
+++ b/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift
@@ -137,40 +137,33 @@ public final class LokiFileServerAPI : LokiDotNetAPI {
}
// MARK: Profile Pictures (Public API)
- public static func setProfilePicture(_ profilePicture: Data) -> Promise {
- return Promise() { seal in
- guard profilePicture.count < maxFileSize else { return seal.reject(LokiDotNetAPIError.maxFileSizeExceeded) }
- getAuthToken(for: server).done { token in
- let url = "\(server)/users/me/avatar"
- let parameters: JSON = [ "type" : attachmentType, "Content-Type" : "application/binary" ]
- var error: NSError?
- var request = AFHTTPRequestSerializer().multipartFormRequest(withMethod: "POST", urlString: url, parameters: parameters, constructingBodyWith: { formData in
- formData.appendPart(withFileData: profilePicture, name: "avatar", fileName: UUID().uuidString, mimeType: "application/binary")
- }, error: &error)
- request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
- if let error = error {
- print("[Loki] Couldn't upload profile picture due to error: \(error).")
- throw error
- }
- let _ = LokiFileServerProxy(for: server).performLokiFileServerNSURLRequest(request as NSURLRequest).done { responseObject in
- 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).")
- 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)
+ public static func uploadProfilePicture(_ profilePicture: Data) -> Promise {
+ guard profilePicture.count < maxFileSize else { return Promise(error: LokiDotNetAPIError.maxFileSizeExceeded) }
+ let url = "\(server)/files"
+ let parameters: JSON = [ "type" : attachmentType, "Content-Type" : "application/binary" ]
+ var error: NSError?
+ var request = AFHTTPRequestSerializer().multipartFormRequest(withMethod: "POST", urlString: url, parameters: parameters, constructingBodyWith: { formData in
+ formData.appendPart(withFileData: profilePicture, name: "content", fileName: UUID().uuidString, mimeType: "application/binary")
+ }, error: &error)
+ // Uploads to the Loki File Server shouldn't include any personally identifiable information so use a dummy auth token
+ request.addValue("Bearer loki", forHTTPHeaderField: "Authorization")
+ if let error = error {
+ print("[Loki] Couldn't upload profile picture due to error: \(error).")
+ return Promise(error: error)
+ }
+ return LokiFileServerProxy(for: server).performLokiFileServerNSURLRequest(request as NSURLRequest).map { responseObject in
+ guard let json = responseObject as? JSON, let data = json["data"] as? JSON, let downloadURL = data["url"] as? String else {
+ print("[Loki] Couldn't parse profile picture from: \(responseObject).")
+ throw LokiDotNetAPIError.parsingFailed
}
+ UserDefaults.standard[.lastProfilePictureUpload] = Date().timeIntervalSince1970
+ return downloadURL
}
}
// MARK: Profile Pictures (Public Obj-C API)
- @objc(setProfilePicture:)
- public static func objc_setProfilePicture(_ profilePicture: Data) -> AnyPromise {
- return AnyPromise.from(setProfilePicture(profilePicture))
+ @objc(uploadProfilePicture:)
+ public static func objc_uploadProfilePicture(_ profilePicture: Data) -> AnyPromise {
+ return AnyPromise.from(uploadProfilePicture(profilePicture))
}
}
diff --git a/SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift b/SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift
index f1d426fd7..84921c642 100644
--- a/SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift
+++ b/SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift
@@ -9,7 +9,11 @@ public enum LKUserDefaults {
/// Whether the device was unlinked as a slave device (used to notify the user on the landing screen).
case wasUnlinked
}
-
+
+ public enum Date : Swift.String {
+ case lastProfilePictureUpload
+ }
+
public enum Double : Swift.String {
case lastDeviceTokenUpload = "lastDeviceTokenUploadTime"
}
@@ -36,6 +40,11 @@ public extension UserDefaults {
get { return self.bool(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 {
get { return self.double(forKey: double.rawValue) }