Track UD mode enum instead of two booleans

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

@ -180,29 +180,34 @@ public class ProfileFetcherJob: NSObject {
profileNameEncrypted: signalServiceProfile.profileNameEncrypted,
avatarUrlPath: signalServiceProfile.avatarUrlPath)
// Recipients should be in "UD delivery mode" IFF:
//
// * Their profile includes a unidentifiedAccessVerifier.
// * The unidentifiedAccessVerifier matches the "expected" value derived
// from their profile key (if any).
//
// Recipients should be in "normal delivery mode" otherwise.
var supportsUnidentifiedDelivery = false
if let unidentifiedAccessVerifier = signalServiceProfile.unidentifiedAccessVerifier,
let udAccessKey = udManager.udAccessKeyForRecipient(recipientId) {
let dataToVerify = Data(count: 32)
if let expectedVerfier = Cryptography.computeSHA256HMAC(dataToVerify, withHMACKey: udAccessKey.keyData) {
supportsUnidentifiedDelivery = expectedVerfier == unidentifiedAccessVerifier
} else {
owsFailDebug("could not verify UD")
}
updateUnidentifiedAccess(recipientId: recipientId, verifier: signalServiceProfile.unidentifiedAccessVerifier, hasUnrestrictedAccess: signalServiceProfile.hasUnrestrictedUnidentifiedAccess)
}
private func updateUnidentifiedAccess(recipientId: String, verifier: Data?, hasUnrestrictedAccess: Bool) {
if hasUnrestrictedAccess {
udManager.setUnidentifiedAccessMode(.unrestricted, recipientId: recipientId)
return
}
// TODO: We may want to only call setSupportsUnidentifiedDelivery if
// supportsUnidentifiedDelivery is true.
udManager.setSupportsUnidentifiedDelivery(supportsUnidentifiedDelivery, recipientId: recipientId)
guard let verifier = verifier, let udAccessKey = udManager.udAccessKeyForRecipient(recipientId) else {
udManager.setUnidentifiedAccessMode(.disabled, recipientId: recipientId)
return
}
let dataToVerify = Data(count: 32)
guard let expectedVerfier = Cryptography.computeSHA256HMAC(dataToVerify, withHMACKey: udAccessKey.keyData) else {
owsFailDebug("could not compute verification")
udManager.setUnidentifiedAccessMode(.disabled, recipientId: recipientId)
return
}
guard expectedVerfier == verifier else {
Logger.verbose("verifier mismatch, new profile key?")
udManager.setUnidentifiedAccessMode(.disabled, recipientId: recipientId)
return
}
udManager.setShouldAllowUnrestrictedAccess(recipientId: recipientId, shouldAllowUnrestrictedAccess: signalServiceProfile.hasUnrestrictedUnidentifiedAccess)
udManager.setUnidentifiedAccessMode(.enabled, recipientId: recipientId)
}
private func verifyIdentityUpToDateAsync(recipientId: String, latestIdentityKey: Data) {

@ -70,9 +70,14 @@ public class OWSMessageSend: NSObject {
var udAccessKey: SMKUDAccessKey?
var isLocalNumber: Bool = false
if let recipientId = recipient.uniqueId {
udAccessKey = (udManager.supportsUnidentifiedDelivery(recipientId: recipientId)
? udManager.udAccessKeyForRecipient(recipientId)
: nil)
switch udManager.unidentifiedAccessMode(recipientId: recipientId) {
case .enabled:
udAccessKey = udManager.udAccessKeyForRecipient(recipientId)
case .unrestricted:
udAccessKey = udManager.generateAccessKeyForUnrestrictedRecipient()
case .disabled, .unknown:
udAccessKey = nil
}
isLocalNumber = localNumber == recipientId
} else {
owsFailDebug("SignalRecipient missing recipientId")

@ -1041,7 +1041,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
//
// TODO: Do we want to discriminate based on exact error?
OWSLogDebug(@"UD send failed; failing over to non-UD send.");
[self.udManager setSupportsUnidentifiedDelivery:NO recipientId:recipient.uniqueId];
[self.udManager setUnidentifiedAccessMode:UnidentifiedAccessModeDisabled
recipientId:recipient.uniqueId];
messageSend.hasUDAuthFailed = YES;
dispatch_async([OWSDispatch sendingQueue], ^{
[self sendMessageToRecipient:messageSend];

@ -12,38 +12,47 @@ public enum OWSUDError: Error {
case invalidData(description: String)
}
@objc
public enum UnidentifiedAccessMode: Int {
case unknown
case enabled
case disabled
case unrestricted
}
@objc public protocol OWSUDManager: class {
@objc func setup()
@objc func trustRoot() -> ECPublicKey
// MARK: - Recipient state
// MARK: - Recipient State
@objc func supportsUnidentifiedDelivery(recipientId: String) -> Bool
@objc
func unidentifiedAccessMode(recipientId: String) -> UnidentifiedAccessMode
@objc func setSupportsUnidentifiedDelivery(_ value: Bool, recipientId: String)
@objc
func setUnidentifiedAccessMode(_ mode: UnidentifiedAccessMode, recipientId: String)
// Returns the UD access key for a given recipient if they are
// a UD recipient and we have a valid profile key for them.
@objc func udAccessKeyForRecipient(_ recipientId: String) -> SMKUDAccessKey?
// MARK: - Sender Certificate
@objc
func generateAccessKeyForUnrestrictedRecipient() -> SMKUDAccessKey
// MARK: - Local State
// MARK: Sender Certificate
// We use completion handlers instead of a promise so that message sending
// logic can access the certificate data.
// logic can access the strongly typed certificate data.
@objc func ensureSenderCertificateObjC(success:@escaping (SMKSenderCertificate) -> Void,
failure:@escaping (Error) -> Void)
// MARK: - Unrestricted Access
// MARK: Unrestricted Access
@objc func shouldAllowUnrestrictedAccessLocal() -> Bool
@objc func setShouldAllowUnrestrictedAccessLocal(_ value: Bool)
@objc func shouldAllowUnrestrictedAccess(recipientId: String) -> Bool
@objc func setShouldAllowUnrestrictedAccess(recipientId: String, shouldAllowUnrestrictedAccess: Bool)
}
// MARK: -
@ -53,11 +62,13 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
private let dbConnection: YapDatabaseConnection
// MARK: Local Configuration State
private let kUDCollection = "kUDCollection"
private let kUDCurrentSenderCertificateKey = "kUDCurrentSenderCertificateKey"
private let kUDUnrestrictedAccessKey = "kUDUnrestrictedAccessKey"
private let kUDRecipientModeCollection = "kUDRecipientModeCollection"
private let kUDUnrestrictedAccessCollection = "kUDUnrestrictedAccessCollection"
// MARK: Recipient State
private let kUnidentifiedAccessCollection = "kUnidentifiedAccessCollection"
@objc
public required init(primaryStorage: OWSPrimaryStorage) {
@ -101,20 +112,24 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
// MARK: - Recipient state
@objc
public func supportsUnidentifiedDelivery(recipientId: String) -> Bool {
public func unidentifiedAccessMode(recipientId: String) -> UnidentifiedAccessMode {
if tsAccountManager.localNumber() == recipientId {
return true
if shouldAllowUnrestrictedAccessLocal() {
return .unrestricted
} else {
return .enabled
}
}
guard let existingValue = dbConnection.object(forKey: recipientId, inCollection: kUnidentifiedAccessCollection) as? UnidentifiedAccessMode else {
return .unknown
}
return dbConnection.bool(forKey: recipientId, inCollection: kUDRecipientModeCollection, defaultValue: false)
return existingValue
}
@objc
public func setSupportsUnidentifiedDelivery(_ value: Bool, recipientId: String) {
if value {
dbConnection.setBool(true, forKey: recipientId, inCollection: kUDRecipientModeCollection)
} else {
dbConnection.removeObject(forKey: recipientId, inCollection: kUDRecipientModeCollection)
}
public func setUnidentifiedAccessMode(_ mode: UnidentifiedAccessMode, recipientId: String) {
dbConnection.setObject(mode, forKey: recipientId, inCollection: kUnidentifiedAccessCollection)
}
// Returns the UD access key for a given recipient
@ -134,6 +149,11 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
}
}
@objc
public func generateAccessKeyForUnrestrictedRecipient() -> SMKUDAccessKey {
return SMKUDAccessKey(randomKeyData: ())
}
// MARK: - Sender Certificate
#if DEBUG
@ -251,14 +271,4 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
public func setShouldAllowUnrestrictedAccessLocal(_ value: Bool) {
dbConnection.setBool(value, forKey: kUDUnrestrictedAccessKey, inCollection: kUDCollection)
}
@objc
public func shouldAllowUnrestrictedAccess(recipientId: String) -> Bool {
return dbConnection.bool(forKey: recipientId, inCollection: kUDUnrestrictedAccessCollection, defaultValue: false)
}
@objc
public func setShouldAllowUnrestrictedAccess(recipientId: String, shouldAllowUnrestrictedAccess: Bool) {
dbConnection.setBool(shouldAllowUnrestrictedAccess, forKey: recipientId, inCollection: kUDUnrestrictedAccessCollection)
}
}

Loading…
Cancel
Save