[MM-14836] Prevent sharing of images over max pixels (#2733)

* Prevent sharing of images over max image size

* Prevent sharing of images over max image pixels

* Move readableMaxImagePixels
This commit is contained in:
Miguel Alatzar 2019-04-23 11:45:54 -07:00 committed by GitHub
parent e3b4191af9
commit 39587aa3ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 90 additions and 17 deletions

View file

@ -44,10 +44,16 @@ class ShareViewController: SLComposeServiceViewController {
override func isContentValid() -> Bool {
// Do validation of contentText and/or NSExtensionContext attachments here
if (attachments.count > 0) {
let maxImagePixels = store.getMaxImagePixels()
if attachments.hasImageLargerThan(pixels: maxImagePixels) {
let readableMaxImagePixels = formatImagePixels(pixels: maxImagePixels)
showErrorMessage(title: "", message: "Image attachments shared in Mattermost must be less than \(readableMaxImagePixels).", VC: self)
}
let maxFileSize = store.getMaxFileSize()
if attachments.hasAttachementLargerThan(fileSize: maxFileSize) {
let readableMaxSize = formatFileSize(bytes: Double(maxFileSize))
showErrorMessage(title: "", message: "File attachments shared in Mattermost must be less than \(readableMaxSize).", VC: self)
let readableMaxFileSize = formatFileSize(fileSize: maxFileSize)
showErrorMessage(title: "", message: "File attachments shared in Mattermost must be less than \(readableMaxFileSize).", VC: self)
}
}
@ -169,6 +175,26 @@ class ShareViewController: SLComposeServiceViewController {
}
return section
}
func getImagePixels(imageUrl: URL) -> UInt64 {
guard let imageData = try? Data(contentsOf: imageUrl) else {
return 0
}
guard let image = UIImage.init(data: imageData) else {
return 0
}
return getImagePixels(image: image)
}
func getImagePixels(image: UIImage) -> UInt64 {
guard let cgImage = image.cgImage else {
return 0
}
return UInt64(cgImage.width * cgImage.height)
}
func extractDataFromContext() {
for item in extensionContext?.inputItems as! [NSExtensionItem] {
@ -196,6 +222,7 @@ class ShareViewController: SLComposeServiceViewController {
let attachment = self.saveAttachment(url: url)
if (attachment != nil) {
attachment?.type = kUTTypeImage as String
attachment?.imagePixels = self.getImagePixels(imageUrl: url)
self.attachments.append(attachment!)
}
} else if let image = item as? UIImage {
@ -207,6 +234,7 @@ class ShareViewController: SLComposeServiceViewController {
let attachment = self.saveAttachment(url: tempImageURL!)
if (attachment != nil) {
attachment?.type = kUTTypeImage as String
attachment?.imagePixels = self.getImagePixels(image: image)
self.attachments.append(attachment!)
}
}
@ -370,6 +398,7 @@ class ShareViewController: SLComposeServiceViewController {
attachment.fileName = fileName
attachment.fileURL = tempFileURL
attachment.fileSize = attr.fileSize()
return attachment
} catch {
return nil
@ -388,22 +417,32 @@ class ShareViewController: SLComposeServiceViewController {
VC.present(alert, animated: true, completion: nil)
}
func formatFileSize(bytes: Double) -> String {
guard bytes > 0 else {
return "0 bytes"
func formatImagePixels(pixels: UInt64) -> String {
let suffixes = ["pixels", "KP", "MP", "GP", "TP", "PP", "EP", "ZP", "YP"]
let k: Double = 1000
return formatSize(size: Double(pixels), k: k, suffixes: suffixes)
}
func formatFileSize(fileSize: UInt64) -> String {
let suffixes = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
let k: Double = 1024
return formatSize(size: Double(fileSize), k: k, suffixes: suffixes)
}
func formatSize(size: Double, k: Double, suffixes: Array<String>) -> String {
guard size > 0 else {
return "0 \(suffixes[0])"
}
// Adapted from http://stackoverflow.com/a/18650828
let suffixes = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
let k: Double = 1024
let i = floor(log(bytes) / log(k))
let i = floor(log(size) / log(k))
// Format number with thousands separator and everything below 1 GB with no decimal places.
// Format number with thousands separator and everything below 1 giga with no decimal places.
let numberFormatter = NumberFormatter()
numberFormatter.maximumFractionDigits = i < 3 ? 0 : 1
numberFormatter.numberStyle = .decimal
let numberString = numberFormatter.string(from: NSNumber(value: bytes / pow(k, i))) ?? "Unknown"
let numberString = numberFormatter.string(from: NSNumber(value: size / pow(k, i))) ?? "Unknown"
let suffix = suffixes[Int(i)]
return "\(numberString) \(suffix)"
}

View file

@ -1,3 +1,5 @@
import MobileCoreServices
/// A thread-safe array.
public class AttachmentArray<Element>: NSObject {
fileprivate let queue = DispatchQueue(label: "com.mattermost.SynchronizedArray", attributes: .concurrent)
@ -266,4 +268,17 @@ extension AttachmentArray {
return exceed
}
public func hasImageLargerThan(pixels: UInt64) -> Bool {
var exceed = false
self.queue.sync {
exceed = self.array.contains { element in
let attachment = element as! AttachmentItem
return attachment.imagePixels > pixels
}
}
return exceed
}
}

View file

@ -5,6 +5,7 @@ public class AttachmentItem: NSObject {
public var fileURL: URL?
public var fileSize: UInt64 = 0
public var type: String?
public var imagePixels: UInt64 = 0
public override init() {}
}

View file

@ -3,5 +3,6 @@
@interface Constants : NSObject
extern NSString *APP_GROUP_ID;
extern UInt64 DEFAULT_SERVER_MAX_IMAGE_PIXELS;
extern UInt64 DEFAULT_SERVER_MAX_FILE_SIZE;
@end

View file

@ -2,5 +2,6 @@
@implementation Constants
NSString *APP_GROUP_ID = @"group.com.mattermost.rnbeta";
UInt64 DEFAULT_SERVER_MAX_IMAGE_PIXELS = 6048 * 4032;
UInt64 DEFAULT_SERVER_MAX_FILE_SIZE = 50 * 1024 * 1024;
@end

View file

@ -14,6 +14,7 @@
-(NSString *)getCurrentUserId;
-(NSDictionary *)getDefaultChannel:(NSString *)forTeamId;
-(NSDictionary *)getEntities:(BOOL)loadFromFile;
-(UInt64)getMaxImagePixels;
-(UInt64)getMaxFileSize;
-(NSArray *)getMyTeams;
-(NSString *)getServerUrl;

View file

@ -150,16 +150,31 @@
return [credentials objectForKey:@"token"];
}
-(UInt64)scanValueFromConfig:(NSDictionary *)config key:(NSString *)key {
NSString *value = [config objectForKey:key];
NSScanner *scanner = [NSScanner scannerWithString:value];
unsigned long long convertedValue = 0;
[scanner scanUnsignedLongLong:&convertedValue];
return convertedValue;
}
-(UInt64)getMaxImagePixels {
NSDictionary *config = [self getConfig];
NSString *key = @"MaxImagePixels";
if (config != nil && [config objectForKey:key]) {
return [self scanValueFromConfig:config key:key];
}
return DEFAULT_SERVER_MAX_IMAGE_PIXELS;
}
-(UInt64)getMaxFileSize {
NSDictionary *config = [self getConfig];
if (config != nil && [config objectForKey:@"MaxFileSize"]) {
NSString *maxFileSize = [config objectForKey:@"MaxFileSize"];
NSScanner *scanner = [NSScanner scannerWithString:maxFileSize];
unsigned long long convertedValue = 0;
[scanner scanUnsignedLongLong:&convertedValue];
return convertedValue;
NSString *key = @"MaxFileSize";
if (config != nil && [config objectForKey:key]) {
return [self scanValueFromConfig:config key:key];
}
return DEFAULT_SERVER_MAX_FILE_SIZE;
}