Fix promise usage & clean

pull/43/head
Niels Andriesse 6 years ago
parent 9283012988
commit 3a1d07e5a8

@ -127,7 +127,7 @@ public final class LokiGroupChatPoller : NSObject {
private func pollForModerationPermission() { private func pollForModerationPermission() {
let group = self.group let group = self.group
let _ = LokiGroupChatAPI.isCurrentUserMod(on: group.server).done { [storage] isModerator in let _ = LokiGroupChatAPI.userHasModerationPermission(for: group.serverID, on: group.server).done { [storage] isModerator in
storage.dbReadWriteConnection.readWrite { transaction in storage.dbReadWriteConnection.readWrite { transaction in
storage.setIsModerator(isModerator, for: UInt(group.serverID), on: group.server, in: transaction) storage.setIsModerator(isModerator, for: UInt(group.serverID), on: group.server, in: transaction)
} }

@ -86,7 +86,7 @@ class ConversationViewItemActions: NSObject {
actions.append(copyTextAction) actions.append(copyTextAction)
} }
if !isGroup || conversationViewItem.canDeleteGroupMessage { if !isGroup || conversationViewItem.userCanDeleteGroupMessage {
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: conversationViewItem, delegate: delegate) let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: conversationViewItem, delegate: delegate)
actions.append(deleteAction) actions.append(deleteAction)
} }

@ -305,8 +305,7 @@ class ColorPickerView: UIView, ColorViewDelegate {
@objc @objc
private class MockConversationViewItem: NSObject, ConversationViewItem { private class MockConversationViewItem: NSObject, ConversationViewItem {
var canDeleteGroupMessage: Bool = false var userCanDeleteGroupMessage: Bool = false
var interaction: TSInteraction = TSMessage() var interaction: TSInteraction = TSMessage()
var interactionType: OWSInteractionType = OWSInteractionType.unknown var interactionType: OWSInteractionType = OWSInteractionType.unknown
var quotedReply: OWSQuotedReplyModel? var quotedReply: OWSQuotedReplyModel?

@ -67,7 +67,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
@property (nonatomic, readonly, nullable) OWSQuotedReplyModel *quotedReply; @property (nonatomic, readonly, nullable) OWSQuotedReplyModel *quotedReply;
@property (nonatomic, readonly) BOOL isGroupThread; @property (nonatomic, readonly) BOOL isGroupThread;
@property (nonatomic, readonly) BOOL canDeleteGroupMessage; @property (nonatomic, readonly) BOOL userCanDeleteGroupMessage;
@property (nonatomic, readonly) BOOL hasBodyText; @property (nonatomic, readonly) BOOL hasBodyText;

@ -203,8 +203,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
- (OWSPrimaryStorage *)primaryStorage - (OWSPrimaryStorage *)primaryStorage
{ {
OWSAssertDebug(SSKEnvironment.shared.primaryStorage);
return SSKEnvironment.shared.primaryStorage; return SSKEnvironment.shared.primaryStorage;
} }
@ -1171,25 +1169,25 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
- (void)deleteAction - (void)deleteAction
{ {
// Delete it optimistically
[self.interaction remove]; [self.interaction remove];
if (self.isGroupThread) { if (self.isGroupThread) {
// If it's RSS then skip // Skip if the thread is an RSS feed
TSGroupThread *groupThread = (TSGroupThread *)self.interaction.thread; TSGroupThread *groupThread = (TSGroupThread *)self.interaction.thread;
if (groupThread.isRSSFeed) return; if (groupThread.isRSSFeed) return;
// Only allow deletion on incoming and outgoing messages // Only allow deletion on incoming and outgoing messages
OWSInteractionType interationType = self.interaction.interactionType; OWSInteractionType interationType = self.interaction.interactionType;
if (interationType != OWSInteractionType_OutgoingMessage && interationType != OWSInteractionType_IncomingMessage) return; if (interationType != OWSInteractionType_IncomingMessage && interationType != OWSInteractionType_OutgoingMessage) return;
// Check that we have the server id for the message // Make sure it's a public chat message
TSMessage *message = (TSMessage *)self.interaction; TSMessage *message = (TSMessage *)self.interaction;
if (!message.isPublicChatMessage) return; if (!message.isPublicChatMessage) return;
// Delete the message // Delete the message
[[LKGroupChatAPI deleteMessageWithServerID:message.publicChatMessageID forGroup:LKGroupChatAPI.publicChatServerID onServer:LKGroupChatAPI.publicChatServer isOurOwnMessage:interationType == OWSInteractionType_OutgoingMessage].catch(^(NSError *error) { BOOL isSentByUser = (interationType == OWSInteractionType_OutgoingMessage);
// If we fail then add the interaction back in [[LKGroupChatAPI deleteMessageWithID:message.publicChatMessageID forGroup:LKGroupChatAPI.publicChatServerID onServer:LKGroupChatAPI.publicChatServer isSentByUser:isSentByUser].catch(^(NSError *error) {
// Roll back
[self.interaction save]; [self.interaction save];
}) retainUntilComplete]; }) retainUntilComplete];
} }
@ -1235,11 +1233,11 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
return NO; return NO;
} }
- (BOOL)canDeleteGroupMessage - (BOOL)userCanDeleteGroupMessage
{ {
if (!self.isGroupThread) return false; if (!self.isGroupThread) return false;
// Make sure it's a public chat and not an rss feed // Ensure the thread is a public chat and not an RSS feed
TSGroupThread *groupThread = (TSGroupThread *)self.interaction.thread; TSGroupThread *groupThread = (TSGroupThread *)self.interaction.thread;
if (groupThread.isRSSFeed) return false; if (groupThread.isRSSFeed) return false;
@ -1251,7 +1249,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
TSMessage *message = (TSMessage *)self.interaction; TSMessage *message = (TSMessage *)self.interaction;
if (!message.isPublicChatMessage) return false; if (!message.isPublicChatMessage) return false;
// Don't allow deletion if we're not mods on incoming messages // Only allow deletion on incoming messages if the user has moderation permission
if (interationType == OWSInteractionType_IncomingMessage) { if (interationType == OWSInteractionType_IncomingMessage) {
__block BOOL isModerator; __block BOOL isModerator;
[[self primaryStorage].dbReadWriteConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [[self primaryStorage].dbReadWriteConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {

@ -11,7 +11,7 @@ public final class LokiGroupChatAPI : NSObject {
// MARK: Public Chat // MARK: Public Chat
@objc public static let publicChatServer = "https://chat.lokinet.org" @objc public static let publicChatServer = "https://chat.lokinet.org"
@objc public static let publicChatMessageType = "network.loki.messenger.publicChat" @objc public static let publicChatMessageType = "network.loki.messenger.publicChat"
@objc public static let publicChatServerID: UInt = 1 @objc public static let publicChatServerID: UInt64 = 1
// MARK: Convenience // MARK: Convenience
private static var userDisplayName: String { private static var userDisplayName: String {
@ -28,7 +28,7 @@ public final class LokiGroupChatAPI : NSObject {
// MARK: Error // MARK: Error
public enum Error : Swift.Error { public enum Error : Swift.Error {
case tokenParsingFailed, tokenDecryptionFailed, messageParsingFailed, deletionParsingFailed, jsonParsingFailed case parsingFailed, decryptionFailed
} }
// MARK: Database // MARK: Database
@ -87,7 +87,7 @@ public final class LokiGroupChatAPI : NSObject {
return TSNetworkManager.shared().makePromise(request: request).map { $0.responseObject }.map { rawResponse in return TSNetworkManager.shared().makePromise(request: request).map { $0.responseObject }.map { rawResponse in
guard let json = rawResponse as? JSON, let base64EncodedChallenge = json["cipherText64"] as? String, let base64EncodedServerPublicKey = json["serverPubKey64"] as? String, guard let json = rawResponse as? JSON, let base64EncodedChallenge = json["cipherText64"] as? String, let base64EncodedServerPublicKey = json["serverPubKey64"] as? String,
let challenge = Data(base64Encoded: base64EncodedChallenge), var serverPublicKey = Data(base64Encoded: base64EncodedServerPublicKey) else { let challenge = Data(base64Encoded: base64EncodedChallenge), var serverPublicKey = Data(base64Encoded: base64EncodedServerPublicKey) else {
throw Error.tokenParsingFailed throw Error.parsingFailed
} }
// Discard the "05" prefix if needed // Discard the "05" prefix if needed
if (serverPublicKey.count == 33) { if (serverPublicKey.count == 33) {
@ -97,7 +97,7 @@ public final class LokiGroupChatAPI : NSObject {
// The challenge is prefixed by the 16 bit IV // The challenge is prefixed by the 16 bit IV
guard let tokenAsData = try? DiffieHellman.decrypt(challenge, publicKey: serverPublicKey, privateKey: userKeyPair.privateKey), guard let tokenAsData = try? DiffieHellman.decrypt(challenge, publicKey: serverPublicKey, privateKey: userKeyPair.privateKey),
let token = String(bytes: tokenAsData, encoding: .utf8) else { let token = String(bytes: tokenAsData, encoding: .utf8) else {
throw Error.tokenDecryptionFailed throw Error.decryptionFailed
} }
return token return token
} }
@ -136,7 +136,7 @@ public final class LokiGroupChatAPI : NSObject {
return TSNetworkManager.shared().makePromise(request: request).map { $0.responseObject }.map { rawResponse in return TSNetworkManager.shared().makePromise(request: request).map { $0.responseObject }.map { rawResponse in
guard let json = rawResponse as? JSON, let rawMessages = json["data"] as? [JSON] else { guard let json = rawResponse as? JSON, let rawMessages = json["data"] as? [JSON] else {
print("[Loki] Couldn't parse messages for group chat with ID: \(group) on server: \(server) from: \(rawResponse).") print("[Loki] Couldn't parse messages for group chat with ID: \(group) on server: \(server) from: \(rawResponse).")
throw Error.messageParsingFailed throw Error.parsingFailed
} }
return rawMessages.flatMap { message in return rawMessages.flatMap { message in
guard let annotations = message["annotations"] as? [JSON], let annotation = annotations.first, let value = annotation["value"] as? JSON, guard let annotations = message["annotations"] as? [JSON], let annotation = annotations.first, let value = annotation["value"] as? JSON,
@ -167,7 +167,7 @@ public final class LokiGroupChatAPI : NSObject {
guard let json = rawResponse as? JSON, let messageAsJSON = json["data"] as? JSON, let serverID = messageAsJSON["id"] as? UInt64, let body = messageAsJSON["text"] as? String, guard let json = rawResponse as? JSON, let messageAsJSON = json["data"] as? JSON, let serverID = messageAsJSON["id"] as? UInt64, let body = messageAsJSON["text"] as? String,
let dateAsString = messageAsJSON["created_at"] as? String, let date = dateFormatter.date(from: dateAsString) else { let dateAsString = messageAsJSON["created_at"] as? String, let date = dateFormatter.date(from: dateAsString) else {
print("[Loki] Couldn't parse message for group chat with ID: \(group) on server: \(server) from: \(rawResponse).") print("[Loki] Couldn't parse message for group chat with ID: \(group) on server: \(server) from: \(rawResponse).")
throw Error.messageParsingFailed throw Error.parsingFailed
} }
let timestamp = UInt64(date.timeIntervalSince1970) * 1000 let timestamp = UInt64(date.timeIntervalSince1970) * 1000
return LokiGroupMessage(serverID: serverID, hexEncodedPublicKey: userHexEncodedPublicKey, displayName: displayName, body: body, type: publicChatMessageType, timestamp: timestamp) return LokiGroupMessage(serverID: serverID, hexEncodedPublicKey: userHexEncodedPublicKey, displayName: displayName, body: body, type: publicChatMessageType, timestamp: timestamp)
@ -194,7 +194,7 @@ public final class LokiGroupChatAPI : NSObject {
return TSNetworkManager.shared().makePromise(request: request).map { $0.responseObject }.map { rawResponse in return TSNetworkManager.shared().makePromise(request: request).map { $0.responseObject }.map { rawResponse in
guard let json = rawResponse as? JSON, let deletions = json["data"] as? [JSON] else { guard let json = rawResponse as? JSON, let deletions = json["data"] as? [JSON] else {
print("[Loki] Couldn't parse deleted messages for group chat with ID: \(group) on server: \(server) from: \(rawResponse).") print("[Loki] Couldn't parse deleted messages for group chat with ID: \(group) on server: \(server) from: \(rawResponse).")
throw Error.deletionParsingFailed throw Error.parsingFailed
} }
return deletions.flatMap { deletion in return deletions.flatMap { deletion in
guard let serverID = deletion["id"] as? UInt64, let messageServerID = deletion["message_id"] as? UInt64 else { guard let serverID = deletion["id"] as? UInt64, let messageServerID = deletion["message_id"] as? UInt64 else {
@ -208,43 +208,30 @@ public final class LokiGroupChatAPI : NSObject {
} }
} }
public static func deleteMessageWithServerID(_ messageServerID: UInt, for group: UInt64, on server: String, isOurOwnMessage: Bool = true) -> Promise<Void> { public static func deleteMessage(with messageID: UInt, for group: UInt64, on server: String, isSentByUser: Bool) -> Promise<Void> {
return getAuthToken(for: server).then { token -> Promise<Void> in return getAuthToken(for: server).then { token -> Promise<Void> in
let modTag = isOurOwnMessage ? "" : "[Mod]" let isModerationRequest = !isSentByUser
print("[Loki]\(modTag) Deleting message with server ID: \(messageServerID) for group chat with ID: \(group) on server: \(server).") print("[Loki] Deleting message with ID: \(messageID) for group chat with ID: \(group) on server: \(server) (isModerationRequest = \(isModerationRequest)).")
let urlAsString = isSentByUser ? "\(server)/channels/\(group)/messages/\(messageID)" : "\(server)/loki/v1/moderation/message/\(messageID)"
let endpoint = isOurOwnMessage ? "\(server)/channels/\(group)/messages/\(messageServerID)" : "\(server)/loki/v1/moderation/message/\(messageServerID)" let url = URL(string: urlAsString)!
let url = URL(string: endpoint)!
let request = TSRequest(url: url, method: "DELETE", parameters: [:]) let request = TSRequest(url: url, method: "DELETE", parameters: [:])
request.allHTTPHeaderFields = [ "Content-Type" : "application/json", "Authorization" : "Bearer \(token)" ] request.allHTTPHeaderFields = [ "Content-Type" : "application/json", "Authorization" : "Bearer \(token)" ]
return TSNetworkManager.shared().makePromise(request: request).map { result -> Void in return TSNetworkManager.shared().makePromise(request: request).done { result -> Void in
print("[Loki]\(modTag) Deleted message \(messageServerID) on server \(server).") print("[Loki] Deleted message with ID: \(messageID) on server: \(server).")
}.recover { error in
// If we got 404 or 410 then message doesn't exist on the server
if let error = error as? NetworkManagerError, error.statusCode == 404 || error.statusCode == 410 {
print("[Loki]\(modTag) Message \(messageServerID) was already deleted on the server.")
return
}
print("[Loki]\(modTag) Failed to delete message \(messageServerID) on server \(server).")
throw error
} }
} }
} }
public static func isCurrentUserMod(on server: String) -> Promise<Bool> { public static func userHasModerationPermission(for group: UInt64, on server: String) -> Promise<Bool> {
return getAuthToken(for: server).then { token -> Promise<Bool> in return getAuthToken(for: server).then { token -> Promise<Bool> in
let url = URL(string: "\(server)/loki/v1/user_info")! let url = URL(string: "\(server)/loki/v1/user_info")!
let request = TSRequest(url: url) let request = TSRequest(url: url)
request.allHTTPHeaderFields = [ "Content-Type" : "application/json", "Authorization" : "Bearer \(token)" ] request.allHTTPHeaderFields = [ "Content-Type" : "application/json", "Authorization" : "Bearer \(token)" ]
return TSNetworkManager.shared().makePromise(request: request).map { $0.responseObject }.map { rawResponse in return TSNetworkManager.shared().makePromise(request: request).map { $0.responseObject }.map { rawResponse in
guard let json = rawResponse as? JSON, let data = json["data"] as? JSON else { guard let json = rawResponse as? JSON, let data = json["data"] as? JSON else {
print("[Loki] Couldn't parse json for user info.") print("[Loki] Couldn't parse moderation permission for group chat with ID: \(group) on server: \(server) from: \(rawResponse).")
throw Error.jsonParsingFailed throw Error.parsingFailed
} }
// moderator_status is not set for users that are not mods
return data["moderator_status"] as? Bool ?? false return data["moderator_status"] as? Bool ?? false
} }
} }
@ -261,8 +248,8 @@ public final class LokiGroupChatAPI : NSObject {
return AnyPromise.from(sendMessage(message, to: group, on: server)) return AnyPromise.from(sendMessage(message, to: group, on: server))
} }
@objc (deleteMessageWithServerID:forGroup:onServer:isOurOwnMessage:) @objc (deleteMessageWithID:forGroup:onServer:isSentByUser:)
public static func objc_deleteMessageWithServerID(_ messageServerID: UInt, for group: UInt64, on server: String, ourMessage: Bool = true) -> AnyPromise { public static func objc_deleteMessage(with messageID: UInt, for group: UInt64, on server: String, isSentByUser: Bool) -> AnyPromise {
return AnyPromise.from(deleteMessageWithServerID(messageServerID, for: group, on: server, isOurOwnMessage: ourMessage)) return AnyPromise.from(deleteMessage(with: messageID, for: group, on: server, isSentByUser: isSentByUser))
} }
} }

@ -72,7 +72,7 @@ NS_ASSUME_NONNULL_BEGIN
*/ */
- (void)removePreKeyBundleForContact:(NSString *)pubKey transaction:(YapDatabaseReadWriteTransaction *)transaction; - (void)removePreKeyBundleForContact:(NSString *)pubKey transaction:(YapDatabaseReadWriteTransaction *)transaction;
# pragma mark - Last Hash Handling # pragma mark - Last Hash
/** /**
Get the last message hash for the given service node. Get the last message hash for the given service node.
@ -95,7 +95,7 @@ NS_ASSUME_NONNULL_BEGIN
*/ */
- (void)setLastMessageHashForServiceNode:(NSString *)serviceNode hash:(NSString *)hash expiresAt:(u_int64_t)expiresAt transaction:(YapDatabaseReadWriteTransaction *)transaction NS_SWIFT_NAME(setLastMessageHash(forServiceNode:hash:expiresAt:transaction:)); - (void)setLastMessageHashForServiceNode:(NSString *)serviceNode hash:(NSString *)hash expiresAt:(u_int64_t)expiresAt transaction:(YapDatabaseReadWriteTransaction *)transaction NS_SWIFT_NAME(setLastMessageHash(forServiceNode:hash:expiresAt:transaction:));
# pragma mark - Public chat # pragma mark - Group Chat
- (void)setIDForMessageWithServerID:(NSUInteger)serverID to:(NSString *)messageID in:(YapDatabaseReadWriteTransaction *)transaction; - (void)setIDForMessageWithServerID:(NSUInteger)serverID to:(NSString *)messageID in:(YapDatabaseReadWriteTransaction *)transaction;
- (NSString *_Nullable)getIDForMessageWithServerID:(NSUInteger)serverID in:(YapDatabaseReadTransaction *)transaction; - (NSString *_Nullable)getIDForMessageWithServerID:(NSUInteger)serverID in:(YapDatabaseReadTransaction *)transaction;

@ -164,6 +164,8 @@
[transaction removeObjectForKey:serviceNode inCollection:LKLastMessageHashCollection]; [transaction removeObjectForKey:serviceNode inCollection:LKLastMessageHashCollection];
} }
# pragma mark - Group Chat
- (void)setIDForMessageWithServerID:(NSUInteger)serverID to:(NSString *)messageID in:(YapDatabaseReadWriteTransaction *)transaction { - (void)setIDForMessageWithServerID:(NSUInteger)serverID to:(NSString *)messageID in:(YapDatabaseReadWriteTransaction *)transaction {
NSString *key = [NSString stringWithFormat:@"%@", @(serverID)]; NSString *key = [NSString stringWithFormat:@"%@", @(serverID)];
[transaction setObject:messageID forKey:key inCollection:LKMessageIDCollection]; [transaction setObject:messageID forKey:key inCollection:LKMessageIDCollection];

Loading…
Cancel
Save