Merge branch 'charlesmchen/websocketRequests'

pull/1/head
Matthew Chen 7 years ago
commit ebd24feff6

@ -1 +1 @@
Subproject commit 086242800e27b3ee431ad23e9f29f3358e813059
Subproject commit ba63216170bbe6d85d9c46c4ee37cdf672f6a7a7

@ -6,7 +6,7 @@ PROTOC=protoc \
--proto_path="${HOME}/src/signal/protobuf-objc/src/compiler/google/protobuf/" \
--proto_path='./'
all: signal_service_proto provisioning_protos fingerprint_protos
all: signal_service_proto provisioning_protos fingerprint_protos websocket_protos
signal_service_proto: OWSSignalServiceProtos.proto
$(PROTOC) --objc_out=../src/Messages/ \
@ -20,3 +20,6 @@ fingerprint_protos: OWSFingerprintProtos.proto
$(PROTOC) --objc_out=../src/Security/ \
OWSFingerprintProtos.proto
websocket_protos: WebSocketResources.proto
$(PROTOC) --objc_out=../src/Network/WebSockets/ \
WebSocketResources.proto

@ -0,0 +1,45 @@
/**
* Copyright (C) 2014-2016 Open Whisper Systems
*
* Licensed according to the LICENSE file in this repository.
*/
package signalservice;
option java_package = "org.whispersystems.signalservice.internal.websocket";
option java_outer_classname = "WebSocketProtos";
// Signal-iOS
import "objectivec-descriptor.proto";
option (google.protobuf.objectivec_file_options).class_prefix = "WebSocketResources";
message WebSocketRequestMessage
{
optional string verb = 1;
optional string path = 2;
optional bytes body = 3;
repeated string headers = 5;
optional uint64 id = 4;
}
message WebSocketResponseMessage
{
optional uint64 id = 1;
optional uint32 status = 2;
optional string message = 3;
repeated string headers = 5;
optional bytes body = 4;
}
message WebSocketMessage
{
enum Type {
UNKNOWN = 0;
REQUEST = 1;
RESPONSE = 2;
}
optional Type type = 1;
optional WebSocketRequestMessage request = 2;
optional WebSocketResponseMessage response = 3;
}

@ -39,6 +39,7 @@
#import "TSOutgoingMessage.h"
#import "TSPreKeyManager.h"
#import "TSQuotedMessage.h"
#import "TSSocketManager.h"
#import "TSThread.h"
#import "Threading.h"
#import <AxolotlKit/AxolotlExceptions.h>
@ -975,117 +976,192 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
messages:deviceMessages
relay:recipient.relay
timeStamp:message.timestamp];
[self.networkManager makeRequest:request
success:^(NSURLSessionDataTask *task, id responseObject) {
if (isLocalNumber && deviceMessages.count == 0) {
DDLogInfo(@"%@ Sent a message with no device messages; clearing 'mayHaveLinkedDevices'.", self.logTag);
// In order to avoid skipping necessary sync messages, the default value
// for mayHaveLinkedDevices is YES. Once we've successfully sent a
// sync message with no device messages (e.g. the service has confirmed
// that we have no linked devices), we can set mayHaveLinkedDevices to NO
// to avoid unnecessary message sends for sync messages until we learn
// of a linked device (e.g. through the device linking UI or by receiving
// a sync message, etc.).
[OWSDeviceManager.sharedManager clearMayHaveLinkedDevicesIfNotSet];
if (TSSocketManager.sharedManager.canMakeRequests) {
[TSSocketManager.sharedManager makeRequest:request
success:^(id _Nullable responseObject) {
[self messageSendDidSucceed:message
recipient:recipient
isLocalNumber:isLocalNumber
deviceMessages:deviceMessages
success:successHandler];
}
failure:^(NSInteger statusCode, NSError *error) {
[self messageSendDidFail:message
recipient:recipient
thread:thread
isLocalNumber:isLocalNumber
deviceMessages:deviceMessages
remainingAttempts:remainingAttempts
statusCode:statusCode
error:error
success:successHandler
failure:failureHandler];
}];
} else {
[self.networkManager makeRequest:request
success:^(NSURLSessionDataTask *task, id responseObject) {
[self messageSendDidSucceed:message
recipient:recipient
isLocalNumber:isLocalNumber
deviceMessages:deviceMessages
success:successHandler];
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
NSInteger statusCode = response.statusCode;
[self messageSendDidFail:message
recipient:recipient
thread:thread
isLocalNumber:isLocalNumber
deviceMessages:deviceMessages
remainingAttempts:remainingAttempts
statusCode:statusCode
error:error
success:successHandler
failure:failureHandler];
}];
}
}
dispatch_async([OWSDispatch sendingQueue], ^{
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[recipient saveWithTransaction:transaction];
[message updateWithSentRecipient:recipient.uniqueId transaction:transaction];
}];
- (void)messageSendDidSucceed:(TSOutgoingMessage *)message
recipient:(SignalRecipient *)recipient
isLocalNumber:(BOOL)isLocalNumber
deviceMessages:(NSArray<NSDictionary *> *)deviceMessages
success:(void (^)(void))successHandler
{
OWSAssert(message);
OWSAssert(recipient);
OWSAssert(deviceMessages);
OWSAssert(successHandler);
DDLogInfo(@"%@ Message send succeeded.", self.logTag);
if (isLocalNumber && deviceMessages.count == 0) {
DDLogInfo(@"%@ Sent a message with no device messages; clearing 'mayHaveLinkedDevices'.", self.logTag);
// In order to avoid skipping necessary sync messages, the default value
// for mayHaveLinkedDevices is YES. Once we've successfully sent a
// sync message with no device messages (e.g. the service has confirmed
// that we have no linked devices), we can set mayHaveLinkedDevices to NO
// to avoid unnecessary message sends for sync messages until we learn
// of a linked device (e.g. through the device linking UI or by receiving
// a sync message, etc.).
[OWSDeviceManager.sharedManager clearMayHaveLinkedDevicesIfNotSet];
}
[self handleMessageSentLocally:message];
successHandler();
});
dispatch_async([OWSDispatch sendingQueue], ^{
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[recipient saveWithTransaction:transaction];
[message updateWithSentRecipient:recipient.uniqueId transaction:transaction];
}];
[self handleMessageSentLocally:message];
successHandler();
});
}
- (void)messageSendDidFail:(TSOutgoingMessage *)message
recipient:(SignalRecipient *)recipient
thread:(TSThread *)thread
isLocalNumber:(BOOL)isLocalNumber
deviceMessages:(NSArray<NSDictionary *> *)deviceMessages
remainingAttempts:(int)remainingAttempts
statusCode:(NSInteger)statusCode
error:(NSError *)error
success:(void (^)(void))successHandler
failure:(RetryableFailureHandler)failureHandler
{
OWSAssert(message);
OWSAssert(recipient);
OWSAssert(thread);
OWSAssert(deviceMessages);
OWSAssert(error);
OWSAssert(successHandler);
OWSAssert(failureHandler);
DDLogInfo(@"%@ sending to recipient: %@, failed with error.", self.logTag, recipient.uniqueId);
[DDLog flushLog];
NSData *responseData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
void (^retrySend)(void) = ^void() {
if (remainingAttempts <= 0) {
// Since we've already repeatedly failed to send to the messaging API,
// it's unlikely that repeating the whole process will succeed.
[error setIsRetryable:NO];
return failureHandler(error);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
DDLogInfo(@"%@ sending to recipient: %@, failed with error.", self.logTag, recipient.uniqueId);
[DDLog flushLog];
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
long statuscode = response.statusCode;
NSData *responseData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
void (^retrySend)(void) = ^void() {
if (remainingAttempts <= 0) {
// Since we've already repeatedly failed to send to the messaging API,
// it's unlikely that repeating the whole process will succeed.
[error setIsRetryable:NO];
return failureHandler(error);
}
dispatch_async([OWSDispatch sendingQueue], ^{
DDLogDebug(@"%@ Retrying: %@", self.logTag, message.debugDescription);
[self sendMessageToService:message
recipient:recipient
thread:thread
attempts:remainingAttempts
success:successHandler
failure:failureHandler];
});
};
switch (statuscode) {
case 401: {
DDLogWarn(@"%@ Unable to send due to invalid credentials. Did the user's client get de-authed by "
@"registering elsewhere?",
self.logTag);
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceFailure, NSLocalizedString(@"ERROR_DESCRIPTION_SENDING_UNAUTHORIZED", @"Error message when attempting to send message"));
// No need to retry if we've been de-authed.
[error setIsRetryable:NO];
return failureHandler(error);
}
case 404: {
DDLogWarn(@"%@ Unregistered recipient: %@", self.logTag, recipient.uniqueId);
dispatch_async([OWSDispatch sendingQueue], ^{
DDLogDebug(@"%@ Retrying: %@", self.logTag, message.debugDescription);
[self sendMessageToService:message
recipient:recipient
thread:thread
attempts:remainingAttempts
success:successHandler
failure:failureHandler];
});
};
[self unregisteredRecipient:recipient message:message thread:thread];
NSError *error = OWSErrorMakeNoSuchSignalRecipientError();
// No need to retry if the recipient is not registered.
[error setIsRetryable:NO];
// If one member of a group deletes their account,
// the group should ignore errors when trying to send
// messages to this ex-member.
[error setShouldBeIgnoredForGroups:YES];
return failureHandler(error);
}
case 409: {
// Mismatched devices
DDLogWarn(@"%@ Mismatch Devices for recipient: %@", self.logTag, recipient.uniqueId);
NSError *error;
NSDictionary *serializedResponse =
[NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
if (error) {
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotParseMismatchedDevicesJson]);
[error setIsRetryable:YES];
return failureHandler(error);
}
switch (statusCode) {
case 401: {
DDLogWarn(@"%@ Unable to send due to invalid credentials. Did the user's client get de-authed by "
@"registering elsewhere?",
self.logTag);
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceFailure,
NSLocalizedString(
@"ERROR_DESCRIPTION_SENDING_UNAUTHORIZED", @"Error message when attempting to send message"));
// No need to retry if we've been de-authed.
[error setIsRetryable:NO];
return failureHandler(error);
}
case 404: {
DDLogWarn(@"%@ Unregistered recipient: %@", self.logTag, recipient.uniqueId);
[self handleMismatchedDevices:serializedResponse recipient:recipient completion:retrySend];
break;
}
case 410: {
// Stale devices
DDLogWarn(@"%@ Stale devices for recipient: %@", self.logTag, recipient.uniqueId);
if (!responseData) {
DDLogWarn(@"Stale devices but server didn't specify devices in response.");
NSError *error = OWSErrorMakeUnableToProcessServerResponseError();
[error setIsRetryable:YES];
return failureHandler(error);
}
[self unregisteredRecipient:recipient message:message thread:thread];
NSError *error = OWSErrorMakeNoSuchSignalRecipientError();
// No need to retry if the recipient is not registered.
[error setIsRetryable:NO];
// If one member of a group deletes their account,
// the group should ignore errors when trying to send
// messages to this ex-member.
[error setShouldBeIgnoredForGroups:YES];
return failureHandler(error);
}
case 409: {
// Mismatched devices
DDLogWarn(@"%@ Mismatch Devices for recipient: %@", self.logTag, recipient.uniqueId);
[self handleStaleDevicesWithResponse:responseData
recipientId:recipient.uniqueId
completion:retrySend];
break;
}
default:
retrySend();
break;
NSError *error;
NSDictionary *serializedResponse =
[NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
if (error) {
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotParseMismatchedDevicesJson]);
[error setIsRetryable:YES];
return failureHandler(error);
}
}];
[self handleMismatchedDevices:serializedResponse recipient:recipient completion:retrySend];
break;
}
case 410: {
// Stale devices
DDLogWarn(@"%@ Stale devices for recipient: %@", self.logTag, recipient.uniqueId);
if (!responseData) {
DDLogWarn(@"Stale devices but server didn't specify devices in response.");
NSError *error = OWSErrorMakeUnableToProcessServerResponseError();
[error setIsRetryable:YES];
return failureHandler(error);
}
[self handleStaleDevicesWithResponse:responseData recipientId:recipient.uniqueId completion:retrySend];
break;
}
default:
retrySend();
break;
}
}
- (void)handleMismatchedDevices:(NSDictionary *)dictionary

@ -1,273 +0,0 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
#import <ProtocolBuffers/ProtocolBuffers.h>
// @@protoc_insertion_point(imports)
@class WebSocketMessage;
@class WebSocketMessageBuilder;
@class WebSocketRequestMessage;
@class WebSocketRequestMessageBuilder;
@class WebSocketResponseMessage;
@class WebSocketResponseMessageBuilder;
#ifndef __has_feature
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif // __has_feature
#ifndef NS_RETURNS_NOT_RETAINED
#if __has_feature(attribute_ns_returns_not_retained)
#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
#else
#define NS_RETURNS_NOT_RETAINED
#endif
#endif
typedef enum {
WebSocketMessageTypeUnknown = 0,
WebSocketMessageTypeRequest = 1,
WebSocketMessageTypeResponse = 2,
} WebSocketMessageType;
BOOL WebSocketMessageTypeIsValidValue(WebSocketMessageType value);
@interface SubProtocolRoot : NSObject {
}
+ (PBExtensionRegistry *)extensionRegistry;
+ (void)registerAllExtensions:(PBMutableExtensionRegistry *)registry;
@end
@interface WebSocketRequestMessage : PBGeneratedMessage {
@private
BOOL hasId_ : 1;
BOOL hasVerb_ : 1;
BOOL hasPath_ : 1;
BOOL hasBody_ : 1;
UInt64 id;
NSString *verb;
NSString *path;
NSData *body;
}
- (BOOL)hasVerb;
- (BOOL)hasPath;
- (BOOL)hasBody;
- (BOOL)hasId;
@property (readonly, strong) NSString *verb;
@property (readonly, strong) NSString *path;
@property (readonly, strong) NSData *body;
@property (readonly) UInt64 id;
+ (WebSocketRequestMessage *)defaultInstance;
- (WebSocketRequestMessage *)defaultInstance;
- (BOOL)isInitialized;
- (void)writeToCodedOutputStream:(PBCodedOutputStream *)output;
- (WebSocketRequestMessageBuilder *)builder;
+ (WebSocketRequestMessageBuilder *)builder;
+ (WebSocketRequestMessageBuilder *)builderWithPrototype:(WebSocketRequestMessage *)prototype;
- (WebSocketRequestMessageBuilder *)toBuilder;
+ (WebSocketRequestMessage *)parseFromData:(NSData *)data;
+ (WebSocketRequestMessage *)parseFromData:(NSData *)data extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
+ (WebSocketRequestMessage *)parseFromInputStream:(NSInputStream *)input;
+ (WebSocketRequestMessage *)parseFromInputStream:(NSInputStream *)input
extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
+ (WebSocketRequestMessage *)parseFromCodedInputStream:(PBCodedInputStream *)input;
+ (WebSocketRequestMessage *)parseFromCodedInputStream:(PBCodedInputStream *)input
extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
@end
@interface WebSocketRequestMessageBuilder : PBGeneratedMessageBuilder {
@private
WebSocketRequestMessage *result;
}
- (WebSocketRequestMessage *)defaultInstance;
- (WebSocketRequestMessageBuilder *)clear;
- (WebSocketRequestMessageBuilder *)clone;
- (WebSocketRequestMessage *)build;
- (WebSocketRequestMessage *)buildPartial;
- (WebSocketRequestMessageBuilder *)mergeFrom:(WebSocketRequestMessage *)other;
- (WebSocketRequestMessageBuilder *)mergeFromCodedInputStream:(PBCodedInputStream *)input;
- (WebSocketRequestMessageBuilder *)mergeFromCodedInputStream:(PBCodedInputStream *)input
extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
- (BOOL)hasVerb;
- (NSString *)verb;
- (WebSocketRequestMessageBuilder *)setVerb:(NSString *)value;
- (WebSocketRequestMessageBuilder *)clearVerb;
- (BOOL)hasPath;
- (NSString *)path;
- (WebSocketRequestMessageBuilder *)setPath:(NSString *)value;
- (WebSocketRequestMessageBuilder *)clearPath;
- (BOOL)hasBody;
- (NSData *)body;
- (WebSocketRequestMessageBuilder *)setBody:(NSData *)value;
- (WebSocketRequestMessageBuilder *)clearBody;
- (BOOL)hasId;
- (UInt64)id;
- (WebSocketRequestMessageBuilder *)setId:(UInt64)value;
- (WebSocketRequestMessageBuilder *)clearId;
@end
@interface WebSocketResponseMessage : PBGeneratedMessage {
@private
BOOL hasId_ : 1;
BOOL hasMessage_ : 1;
BOOL hasBody_ : 1;
BOOL hasStatus_ : 1;
UInt64 id;
NSString *message;
NSData *body;
UInt32 status;
}
- (BOOL)hasId;
- (BOOL)hasStatus;
- (BOOL)hasMessage;
- (BOOL)hasBody;
@property (readonly) UInt64 id;
@property (readonly) UInt32 status;
@property (readonly, strong) NSString *message;
@property (readonly, strong) NSData *body;
+ (WebSocketResponseMessage *)defaultInstance;
- (WebSocketResponseMessage *)defaultInstance;
- (BOOL)isInitialized;
- (void)writeToCodedOutputStream:(PBCodedOutputStream *)output;
- (WebSocketResponseMessageBuilder *)builder;
+ (WebSocketResponseMessageBuilder *)builder;
+ (WebSocketResponseMessageBuilder *)builderWithPrototype:(WebSocketResponseMessage *)prototype;
- (WebSocketResponseMessageBuilder *)toBuilder;
+ (WebSocketResponseMessage *)parseFromData:(NSData *)data;
+ (WebSocketResponseMessage *)parseFromData:(NSData *)data extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
+ (WebSocketResponseMessage *)parseFromInputStream:(NSInputStream *)input;
+ (WebSocketResponseMessage *)parseFromInputStream:(NSInputStream *)input
extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
+ (WebSocketResponseMessage *)parseFromCodedInputStream:(PBCodedInputStream *)input;
+ (WebSocketResponseMessage *)parseFromCodedInputStream:(PBCodedInputStream *)input
extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
@end
@interface WebSocketResponseMessageBuilder : PBGeneratedMessageBuilder {
@private
WebSocketResponseMessage *result;
}
- (WebSocketResponseMessage *)defaultInstance;
- (WebSocketResponseMessageBuilder *)clear;
- (WebSocketResponseMessageBuilder *)clone;
- (WebSocketResponseMessage *)build;
- (WebSocketResponseMessage *)buildPartial;
- (WebSocketResponseMessageBuilder *)mergeFrom:(WebSocketResponseMessage *)other;
- (WebSocketResponseMessageBuilder *)mergeFromCodedInputStream:(PBCodedInputStream *)input;
- (WebSocketResponseMessageBuilder *)mergeFromCodedInputStream:(PBCodedInputStream *)input
extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
- (BOOL)hasId;
- (UInt64)id;
- (WebSocketResponseMessageBuilder *)setId:(UInt64)value;
- (WebSocketResponseMessageBuilder *)clearId;
- (BOOL)hasStatus;
- (UInt32)status;
- (WebSocketResponseMessageBuilder *)setStatus:(UInt32)value;
- (WebSocketResponseMessageBuilder *)clearStatus;
- (BOOL)hasMessage;
- (NSString *)message;
- (WebSocketResponseMessageBuilder *)setMessage:(NSString *)value;
- (WebSocketResponseMessageBuilder *)clearMessage;
- (BOOL)hasBody;
- (NSData *)body;
- (WebSocketResponseMessageBuilder *)setBody:(NSData *)value;
- (WebSocketResponseMessageBuilder *)clearBody;
@end
@interface WebSocketMessage : PBGeneratedMessage {
@private
BOOL hasRequest_ : 1;
BOOL hasResponse_ : 1;
BOOL hasType_ : 1;
WebSocketRequestMessage *request;
WebSocketResponseMessage *response;
WebSocketMessageType type;
}
- (BOOL)hasType;
- (BOOL)hasRequest;
- (BOOL)hasResponse;
@property (readonly) WebSocketMessageType type;
@property (readonly, strong) WebSocketRequestMessage *request;
@property (readonly, strong) WebSocketResponseMessage *response;
+ (WebSocketMessage *)defaultInstance;
- (WebSocketMessage *)defaultInstance;
- (BOOL)isInitialized;
- (void)writeToCodedOutputStream:(PBCodedOutputStream *)output;
- (WebSocketMessageBuilder *)builder;
+ (WebSocketMessageBuilder *)builder;
+ (WebSocketMessageBuilder *)builderWithPrototype:(WebSocketMessage *)prototype;
- (WebSocketMessageBuilder *)toBuilder;
+ (WebSocketMessage *)parseFromData:(NSData *)data;
+ (WebSocketMessage *)parseFromData:(NSData *)data extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
+ (WebSocketMessage *)parseFromInputStream:(NSInputStream *)input;
+ (WebSocketMessage *)parseFromInputStream:(NSInputStream *)input
extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
+ (WebSocketMessage *)parseFromCodedInputStream:(PBCodedInputStream *)input;
+ (WebSocketMessage *)parseFromCodedInputStream:(PBCodedInputStream *)input
extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
@end
@interface WebSocketMessageBuilder : PBGeneratedMessageBuilder {
@private
WebSocketMessage *result;
}
- (WebSocketMessage *)defaultInstance;
- (WebSocketMessageBuilder *)clear;
- (WebSocketMessageBuilder *)clone;
- (WebSocketMessage *)build;
- (WebSocketMessage *)buildPartial;
- (WebSocketMessageBuilder *)mergeFrom:(WebSocketMessage *)other;
- (WebSocketMessageBuilder *)mergeFromCodedInputStream:(PBCodedInputStream *)input;
- (WebSocketMessageBuilder *)mergeFromCodedInputStream:(PBCodedInputStream *)input
extensionRegistry:(PBExtensionRegistry *)extensionRegistry;
- (BOOL)hasType;
- (WebSocketMessageType)type;
- (WebSocketMessageBuilder *)setType:(WebSocketMessageType)value;
- (WebSocketMessageBuilder *)clearType;
- (BOOL)hasRequest;
- (WebSocketRequestMessage *)request;
- (WebSocketMessageBuilder *)setRequest:(WebSocketRequestMessage *)value;
- (WebSocketMessageBuilder *)setRequestBuilder:(WebSocketRequestMessageBuilder *)builderForValue;
- (WebSocketMessageBuilder *)mergeRequest:(WebSocketRequestMessage *)value;
- (WebSocketMessageBuilder *)clearRequest;
- (BOOL)hasResponse;
- (WebSocketResponseMessage *)response;
- (WebSocketMessageBuilder *)setResponse:(WebSocketResponseMessage *)value;
- (WebSocketMessageBuilder *)setResponseBuilder:(WebSocketResponseMessageBuilder *)builderForValue;
- (WebSocketMessageBuilder *)mergeResponse:(WebSocketResponseMessage *)value;
- (WebSocketMessageBuilder *)clearResponse;
@end
// @@protoc_insertion_point(global_scope)

File diff suppressed because it is too large Load Diff

@ -1,9 +1,11 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <SocketRocket/SRWebSocket.h>
NS_ASSUME_NONNULL_BEGIN
static void *SocketManagerStateObservationContext = &SocketManagerStateObservationContext;
extern NSString *const kNSNotification_SocketManagerStateDidChange;
@ -14,9 +16,16 @@ typedef NS_ENUM(NSUInteger, SocketManagerState) {
SocketManagerStateOpen,
};
typedef void (^TSSocketMessageSuccess)(id _Nullable responseObject);
// statusCode is zero by default, if request never made or failed.
typedef void (^TSSocketMessageFailure)(NSInteger statusCode, NSError *error);
@class TSRequest;
@interface TSSocketManager : NSObject <SRWebSocketDelegate>
@property (nonatomic, readonly) SocketManagerState state;
@property (atomic, readonly) BOOL canMakeRequests;
+ (instancetype)sharedManager;
@ -33,4 +42,12 @@ typedef NS_ENUM(NSUInteger, SocketManagerState) {
// This method can be called from any thread.
+ (void)requestSocketOpen;
#pragma mark - Message Sending
- (void)makeRequest:(TSRequest *)request
success:(TSSocketMessageSuccess)success
failure:(TSSocketMessageFailure)failure;
@end
NS_ASSUME_NONNULL_END

@ -10,18 +10,22 @@
#import "NSTimer+OWS.h"
#import "NotificationsProtocol.h"
#import "OWSBackgroundTask.h"
#import "OWSError.h"
#import "OWSMessageManager.h"
#import "OWSMessageReceiver.h"
#import "OWSPrimaryStorage.h"
#import "OWSSignalService.h"
#import "OWSSignalServiceProtos.pb.h"
#import "OWSWebsocketSecurityPolicy.h"
#import "SubProtocol.pb.h"
#import "TSAccountManager.h"
#import "TSConstants.h"
#import "TSErrorMessage.h"
#import "TSRequest.h"
#import "TextSecureKitEnv.h"
#import "Threading.h"
#import "WebSocketResources.pb.h"
NS_ASSUME_NONNULL_BEGIN
static const CGFloat kSocketHeartbeatPeriodSeconds = 30.f;
static const CGFloat kSocketReconnectDelaySeconds = 5.f;
@ -33,9 +37,102 @@ static const CGFloat kSocketReconnectDelaySeconds = 5.f;
static const CGFloat kBackgroundOpenSocketDurationSeconds = 25.f;
// b) It has received a message over the socket in the last 15 seconds.
static const CGFloat kBackgroundKeepSocketAliveDurationSeconds = 15.f;
// c) It is in the process of making a request.
static const CGFloat kMakeRequestKeepSocketAliveDurationSeconds = 30.f;
NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_SocketManagerStateDidChange";
@interface TSSocketMessage : NSObject
@property (nonatomic, readonly) UInt64 requestId;
@property (nonatomic, nullable) TSSocketMessageSuccess success;
@property (nonatomic, nullable) TSSocketMessageFailure failure;
@property (nonatomic) BOOL hasCompleted;
@property (nonatomic, readonly) OWSBackgroundTask *backgroundTask;
- (instancetype)init NS_UNAVAILABLE;
@end
#pragma mark -
@implementation TSSocketMessage
- (instancetype)initWithRequestId:(UInt64)requestId
success:(TSSocketMessageSuccess)success
failure:(TSSocketMessageFailure)failure
{
if (self = [super init]) {
OWSAssert(success);
OWSAssert(failure);
_requestId = requestId;
_success = success;
_failure = failure;
_backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
}
return self;
}
- (void)didSucceedWithResponseObject:(id _Nullable)responseObject
{
@synchronized(self)
{
if (self.hasCompleted) {
return;
}
self.hasCompleted = YES;
}
OWSAssert(self.success);
OWSAssert(self.failure);
TSSocketMessageSuccess success = self.success;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
success(responseObject);
});
self.success = nil;
self.failure = nil;
}
- (void)didFailBeforeSending
{
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageRequestFailed,
NSLocalizedString(@"ERROR_DESCRIPTION_REQUEST_FAILED", @"Error indicating that a socket request failed."));
[self didFailWithStatusCode:0 error:error];
}
- (void)didFailWithStatusCode:(NSInteger)statusCode error:(NSError *)error
{
OWSAssert(error);
@synchronized(self)
{
if (self.hasCompleted) {
return;
}
self.hasCompleted = YES;
}
OWSAssert(self.success);
OWSAssert(self.failure);
TSSocketMessageFailure failure = self.failure;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
failure(statusCode, error);
});
self.success = nil;
self.failure = nil;
}
@end
#pragma mark -
// TSSocketManager's properties should only be accessed from the main thread.
@interface TSSocketManager ()
@ -46,9 +143,9 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
//
// The first tier is the actual websocket and the timers used
// to keep it alive and connected.
@property (nonatomic) SRWebSocket *websocket;
@property (nonatomic) NSTimer *heartbeatTimer;
@property (nonatomic) NSTimer *reconnectTimer;
@property (nonatomic, nullable) SRWebSocket *websocket;
@property (nonatomic, nullable) NSTimer *heartbeatTimer;
@property (nonatomic, nullable) NSTimer *reconnectTimer;
#pragma mark -
@ -60,6 +157,8 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
// Due to concurrency, this property can fall out of sync with the
// websocket's actual state, so we're defensive and distrustful of
// this property.
//
// We only ever access this state on the main thread.
@property (nonatomic) SocketManagerState state;
#pragma mark -
@ -72,13 +171,13 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
// trying to keep the socket open), all three should be clear.
//
// This represents how long we're trying to keep the socket open.
@property (nonatomic) NSDate *backgroundKeepAliveUntilDate;
@property (nonatomic, nullable) NSDate *backgroundKeepAliveUntilDate;
// This timer is used to check periodically whether we should
// close the socket.
@property (nonatomic) NSTimer *backgroundKeepAliveTimer;
@property (nonatomic, nullable) NSTimer *backgroundKeepAliveTimer;
// This is used to manage the iOS "background task" used to
// keep the app alive in the background.
@property (nonatomic) OWSBackgroundTask *backgroundTask;
@property (nonatomic, nullable) OWSBackgroundTask *backgroundTask;
// We cache this value instead of consulting [UIApplication sharedApplication].applicationState,
// because UIKit only provides a "will resign active" notification, not a "did resign active"
@ -87,6 +186,11 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
@property (nonatomic) BOOL hasObservedNotifications;
// This property should only be accessed while synchronized on the socket manager.
@property (nonatomic, readonly) NSMutableDictionary<NSNumber *, TSSocketMessage *> *socketMessageMap;
@property (atomic) BOOL canMakeRequests;
@end
#pragma mark -
@ -106,6 +210,7 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
_signalService = [OWSSignalService sharedInstance];
_messageReceiver = [OWSMessageReceiver sharedInstance];
_state = SocketManagerStateClosed;
_socketMessageMap = [NSMutableDictionary new];
OWSSingletonAssert();
@ -290,13 +395,17 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
// the socket failed immediately for some reason), so we update the state
// _before_ calling it, not after.
_state = state;
_canMakeRequests = state == SocketManagerStateOpen;
[socket open];
[self failAllPendingSocketMessagesIfNecessary];
return;
}
}
_state = state;
_canMakeRequests = state == SocketManagerStateOpen;
[self failAllPendingSocketMessagesIfNecessary];
[self notifyStatusChange];
}
@ -330,6 +439,201 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
self.state = SocketManagerStateClosed;
}
#pragma mark - Message Sending
- (void)makeRequest:(TSRequest *)request success:(TSSocketMessageSuccess)success failure:(TSSocketMessageFailure)failure
{
OWSAssert(request);
OWSAssert(request.HTTPMethod.length > 0);
OWSAssert(success);
OWSAssert(failure);
TSSocketMessage *socketMessage =
[[TSSocketMessage alloc] initWithRequestId:[Cryptography randomUInt64] success:success failure:failure];
@synchronized(self)
{
self.socketMessageMap[@(socketMessage.requestId)] = socketMessage;
}
NSURL *requestUrl = request.URL;
NSString *requestPath = [@"/" stringByAppendingString:requestUrl.path];
NSData *_Nullable jsonData = nil;
if (request.parameters) {
NSError *error;
jsonData = [NSJSONSerialization
dataWithJSONObject:request.parameters
options:(NSJSONWritingOptions)0
error:&error];
if (!jsonData || error) {
OWSProdLogAndFail(@"%@ could not serialize request JSON: %@", self.logTag, error);
[socketMessage didFailBeforeSending];
return;
}
}
WebSocketResourcesWebSocketRequestMessageBuilder *requestBuilder =
[WebSocketResourcesWebSocketRequestMessageBuilder new];
requestBuilder.id = socketMessage.requestId;
[requestBuilder setVerb:request.HTTPMethod];
[requestBuilder setPath:requestPath];
if (jsonData) {
// TODO: Do we need body & headers for requests with no parameters?
[requestBuilder setBody:jsonData];
[requestBuilder setHeadersArray:@[
@"content-type:application/json",
]];
}
WebSocketResourcesWebSocketMessageBuilder *messageBuilder = [WebSocketResourcesWebSocketMessageBuilder new];
[messageBuilder setType:WebSocketResourcesWebSocketMessageTypeRequest];
[messageBuilder setRequestBuilder:requestBuilder];
NSData *messageData = [messageBuilder build].data;
if (!messageData) {
OWSProdLogAndFail(@"%@ could not serialize message.", self.logTag);
[socketMessage didFailBeforeSending];
return;
}
if (!self.canMakeRequests) {
DDLogError(@"%@ makeRequest: socket not open.", self.logTag);
[socketMessage didFailBeforeSending];
return;
}
NSError *error;
BOOL wasScheduled = [self.websocket sendDataNoCopy:messageData error:&error];
if (!wasScheduled || error) {
OWSProdLogAndFail(@"%@ could not serialize request JSON: %@", self.logTag, error);
[socketMessage didFailBeforeSending];
return;
}
DDLogVerbose(@"%@ message scheduled: %lld, %@, %@, %zd.",
self.logTag,
socketMessage.requestId,
request.HTTPMethod,
requestPath,
jsonData.length);
const int64_t kSocketTimeoutSeconds = 10;
__weak TSSocketMessage *weakSocketMessage = socketMessage;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kSocketTimeoutSeconds * NSEC_PER_SEC),
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
[weakSocketMessage didFailBeforeSending];
});
}
- (void)processWebSocketResponseMessage:(WebSocketResourcesWebSocketResponseMessage *)message
{
OWSAssertIsOnMainThread();
OWSAssert(message);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self processWebSocketResponseMessageAsync:message];
});
}
- (void)processWebSocketResponseMessageAsync:(WebSocketResourcesWebSocketResponseMessage *)message
{
OWSAssert(message);
DDLogInfo(@"%@ received WebSocket response.", self.logTag);
if (![message hasId]) {
DDLogError(@"%@ received incomplete WebSocket response.", self.logTag);
return;
}
DispatchMainThreadSafe(^{
[self requestSocketAliveForAtLeastSeconds:kMakeRequestKeepSocketAliveDurationSeconds];
});
UInt64 requestId = message.id;
UInt32 responseStatus = 0;
if (message.hasStatus) {
responseStatus = message.status;
}
NSString *_Nullable responseMessage;
if (message.hasMessage) {
responseMessage = message.message;
}
NSData *_Nullable responseBody;
if (message.hasBody) {
responseBody = message.body;
}
NSArray<NSString *> *_Nullable responseHeaders = message.headers;
BOOL hasValidResponse = YES;
id responseObject = responseBody;
if (responseBody) {
NSError *error;
id _Nullable responseJson =
[NSJSONSerialization JSONObjectWithData:responseBody options:(NSJSONReadingOptions)0 error:&error];
if (!responseJson || error) {
OWSProdLogAndFail(@"%@ could not parse WebSocket response JSON: %@.", self.logTag, error);
hasValidResponse = NO;
} else {
responseObject = responseJson;
}
}
TSSocketMessage *_Nullable socketMessage;
@synchronized(self)
{
socketMessage = self.socketMessageMap[@(requestId)];
[self.socketMessageMap removeObjectForKey:@(requestId)];
}
if (!socketMessage) {
DDLogError(@"%@ received response to unknown request.", self.logTag);
} else {
BOOL hasSuccessStatus = 200 <= responseStatus && responseStatus <= 299;
BOOL didSucceed = hasSuccessStatus && hasValidResponse;
if (didSucceed) {
[socketMessage didSucceedWithResponseObject:responseObject];
} else {
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageResponseFailed,
NSLocalizedString(
@"ERROR_DESCRIPTION_RESPONSE_FAILED", @"Error indicating that a socket response failed."));
[socketMessage didFailWithStatusCode:(NSInteger)responseStatus error:error];
}
}
DDLogVerbose(@"%@ received WebSocket response: %llu, %zd, %@, %zd, %@, %d, %@.",
self.logTag,
(unsigned long long)requestId,
(NSInteger)responseStatus,
responseMessage,
responseBody.length,
responseHeaders,
socketMessage != nil,
responseObject);
}
- (void)failAllPendingSocketMessagesIfNecessary
{
if (!self.canMakeRequests) {
[self failAllPendingSocketMessages];
}
}
- (void)failAllPendingSocketMessages
{
NSArray<TSSocketMessage *> *socketMessages;
@synchronized(self)
{
socketMessages = self.socketMessageMap.allValues;
[self.socketMessageMap removeAllObjects];
}
for (TSSocketMessage *socketMessage in socketMessages) {
[socketMessage didFailBeforeSending];
}
}
#pragma mark - Delegate methods
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
@ -359,23 +663,32 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(NSData *)data {
OWSAssertIsOnMainThread();
OWSAssert(webSocket);
if (webSocket != self.websocket) {
// Ignore events from obsolete web sockets.
return;
}
WebSocketMessage *wsMessage = [WebSocketMessage parseFromData:data];
WebSocketResourcesWebSocketMessage *wsMessage;
@try {
wsMessage = [WebSocketResourcesWebSocketMessage parseFromData:data];
} @catch (NSException *exception) {
OWSProdLogAndFail(@"%@ Received an invalid message: %@", self.logTag, exception.debugDescription);
// TODO: Add analytics.
return;
}
if (wsMessage.type == WebSocketMessageTypeRequest) {
if (wsMessage.type == WebSocketResourcesWebSocketMessageTypeRequest) {
[self processWebSocketRequestMessage:wsMessage.request];
} else if (wsMessage.type == WebSocketMessageTypeResponse) {
} else if (wsMessage.type == WebSocketResourcesWebSocketMessageTypeResponse) {
[self processWebSocketResponseMessage:wsMessage.response];
} else {
DDLogWarn(@"Got a WebSocketMessage of unknown type");
DDLogWarn(@"%@ webSocket:didReceiveMessage: unknown.", self.logTag);
}
}
- (void)processWebSocketRequestMessage:(WebSocketRequestMessage *)message {
- (void)processWebSocketRequestMessage:(WebSocketResourcesWebSocketRequestMessage *)message
{
OWSAssertIsOnMainThread();
DDLogInfo(@"%@ Got message with verb: %@ and path: %@", self.logTag, message.verb, message.path);
@ -432,23 +745,18 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
}
}
- (void)processWebSocketResponseMessage:(WebSocketResponseMessage *)message {
OWSAssertIsOnMainThread();
DDLogWarn(@"Client should not receive WebSocket Respond messages");
}
- (void)sendWebSocketMessageAcknowledgement:(WebSocketRequestMessage *)request {
- (void)sendWebSocketMessageAcknowledgement:(WebSocketResourcesWebSocketRequestMessage *)request
{
OWSAssertIsOnMainThread();
WebSocketResponseMessageBuilder *response = [WebSocketResponseMessage builder];
WebSocketResourcesWebSocketResponseMessageBuilder *response = [WebSocketResourcesWebSocketResponseMessage builder];
[response setStatus:200];
[response setMessage:@"OK"];
[response setId:request.id];
WebSocketMessageBuilder *message = [WebSocketMessage builder];
WebSocketResourcesWebSocketMessageBuilder *message = [WebSocketResourcesWebSocketMessage builder];
[message setResponse:response.build];
[message setType:WebSocketMessageTypeResponse];
[message setType:WebSocketResourcesWebSocketMessageTypeResponse];
NSError *error;
[self.websocket sendDataNoCopy:message.build.data error:&error];
@ -475,9 +783,10 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
}
- (void)webSocket:(SRWebSocket *)webSocket
didCloseWithCode:(NSInteger)code
reason:(NSString *)reason
wasClean:(BOOL)wasClean {
didCloseWithCode:(NSInteger)code
reason:(nullable NSString *)reason
wasClean:(BOOL)wasClean
{
OWSAssertIsOnMainThread();
OWSAssert(webSocket);
if (webSocket != self.websocket) {
@ -730,3 +1039,5 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
}
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,330 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
#import <ProtocolBuffers/ProtocolBuffers.h>
// @@protoc_insertion_point(imports)
@class ObjectiveCFileOptions;
@class ObjectiveCFileOptionsBuilder;
@class PBDescriptorProto;
@class PBDescriptorProtoBuilder;
@class PBDescriptorProtoExtensionRange;
@class PBDescriptorProtoExtensionRangeBuilder;
@class PBEnumDescriptorProto;
@class PBEnumDescriptorProtoBuilder;
@class PBEnumOptions;
@class PBEnumOptionsBuilder;
@class PBEnumValueDescriptorProto;
@class PBEnumValueDescriptorProtoBuilder;
@class PBEnumValueOptions;
@class PBEnumValueOptionsBuilder;
@class PBFieldDescriptorProto;
@class PBFieldDescriptorProtoBuilder;
@class PBFieldOptions;
@class PBFieldOptionsBuilder;
@class PBFileDescriptorProto;
@class PBFileDescriptorProtoBuilder;
@class PBFileDescriptorSet;
@class PBFileDescriptorSetBuilder;
@class PBFileOptions;
@class PBFileOptionsBuilder;
@class PBMessageOptions;
@class PBMessageOptionsBuilder;
@class PBMethodDescriptorProto;
@class PBMethodDescriptorProtoBuilder;
@class PBMethodOptions;
@class PBMethodOptionsBuilder;
@class PBOneofDescriptorProto;
@class PBOneofDescriptorProtoBuilder;
@class PBServiceDescriptorProto;
@class PBServiceDescriptorProtoBuilder;
@class PBServiceOptions;
@class PBServiceOptionsBuilder;
@class PBSourceCodeInfo;
@class PBSourceCodeInfoBuilder;
@class PBSourceCodeInfoLocation;
@class PBSourceCodeInfoLocationBuilder;
@class PBUninterpretedOption;
@class PBUninterpretedOptionBuilder;
@class PBUninterpretedOptionNamePart;
@class PBUninterpretedOptionNamePartBuilder;
@class WebSocketResourcesWebSocketMessage;
@class WebSocketResourcesWebSocketMessageBuilder;
@class WebSocketResourcesWebSocketRequestMessage;
@class WebSocketResourcesWebSocketRequestMessageBuilder;
@class WebSocketResourcesWebSocketResponseMessage;
@class WebSocketResourcesWebSocketResponseMessageBuilder;
typedef NS_ENUM(SInt32, WebSocketResourcesWebSocketMessageType) {
WebSocketResourcesWebSocketMessageTypeUnknown = 0,
WebSocketResourcesWebSocketMessageTypeRequest = 1,
WebSocketResourcesWebSocketMessageTypeResponse = 2,
};
BOOL WebSocketResourcesWebSocketMessageTypeIsValidValue(WebSocketResourcesWebSocketMessageType value);
NSString *NSStringFromWebSocketResourcesWebSocketMessageType(WebSocketResourcesWebSocketMessageType value);
@interface WebSocketResourcesWebSocketResourcesRoot : NSObject {
}
+ (PBExtensionRegistry*) extensionRegistry;
+ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry;
@end
#define WebSocketRequestMessage_verb @"verb"
#define WebSocketRequestMessage_path @"path"
#define WebSocketRequestMessage_body @"body"
#define WebSocketRequestMessage_headers @"headers"
#define WebSocketRequestMessage_id @"id"
@interface WebSocketResourcesWebSocketRequestMessage : PBGeneratedMessage<GeneratedMessageProtocol> {
@private
BOOL hasId_:1;
BOOL hasVerb_:1;
BOOL hasPath_:1;
BOOL hasBody_:1;
UInt64 id;
NSString* verb;
NSString* path;
NSData* body;
NSMutableArray * headersArray;
}
- (BOOL) hasVerb;
- (BOOL) hasPath;
- (BOOL) hasBody;
- (BOOL) hasId;
@property (readonly, strong) NSString* verb;
@property (readonly, strong) NSString* path;
@property (readonly, strong) NSData* body;
@property (readonly, strong) NSArray * headers;
@property (readonly) UInt64 id;
- (NSString*)headersAtIndex:(NSUInteger)index;
+ (instancetype) defaultInstance;
- (instancetype) defaultInstance;
- (BOOL) isInitialized;
- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) builder;
+ (WebSocketResourcesWebSocketRequestMessageBuilder*) builder;
+ (WebSocketResourcesWebSocketRequestMessageBuilder*) builderWithPrototype:(WebSocketResourcesWebSocketRequestMessage*) prototype;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) toBuilder;
+ (WebSocketResourcesWebSocketRequestMessage*) parseFromData:(NSData*) data;
+ (WebSocketResourcesWebSocketRequestMessage*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+ (WebSocketResourcesWebSocketRequestMessage*) parseFromInputStream:(NSInputStream*) input;
+ (WebSocketResourcesWebSocketRequestMessage*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+ (WebSocketResourcesWebSocketRequestMessage*) parseFromCodedInputStream:(PBCodedInputStream*) input;
+ (WebSocketResourcesWebSocketRequestMessage*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
@end
@interface WebSocketResourcesWebSocketRequestMessageBuilder : PBGeneratedMessageBuilder {
@private
WebSocketResourcesWebSocketRequestMessage* resultWebSocketRequestMessage;
}
- (WebSocketResourcesWebSocketRequestMessage*) defaultInstance;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) clear;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) clone;
- (WebSocketResourcesWebSocketRequestMessage*) build;
- (WebSocketResourcesWebSocketRequestMessage*) buildPartial;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) mergeFrom:(WebSocketResourcesWebSocketRequestMessage*) other;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
- (BOOL) hasVerb;
- (NSString*) verb;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) setVerb:(NSString*) value;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) clearVerb;
- (BOOL) hasPath;
- (NSString*) path;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) setPath:(NSString*) value;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) clearPath;
- (BOOL) hasBody;
- (NSData*) body;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) setBody:(NSData*) value;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) clearBody;
- (NSMutableArray *)headers;
- (NSString*)headersAtIndex:(NSUInteger)index;
- (WebSocketResourcesWebSocketRequestMessageBuilder *)addHeaders:(NSString*)value;
- (WebSocketResourcesWebSocketRequestMessageBuilder *)setHeadersArray:(NSArray *)array;
- (WebSocketResourcesWebSocketRequestMessageBuilder *)clearHeaders;
- (BOOL) hasId;
- (UInt64) id;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) setId:(UInt64) value;
- (WebSocketResourcesWebSocketRequestMessageBuilder*) clearId;
@end
#define WebSocketResponseMessage_id @"id"
#define WebSocketResponseMessage_status @"status"
#define WebSocketResponseMessage_message @"message"
#define WebSocketResponseMessage_headers @"headers"
#define WebSocketResponseMessage_body @"body"
@interface WebSocketResourcesWebSocketResponseMessage : PBGeneratedMessage<GeneratedMessageProtocol> {
@private
BOOL hasId_:1;
BOOL hasMessage_:1;
BOOL hasBody_:1;
BOOL hasStatus_:1;
UInt64 id;
NSString* message;
NSData* body;
UInt32 status;
NSMutableArray * headersArray;
}
- (BOOL) hasId;
- (BOOL) hasStatus;
- (BOOL) hasMessage;
- (BOOL) hasBody;
@property (readonly) UInt64 id;
@property (readonly) UInt32 status;
@property (readonly, strong) NSString* message;
@property (readonly, strong) NSArray * headers;
@property (readonly, strong) NSData* body;
- (NSString*)headersAtIndex:(NSUInteger)index;
+ (instancetype) defaultInstance;
- (instancetype) defaultInstance;
- (BOOL) isInitialized;
- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) builder;
+ (WebSocketResourcesWebSocketResponseMessageBuilder*) builder;
+ (WebSocketResourcesWebSocketResponseMessageBuilder*) builderWithPrototype:(WebSocketResourcesWebSocketResponseMessage*) prototype;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) toBuilder;
+ (WebSocketResourcesWebSocketResponseMessage*) parseFromData:(NSData*) data;
+ (WebSocketResourcesWebSocketResponseMessage*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+ (WebSocketResourcesWebSocketResponseMessage*) parseFromInputStream:(NSInputStream*) input;
+ (WebSocketResourcesWebSocketResponseMessage*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+ (WebSocketResourcesWebSocketResponseMessage*) parseFromCodedInputStream:(PBCodedInputStream*) input;
+ (WebSocketResourcesWebSocketResponseMessage*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
@end
@interface WebSocketResourcesWebSocketResponseMessageBuilder : PBGeneratedMessageBuilder {
@private
WebSocketResourcesWebSocketResponseMessage* resultWebSocketResponseMessage;
}
- (WebSocketResourcesWebSocketResponseMessage*) defaultInstance;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) clear;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) clone;
- (WebSocketResourcesWebSocketResponseMessage*) build;
- (WebSocketResourcesWebSocketResponseMessage*) buildPartial;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) mergeFrom:(WebSocketResourcesWebSocketResponseMessage*) other;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
- (BOOL) hasId;
- (UInt64) id;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) setId:(UInt64) value;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) clearId;
- (BOOL) hasStatus;
- (UInt32) status;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) setStatus:(UInt32) value;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) clearStatus;
- (BOOL) hasMessage;
- (NSString*) message;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) setMessage:(NSString*) value;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) clearMessage;
- (NSMutableArray *)headers;
- (NSString*)headersAtIndex:(NSUInteger)index;
- (WebSocketResourcesWebSocketResponseMessageBuilder *)addHeaders:(NSString*)value;
- (WebSocketResourcesWebSocketResponseMessageBuilder *)setHeadersArray:(NSArray *)array;
- (WebSocketResourcesWebSocketResponseMessageBuilder *)clearHeaders;
- (BOOL) hasBody;
- (NSData*) body;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) setBody:(NSData*) value;
- (WebSocketResourcesWebSocketResponseMessageBuilder*) clearBody;
@end
#define WebSocketMessage_type @"type"
#define WebSocketMessage_request @"request"
#define WebSocketMessage_response @"response"
@interface WebSocketResourcesWebSocketMessage : PBGeneratedMessage<GeneratedMessageProtocol> {
@private
BOOL hasRequest_:1;
BOOL hasResponse_:1;
BOOL hasType_:1;
WebSocketResourcesWebSocketRequestMessage* request;
WebSocketResourcesWebSocketResponseMessage* response;
WebSocketResourcesWebSocketMessageType type;
}
- (BOOL) hasType;
- (BOOL) hasRequest;
- (BOOL) hasResponse;
@property (readonly) WebSocketResourcesWebSocketMessageType type;
@property (readonly, strong) WebSocketResourcesWebSocketRequestMessage* request;
@property (readonly, strong) WebSocketResourcesWebSocketResponseMessage* response;
+ (instancetype) defaultInstance;
- (instancetype) defaultInstance;
- (BOOL) isInitialized;
- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
- (WebSocketResourcesWebSocketMessageBuilder*) builder;
+ (WebSocketResourcesWebSocketMessageBuilder*) builder;
+ (WebSocketResourcesWebSocketMessageBuilder*) builderWithPrototype:(WebSocketResourcesWebSocketMessage*) prototype;
- (WebSocketResourcesWebSocketMessageBuilder*) toBuilder;
+ (WebSocketResourcesWebSocketMessage*) parseFromData:(NSData*) data;
+ (WebSocketResourcesWebSocketMessage*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+ (WebSocketResourcesWebSocketMessage*) parseFromInputStream:(NSInputStream*) input;
+ (WebSocketResourcesWebSocketMessage*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+ (WebSocketResourcesWebSocketMessage*) parseFromCodedInputStream:(PBCodedInputStream*) input;
+ (WebSocketResourcesWebSocketMessage*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
@end
@interface WebSocketResourcesWebSocketMessageBuilder : PBGeneratedMessageBuilder {
@private
WebSocketResourcesWebSocketMessage* resultWebSocketMessage;
}
- (WebSocketResourcesWebSocketMessage*) defaultInstance;
- (WebSocketResourcesWebSocketMessageBuilder*) clear;
- (WebSocketResourcesWebSocketMessageBuilder*) clone;
- (WebSocketResourcesWebSocketMessage*) build;
- (WebSocketResourcesWebSocketMessage*) buildPartial;
- (WebSocketResourcesWebSocketMessageBuilder*) mergeFrom:(WebSocketResourcesWebSocketMessage*) other;
- (WebSocketResourcesWebSocketMessageBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
- (WebSocketResourcesWebSocketMessageBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
- (BOOL) hasType;
- (WebSocketResourcesWebSocketMessageType) type;
- (WebSocketResourcesWebSocketMessageBuilder*) setType:(WebSocketResourcesWebSocketMessageType) value;
- (WebSocketResourcesWebSocketMessageBuilder*) clearType;
- (BOOL) hasRequest;
- (WebSocketResourcesWebSocketRequestMessage*) request;
- (WebSocketResourcesWebSocketMessageBuilder*) setRequest:(WebSocketResourcesWebSocketRequestMessage*) value;
- (WebSocketResourcesWebSocketMessageBuilder*) setRequestBuilder:(WebSocketResourcesWebSocketRequestMessageBuilder*) builderForValue;
- (WebSocketResourcesWebSocketMessageBuilder*) mergeRequest:(WebSocketResourcesWebSocketRequestMessage*) value;
- (WebSocketResourcesWebSocketMessageBuilder*) clearRequest;
- (BOOL) hasResponse;
- (WebSocketResourcesWebSocketResponseMessage*) response;
- (WebSocketResourcesWebSocketMessageBuilder*) setResponse:(WebSocketResourcesWebSocketResponseMessage*) value;
- (WebSocketResourcesWebSocketMessageBuilder*) setResponseBuilder:(WebSocketResourcesWebSocketResponseMessageBuilder*) builderForValue;
- (WebSocketResourcesWebSocketMessageBuilder*) mergeResponse:(WebSocketResourcesWebSocketResponseMessage*) value;
- (WebSocketResourcesWebSocketMessageBuilder*) clearResponse;
@end
// @@protoc_insertion_point(global_scope)

@ -1,5 +1,5 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@ -36,6 +36,9 @@ typedef NS_ENUM(NSInteger, TSMACType) {
+ (NSData *)generateRandomBytes:(NSUInteger)numberBytes;
+ (uint32_t)randomUInt32;
+ (uint64_t)randomUInt64;
#pragma mark SHA and HMAC methods
// Full length SHA256 digest for `data`

@ -102,7 +102,25 @@ const NSUInteger kAES256_KeyByteLength = 32;
+ (NSData *)generateRandomBytes:(NSUInteger)numberBytes
{
return [Randomness generateRandomBytes:numberBytes];
return [Randomness generateRandomBytes:(int)numberBytes];
}
+ (uint32_t)randomUInt32
{
size_t size = sizeof(uint32_t);
NSData *data = [self generateRandomBytes:size];
uint32_t result = 0;
[data getBytes:&result range:NSMakeRange(0, size)];
return result;
}
+ (uint64_t)randomUInt64
{
size_t size = sizeof(uint64_t);
NSData *data = [self generateRandomBytes:size];
uint64_t result = 0;
[data getBytes:&result range:NSMakeRange(0, size)];
return result;
}
#pragma mark SHA1

@ -43,6 +43,8 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) {
// A non-recoverable while importing or exporting a backup.
OWSErrorCodeBackupFailure = 777419,
OWSErrorCodeLocalAuthenticationError = 777420,
OWSErrorCodeMessageRequestFailed = 777421,
OWSErrorCodeMessageResponseFailed = 777422,
};
extern NSString *const OWSErrorRecipientIdentifierKey;

Loading…
Cancel
Save