|
|
|
@ -20,6 +20,19 @@ public enum UnidentifiedAccessMode: Int {
|
|
|
|
|
case unrestricted
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private func string(forUnidentifiedAccessMode mode: UnidentifiedAccessMode) -> String {
|
|
|
|
|
switch mode {
|
|
|
|
|
case .unknown:
|
|
|
|
|
return "unknown"
|
|
|
|
|
case .enabled:
|
|
|
|
|
return "enabled"
|
|
|
|
|
case .disabled:
|
|
|
|
|
return "disabled"
|
|
|
|
|
case .unrestricted:
|
|
|
|
|
return "unrestricted"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc public protocol OWSUDManager: class {
|
|
|
|
|
|
|
|
|
|
@objc func setup()
|
|
|
|
@ -28,39 +41,39 @@ public enum UnidentifiedAccessMode: Int {
|
|
|
|
|
|
|
|
|
|
@objc func isUDEnabled() -> Bool
|
|
|
|
|
|
|
|
|
|
@objc func isUDVerboseLoggingEnabled() -> Bool
|
|
|
|
|
|
|
|
|
|
// MARK: - Recipient State
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
func setUnidentifiedAccessMode(_ mode: UnidentifiedAccessMode, recipientId: String)
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
func getAccess(forRecipientId recipientId: RecipientIdentifier) -> SSKUnidentifiedAccessPair?
|
|
|
|
|
func randomUDAccessKey() -> SMKUDAccessKey
|
|
|
|
|
|
|
|
|
|
// Returns the UD access key for a given recipient if:
|
|
|
|
|
//
|
|
|
|
|
// * UD is enabled.
|
|
|
|
|
// * Their UD mode is enabled or unrestricted.
|
|
|
|
|
// * We have a valid profile key for them.
|
|
|
|
|
@objc func enabledUDAccessKeyForRecipient(_ recipientId: RecipientIdentifier) -> SMKUDAccessKey?
|
|
|
|
|
@objc
|
|
|
|
|
func unidentifiedAccessMode(forRecipientId recipientId: RecipientIdentifier) -> UnidentifiedAccessMode
|
|
|
|
|
|
|
|
|
|
// Returns the UD access key for a given recipient if:
|
|
|
|
|
//
|
|
|
|
|
// * We have a valid profile key for them.
|
|
|
|
|
@objc func rawUDAccessKeyForRecipient(_ recipientId: RecipientIdentifier) -> SMKUDAccessKey?
|
|
|
|
|
@objc
|
|
|
|
|
func udAccessKey(forRecipientId recipientId: RecipientIdentifier) -> SMKUDAccessKey?
|
|
|
|
|
|
|
|
|
|
// MARK: - Local State
|
|
|
|
|
@objc
|
|
|
|
|
func udSendAccessKey(forRecipientId recipientId: RecipientIdentifier) -> SMKUDAccessKey?
|
|
|
|
|
|
|
|
|
|
// MARK: Sender Certificate
|
|
|
|
|
|
|
|
|
|
// We use completion handlers instead of a promise so that message sending
|
|
|
|
|
// logic can access the strongly typed certificate data.
|
|
|
|
|
@objc func ensureSenderCertificateObjC(success:@escaping (SMKSenderCertificate) -> Void,
|
|
|
|
|
@objc
|
|
|
|
|
func ensureSenderCertificateObjC(success:@escaping (SMKSenderCertificate) -> Void,
|
|
|
|
|
failure:@escaping (Error) -> Void)
|
|
|
|
|
|
|
|
|
|
// MARK: Unrestricted Access
|
|
|
|
|
|
|
|
|
|
@objc func shouldAllowUnrestrictedAccessLocal() -> Bool
|
|
|
|
|
@objc func setShouldAllowUnrestrictedAccessLocal(_ value: Bool)
|
|
|
|
|
@objc
|
|
|
|
|
func shouldAllowUnrestrictedAccessLocal() -> Bool
|
|
|
|
|
@objc
|
|
|
|
|
func setShouldAllowUnrestrictedAccessLocal(_ value: Bool)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: -
|
|
|
|
@ -111,6 +124,24 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
|
|
|
|
|
ensureSenderCertificate().retainUntilComplete()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: -
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func isUDEnabled() -> Bool {
|
|
|
|
|
// Only enable UD if UD is supported by all linked devices,
|
|
|
|
|
// so that sync messages can also be sent via UD.
|
|
|
|
|
guard let localNumber = tsAccountManager.localNumber() else {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
let ourAccessMode = unidentifiedAccessMode(forRecipientId: localNumber)
|
|
|
|
|
return ourAccessMode == .enabled || ourAccessMode == .unrestricted
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func isUDVerboseLoggingEnabled() -> Bool {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: - Dependencies
|
|
|
|
|
|
|
|
|
|
private var profileManager: ProfileManagerProtocol {
|
|
|
|
@ -124,44 +155,13 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
|
|
|
|
|
// MARK: - Recipient state
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func getAccess(forRecipientId recipientId: RecipientIdentifier) -> SSKUnidentifiedAccessPair? {
|
|
|
|
|
let theirAccessMode = unidentifiedAccessMode(recipientId: recipientId)
|
|
|
|
|
guard theirAccessMode == .enabled || theirAccessMode == .unrestricted else {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guard let theirAccessKey = enabledUDAccessKeyForRecipient(recipientId) else {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guard let ourSenderCertificate = senderCertificate() else {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guard let ourAccessKey: SMKUDAccessKey = {
|
|
|
|
|
if shouldAllowUnrestrictedAccessLocal() {
|
|
|
|
|
public func randomUDAccessKey() -> SMKUDAccessKey {
|
|
|
|
|
return SMKUDAccessKey(randomKeyData: ())
|
|
|
|
|
} else {
|
|
|
|
|
guard let localNumber = tsAccountManager.localNumber() else {
|
|
|
|
|
owsFailDebug("localNumber was unexpectedly nil")
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return enabledUDAccessKeyForRecipient(localNumber)
|
|
|
|
|
}
|
|
|
|
|
}() else {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let targetUnidentifiedAccess = SSKUnidentifiedAccess(accessKey: theirAccessKey, senderCertificate: ourSenderCertificate)
|
|
|
|
|
let selfUnidentifiedAccess = SSKUnidentifiedAccess(accessKey: ourAccessKey, senderCertificate: ourSenderCertificate)
|
|
|
|
|
return SSKUnidentifiedAccessPair(targetUnidentifiedAccess: targetUnidentifiedAccess,
|
|
|
|
|
selfUnidentifiedAccess: selfUnidentifiedAccess)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
func unidentifiedAccessMode(recipientId: RecipientIdentifier) -> UnidentifiedAccessMode {
|
|
|
|
|
guard let existingRawValue = dbConnection.object(forKey: recipientId, inCollection: kUnidentifiedAccessCollection) as? Int else {
|
|
|
|
|
private func unidentifiedAccessMode(forRecipientId recipientId: RecipientIdentifier,
|
|
|
|
|
transaction: YapDatabaseReadTransaction) -> UnidentifiedAccessMode {
|
|
|
|
|
guard let existingRawValue = transaction.object(forKey: recipientId, inCollection: kUnidentifiedAccessCollection) as? Int else {
|
|
|
|
|
return .unknown
|
|
|
|
|
}
|
|
|
|
|
guard let existingValue = UnidentifiedAccessMode(rawValue: existingRawValue) else {
|
|
|
|
@ -170,35 +170,38 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
|
|
|
|
|
return existingValue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func unidentifiedAccessMode(forRecipientId recipientId: RecipientIdentifier) -> UnidentifiedAccessMode {
|
|
|
|
|
var mode: UnidentifiedAccessMode = .unknown
|
|
|
|
|
dbConnection.read { (transaction) in
|
|
|
|
|
mode = self.unidentifiedAccessMode(forRecipientId: recipientId, transaction: transaction)
|
|
|
|
|
}
|
|
|
|
|
return mode
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func setUnidentifiedAccessMode(_ mode: UnidentifiedAccessMode, recipientId: String) {
|
|
|
|
|
if let localNumber = tsAccountManager.localNumber() {
|
|
|
|
|
if recipientId == localNumber {
|
|
|
|
|
Logger.info("Setting local UD access mode: \(mode.rawValue)")
|
|
|
|
|
Logger.info("Setting local UD access mode: \(string(forUnidentifiedAccessMode: mode))")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dbConnection.setObject(mode.rawValue as Int, forKey: recipientId, inCollection: kUnidentifiedAccessCollection)
|
|
|
|
|
}
|
|
|
|
|
dbConnection.readWrite { (transaction) in
|
|
|
|
|
let oldMode = self.unidentifiedAccessMode(forRecipientId: recipientId, transaction: transaction)
|
|
|
|
|
|
|
|
|
|
// Returns the UD access key for a given recipient
|
|
|
|
|
// if we have a valid profile key for them.
|
|
|
|
|
@objc
|
|
|
|
|
public func enabledUDAccessKeyForRecipient(_ recipientId: RecipientIdentifier) -> SMKUDAccessKey? {
|
|
|
|
|
guard isUDEnabled() else {
|
|
|
|
|
return nil
|
|
|
|
|
transaction.setObject(mode.rawValue as Int, forKey: recipientId, inCollection: self.kUnidentifiedAccessCollection)
|
|
|
|
|
|
|
|
|
|
if mode != oldMode {
|
|
|
|
|
Logger.info("Setting UD access mode for \(recipientId): \(string(forUnidentifiedAccessMode: oldMode)) -> \(string(forUnidentifiedAccessMode: mode))")
|
|
|
|
|
}
|
|
|
|
|
let theirAccessMode = unidentifiedAccessMode(recipientId: recipientId)
|
|
|
|
|
if theirAccessMode == .unrestricted {
|
|
|
|
|
return SMKUDAccessKey(randomKeyData: ())
|
|
|
|
|
}
|
|
|
|
|
return rawUDAccessKeyForRecipient(recipientId)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns the UD access key for a given recipient
|
|
|
|
|
// if we have a valid profile key for them.
|
|
|
|
|
@objc
|
|
|
|
|
public func rawUDAccessKeyForRecipient(_ recipientId: RecipientIdentifier) -> SMKUDAccessKey? {
|
|
|
|
|
public func udAccessKey(forRecipientId recipientId: RecipientIdentifier) -> SMKUDAccessKey? {
|
|
|
|
|
guard let profileKey = profileManager.profileKeyData(forRecipientId: recipientId) else {
|
|
|
|
|
// Mark as "not a UD recipient".
|
|
|
|
|
return nil
|
|
|
|
@ -212,6 +215,50 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns the UD access key for sending to a given recipient.
|
|
|
|
|
@objc
|
|
|
|
|
public func udSendAccessKey(forRecipientId recipientId: RecipientIdentifier) -> SMKUDAccessKey? {
|
|
|
|
|
// This check is currently redundant with the "send access key for local number"
|
|
|
|
|
// check below, but behavior of isUDEnabled() may change.
|
|
|
|
|
guard isUDEnabled() else {
|
|
|
|
|
if isUDVerboseLoggingEnabled() {
|
|
|
|
|
Logger.info("UD Send disabled for \(recipientId), UD disabled.")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
guard let localNumber = tsAccountManager.localNumber() else {
|
|
|
|
|
if isUDVerboseLoggingEnabled() {
|
|
|
|
|
Logger.info("UD Send disabled for \(recipientId), no local number.")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if localNumber != recipientId {
|
|
|
|
|
guard udSendAccessKey(forRecipientId: localNumber) != nil else {
|
|
|
|
|
if isUDVerboseLoggingEnabled() {
|
|
|
|
|
Logger.info("UD Send disabled for \(recipientId), UD disabled for sync messages.")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let accessMode = unidentifiedAccessMode(forRecipientId: localNumber)
|
|
|
|
|
if accessMode == .unrestricted {
|
|
|
|
|
if isUDVerboseLoggingEnabled() {
|
|
|
|
|
Logger.info("UD Send enabled for \(recipientId) with random key.")
|
|
|
|
|
}
|
|
|
|
|
return randomUDAccessKey()
|
|
|
|
|
}
|
|
|
|
|
guard accessMode == .enabled else {
|
|
|
|
|
if isUDVerboseLoggingEnabled() {
|
|
|
|
|
Logger.info("UD Send disabled for \(recipientId), UD not enabled for this recipient.")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if isUDVerboseLoggingEnabled() {
|
|
|
|
|
Logger.info("UD Send enabled for \(recipientId).")
|
|
|
|
|
}
|
|
|
|
|
return udAccessKey(forRecipientId: recipientId)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: - Sender Certificate
|
|
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
@ -309,17 +356,6 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func isUDEnabled() -> Bool {
|
|
|
|
|
// Only enable UD if UD is supported by all linked devices,
|
|
|
|
|
// so that sync messages can also be sent via UD.
|
|
|
|
|
guard let localNumber = tsAccountManager.localNumber() else {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
let ourAccessMode = unidentifiedAccessMode(recipientId: localNumber)
|
|
|
|
|
return ourAccessMode == .enabled || ourAccessMode == .unrestricted
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func trustRoot() -> ECPublicKey {
|
|
|
|
|
return OWSUDManagerImpl.trustRoot()
|
|
|
|
|