Add compact poll endpoint

pull/388/head
Niels Andriesse 4 years ago
parent 69c30fef70
commit 2eab06cec9

@ -119,6 +119,36 @@ public final class OpenGroupAPIV2 : NSObject {
}
}
public static func compactPoll(_ server: String) -> Promise<[(room: String, messages: [OpenGroupMessageV2], deletions: [Int64], moderators: [String])]> {
let storage = SNMessagingKitConfiguration.shared.storage
let rooms = storage.getAllV2OpenGroups().values.filter { $0.server == server }.map { $0.room }
var body: [JSON] = []
for room in rooms {
let authToken = try! getAuthToken(for: room, on: server).wait() // TODO: This should be async
var json: JSON = [ "room_id" : room, "auth_token" : authToken ]
if let lastMessageServerID = storage.getLastMessageServerID(for: room, on: server) {
json["from_message_server_id"] = String(lastMessageServerID)
}
if let lastDeletionServerID = storage.getLastDeletionServerID(for: room, on: server) {
json["from_deletion_server_id"] = String(lastDeletionServerID)
}
body.append(json)
}
let request = Request(verb: .post, room: nil, server: server, endpoint: "compact_poll", parameters: [ "requests" : body ], isAuthRequired: false)
return send(request).map(on: DispatchQueue.global(qos: .userInitiated)) { json in
guard let results = json["results"] as? [JSON] else { throw Error.parsingFailed }
var x: [(room: String, messages: [OpenGroupMessageV2], deletions: [Int64], moderators: [String])] = []
for result in results {
guard let room = result["room_id"] as? String else { continue }
let messages = try! parseMessages(from: result, for: room, on: server).wait() // TODO: This should be async
let deletions = result["deletions"] as? [Int64] ?? []
let moderators = result["moderators"] as? [String] ?? []
x.append((room: room, messages: messages, deletions: deletions, moderators: moderators))
}
return x
}
}
// MARK: Authorization
private static func getAuthToken(for room: String, on server: String) -> Promise<String> {
let storage = SNMessagingKitConfiguration.shared.storage
@ -224,35 +254,40 @@ public final class OpenGroupAPIV2 : NSObject {
}
let request = Request(verb: .get, room: room, server: server, endpoint: "messages", queryParameters: queryParameters)
return send(request).then(on: DispatchQueue.global(qos: .userInitiated)) { json -> Promise<[OpenGroupMessageV2]> in
guard let rawMessages = json["messages"] as? [[String:Any]] else { throw Error.parsingFailed }
let messages: [OpenGroupMessageV2] = rawMessages.compactMap { json in
guard let message = OpenGroupMessageV2.fromJSON(json), message.serverID != nil, let sender = message.sender, let data = Data(base64Encoded: message.base64EncodedData),
let base64EncodedSignature = message.base64EncodedSignature, let signature = Data(base64Encoded: base64EncodedSignature) else {
SNLog("Couldn't parse open group message from JSON: \(json).")
return nil
}
// Validate the message signature
let publicKey = Data(hex: sender.removing05PrefixIfNeeded())
let isValid = (try? Ed25519.verifySignature(signature, publicKey: publicKey, data: data)) ?? false
guard isValid else {
SNLog("Ignoring message with invalid signature.")
return nil
}
return message
try parseMessages(from: json, for: room, on: server)
}
}
private static func parseMessages(from json: JSON, for room: String, on server: String) throws -> Promise<[OpenGroupMessageV2]> {
let storage = SNMessagingKitConfiguration.shared.storage
guard let rawMessages = json["messages"] as? [JSON] else { throw Error.parsingFailed }
let messages: [OpenGroupMessageV2] = rawMessages.compactMap { json in
guard let message = OpenGroupMessageV2.fromJSON(json), message.serverID != nil, let sender = message.sender, let data = Data(base64Encoded: message.base64EncodedData),
let base64EncodedSignature = message.base64EncodedSignature, let signature = Data(base64Encoded: base64EncodedSignature) else {
SNLog("Couldn't parse open group message from JSON: \(json).")
return nil
}
let serverID = messages.map { $0.serverID! }.max() ?? 0 // Safe because messages with a nil serverID are filtered out
let lastMessageServerID = storage.getLastMessageServerID(for: room, on: server) ?? 0
if serverID > lastMessageServerID {
let (promise, seal) = Promise<[OpenGroupMessageV2]>.pending()
storage.write(with: { transaction in
storage.setLastMessageServerID(for: room, on: server, to: serverID, using: transaction)
}, completion: {
seal.fulfill(messages)
})
return promise
} else {
return Promise.value(messages)
// Validate the message signature
let publicKey = Data(hex: sender.removing05PrefixIfNeeded())
let isValid = (try? Ed25519.verifySignature(signature, publicKey: publicKey, data: data)) ?? false
guard isValid else {
SNLog("Ignoring message with invalid signature.")
return nil
}
return message
}
let serverID = messages.map { $0.serverID! }.max() ?? 0 // Safe because messages with a nil serverID are filtered out
let lastMessageServerID = storage.getLastMessageServerID(for: room, on: server) ?? 0
if serverID > lastMessageServerID {
let (promise, seal) = Promise<[OpenGroupMessageV2]>.pending()
storage.write(with: { transaction in
storage.setLastMessageServerID(for: room, on: server, to: serverID, using: transaction)
}, completion: {
seal.fulfill(messages)
})
return promise
} else {
return Promise.value(messages)
}
}

Loading…
Cancel
Save