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