Clean up ahead of protocol changes

pull/216/head
nielsandriesse 5 years ago
parent 6f17baa7ac
commit e34e66ccfd

@ -12,7 +12,6 @@
241C6314231F64C000B4198E /* JazzIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241C630E231F5AAC00B4198E /* JazzIcon.swift */; };
241C6315231F64CE00B4198E /* CGFloat+Rounding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241C6312231F5F1D00B4198E /* CGFloat+Rounding.swift */; };
241C6316231F64CE00B4198E /* UIColor+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241C6310231F5C4400B4198E /* UIColor+Helper.swift */; };
24A830A22293CD0100F4CAC0 /* LokiP2PServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A830A12293CD0100F4CAC0 /* LokiP2PServer.swift */; };
2AE2882E4C2B96BFFF9EE27C /* Pods_SignalShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F94C85CB0B235DA37F68ED0 /* Pods_SignalShareExtension.framework */; };
3403B95D20EA9527001A1F44 /* OWSContactShareButtonsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3403B95B20EA9526001A1F44 /* OWSContactShareButtonsView.m */; };
34074F61203D0CBE004596AE /* OWSSounds.m in Sources */ = {isa = PBXBuildFile; fileRef = 34074F5F203D0CBD004596AE /* OWSSounds.m */; };
@ -751,7 +750,6 @@
241C630E231F5AAC00B4198E /* JazzIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JazzIcon.swift; sourceTree = "<group>"; };
241C6310231F5C4400B4198E /* UIColor+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Helper.swift"; sourceTree = "<group>"; };
241C6312231F5F1D00B4198E /* CGFloat+Rounding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat+Rounding.swift"; sourceTree = "<group>"; };
24A830A12293CD0100F4CAC0 /* LokiP2PServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LokiP2PServer.swift; sourceTree = "<group>"; };
264242150E87D10A357DB07B /* Pods_SignalMessaging.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalMessaging.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3403B95B20EA9526001A1F44 /* OWSContactShareButtonsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactShareButtonsView.m; sourceTree = "<group>"; };
3403B95C20EA9527001A1F44 /* OWSContactShareButtonsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactShareButtonsView.h; sourceTree = "<group>"; };
@ -2842,7 +2840,6 @@
B8BFFF392355426100102A27 /* Shelved */ = {
isa = PBXGroup;
children = (
24A830A12293CD0100F4CAC0 /* LokiP2PServer.swift */,
B825849F2315024B001B41CB /* LokiRSSFeedPoller.swift */,
);
path = Shelved;
@ -4107,7 +4104,6 @@
4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */,
3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */,
B82584A02315024B001B41CB /* LokiRSSFeedPoller.swift in Sources */,
24A830A22293CD0100F4CAC0 /* LokiP2PServer.swift in Sources */,
349ED990221B0194008045B0 /* Onboarding2FAViewController.swift in Sources */,
C353F8F7244808E90011121A /* PNModeSheet.swift in Sources */,
45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */,

@ -65,7 +65,6 @@ static NSTimeInterval launchStartedAt;
@property (nonatomic) BOOL didAppLaunchFail;
// Loki
@property (nonatomic) LKP2PServer *lokiP2PServer;
@property (nonatomic) LKPoller *lokiPoller;
@property (nonatomic) LKRSSFeedPoller *lokiNewsFeedPoller;
@property (nonatomic) LKRSSFeedPoller *lokiMessengerUpdatesFeedPoller;
@ -201,8 +200,6 @@ static NSTimeInterval launchStartedAt;
// Loki: Stop pollers
[self stopPollerIfNeeded];
[self stopOpenGroupPollersIfNeeded];
if (self.lokiP2PServer) { [self.lokiP2PServer stop]; }
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
@ -757,9 +754,6 @@ static NSTimeInterval launchStartedAt;
NSString *userHexEncodedPublicKey = self.tsAccountManager.localNumber;
// Loki: Tell our friends that we are online
[LKP2PAPI broadcastOnlineStatus];
// Loki: Start pollers
[self startPollerIfNeeded];
[self startOpenGroupPollersIfNeeded];

@ -1,104 +0,0 @@
import GCDWebServer
// TODO: Clean
private extension GCDWebServerResponse {
convenience init<E: RawRepresentable>(statusCode: E) where E.RawValue == Int {
self.init(statusCode: statusCode.rawValue)
}
}
private extension GCDWebServerDataRequest {
var truncatedContentType: String? {
guard let contentType = contentType else { return nil }
guard let substring = contentType.split(separator: ";").first else { return contentType }
return String(substring)
}
// GCDWebServerDataRequest already provides this implementation
// However it will abort when running in DEBUG, we don't want that so we just override it with a version which doesn't abort
var jsonObject: JSON? {
let acceptedMimeTypes = [ "application/json", "text/json", "text/javascript" ]
guard let mimeType = truncatedContentType, acceptedMimeTypes.contains(mimeType) else { return nil }
do {
let object = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
return object as? JSON
} catch let error {
print("[Loki] Failed to serialize JSON: \(error).")
}
return nil
}
}
@objc(LKP2PServer)
final class LokiP2PServer : NSObject {
private enum StatusCode : Int {
case ok = 200
case badRequest = 400
case notFound = 404
case methodNotAllowed = 405
case internalServerError = 500
}
private lazy var webServer: GCDWebServer = {
let webServer = GCDWebServer()
// Don't allow specific methods
let invalidMethodProcessBlock: (GCDWebServerRequest) -> GCDWebServerResponse? = { _ in
return GCDWebServerResponse(statusCode: StatusCode.methodNotAllowed)
}
let invalidMethods = [ "GET", "PUT", "DELETE" ]
for method in invalidMethods {
webServer.addDefaultHandler(forMethod: method, request: GCDWebServerRequest.self, processBlock: invalidMethodProcessBlock)
}
// By default send 404 for any path
webServer.addDefaultHandler(forMethod: "POST", request: GCDWebServerRequest.self, processBlock: { _ in
return GCDWebServerResponse(statusCode: StatusCode.notFound)
})
// Handle our specific storage path
webServer.addHandler(forMethod: "POST", path: "/storage_rpc/v1", request: GCDWebServerDataRequest.self, processBlock: { request in
// Make sure we were sent a good request
guard let dataRequest = request as? GCDWebServerDataRequest, let json = dataRequest.jsonObject else {
return GCDWebServerResponse(statusCode: StatusCode.badRequest)
}
// Only allow the store method
guard let method = json["method"] as? String, method == "store" else {
return GCDWebServerResponse(statusCode: StatusCode.notFound)
}
// Make sure we have the data
guard let params = json["params"] as? [String: String], let data = params["data"] else {
return GCDWebServerResponse(statusCode: StatusCode.badRequest)
}
// Pass it off to the message handler
LokiP2PAPI.handleReceivedMessage(base64EncodedData: data)
// Send a response back
return GCDWebServerResponse(statusCode: StatusCode.ok.rawValue)
})
return webServer
}()
@objc public var serverURL: URL? { return webServer.serverURL }
@objc public var isRunning: Bool { return webServer.isRunning }
@discardableResult
@objc func start(onPort port: UInt) -> Bool {
guard !webServer.isRunning else { return false }
webServer.start(withPort: port, bonjourName: nil)
return webServer.isRunning
}
@objc func stop() { webServer.stop() }
}

@ -91,7 +91,6 @@
#import <SessionServiceKit/OWSContactsOutputStream.h>
#import <SessionServiceKit/OWSDispatch.h>
#import <SessionServiceKit/OWSEndSessionMessage.h>
#import <SessionServiceKit/LKEphemeralMessage.h>
#import <SessionServiceKit/LKDeviceLinkMessage.h>
#import <SessionServiceKit/OWSError.h>
#import <SessionServiceKit/OWSFileSystem.h>

@ -85,9 +85,7 @@ public class AvatarImageView: UIImageView {
}
@objc func updateOnlineStatusIndicator() {
let peerInfo = LokiP2PAPI.getInfo(for: contactID)
let isOnline = peerInfo?.isOnline ?? false
let color: UIColor = isOnline ? .lokiGreen() : .lokiGray()
let color = UIColor.lokiGray()
let currentUserID = getUserHexEncodedPublicKey()
let isCurrentUser = (contactID == currentUserID)
layer.borderColor = isCurrentUser ? UIColor.clear.cgColor : color.cgColor

@ -78,54 +78,27 @@ public final class LokiAPI : NSObject {
guard let lokiMessage = LokiMessage.from(signalMessage: signalMessage) else { return Promise(error: LokiAPIError.messageConversionFailed) }
let notificationCenter = NotificationCenter.default
let destination = lokiMessage.destination
func sendLokiMessage(_ lokiMessage: LokiMessage, to target: LokiAPITarget) -> RawResponsePromise {
let parameters = lokiMessage.toJSON()
return attempt(maxRetryCount: maxRetryCount) {
invoke(.sendMessage, on: target, associatedWith: destination, parameters: parameters)
}
}
func sendLokiMessageUsingSwarmAPI() -> Promise<Set<RawResponsePromise>> {
notificationCenter.post(name: .calculatingPoW, object: NSNumber(value: signalMessage.timestamp))
return lokiMessage.calculatePoW().then2 { lokiMessageWithPoW -> Promise<Set<RawResponsePromise>> in
notificationCenter.post(name: .routing, object: NSNumber(value: signalMessage.timestamp))
return getTargetSnodes(for: destination).map2 { snodes in
return Set(snodes.map { snode in
notificationCenter.post(name: .messageSending, object: NSNumber(value: signalMessage.timestamp))
return sendLokiMessage(lokiMessageWithPoW, to: snode).map2 { rawResponse in
if let json = rawResponse as? JSON, let powDifficulty = json["difficulty"] as? Int {
guard powDifficulty != LokiAPI.powDifficulty else { return rawResponse }
print("[Loki] Setting proof of work difficulty to \(powDifficulty).")
LokiAPI.powDifficulty = UInt(powDifficulty)
} else {
print("[Loki] Failed to update proof of work difficulty from: \(rawResponse).")
}
return rawResponse
notificationCenter.post(name: .calculatingPoW, object: NSNumber(value: signalMessage.timestamp))
return lokiMessage.calculatePoW().then2 { lokiMessageWithPoW -> Promise<Set<RawResponsePromise>> in
notificationCenter.post(name: .routing, object: NSNumber(value: signalMessage.timestamp))
return getTargetSnodes(for: destination).map2 { snodes in
return Set(snodes.map { snode in
notificationCenter.post(name: .messageSending, object: NSNumber(value: signalMessage.timestamp))
let parameters = lokiMessageWithPoW.toJSON()
return attempt(maxRetryCount: maxRetryCount) {
invoke(.sendMessage, on: snode, associatedWith: destination, parameters: parameters)
}.map2 { rawResponse in
if let json = rawResponse as? JSON, let powDifficulty = json["difficulty"] as? Int {
guard powDifficulty != LokiAPI.powDifficulty else { return rawResponse }
print("[Loki] Setting proof of work difficulty to \(powDifficulty).")
LokiAPI.powDifficulty = UInt(powDifficulty)
} else {
print("[Loki] Failed to update proof of work difficulty from: \(rawResponse).")
}
})
}
}
}
if let peer = LokiP2PAPI.getInfo(for: destination), (lokiMessage.isPing || peer.isOnline) {
let target = LokiAPITarget(address: peer.address, port: peer.port, publicKeySet: nil)
// TODO: Retrying
return Promise.value([ target ]).mapValues2 { sendLokiMessage(lokiMessage, to: $0) }.map2 { Set($0) }.get2 { _ in
LokiP2PAPI.markOnline(destination)
onP2PSuccess()
}.recover2 { error -> Promise<Set<RawResponsePromise>> in
LokiP2PAPI.markOffline(destination)
if lokiMessage.isPing {
print("[Loki] Failed to ping \(destination); marking contact as offline.")
if let error = error as? NSError {
error.isRetryable = false
throw error
} else {
throw error
return rawResponse
}
}
return sendLokiMessageUsingSwarmAPI()
})
}
} else {
return sendLokiMessageUsingSwarmAPI()
}
}

@ -1,14 +0,0 @@
#import "LKFriendRequestMessage.h"
NS_ASSUME_NONNULL_BEGIN
// TODO: This is just a friend request message with a flag set. Not sure if it needs to be its own type.
NS_SWIFT_NAME(SessionRequestMessage)
@interface LKSessionRequestMessage : LKFriendRequestMessage
- (instancetype)initWithThread:(TSThread *)thread;
@end
NS_ASSUME_NONNULL_END

@ -1,27 +0,0 @@
#import "LKSessionRequestMessage.h"
#import <SessionCoreKit/NSDate+OWS.h>
#import <SessionServiceKit/SessionServiceKit-Swift.h>
@implementation LKSessionRequestMessage
#pragma mark Initialization
- (instancetype)initWithThread:(TSThread *)thread {
return [self initOutgoingMessageWithTimestamp:NSDate.ows_millisecondTimeStamp inThread:thread messageBody:@"" attachmentIds:[NSMutableArray<NSString *> new]
expiresInSeconds:0 expireStartedAt:0 isVoiceMessage:NO groupMetaMessage:TSGroupMetaMessageUnspecified quotedMessage:nil contactShare:nil linkPreview:nil];
}
#pragma mark Building
- (nullable SSKProtoDataMessageBuilder *)dataMessageBuilder
{
SSKProtoDataMessageBuilder *builder = super.dataMessageBuilder;
if (builder == nil) { return nil; }
[builder setFlags:SSKProtoDataMessageFlagsSessionRequest];
return builder;
}
#pragma mark Settings
- (BOOL)shouldBeSaved { return NO; }
- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeSessionRequest]; }
- (BOOL)shouldSyncTranscript { return NO; }
@end

@ -143,7 +143,7 @@ public final class FriendRequestProtocol : NSObject {
return
}
let thread = TSContactThread.getOrCreateThread(withContactId: hexEncodedPublicKey, transaction: transaction)
let ephemeralMessage = EphemeralMessage(in: thread)
let ephemeralMessage = EphemeralMessage(thread: thread)
let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue
messageSenderJobQueue.add(message: ephemeralMessage, transaction: transaction)
}

@ -0,0 +1,23 @@
@objc(LKEphemeralMessage)
internal final class EphemeralMessage : TSOutgoingMessage {
@objc internal override var ttl: UInt32 { return UInt32(TTLUtilities.getTTL(for: .ephemeral)) }
@objc internal override func shouldBeSaved() -> Bool { return false }
@objc internal override func shouldSyncTranscript() -> Bool { return false }
@objc internal init(thread: TSThread) {
super.init(outgoingMessageWithTimestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageBody: "",
attachmentIds: NSMutableArray(), expiresInSeconds: 0, expireStartedAt: 0, isVoiceMessage: false,
groupMetaMessage: .unspecified, quotedMessage: nil, contactShare: nil, linkPreview: nil)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
required init(dictionary: [String:Any]) throws {
try super.init(dictionary: dictionary)
}
}

@ -0,0 +1,29 @@
@objc(LKSessionRequestMessage)
internal final class SessionRequestMessage : TSOutgoingMessage {
@objc internal override var ttl: UInt32 { return UInt32(TTLUtilities.getTTL(for: .sessionRequest)) }
@objc internal override func shouldBeSaved() -> Bool { return false }
@objc internal override func shouldSyncTranscript() -> Bool { return false }
@objc internal init(thread: TSThread) {
super.init(outgoingMessageWithTimestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageBody: "",
attachmentIds: NSMutableArray(), expiresInSeconds: 0, expireStartedAt: 0, isVoiceMessage: false,
groupMetaMessage: .unspecified, quotedMessage: nil, contactShare: nil, linkPreview: nil)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
required init(dictionary: [String:Any]) throws {
try super.init(dictionary: dictionary)
}
@objc internal override func dataMessageBuilder() -> Any? {
guard let builder = super.dataMessageBuilder() as? SSKProtoDataMessage.SSKProtoDataMessageBuilder else { return nil }
builder.setFlags(UInt32(SSKProtoDataMessage.SSKProtoDataMessageFlags.sessionRequest.rawValue))
return builder
}
}

@ -1,16 +0,0 @@
#import "LKEphemeralMessage.h"
NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(LokiAddressMessage)
@interface LKAddressMessage : LKEphemeralMessage
@property (nonatomic, readonly) NSString *address;
@property (nonatomic, readonly) uint16_t port;
@property (nonatomic, readonly) BOOL isPing;
- (instancetype)initInThread:(nullable TSThread *)thread address:(NSString *)address port:(uint16_t)port isPing:(BOOL)isPing;
@end
NS_ASSUME_NONNULL_END

@ -1,49 +0,0 @@
#import "LKAddressMessage.h"
#import "NSDate+OWS.h"
#import "SignalRecipient.h"
#import <SessionServiceKit/SessionServiceKit-Swift.h>
@interface LKAddressMessage ()
@property (nonatomic) NSString *address;
@property (nonatomic) uint16_t port;
@property (nonatomic) BOOL isPing;
@end
@implementation LKAddressMessage
#pragma mark Initialization
- (instancetype)initInThread:(nullable TSThread *)thread address:(NSString *)address port:(uint16_t)port isPing:(bool)isPing
{
self = [super initInThread:thread];
if (self) {
_address = address;
_port = port;
_isPing = isPing;
}
return self;
}
#pragma mark Building
- (SSKProtoContentBuilder *)prepareCustomContentBuilder:(SignalRecipient *)recipient {
SSKProtoContentBuilder *contentBuilder = [super prepareCustomContentBuilder:recipient];
SSKProtoLokiAddressMessageBuilder *addressMessageBuilder = SSKProtoLokiAddressMessage.builder;
[addressMessageBuilder setPtpAddress:self.address];
uint32_t portAsUInt32 = self.port;
[addressMessageBuilder setPtpPort:portAsUInt32];
NSError *error;
SSKProtoLokiAddressMessage *addressMessage = [addressMessageBuilder buildAndReturnError:&error];
if (error || addressMessage == nil) {
OWSFailDebug(@"Failed to build Loki address message for: %@ due to error: %@.", recipient.recipientId, error);
return nil;
} else {
[contentBuilder setLokiAddressMessage:addressMessage];
}
return contentBuilder;
}
#pragma mark Settings
- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeAddress]; }
@end

@ -1,12 +0,0 @@
#import "TSOutgoingMessage.h"
NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(EphemeralMessage)
@interface LKEphemeralMessage : TSOutgoingMessage
- (instancetype)initInThread:(nullable TSThread *)thread;
@end
NS_ASSUME_NONNULL_END

@ -1,18 +0,0 @@
#import "LKEphemeralMessage.h"
#import <SessionCoreKit/NSDate+OWS.h>
#import <SessionServiceKit/SessionServiceKit-Swift.h>
@implementation LKEphemeralMessage
#pragma mark Initialization
- (instancetype)initInThread:(nullable TSThread *)thread {
return [self initOutgoingMessageWithTimestamp:NSDate.ows_millisecondTimeStamp inThread:thread messageBody:@"" attachmentIds:[NSMutableArray<NSString *> new]
expiresInSeconds:0 expireStartedAt:0 isVoiceMessage:NO groupMetaMessage:TSGroupMetaMessageUnspecified quotedMessage:nil contactShare:nil linkPreview:nil];
}
#pragma mark Settings
- (BOOL)shouldSyncTranscript { return NO; }
- (BOOL)shouldBeSaved { return NO; }
- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeEphemeral]; }
@end

@ -141,16 +141,4 @@ public final class SessionMetaProtocol : NSObject {
// This dispatches async on the main queue internally where it starts a new write transaction
profileManager.setProfileKeyData(profileKey, forRecipientId: hexEncodedPublicKey, avatarURL: profilePictureURL)
}
// MARK: P2P
@objc(handleP2PAddressMessageIfNeeded:wrappedIn:)
public static func handleP2PAddressMessageIfNeeded(_ protoContent: SSKProtoContent, wrappedIn envelope: SSKProtoEnvelope) {
// The envelope source is set during UD decryption
let hexEncodedPublicKey = envelope.source!
guard let addressMessage = protoContent.lokiAddressMessage, let address = addressMessage.ptpAddress else { return }
let portAsUInt32 = addressMessage.ptpPort
guard portAsUInt32 != 0, portAsUInt32 < UInt16.max else { return }
let port = UInt16(portAsUInt32)
LokiP2PAPI.didReceiveLokiAddressMessage(forContact: hexEncodedPublicKey, address: address, port: port, receivedThroughP2P: envelope.isPtpMessage)
}
}

@ -11,7 +11,7 @@
}
#pragma mark Building
- (nullable SSKProtoDataMessageBuilder *)dataMessageBuilder
- (nullable id)dataMessageBuilder
{
SSKProtoDataMessageBuilder *builder = super.dataMessageBuilder;
if (builder == nil) { return nil; }

@ -11,7 +11,7 @@
}
#pragma mark Building
- (nullable SSKProtoDataMessageBuilder *)dataMessageBuilder
- (nullable id)dataMessageBuilder
{
SSKProtoDataMessageBuilder *builder = super.dataMessageBuilder;
if (builder == nil) { return nil; }

@ -51,7 +51,7 @@ public class LokiSessionResetImplementation : NSObject, SessionResetProtocol {
}
// If the current user initiated the reset then send back an empty message to acknowledge the completion of the session reset
if thread.sessionResetStatus == .initiated {
let emptyMessage = EphemeralMessage(in: thread)
let emptyMessage = EphemeralMessage(thread: thread)
SSKEnvironment.shared.messageSender.sendPromise(message: emptyMessage).retainUntilComplete()
}
// Show session reset done message

@ -216,7 +216,7 @@ public final class SessionManagementProtocol : NSObject {
}
guard validHEPKs.contains(hexEncodedPublicKey) else { return }
let thread = TSContactThread.getOrCreateThread(withContactId: hexEncodedPublicKey, transaction: transaction)
let ephemeralMessage = EphemeralMessage(in: thread)
let ephemeralMessage = EphemeralMessage(thread: thread)
let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue
messageSenderJobQueue.add(message: ephemeralMessage, transaction: transaction)
}
@ -243,7 +243,7 @@ public final class SessionManagementProtocol : NSObject {
// Archive all sessions
storage.archiveAllSessions(forContact: hexEncodedPublicKey, protocolContext: transaction)
// Send an ephemeral message
let ephemeralMessage = EphemeralMessage(in: thread)
let ephemeralMessage = EphemeralMessage(thread: thread)
let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue
messageSenderJobQueue.add(message: ephemeralMessage, transaction: transaction)
}
@ -263,7 +263,7 @@ public final class SessionManagementProtocol : NSObject {
thread.sessionResetStatus = .requestReceived
thread.save(with: transaction)
// Send an ephemeral message
let ephemeralMessage = EphemeralMessage(in: thread)
let ephemeralMessage = EphemeralMessage(thread: thread)
let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue
messageSenderJobQueue.add(message: ephemeralMessage, transaction: transaction)
}

@ -1,233 +0,0 @@
// TODO: Match Android design
@objc(LKP2PAPI)
public class LokiP2PAPI : NSObject {
private static let storage = OWSPrimaryStorage.shared()
private static let messageSender = SSKEnvironment.shared.messageSender
private static let messageReceiver = SSKEnvironment.shared.messageReceiver
private static let ourHexEncodedPubKey = getUserHexEncodedPublicKey()
/// The amount of time before pinging when a user is set to offline
private static let offlinePingTime = 2 * kMinuteInterval
/// A p2p state struct
public struct PeerInfo {
public var address: String
public var port: UInt16
public var isOnline: Bool
public var timerDuration: Double
public var pingTimer: Timer? = nil
}
/// Our p2p address
private static var ourP2PAddress: LokiAPITarget? = nil
/// This is where we store the p2p details of our contacts
private static var peerInfo = [String:PeerInfo]()
// MARK: - Public functions
/// Set our local P2P address
///
/// - Parameter url: The url to our local server
@objc public static func setOurP2PAddress(url: URL) {
guard let scheme = url.scheme, let host = url.host, let port = url.port else { return }
let target = LokiAPITarget(address: "\(scheme)://\(host)", port: UInt16(port), publicKeySet: nil)
ourP2PAddress = target
}
/// Ping a contact
///
/// - Parameter pubKey: The contact hex pubkey
@objc(pingContact:)
public static func ping(contact pubKey: String) {
// Dispatch on the main queue so we escape any transaction blocks
DispatchQueue.main.async {
var contactThread: TSThread? = nil
storage.dbReadConnection.read { transaction in
contactThread = TSContactThread.getWithContactId(pubKey, transaction: transaction)
}
guard let thread = contactThread else {
print("[Loki] Failed to fetch thread when attempting to ping: \(pubKey).")
return
}
guard let message = createLokiAddressMessage(for: thread, isPing: true) else {
print("[Loki] Failed to build ping message for: \(pubKey).")
return
}
messageSender.sendPromise(message: message).retainUntilComplete()
}
}
/// Broadcast an online message to all our friends.
/// This shouldn't be called inside a transaction.
@objc public static func broadcastOnlineStatus() {
// Escape any transaction blocks
DispatchQueue.main.async {
let friendThreads = getAllFriendThreads()
for thread in friendThreads {
sendOnlineBroadcastMessage(forThread: thread)
}
}
}
public static func handleReceivedMessage(base64EncodedData: String) {
guard let data = Data(base64Encoded: base64EncodedData) else {
print("[Loki] Failed to decode data for P2P message.")
return
}
guard let envelope = try? LokiMessageWrapper.unwrap(data: data) else {
print("[Loki] Failed to unwrap data for P2P message.")
return
}
// We need to set the P2P field on the envelope
let builder = envelope.asBuilder()
builder.setIsPtpMessage(true)
// Send it to the message receiver
do {
let newEnvelope = try builder.build()
let envelopeData = try newEnvelope.serializedData()
messageReceiver.handleReceivedEnvelopeData(envelopeData)
} catch let error {
print("[Loki] Something went wrong during proto conversion: \(error).")
}
}
// MARK: - Internal functions
/// Get the P2P details for the given contact.
///
/// - Parameter pubKey: The contact hex pubkey
/// - Returns: The P2P Details or nil if they don't exist
public static func getInfo(for hexEncodedPublicKey: String) -> PeerInfo? {
return peerInfo[hexEncodedPublicKey]
}
/// Get the `LokiAddressMessage` for the given thread.
///
/// - Parameter thread: The contact thread.
/// - Returns: The `LokiAddressMessage` for that thread.
@objc public static func onlineBroadcastMessage(forThread thread: TSThread) -> LokiAddressMessage? {
return createLokiAddressMessage(for: thread, isPing: false)
}
/// Handle P2P logic when we receive a `LokiAddressMessage`
///
/// - Parameters:
/// - pubKey: The other users pubKey
/// - address: The pther users p2p address
/// - port: The other users p2p port
/// - receivedThroughP2P: Wether we received the message through p2p
@objc internal static func didReceiveLokiAddressMessage(forContact pubKey: String, address: String, port: UInt16, receivedThroughP2P: Bool) {
// Stagger the ping timers so that contacts don't ping each other at the same time
let timerDuration = pubKey < ourHexEncodedPubKey ? 1 * kMinuteInterval : 2 * kMinuteInterval
// Get out current contact details
let oldContactInfo = peerInfo[pubKey]
// Set the new contact details
// A contact is always assumed to be offline unless the specific conditions below are met
let info = PeerInfo(address: address, port: port, isOnline: false, timerDuration: timerDuration, pingTimer: nil)
peerInfo[pubKey] = info
// Set up our checks
let oldContactExists = oldContactInfo != nil
let wasOnline = oldContactInfo?.isOnline ?? false
let isPeerInfoMatching = oldContactInfo?.address == address && oldContactInfo?.port == port
/*
We need to check if we should ping the user.
We don't ping the user IF:
- We had old contact details
- We got a P2P message
- The old contact was set as `Online`
- The new p2p details match the old one
*/
if oldContactExists && receivedThroughP2P && wasOnline && isPeerInfoMatching {
setOnline(true, forContact: pubKey)
return
}
/*
Ping the contact.
This happens in the following scenarios:
1. We didn't have the contact, we need to ping them to let them know our details.
2. wasP2PMessage = false, so we assume the contact doesn't have our details.
3. We had the contact marked as offline, we need to make sure that we can reach their server.
4. The other contact details have changed, we need to make sure that we can reach their new server.
*/
ping(contact: pubKey)
}
internal static func markOnline(_ hexEncodedPublicKey: String) {
setOnline(true, forContact: hexEncodedPublicKey)
}
internal static func markOffline(_ hexEncodedPublicKey: String) {
setOnline(false, forContact: hexEncodedPublicKey)
}
/// Mark a contact as online or offline.
///
/// - Parameters:
/// - isOnline: Whether to set the contact to online or offline.
/// - pubKey: The contact hex pubKey
@objc internal static func setOnline(_ isOnline: Bool, forContact pubKey: String) {
// Make sure we are on the main thread
DispatchQueue.main.async {
guard var info = peerInfo[pubKey] else { return }
let interval = isOnline ? info.timerDuration : offlinePingTime
// Setup a new timer
info.pingTimer?.invalidate()
info.pingTimer = WeakTimer.scheduledTimer(timeInterval: interval, target: self, userInfo: nil, repeats: true) { _ in ping(contact: pubKey) }
info.isOnline = isOnline
peerInfo[pubKey] = info
NotificationCenter.default.post(name: .contactOnlineStatusChanged, object: pubKey)
}
}
// MARK: - Private functions
private static func sendOnlineBroadcastMessage(forThread thread: TSContactThread) {
AssertIsOnMainThread()
guard let message = onlineBroadcastMessage(forThread: thread) else {
// print("[Loki] P2P address not set.")
return
}
messageSender.sendPromise(message: message).catch2 { error in
Logger.warn("Failed to send online status to \(thread.contactIdentifier()).")
}.retainUntilComplete()
}
private static func getAllFriendThreads() -> [TSContactThread] {
var friendThreadIDs: [String] = []
storage.dbReadConnection.read { transaction in
TSContactThread.enumerateCollectionObjects(with: transaction) { object, _ in
guard let thread = object as? TSContactThread, let uniqueID = thread.uniqueId, thread.contactIdentifier() != ourHexEncodedPubKey else { return }
let status = storage.getFriendRequestStatus(for: thread.contactIdentifier(), transaction: transaction)
guard status == .friends else { return }
friendThreadIDs.append(uniqueID)
}
}
return friendThreadIDs.compactMap { TSContactThread.fetch(uniqueId: $0) }
}
private static func createLokiAddressMessage(for thread: TSThread, isPing: Bool) -> LokiAddressMessage? {
guard let ourAddress = ourP2PAddress else {
// print("[Loki] P2P address not set.")
return nil
}
return LokiAddressMessage(in: thread, address: ourAddress.address, port: ourAddress.port, isPing: isPing)
}
}

@ -61,7 +61,7 @@ NS_ASSUME_NONNULL_BEGIN
return YES;
}
- (nullable SSKProtoDataMessageBuilder *)dataMessageBuilder
- (nullable id)dataMessageBuilder
{
SSKProtoGroupContextBuilder *groupContextBuilder =
[SSKProtoGroupContext builderWithId:self.groupId type:SSKProtoGroupContextTypeRequestInfo];

@ -50,7 +50,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (nullable SSKProtoDataMessageBuilder *)dataMessageBuilder
- (nullable id)dataMessageBuilder
{
SSKProtoDataMessageBuilder *_Nullable dataMessageBuilder = [super dataMessageBuilder];
if (!dataMessageBuilder) {

@ -38,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
- (uint)ttl { return (uint)[LKTTLUtilities getTTLFor:LKMessageTypeEphemeral]; }
- (nullable SSKProtoDataMessageBuilder *)dataMessageBuilder
- (nullable id)dataMessageBuilder
{
SSKProtoDataMessageBuilder *_Nullable builder = [super dataMessageBuilder];
if (!builder) {

@ -157,7 +157,7 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) {
* Intermediate protobuf representation
* Subclasses can augment if they want to manipulate the data message before building.
*/
- (nullable SSKProtoDataMessageBuilder *)dataMessageBuilder;
- (nullable id)dataMessageBuilder;
- (nullable SSKProtoDataMessage *)buildDataMessage:(NSString *_Nullable)recipientId;

@ -900,7 +900,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt
#pragma mark -
- (nullable SSKProtoDataMessageBuilder *)dataMessageBuilder
- (nullable id)dataMessageBuilder
{
TSThread *thread = self.thread;
OWSAssertDebug(thread);

@ -19,8 +19,6 @@
#import "OWSDisappearingConfigurationUpdateInfoMessage.h"
#import "OWSDisappearingMessagesConfiguration.h"
#import "OWSDisappearingMessagesJob.h"
#import "LKEphemeralMessage.h"
#import "LKSessionRequestMessage.h"
#import "LKDeviceLinkMessage.h"
#import "OWSIdentityManager.h"
#import "OWSIncomingMessageFinder.h"
@ -449,11 +447,6 @@ NS_ASSUME_NONNULL_BEGIN
// Loki: Handle pre key bundle message if needed
[LKSessionManagementProtocol handlePreKeyBundleMessageIfNeeded:contentProto wrappedIn:envelope using:transaction];
// Loki: Handle address message if needed
/*
[LKSessionMetaProtocol handleP2PAddressMessageIfNeeded:contentProto wrappedIn:envelope];
*/
// Loki: Handle device linking message if needed
if (contentProto.lokiDeviceLinkMessage != nil) {

@ -45,11 +45,9 @@
#import "TSThread.h"
#import "TSContactThread.h"
#import "LKFriendRequestMessage.h"
#import "LKSessionRequestMessage.h"
#import "LKSessionRestoreMessage.h"
#import "LKDeviceLinkMessage.h"
#import "LKUnlinkDeviceMessage.h"
#import "LKAddressMessage.h"
#import <SessionAxolotlKit/AxolotlExceptions.h>
#import <SessionAxolotlKit/CipherMessage.h>
#import <SessionAxolotlKit/PreKeyBundle.h>
@ -1933,9 +1931,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
BOOL isSilent = message.isSilent;
BOOL isOnline = message.isOnline;
BOOL isPing = NO;
LKAddressMessage *addressMessage = [message as:[LKAddressMessage class]];
BOOL isPing = addressMessage != nil && addressMessage.isPing;
OWSMessageServiceParams *messageParams =
[[OWSMessageServiceParams alloc] initWithType:messageType
recipientId:recipientID

Loading…
Cancel
Save