Respond to Cr.

This commit is contained in:
Matthew Chen 2019-01-15 10:36:21 -05:00
parent 55376975f5
commit f13c1de738
5 changed files with 128 additions and 22 deletions

View File

@ -45,8 +45,15 @@ NS_ASSUME_NONNULL_BEGIN
_quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:_dataMessage thread:_thread transaction:transaction];
_contact = [OWSContacts contactForDataMessage:_dataMessage transaction:transaction];
_linkPreview =
[OWSLinkPreview buildValidatedLinkPreviewWithDataMessage:_dataMessage body:_body transaction:transaction];
NSError *linkPreviewError;
_linkPreview = [OWSLinkPreview buildValidatedLinkPreviewWithDataMessage:_dataMessage
body:_body
transaction:transaction
error:&linkPreviewError];
if (linkPreviewError && ![OWSLinkPreview isNoPreviewError:linkPreviewError]) {
OWSLogError(@"linkPreviewError: %@", linkPreviewError);
}
if (sentProto.unidentifiedStatus.count > 0) {
NSMutableArray<NSString *> *nonUdRecipientIds = [NSMutableArray new];

View File

@ -4,6 +4,13 @@
import Foundation
@objc
public enum LinkPreviewError: Int, Error {
case invalidInput
case assertionFailure
case noPreview
}
@objc(OWSLinkPreview)
public class OWSLinkPreview: MTLModel {
@objc
@ -13,13 +20,13 @@ public class OWSLinkPreview: MTLModel {
public var title: String?
@objc
public var attachmentId: String?
public var imageAttachmentId: String?
@objc
public init(urlString: String, title: String?, attachmentId: String?) {
public init(urlString: String, title: String?, imageAttachmentId: String?) {
self.urlString = urlString
self.title = title
self.attachmentId = attachmentId
self.imageAttachmentId = imageAttachmentId
super.init()
}
@ -34,28 +41,36 @@ public class OWSLinkPreview: MTLModel {
try super.init(dictionary: dictionaryValue)
}
@objc
public class func isNoPreviewError(_ error: Error) -> Bool {
guard let error = error as? LinkPreviewError else {
return false
}
return error == .noPreview
}
@objc
public class func buildValidatedLinkPreview(dataMessage: SSKProtoDataMessage,
body: String?,
transaction: YapDatabaseReadWriteTransaction) -> OWSLinkPreview? {
transaction: YapDatabaseReadWriteTransaction) throws -> OWSLinkPreview {
guard let previewProto = dataMessage.preview else {
return nil
throw LinkPreviewError.noPreview
}
let urlString = previewProto.url
guard URL(string: urlString) != nil else {
owsFailDebug("Could not parse preview URL.")
return nil
Logger.error("Could not parse preview URL.")
throw LinkPreviewError.invalidInput
}
guard let body = body else {
owsFailDebug("Preview for message without body.")
return nil
Logger.error("Preview for message without body.")
throw LinkPreviewError.invalidInput
}
let bodyComponents = body.components(separatedBy: .whitespacesAndNewlines)
guard bodyComponents.contains(urlString) else {
owsFailDebug("URL not present in body.")
return nil
Logger.error("URL not present in body.")
throw LinkPreviewError.invalidInput
}
// TODO: Verify that url host is in whitelist.
@ -68,7 +83,8 @@ public class OWSLinkPreview: MTLModel {
imageAttachmentPointer.save(with: transaction)
imageAttachmentId = imageAttachmentPointer.uniqueId
} else {
owsFailDebug("Could not parse image proto.")
Logger.error("Could not parse image proto.")
throw LinkPreviewError.invalidInput
}
}
@ -78,20 +94,20 @@ public class OWSLinkPreview: MTLModel {
}
let hasImage = imageAttachmentId != nil
if !hasTitle && !hasImage {
owsFailDebug("Preview has neither title nor image.")
return nil
Logger.error("Preview has neither title nor image.")
throw LinkPreviewError.invalidInput
}
return OWSLinkPreview(urlString: urlString, title: title, attachmentId: imageAttachmentId)
return OWSLinkPreview(urlString: urlString, title: title, imageAttachmentId: imageAttachmentId)
}
@objc
public func removeAttachment(transaction: YapDatabaseReadWriteTransaction) {
guard let attachmentId = attachmentId else {
guard let imageAttachmentId = imageAttachmentId else {
owsFailDebug("No attachment id.")
return
}
guard let attachment = TSAttachment.fetch(uniqueId: attachmentId, transaction: transaction) else {
guard let attachment = TSAttachment.fetch(uniqueId: imageAttachmentId, transaction: transaction) else {
owsFailDebug("Could not load attachment.")
return
}

View File

@ -351,7 +351,7 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
[self.contactShare removeAvatarAttachmentWithTransaction:transaction];
}
if (self.linkPreview.attachmentId) {
if (self.linkPreview.imageAttachmentId) {
[self.linkPreview removeAttachmentWithTransaction:transaction];
}

View File

@ -1287,10 +1287,15 @@ NS_ASSUME_NONNULL_BEGIN
thread:oldGroupThread
transaction:transaction];
NSError *linkPreviewError;
OWSLinkPreview *_Nullable linkPreview =
[OWSLinkPreview buildValidatedLinkPreviewWithDataMessage:dataMessage
body:body
transaction:transaction];
transaction:transaction
error:&linkPreviewError];
if (linkPreviewError && ![OWSLinkPreview isNoPreviewError:linkPreviewError]) {
OWSLogError(@"linkPreviewError: %@", linkPreviewError);
}
OWSLogDebug(@"incoming message from: %@ for group: %@ with timestamp: %lu",
envelopeAddress(envelope),
@ -1355,8 +1360,15 @@ NS_ASSUME_NONNULL_BEGIN
thread:thread
transaction:transaction];
NSError *linkPreviewError;
OWSLinkPreview *_Nullable linkPreview =
[OWSLinkPreview buildValidatedLinkPreviewWithDataMessage:dataMessage body:body transaction:transaction];
[OWSLinkPreview buildValidatedLinkPreviewWithDataMessage:dataMessage
body:body
transaction:transaction
error:&linkPreviewError];
if (linkPreviewError && ![OWSLinkPreview isNoPreviewError:linkPreviewError]) {
OWSLogError(@"linkPreviewError: %@", linkPreviewError);
}
// Legit usage of senderTimestamp when creating incoming message from received envelope
TSIncomingMessage *incomingMessage =

View File

@ -18,6 +18,77 @@ class OWSLinkPreviewTest: SSKBaseTestSwift {
super.tearDown()
}
func testBuildValidatedLinkPreview_TitleAndImage() {
let url = "https://www.youtube.com/watch?v=tP-Ipsat90c"
let body = "\(url)"
let previewBuilder = SSKProtoDataMessagePreview.builder(url: url)
previewBuilder.setTitle("Some Youtube Video")
let imageAttachmentBuilder = SSKProtoAttachmentPointer.builder(id: 1)
imageAttachmentBuilder.setKey(Randomness.generateRandomBytes(32))
imageAttachmentBuilder.setContentType(OWSMimeTypeImageJpeg)
previewBuilder.setImage(try! imageAttachmentBuilder.build())
let dataBuilder = SSKProtoDataMessage.builder()
dataBuilder.setPreview(try! previewBuilder.build())
self.readWrite { (transaction) in
XCTAssertNotNil(try! OWSLinkPreview.buildValidatedLinkPreview(dataMessage: try! dataBuilder.build(),
body: body,
transaction: transaction))
}
}
func testBuildValidatedLinkPreview_Title() {
let url = "https://www.youtube.com/watch?v=tP-Ipsat90c"
let body = "\(url)"
let previewBuilder = SSKProtoDataMessagePreview.builder(url: url)
previewBuilder.setTitle("Some Youtube Video")
let dataBuilder = SSKProtoDataMessage.builder()
dataBuilder.setPreview(try! previewBuilder.build())
self.readWrite { (transaction) in
XCTAssertNotNil(try! OWSLinkPreview.buildValidatedLinkPreview(dataMessage: try! dataBuilder.build(),
body: body,
transaction: transaction))
}
}
func testBuildValidatedLinkPreview_Image() {
let url = "https://www.youtube.com/watch?v=tP-Ipsat90c"
let body = "\(url)"
let previewBuilder = SSKProtoDataMessagePreview.builder(url: url)
let imageAttachmentBuilder = SSKProtoAttachmentPointer.builder(id: 1)
imageAttachmentBuilder.setKey(Randomness.generateRandomBytes(32))
imageAttachmentBuilder.setContentType(OWSMimeTypeImageJpeg)
previewBuilder.setImage(try! imageAttachmentBuilder.build())
let dataBuilder = SSKProtoDataMessage.builder()
dataBuilder.setPreview(try! previewBuilder.build())
self.readWrite { (transaction) in
XCTAssertNotNil(try! OWSLinkPreview.buildValidatedLinkPreview(dataMessage: try! dataBuilder.build(),
body: body,
transaction: transaction))
}
}
func testBuildValidatedLinkPreview_NoTitleOrImage() {
let url = "https://www.youtube.com/watch?v=tP-Ipsat90c"
let body = "\(url)"
let previewBuilder = SSKProtoDataMessagePreview.builder(url: url)
let dataBuilder = SSKProtoDataMessage.builder()
dataBuilder.setPreview(try! previewBuilder.build())
self.readWrite { (transaction) in
do {
_ = try OWSLinkPreview.buildValidatedLinkPreview(dataMessage: try! dataBuilder.build(),
body: body,
transaction: transaction)
XCTFail("Missing expected error.")
} catch {
// Do nothing.
}
}
}
func testIsValidLinkUrl() {
XCTAssertTrue(OWSLinkPreview.isValidLinkUrl("https://www.youtube.com/watch?v=tP-Ipsat90c"))
XCTAssertTrue(OWSLinkPreview.isValidLinkUrl("https://youtube.com/watch?v=tP-Ipsat90c"))