Move UD auth into request initializers

pull/1/head
Michael Kirk 7 years ago
parent 39ba413439
commit 0be1f8cca2

@ -56,6 +56,11 @@ public class ProfileFetcherJob: NSObject {
return SSKEnvironment.shared.identityManager return SSKEnvironment.shared.identityManager
} }
private var signalServiceClient: SignalServiceClient {
// TODO hang on SSKEnvironment
return SignalServiceRestClient()
}
// MARK: - // MARK: -
public func run(recipientIds: [String]) { public func run(recipientIds: [String]) {
@ -88,8 +93,7 @@ public class ProfileFetcherJob: NSObject {
} }
enum ProfileFetcherJobError: Error { enum ProfileFetcherJobError: Error {
case throttled(lastTimeInterval: TimeInterval), case throttled(lastTimeInterval: TimeInterval)
unknownNetworkError
} }
public func updateProfile(recipientId: String, remainingRetries: Int = 3) { public func updateProfile(recipientId: String, remainingRetries: Int = 3) {
@ -130,12 +134,11 @@ public class ProfileFetcherJob: NSObject {
Logger.error("getProfile: \(recipientId)") Logger.error("getProfile: \(recipientId)")
let request = OWSRequestFactory.getProfileRequest(withRecipientId: recipientId)
let (promise, fulfill, reject) = Promise<SignalServiceProfile>.pending()
// TODO: Use UD socket for some profile gets. // TODO: Use UD socket for some profile gets.
if socketManager.canMakeRequests(of: .default) { if socketManager.canMakeRequests(of: .default) {
let request = OWSRequestFactory.getProfileRequest(recipientId: recipientId, unidentifiedAccess: nil)
let (promise, fulfill, reject) = Promise<SignalServiceProfile>.pending()
self.socketManager.make(request, self.socketManager.make(request,
webSocketType: .default, webSocketType: .default,
success: { (responseObject: Any?) -> Void in success: { (responseObject: Any?) -> Void in
@ -149,27 +152,11 @@ public class ProfileFetcherJob: NSObject {
failure: { (_: NSInteger, _:Data?, error: Error) in failure: { (_: NSInteger, _:Data?, error: Error) in
reject(error) reject(error)
}) })
return promise
} else { } else {
self.networkManager.makeRequest(request, // TODO unidentified AUTH
success: { (_: URLSessionDataTask?, responseObject: Any?) -> Void in return self.signalServiceClient.retrieveProfile(recipientId: recipientId, unidentifiedAccess: nil)
do {
let profile = try SignalServiceProfile(recipientId: recipientId, responseObject: responseObject)
fulfill(profile)
} catch {
reject(error)
}
},
failure: { (_: URLSessionDataTask?, error: Error?) in
if let error = error {
reject(error)
}
reject(ProfileFetcherJobError.unknownNetworkError)
})
} }
return promise
} }
private func updateProfile(signalServiceProfile: SignalServiceProfile) { private func updateProfile(signalServiceProfile: SignalServiceProfile) {
@ -221,45 +208,3 @@ public class ProfileFetcherJob: NSObject {
} }
} }
} }
@objc
public class SignalServiceProfile: NSObject {
public enum ValidationError: Error {
case invalid(description: String)
case invalidIdentityKey(description: String)
case invalidProfileName(description: String)
}
public let recipientId: String
public let identityKey: Data
public let profileNameEncrypted: Data?
public let avatarUrlPath: String?
public let unidentifiedAccessVerifier: Data?
public let hasUnrestrictedUnidentifiedAccess: Bool
init(recipientId: String, responseObject: Any?) throws {
self.recipientId = recipientId
guard let params = ParamParser(responseObject: responseObject) else {
throw ValidationError.invalid(description: "invalid response: \(String(describing: responseObject))")
}
let identityKeyWithType = try params.requiredBase64EncodedData(key: "identityKey")
let kIdentityKeyLength = 33
guard identityKeyWithType.count == kIdentityKeyLength else {
throw ValidationError.invalidIdentityKey(description: "malformed identity key \(identityKeyWithType.hexadecimalString) with decoded length: \(identityKeyWithType.count)")
}
// `removeKeyType` is an objc category method only on NSData, so temporarily cast.
self.identityKey = (identityKeyWithType as NSData).removeKeyType() as Data
self.profileNameEncrypted = try params.optionalBase64EncodedData(key: "name")
let avatarUrlPath: String? = try params.optional(key: "avatar")
self.avatarUrlPath = avatarUrlPath
self.unidentifiedAccessVerifier = try params.optionalBase64EncodedData(key: "unidentifiedAccess")
self.hasUnrestrictedUnidentifiedAccess = try params.optional(key: "unrestrictedUnidentifiedAccess") ?? false
}
}

@ -36,7 +36,7 @@ public class OWSMessageSend: NSObject {
public var hasUDAuthFailed = false public var hasUDAuthFailed = false
@objc @objc
public let udAccessKey: SMKUDAccessKey? public let unidentifiedAccess: SSKUnidentifiedAccess?
@objc @objc
public let localNumber: String public let localNumber: String
@ -44,9 +44,6 @@ public class OWSMessageSend: NSObject {
@objc @objc
public let isLocalNumber: Bool public let isLocalNumber: Bool
@objc
public let senderCertificate: SMKSenderCertificate?
@objc @objc
public let success: () -> Void public let success: () -> Void
@ -65,10 +62,11 @@ public class OWSMessageSend: NSObject {
self.message = message self.message = message
self.thread = thread self.thread = thread
self.recipient = recipient self.recipient = recipient
self.senderCertificate = senderCertificate
var udAccessKey: SMKUDAccessKey? let senderCertificate = senderCertificate
var isLocalNumber: Bool = false
let udAccessKey: SMKUDAccessKey?
var isLocalNumber: Bool
if let recipientId = recipient.uniqueId { if let recipientId = recipient.uniqueId {
switch udManager.unidentifiedAccessMode(recipientId: recipientId) { switch udManager.unidentifiedAccessMode(recipientId: recipientId) {
case .enabled: case .enabled:
@ -80,9 +78,16 @@ public class OWSMessageSend: NSObject {
} }
isLocalNumber = localNumber == recipientId isLocalNumber = localNumber == recipientId
} else { } else {
isLocalNumber = false
udAccessKey = nil
owsFailDebug("SignalRecipient missing recipientId") owsFailDebug("SignalRecipient missing recipientId")
} }
self.udAccessKey = udAccessKey if let udAccessKey = udAccessKey, let senderCertificate = senderCertificate {
self.unidentifiedAccess = SSKUnidentifiedAccess(accessKey: udAccessKey, senderCertificate: senderCertificate)
} else {
self.unidentifiedAccess = nil
}
self.localNumber = localNumber self.localNumber = localNumber
self.isLocalNumber = isLocalNumber self.isLocalNumber = isLocalNumber
@ -92,6 +97,6 @@ public class OWSMessageSend: NSObject {
@objc @objc
public var isUDSend: Bool { public var isUDSend: Bool {
return (!hasUDAuthFailed && udAccessKey != nil && senderCertificate != nil) return (!hasUDAuthFailed && self.unidentifiedAccess != nil)
} }
} }

@ -998,12 +998,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
TSRequest *request = [OWSRequestFactory submitMessageRequestWithRecipient:recipient.uniqueId TSRequest *request = [OWSRequestFactory submitMessageRequestWithRecipient:recipient.uniqueId
messages:deviceMessages messages:deviceMessages
timeStamp:message.timestamp]; timeStamp:message.timestamp
unidentifiedAccess:messageSend.unidentifiedAccess];
if (messageSend.isUDSend) {
DDLogVerbose(@"UD send.");
[request useUDAuth:messageSend.udAccessKey];
}
OWSWebSocketType webSocketType = (messageSend.isUDSend ? OWSWebSocketTypeUD : OWSWebSocketTypeDefault); OWSWebSocketType webSocketType = (messageSend.isUDSend ? OWSWebSocketTypeUD : OWSWebSocketTypeDefault);
BOOL canMakeWebsocketRequests = ([TSSocketManager.shared canMakeRequestsOfType:webSocketType] && BOOL canMakeWebsocketRequests = ([TSSocketManager.shared canMakeRequestsOfType:webSocketType] &&
@ -1090,7 +1086,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[SignalRecipient markRecipientAsRegisteredAndGet:recipient.recipientId transaction:transaction]; [SignalRecipient markRecipientAsRegisteredAndGet:recipient.recipientId transaction:transaction];
}]; }];
[self handleMessageSentLocally:messageSend.message senderCertificate:messageSend.senderCertificate]; [self handleMessageSentLocally:messageSend.message
senderCertificate:messageSend.unidentifiedAccess.senderCertificate];
messageSend.success(); messageSend.success();
}); });
} }
@ -1399,13 +1396,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// To avoid deadlock, we need to ensure that our success/failure completions // To avoid deadlock, we need to ensure that our success/failure completions
// are called _off_ the main thread. Otherwise we'll deadlock if the main // are called _off_ the main thread. Otherwise we'll deadlock if the main
// thread is blocked on opening a transaction. // thread is blocked on opening a transaction.
TSRequest *request = TSRequest *request = [OWSRequestFactory recipientPrekeyRequestWithRecipient:recipientId
[OWSRequestFactory recipientPrekeyRequestWithRecipient:recipientId deviceId:[deviceId stringValue]]; deviceId:[deviceId stringValue]
unidentifiedAccess:messageSend.unidentifiedAccess];
if (messageSend.isUDSend) {
DDLogVerbose(@"UD prekey request.");
[request useUDAuth:messageSend.udAccessKey];
}
[self.networkManager makeRequest:request [self.networkManager makeRequest:request
completionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) completionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
@ -1509,7 +1502,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
serializedMessage = [secretCipher encryptMessageWithRecipientId:recipientId serializedMessage = [secretCipher encryptMessageWithRecipientId:recipientId
deviceId:deviceId.intValue deviceId:deviceId.intValue
paddedPlaintext:[plainText paddedMessageBody] paddedPlaintext:[plainText paddedMessageBody]
senderCertificate:messageSend.senderCertificate senderCertificate:messageSend.unidentifiedAccess.senderCertificate
protocolContext:transaction protocolContext:transaction
error:&error]; error:&error];
messageType = TSUnidentifiedSenderMessageType; messageType = TSUnidentifiedSenderMessageType;

@ -7,6 +7,7 @@ NS_ASSUME_NONNULL_BEGIN
@class ECKeyPair; @class ECKeyPair;
@class OWSDevice; @class OWSDevice;
@class PreKeyRecord; @class PreKeyRecord;
@class SSKUnidentifiedAccess;
@class SignedPreKeyRecord; @class SignedPreKeyRecord;
@class TSRequest; @class TSRequest;
@ -35,7 +36,9 @@ typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVo
+ (TSRequest *)getMessagesRequest; + (TSRequest *)getMessagesRequest;
+ (TSRequest *)getProfileRequestWithRecipientId:(NSString *)recipientId; + (TSRequest *)getProfileRequestWithRecipientId:(NSString *)recipientId
unidentifiedAccess:(nullable SSKUnidentifiedAccess *)unidentifiedAccess
NS_SWIFT_NAME(getProfileRequest(recipientId:unidentifiedAccess:));
+ (TSRequest *)turnServerInfoRequest; + (TSRequest *)turnServerInfoRequest;
@ -58,7 +61,8 @@ typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVo
+ (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId + (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId
messages:(NSArray *)messages messages:(NSArray *)messages
timeStamp:(uint64_t)timeStamp; timeStamp:(uint64_t)timeStamp
unidentifiedAccess:(nullable SSKUnidentifiedAccess *)unidentifiedAccess;
+ (TSRequest *)verifyCodeRequestWithVerificationCode:(NSString *)verificationCode + (TSRequest *)verifyCodeRequestWithVerificationCode:(NSString *)verificationCode
forNumber:(NSString *)phoneNumber forNumber:(NSString *)phoneNumber
@ -72,7 +76,9 @@ typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVo
+ (TSRequest *)currentSignedPreKeyRequest; + (TSRequest *)currentSignedPreKeyRequest;
+ (TSRequest *)recipientPrekeyRequestWithRecipient:(NSString *)recipientNumber deviceId:(NSString *)deviceId; + (TSRequest *)recipientPrekeyRequestWithRecipient:(NSString *)recipientNumber
deviceId:(NSString *)deviceId
unidentifiedAccess:(nullable SSKUnidentifiedAccess *)unidentifiedAccess;
+ (TSRequest *)registerSignedPrekeyRequestWithSignedPreKeyRecord:(SignedPreKeyRecord *)signedPreKey; + (TSRequest *)registerSignedPrekeyRequestWithSignedPreKeyRecord:(SignedPreKeyRecord *)signedPreKey;

@ -124,11 +124,16 @@ NS_ASSUME_NONNULL_BEGIN
} }
+ (TSRequest *)getProfileRequestWithRecipientId:(NSString *)recipientId + (TSRequest *)getProfileRequestWithRecipientId:(NSString *)recipientId
unidentifiedAccess:(nullable SSKUnidentifiedAccess *)unidentifiedAccess
{ {
OWSAssertDebug(recipientId.length > 0); OWSAssertDebug(recipientId.length > 0);
NSString *path = [NSString stringWithFormat:textSecureProfileAPIFormat, recipientId]; NSString *path = [NSString stringWithFormat:textSecureProfileAPIFormat, recipientId];
return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}];
if (unidentifiedAccess != nil) {
[request useUDAuthWithAccessKey:unidentifiedAccess.accessKey];
}
return request;
} }
+ (TSRequest *)turnServerInfoRequest + (TSRequest *)turnServerInfoRequest
@ -181,13 +186,20 @@ NS_ASSUME_NONNULL_BEGIN
return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}];
} }
+ (TSRequest *)recipientPrekeyRequestWithRecipient:(NSString *)recipientNumber deviceId:(NSString *)deviceId + (TSRequest *)recipientPrekeyRequestWithRecipient:(NSString *)recipientNumber
deviceId:(NSString *)deviceId
unidentifiedAccess:(nullable SSKUnidentifiedAccess *)unidentifiedAccess;
{ {
OWSAssertDebug(recipientNumber.length > 0); OWSAssertDebug(recipientNumber.length > 0);
OWSAssertDebug(deviceId.length > 0); OWSAssertDebug(deviceId.length > 0);
NSString *path = [NSString stringWithFormat:@"%@/%@/%@", textSecureKeysAPI, recipientNumber, deviceId]; NSString *path = [NSString stringWithFormat:@"%@/%@/%@", textSecureKeysAPI, recipientNumber, deviceId];
return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}];
TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}];
if (unidentifiedAccess != nil) {
[request useUDAuthWithAccessKey:unidentifiedAccess.accessKey];
}
return request;
} }
+ (TSRequest *)registerForPushRequestWithPushIdentifier:(NSString *)identifier voipIdentifier:(NSString *)voipId + (TSRequest *)registerForPushRequestWithPushIdentifier:(NSString *)identifier voipIdentifier:(NSString *)voipId
@ -316,6 +328,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId + (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId
messages:(NSArray *)messages messages:(NSArray *)messages
timeStamp:(uint64_t)timeStamp timeStamp:(uint64_t)timeStamp
unidentifiedAccess:(nullable SSKUnidentifiedAccess *)unidentifiedAccess
{ {
// NOTE: messages may be empty; See comments in OWSDeviceManager. // NOTE: messages may be empty; See comments in OWSDeviceManager.
OWSAssertDebug(recipientId.length > 0); OWSAssertDebug(recipientId.length > 0);
@ -327,7 +340,11 @@ NS_ASSUME_NONNULL_BEGIN
@"timestamp" : @(timeStamp), @"timestamp" : @(timeStamp),
}; };
return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:parameters]; TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:parameters];
if (unidentifiedAccess != nil) {
[request useUDAuthWithAccessKey:unidentifiedAccess.accessKey];
}
return request;
} }
+ (TSRequest *)registerSignedPrekeyRequestWithSignedPreKeyRecord:(SignedPreKeyRecord *)signedPreKey + (TSRequest *)registerSignedPrekeyRequestWithSignedPreKeyRecord:(SignedPreKeyRecord *)signedPreKey

@ -30,6 +30,6 @@
#pragma mark - UD #pragma mark - UD
- (void)useUDAuth:(SMKUDAccessKey *)udAccessKey; - (void)useUDAuthWithAccessKey:(SMKUDAccessKey *)udAccessKey;
@end @end

@ -114,7 +114,7 @@
#pragma mark - UD #pragma mark - UD
- (void)useUDAuth:(SMKUDAccessKey *)udAccessKey - (void)useUDAuthWithAccessKey:(SMKUDAccessKey *)udAccessKey
{ {
OWSAssertDebug(udAccessKey); OWSAssertDebug(udAccessKey);

@ -0,0 +1,47 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
@objc
public class SignalServiceProfile: NSObject {
public enum ValidationError: Error {
case invalid(description: String)
case invalidIdentityKey(description: String)
case invalidProfileName(description: String)
}
public let recipientId: String
public let identityKey: Data
public let profileNameEncrypted: Data?
public let avatarUrlPath: String?
public let unidentifiedAccessVerifier: Data?
public let hasUnrestrictedUnidentifiedAccess: Bool
public init(recipientId: String, responseObject: Any?) throws {
self.recipientId = recipientId
guard let params = ParamParser(responseObject: responseObject) else {
throw ValidationError.invalid(description: "invalid response: \(String(describing: responseObject))")
}
let identityKeyWithType = try params.requiredBase64EncodedData(key: "identityKey")
let kIdentityKeyLength = 33
guard identityKeyWithType.count == kIdentityKeyLength else {
throw ValidationError.invalidIdentityKey(description: "malformed identity key \(identityKeyWithType.hexadecimalString) with decoded length: \(identityKeyWithType.count)")
}
// `removeKeyType` is an objc category method only on NSData, so temporarily cast.
self.identityKey = (identityKeyWithType as NSData).removeKeyType() as Data
self.profileNameEncrypted = try params.optionalBase64EncodedData(key: "name")
let avatarUrlPath: String? = try params.optional(key: "avatar")
self.avatarUrlPath = avatarUrlPath
self.unidentifiedAccessVerifier = try params.optionalBase64EncodedData(key: "unidentifiedAccess")
self.hasUnrestrictedUnidentifiedAccess = try params.optional(key: "unrestrictedUnidentifiedAccess") ?? false
}
}

@ -4,13 +4,31 @@
import Foundation import Foundation
import PromiseKit import PromiseKit
import SignalMetadataKit
protocol SignalServiceClient { public typealias RecipientIdentifier = String
@objc
public class SSKUnidentifiedAccess: NSObject {
@objc
let accessKey: SMKUDAccessKey
@objc
let senderCertificate: SMKSenderCertificate
init(accessKey: SMKUDAccessKey, senderCertificate: SMKSenderCertificate) {
self.accessKey = accessKey
self.senderCertificate = senderCertificate
}
}
public protocol SignalServiceClient {
func getAvailablePreKeys() -> Promise<Int> func getAvailablePreKeys() -> Promise<Int>
func registerPreKeys(identityKey: IdentityKey, signedPreKeyRecord: SignedPreKeyRecord, preKeyRecords: [PreKeyRecord]) -> Promise<Void> func registerPreKeys(identityKey: IdentityKey, signedPreKeyRecord: SignedPreKeyRecord, preKeyRecords: [PreKeyRecord]) -> Promise<Void>
func setCurrentSignedPreKey(_ signedPreKey: SignedPreKeyRecord) -> Promise<Void> func setCurrentSignedPreKey(_ signedPreKey: SignedPreKeyRecord) -> Promise<Void>
func requestUDSenderCertificate() -> Promise<Data> func requestUDSenderCertificate() -> Promise<Data>
func updateAcountAttributes() -> Promise<Void> func updateAcountAttributes() -> Promise<Void>
func retrieveProfile(recipientId: RecipientIdentifier, unidentifiedAccess: SSKUnidentifiedAccess?) -> Promise<SignalServiceProfile>
} }
/// Based on libsignal-service-java's PushServiceSocket class /// Based on libsignal-service-java's PushServiceSocket class
@ -25,7 +43,7 @@ public class SignalServiceRestClient: NSObject, SignalServiceClient {
return OWSErrorMakeUnableToProcessServerResponseError() return OWSErrorMakeUnableToProcessServerResponseError()
} }
func getAvailablePreKeys() -> Promise<Int> { public func getAvailablePreKeys() -> Promise<Int> {
Logger.debug("") Logger.debug("")
let request = OWSRequestFactory.availablePreKeysCountRequest() let request = OWSRequestFactory.availablePreKeysCountRequest()
@ -41,7 +59,7 @@ public class SignalServiceRestClient: NSObject, SignalServiceClient {
} }
} }
func registerPreKeys(identityKey: IdentityKey, signedPreKeyRecord: SignedPreKeyRecord, preKeyRecords: [PreKeyRecord]) -> Promise<Void> { public func registerPreKeys(identityKey: IdentityKey, signedPreKeyRecord: SignedPreKeyRecord, preKeyRecords: [PreKeyRecord]) -> Promise<Void> {
Logger.debug("") Logger.debug("")
let request = OWSRequestFactory.registerPrekeysRequest(withPrekeyArray: preKeyRecords, identityKey: identityKey, signedPreKey: signedPreKeyRecord) let request = OWSRequestFactory.registerPrekeysRequest(withPrekeyArray: preKeyRecords, identityKey: identityKey, signedPreKey: signedPreKeyRecord)
@ -83,4 +101,11 @@ public class SignalServiceRestClient: NSObject, SignalServiceClient {
}) })
return promise return promise
} }
public func retrieveProfile(recipientId: RecipientIdentifier, unidentifiedAccess: SSKUnidentifiedAccess?) -> Promise<SignalServiceProfile> {
let request = OWSRequestFactory.getProfileRequest(recipientId: recipientId, unidentifiedAccess: unidentifiedAccess)
return networkManager.makePromise(request: request).then { (task: URLSessionDataTask, responseObject: Any?) in
return try SignalServiceProfile(recipientId: recipientId, responseObject: responseObject)
}
}
} }

Loading…
Cancel
Save