Further build out device link authorization

This commit is contained in:
Niels Andriesse 2019-09-24 15:05:59 +10:00
parent 96872c523b
commit 5b04b5ed3b
10 changed files with 104 additions and 55 deletions

View file

@ -570,12 +570,12 @@
B86BD08123399883000F5AE3 /* QRCodeModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08023399883000F5AE3 /* QRCodeModal.swift */; }; B86BD08123399883000F5AE3 /* QRCodeModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08023399883000F5AE3 /* QRCodeModal.swift */; };
B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; };
B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; };
B86BD08C2339AE43000F5AE3 /* DeviceLinkingModalDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08B2339AE43000F5AE3 /* DeviceLinkingModalDelegate.swift */; };
B885D5F4233491AB00EE0D8E /* DeviceLinkingModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */; }; B885D5F4233491AB00EE0D8E /* DeviceLinkingModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */; };
B885D5F62334A32100EE0D8E /* UIView+Constraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = B885D5F52334A32100EE0D8E /* UIView+Constraint.swift */; }; B885D5F62334A32100EE0D8E /* UIView+Constraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = B885D5F52334A32100EE0D8E /* UIView+Constraint.swift */; };
B891105C2320872800F15FCC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B891105B2320872800F15FCC /* GoogleService-Info.plist */; }; B891105C2320872800F15FCC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B891105B2320872800F15FCC /* GoogleService-Info.plist */; };
B891105E2320872800F15FCC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B891105B2320872800F15FCC /* GoogleService-Info.plist */; }; B891105E2320872800F15FCC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B891105B2320872800F15FCC /* GoogleService-Info.plist */; };
B891105F2320872800F15FCC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B891105B2320872800F15FCC /* GoogleService-Info.plist */; }; B891105F2320872800F15FCC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B891105B2320872800F15FCC /* GoogleService-Info.plist */; };
B894D0712339D6F300B4D94D /* DeviceLinkingModalDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B894D0702339D6F300B4D94D /* DeviceLinkingModalDelegate.swift */; };
B89841E322B7579F00B1BDC6 /* NewConversationVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B89841E222B7579F00B1BDC6 /* NewConversationVC.swift */; }; B89841E322B7579F00B1BDC6 /* NewConversationVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B89841E222B7579F00B1BDC6 /* NewConversationVC.swift */; };
B90418E6183E9DD40038554A /* DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B90418E5183E9DD40038554A /* DateUtil.m */; }; B90418E6183E9DD40038554A /* DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B90418E5183E9DD40038554A /* DateUtil.m */; };
B9EB5ABD1884C002007CBB57 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9EB5ABC1884C002007CBB57 /* MessageUI.framework */; }; B9EB5ABD1884C002007CBB57 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9EB5ABC1884C002007CBB57 /* MessageUI.framework */; };
@ -1378,10 +1378,10 @@
B86BD08023399883000F5AE3 /* QRCodeModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeModal.swift; sourceTree = "<group>"; }; B86BD08023399883000F5AE3 /* QRCodeModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeModal.swift; sourceTree = "<group>"; };
B86BD08323399ACF000F5AE3 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = "<group>"; }; B86BD08323399ACF000F5AE3 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = "<group>"; };
B86BD08523399CEF000F5AE3 /* SeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedModal.swift; sourceTree = "<group>"; }; B86BD08523399CEF000F5AE3 /* SeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedModal.swift; sourceTree = "<group>"; };
B86BD08B2339AE43000F5AE3 /* DeviceLinkingModalDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinkingModalDelegate.swift; sourceTree = "<group>"; };
B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinkingModal.swift; sourceTree = "<group>"; }; B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinkingModal.swift; sourceTree = "<group>"; };
B885D5F52334A32100EE0D8E /* UIView+Constraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Constraint.swift"; sourceTree = "<group>"; }; B885D5F52334A32100EE0D8E /* UIView+Constraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Constraint.swift"; sourceTree = "<group>"; };
B891105B2320872800F15FCC /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; }; B891105B2320872800F15FCC /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
B894D0702339D6F300B4D94D /* DeviceLinkingModalDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinkingModalDelegate.swift; sourceTree = "<group>"; };
B89841E222B7579F00B1BDC6 /* NewConversationVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationVC.swift; sourceTree = "<group>"; }; B89841E222B7579F00B1BDC6 /* NewConversationVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationVC.swift; sourceTree = "<group>"; };
B90418E4183E9DD40038554A /* DateUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateUtil.h; sourceTree = "<group>"; }; B90418E4183E9DD40038554A /* DateUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateUtil.h; sourceTree = "<group>"; };
B90418E5183E9DD40038554A /* DateUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DateUtil.m; sourceTree = "<group>"; }; B90418E5183E9DD40038554A /* DateUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DateUtil.m; sourceTree = "<group>"; };
@ -2668,7 +2668,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */, B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */,
B86BD08B2339AE43000F5AE3 /* DeviceLinkingModalDelegate.swift */, B894D0702339D6F300B4D94D /* DeviceLinkingModalDelegate.swift */,
B86BD08023399883000F5AE3 /* QRCodeModal.swift */, B86BD08023399883000F5AE3 /* QRCodeModal.swift */,
B86BD08523399CEF000F5AE3 /* SeedModal.swift */, B86BD08523399CEF000F5AE3 /* SeedModal.swift */,
); );
@ -3913,7 +3913,7 @@
45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */, 45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */,
34D1F0B01F867BFC0066283D /* OWSSystemMessageCell.m in Sources */, 34D1F0B01F867BFC0066283D /* OWSSystemMessageCell.m in Sources */,
45A663C51F92EC760027B59E /* GroupTableViewCell.swift in Sources */, 45A663C51F92EC760027B59E /* GroupTableViewCell.swift in Sources */,
B86BD08C2339AE43000F5AE3 /* DeviceLinkingModalDelegate.swift in Sources */, B894D0712339D6F300B4D94D /* DeviceLinkingModalDelegate.swift in Sources */,
34CA631B2097806F00E526A0 /* OWSContactShareView.m in Sources */, 34CA631B2097806F00E526A0 /* OWSContactShareView.m in Sources */,
B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */, B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */,
34D1F0861F8678AA0066283D /* ConversationViewController.m in Sources */, 34D1F0861F8678AA0066283D /* ConversationViewController.m in Sources */,

View file

@ -51,32 +51,32 @@ public final class GroupChatPoller : NSObject {
let cutoffIndex = senderHexEncodedPublicKey.index(endIndex, offsetBy: -8) let cutoffIndex = senderHexEncodedPublicKey.index(endIndex, offsetBy: -8)
let senderDisplayName = "\(message.displayName) (...\(senderHexEncodedPublicKey[cutoffIndex..<endIndex]))" let senderDisplayName = "\(message.displayName) (...\(senderHexEncodedPublicKey[cutoffIndex..<endIndex]))"
let id = group.id.data(using: String.Encoding.utf8)! let id = group.id.data(using: String.Encoding.utf8)!
let x1 = SSKProtoGroupContext.builder(id: id, type: .deliver) let groupContext = SSKProtoGroupContext.builder(id: id, type: .deliver)
x1.setName(group.displayName) groupContext.setName(group.displayName)
let x2 = SSKProtoDataMessage.builder() let dataMessage = SSKProtoDataMessage.builder()
x2.setTimestamp(message.timestamp) dataMessage.setTimestamp(message.timestamp)
x2.setGroup(try! x1.build()) dataMessage.setGroup(try! groupContext.build())
if let quote = message.quote { if let quote = message.quote {
let x5 = SSKProtoDataMessageQuote.builder(id: quote.quotedMessageTimestamp, author: quote.quoteeHexEncodedPublicKey) let signalQuote = SSKProtoDataMessageQuote.builder(id: quote.quotedMessageTimestamp, author: quote.quoteeHexEncodedPublicKey)
x5.setText(quote.quotedMessageBody) signalQuote.setText(quote.quotedMessageBody)
x2.setQuote(try! x5.build()) dataMessage.setQuote(try! signalQuote.build())
} }
x2.setBody(message.body) dataMessage.setBody(message.body)
if let messageServerID = message.serverID { if let messageServerID = message.serverID {
let publicChatInfo = SSKProtoPublicChatInfo.builder() let publicChatInfo = SSKProtoPublicChatInfo.builder()
publicChatInfo.setServerID(messageServerID) publicChatInfo.setServerID(messageServerID)
x2.setPublicChatInfo(try! publicChatInfo.build()) dataMessage.setPublicChatInfo(try! publicChatInfo.build())
} }
let x3 = SSKProtoContent.builder() let content = SSKProtoContent.builder()
x3.setDataMessage(try! x2.build()) content.setDataMessage(try! dataMessage.build())
let x4 = SSKProtoEnvelope.builder(type: .ciphertext, timestamp: message.timestamp) let envelope = SSKProtoEnvelope.builder(type: .ciphertext, timestamp: message.timestamp)
x4.setSource(senderHexEncodedPublicKey) envelope.setSource(senderHexEncodedPublicKey)
x4.setSourceDevice(OWSDevicePrimaryDeviceId) envelope.setSourceDevice(OWSDevicePrimaryDeviceId)
x4.setContent(try! x3.build().serializedData()) envelope.setContent(try! content.build().serializedData())
let storage = OWSPrimaryStorage.shared() let storage = OWSPrimaryStorage.shared()
storage.dbReadWriteConnection.readWrite { transaction in storage.dbReadWriteConnection.readWrite { transaction in
transaction.setObject(senderDisplayName, forKey: senderHexEncodedPublicKey, inCollection: group.id) transaction.setObject(senderDisplayName, forKey: senderHexEncodedPublicKey, inCollection: group.id)
SSKEnvironment.shared.messageManager.throws_processEnvelope(try! x4.build(), plaintextData: try! x3.build().serializedData(), wasReceivedByUD: false, transaction: transaction) SSKEnvironment.shared.messageManager.throws_processEnvelope(try! envelope.build(), plaintextData: try! content.build().serializedData(), wasReceivedByUD: false, transaction: transaction)
} }
} }
// Processing logic for outgoing messages // Processing logic for outgoing messages

View file

@ -49,20 +49,20 @@ public final class RSSFeedPoller : NSObject {
let options = [ NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html ] let options = [ NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html ]
guard let body = try? NSAttributedString(data: bodyAsData, options: options, documentAttributes: nil).string else { return } guard let body = try? NSAttributedString(data: bodyAsData, options: options, documentAttributes: nil).string else { return }
let id = feed.id.data(using: String.Encoding.utf8)! let id = feed.id.data(using: String.Encoding.utf8)!
let x1 = SSKProtoGroupContext.builder(id: id, type: .deliver) let groupContext = SSKProtoGroupContext.builder(id: id, type: .deliver)
x1.setName(feed.displayName) groupContext.setName(feed.displayName)
let x2 = SSKProtoDataMessage.builder() let dataMessage = SSKProtoDataMessage.builder()
x2.setTimestamp(timestamp) dataMessage.setTimestamp(timestamp)
x2.setGroup(try! x1.build()) dataMessage.setGroup(try! groupContext.build())
x2.setBody(body) dataMessage.setBody(body)
let x3 = SSKProtoContent.builder() let content = SSKProtoContent.builder()
x3.setDataMessage(try! x2.build()) content.setDataMessage(try! dataMessage.build())
let x4 = SSKProtoEnvelope.builder(type: .ciphertext, timestamp: timestamp) let envelope = SSKProtoEnvelope.builder(type: .ciphertext, timestamp: timestamp)
x4.setSource(NSLocalizedString("Loki", comment: "")) envelope.setSource(NSLocalizedString("Loki", comment: ""))
x4.setSourceDevice(OWSDevicePrimaryDeviceId) envelope.setSourceDevice(OWSDevicePrimaryDeviceId)
x4.setContent(try! x3.build().serializedData()) envelope.setContent(try! content.build().serializedData())
OWSPrimaryStorage.shared().dbReadWriteConnection.readWrite { transaction in OWSPrimaryStorage.shared().dbReadWriteConnection.readWrite { transaction in
SSKEnvironment.shared.messageManager.throws_processEnvelope(try! x4.build(), plaintextData: try! x3.build().serializedData(), wasReceivedByUD: false, transaction: transaction) SSKEnvironment.shared.messageManager.throws_processEnvelope(try! envelope.build(), plaintextData: try! content.build().serializedData(), wasReceivedByUD: false, transaction: transaction)
} }
} }
} }

View file

@ -337,10 +337,10 @@ final class SeedVC : OnboardingBaseViewController, DeviceLinkingModalDelegate {
case .link: Analytics.shared.track("Device Linked") case .link: Analytics.shared.track("Device Linked")
} }
if mode == .link { if mode == .link {
let masterHexEncodedPublicKey = masterHexEncodedPublicKeyTextField.text!.trimmingCharacters(in: CharacterSet.whitespaces)
let deviceLinkingModal = DeviceLinkingModal(mode: .slave, delegate: self) let deviceLinkingModal = DeviceLinkingModal(mode: .slave, delegate: self)
deviceLinkingModal.modalPresentationStyle = .overFullScreen deviceLinkingModal.modalPresentationStyle = .overFullScreen
present(deviceLinkingModal, animated: true, completion: nil) present(deviceLinkingModal, animated: true, completion: nil)
let masterHexEncodedPublicKey = masterHexEncodedPublicKeyTextField.text!.trimmingCharacters(in: CharacterSet.whitespaces)
let thread = TSContactThread.getOrCreateThread(contactId: masterHexEncodedPublicKey) let thread = TSContactThread.getOrCreateThread(contactId: masterHexEncodedPublicKey)
ThreadUtil.enqueueDeviceLinkingMessage(in: thread) ThreadUtil.enqueueDeviceLinkingMessage(in: thread)
} else { } else {
@ -348,7 +348,7 @@ final class SeedVC : OnboardingBaseViewController, DeviceLinkingModalDelegate {
} }
} }
func handleDeviceLinkingRequestAuthorized() { func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink) {
TSAccountManager.sharedInstance().didRegister() TSAccountManager.sharedInstance().didRegister()
UserDefaults.standard.set(true, forKey: "didUpdateForMainnet") UserDefaults.standard.set(true, forKey: "didUpdateForMainnet")
onboardingController.verificationDidComplete(fromView: self) onboardingController.verificationDidComplete(fromView: self)

View file

@ -71,7 +71,10 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
let _ = DeviceLinkingSession.startListeningForLinkingRequests(with: self) switch mode {
case .master: let _ = DeviceLinkingSession.startListeningForLinkingRequests(with: self)
case .slave: let _ = DeviceLinkingSession.startListeningForLinkingAuthorization(with: self)
}
} }
override func populateContentView() { override func populateContentView() {
@ -107,6 +110,10 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate {
contentView.pin(.bottom, to: .bottom, of: stackView, withInset: 16) contentView.pin(.bottom, to: .bottom, of: stackView, withInset: 16)
} }
deinit {
NotificationCenter.default.removeObserver(self)
}
// MARK: Device Linking // MARK: Device Linking
func requestUserAuthorization(for deviceLink: DeviceLink) { func requestUserAuthorization(for deviceLink: DeviceLink) {
self.deviceLink = deviceLink self.deviceLink = deviceLink
@ -126,4 +133,8 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate {
// TODO: Send device link authorized message // TODO: Send device link authorized message
dismiss(animated: true, completion: nil) dismiss(animated: true, completion: nil)
} }
func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink) {
delegate?.handleDeviceLinkAuthorized(deviceLink)
}
} }

View file

@ -1,7 +1,10 @@
@objc(LKDeviceLinkingModalDelegate) @objc protocol DeviceLinkingModalDelegate {
protocol DeviceLinkingModalDelegate {
/// Provides an opportunity for the slave device to update its UI after the master device has authorized the device linking request. func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink)
func handleDeviceLinkingRequestAuthorized() }
extension DeviceLinkingModalDelegate {
func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink) { /* Do nothing */ }
} }

View file

@ -5,6 +5,7 @@ import PromiseKit
public final class DeviceLinkingSession : NSObject { public final class DeviceLinkingSession : NSObject {
private let delegate: DeviceLinkingSessionDelegate private let delegate: DeviceLinkingSessionDelegate
@objc public var isListeningForLinkingRequests = false @objc public var isListeningForLinkingRequests = false
@objc public var isListeningForLinkingAuthorization = false
// MARK: Lifecycle // MARK: Lifecycle
@objc public static var current: DeviceLinkingSession? @objc public static var current: DeviceLinkingSession?
@ -21,28 +22,57 @@ public final class DeviceLinkingSession : NSObject {
return session return session
} }
@objc public func processLinkingRequest(from slaveHexEncodedPublicKey: String, with slaveSignature: Data) { public static func startListeningForLinkingAuthorization(with delegate: DeviceLinkingSessionDelegate) -> DeviceLinkingSession {
guard isListeningForLinkingRequests else { return } let session = DeviceLinkingSession(delegate: delegate)
stopListeningForLinkingRequests() session.isListeningForLinkingAuthorization = true
let master = DeviceLink.Device(hexEncodedPublicKey: OWSIdentityManager.shared().identityKeyPair()!.hexEncodedPublicKey) DeviceLinkingSession.current = session
return session
}
@objc public func processLinkingRequest(from slaveHexEncodedPublicKey: String, to masterHexEncodedPublicKey: String, with slaveSignature: Data) {
guard isListeningForLinkingRequests, masterHexEncodedPublicKey == OWSIdentityManager.shared().identityKeyPair()!.hexEncodedPublicKey else { return }
let master = DeviceLink.Device(hexEncodedPublicKey: masterHexEncodedPublicKey)
let slave = DeviceLink.Device(hexEncodedPublicKey: slaveHexEncodedPublicKey, signature: slaveSignature) let slave = DeviceLink.Device(hexEncodedPublicKey: slaveHexEncodedPublicKey, signature: slaveSignature)
let deviceLink = DeviceLink(between: master, and: slave) let deviceLink = DeviceLink(between: master, and: slave)
guard isValidLinkingRequest(deviceLink) else { return } guard hasValidSlaveSignature(deviceLink) else { return }
delegate.requestUserAuthorization(for: deviceLink) delegate.requestUserAuthorization(for: deviceLink)
} }
@objc public func processLinkingAuthorization(from masterHexEncodedPublicKey: String, for slaveHexEncodedPublicKey: String, masterSignature: Data, slaveSignature: Data) {
guard isListeningForLinkingAuthorization, slaveHexEncodedPublicKey == OWSIdentityManager.shared().identityKeyPair()!.hexEncodedPublicKey else { return }
let master = DeviceLink.Device(hexEncodedPublicKey: masterHexEncodedPublicKey, signature: masterSignature)
let slave = DeviceLink.Device(hexEncodedPublicKey: slaveHexEncodedPublicKey, signature: slaveSignature)
let deviceLink = DeviceLink(between: master, and: slave)
guard hasValidSlaveSignature(deviceLink) && hasValidMasterSignature(deviceLink) else { return }
delegate.handleDeviceLinkAuthorized(deviceLink)
}
public func stopListeningForLinkingRequests() { public func stopListeningForLinkingRequests() {
DeviceLinkingSession.current = nil DeviceLinkingSession.current = nil
isListeningForLinkingRequests = false isListeningForLinkingRequests = false
} }
public func stopListeningForLinkingAuthorization() {
DeviceLinkingSession.current = nil
isListeningForLinkingAuthorization = false
}
// MARK: Private API // MARK: Private API
private func isValidLinkingRequest(_ deviceLink: DeviceLink) -> Bool {
// When requesting a device link, the slave device signs the master device's public key. When authorizing // When requesting a device link, the slave device signs the master device's public key. When authorizing
// a device link, the master device signs the slave device's public key. // a device link, the master device signs the slave device's public key.
let slaveSignature = deviceLink.slave.signature!
private func hasValidSlaveSignature(_ deviceLink: DeviceLink) -> Bool {
guard let slaveSignature = deviceLink.slave.signature else { return false }
let slavePublicKey = Data(hex: deviceLink.slave.hexEncodedPublicKey) let slavePublicKey = Data(hex: deviceLink.slave.hexEncodedPublicKey)
let masterPublicKey = Data(hex: deviceLink.master.hexEncodedPublicKey) let masterPublicKey = Data(hex: deviceLink.master.hexEncodedPublicKey)
return (try? Ed25519.verifySignature(slaveSignature, publicKey: slavePublicKey, data: masterPublicKey)) ?? false return (try? Ed25519.verifySignature(slaveSignature, publicKey: slavePublicKey, data: masterPublicKey)) ?? false
} }
private func hasValidMasterSignature(_ deviceLink: DeviceLink) -> Bool {
guard let masterSignature = deviceLink.master.signature else { return false }
let slavePublicKey = Data(hex: deviceLink.slave.hexEncodedPublicKey)
let masterPublicKey = Data(hex: deviceLink.master.hexEncodedPublicKey)
return (try? Ed25519.verifySignature(masterSignature, publicKey: masterPublicKey, data: slavePublicKey)) ?? false
}
} }

View file

@ -1,6 +1,6 @@
@objc(LKDeviceLinkingSessionDelegate)
public protocol DeviceLinkingSessionDelegate { public protocol DeviceLinkingSessionDelegate {
@objc func requestUserAuthorization(for deviceLink: DeviceLink) func requestUserAuthorization(for deviceLink: DeviceLink)
func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink)
} }

View file

@ -0,0 +1,4 @@
public extension Notification.Name {
public static let linkingRequestAuthorized = Notification.Name("linkingRequestAuthorized")
}

View file

@ -431,11 +431,12 @@ NS_ASSUME_NONNULL_BEGIN
// Loki: Handle device linking message // Loki: Handle device linking message
if (contentProto.lokiDeviceLinkingMessage != nil && contentProto.lokiDeviceLinkingMessage.type == SSKProtoLokiDeviceLinkingMessageTypeRequest) { if (contentProto.lokiDeviceLinkingMessage != nil && contentProto.lokiDeviceLinkingMessage.type == SSKProtoLokiDeviceLinkingMessageTypeRequest) {
OWSLogInfo(@"[Loki] Received a device linking request from: %@", envelope.source); OWSLogInfo(@"[Loki] Received a device linking request from: %@", envelope.source);
NSData *signature = contentProto.lokiDeviceLinkingMessage.slaveSignature; NSData *slaveSignature = contentProto.lokiDeviceLinkingMessage.slaveSignature;
if (signature == nil) { if (slaveSignature == nil) {
OWSFailDebug(@"Received a device linking request without an attached slave signature."); OWSFailDebug(@"Received a device linking request without an attached slave signature.");
} }
[LKDeviceLinkingSession.current processLinkingRequestFrom:envelope.source with:signature]; NSString *masterHexEncodedPublicKey = contentProto.lokiDeviceLinkingMessage.masterHexEncodedPublicKey;
[LKDeviceLinkingSession.current processLinkingRequestFrom:envelope.source to:masterHexEncodedPublicKey with:slaveSignature];
} }
// Loki: Handle pre key bundle message // Loki: Handle pre key bundle message