From d24c08422330d596cdc49c58833a32c6f8f3540d Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Wed, 17 Apr 2024 19:47:46 +0200 Subject: [PATCH 1/3] Check filesize before uploading file to server and display alert if file is too big. Signed-off-by: Nicolas Buquet --- Riot/Modules/Room/RoomViewController.m | 9 +++++++++ changelog.d/pr-7778.change | 1 + 2 files changed, 10 insertions(+) create mode 100644 changelog.d/pr-7778.change diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 37cc5a7660..ffc4b5184e 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -7721,6 +7721,15 @@ - (void)documentPickerPresenter:(MXKDocumentPickerPresenter *)presenter didPickD { self.documentPickerPresenter = nil; + // Check maxUploadSize accepted by the home server before trying to upload. + NSUInteger maxUploadFileSize = self.roomDataSource.mxSession.maxUploadSize; + NSDictionary *fileAttributes = [NSFileManager.defaultManager attributesOfItemAtPath:url.path error:nil]; + if (fileAttributes && fileAttributes.fileSize > maxUploadFileSize) { + [self showAlertWithTitle:@"The file you want to upload is too big." + message:[NSString stringWithFormat:@"\nThe file you want to upload is too big.\n\nIt mustn't weight more than %ldMB", maxUploadFileSize/(1024*1024)]]; + return; + } + MXKUTI *fileUTI = [[MXKUTI alloc] initWithLocalFileURL:url]; NSString *mimeType = fileUTI.mimeType; diff --git a/changelog.d/pr-7778.change b/changelog.d/pr-7778.change new file mode 100644 index 0000000000..84c0e87b4f --- /dev/null +++ b/changelog.d/pr-7778.change @@ -0,0 +1 @@ +Check filesize before uploading file to server and display alert if file is too big. \ No newline at end of file From f16203a2ea710f444b3343b99668addbfe7b98c6 Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Wed, 15 May 2024 17:03:01 +0200 Subject: [PATCH 2/3] Move hard-coded strings to strings files (only EN and FR) --- Riot/Assets/en.lproj/Vector.strings | 2 ++ Riot/Assets/fr.lproj/Vector.strings | 3 +++ Riot/Modules/Room/RoomViewController.m | 4 ++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 6a7f09c6e9..68f6a055a7 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1715,6 +1715,8 @@ Tap the + to start adding people."; // MARK: File upload "file_upload_error_title" = "File upload"; "file_upload_error_unsupported_file_type_message" = "File type not supported."; +"file_upload_error_too_large_title" = "File too large"; +"file_upload_error_too_large_message" = "Maximum supported file size is %@MB"; // MARK: Emoji picker "emoji_picker_title" = "Reactions"; diff --git a/Riot/Assets/fr.lproj/Vector.strings b/Riot/Assets/fr.lproj/Vector.strings index ee14358945..2c247b4769 100644 --- a/Riot/Assets/fr.lproj/Vector.strings +++ b/Riot/Assets/fr.lproj/Vector.strings @@ -778,6 +778,9 @@ // MARK: File upload "file_upload_error_title" = "Envoi de fichier"; "file_upload_error_unsupported_file_type_message" = "Type de fichier non pris en charge."; +"file_upload_error_too_large_title" = "Fichier trop lourd"; +"file_upload_error_too_large_message" = "La taille maximum autorisée est %@Mo"; + "auth_softlogout_signed_out" = "Vous êtes déconnecté"; "auth_softlogout_sign_in" = "Se connecter"; "auth_softlogout_reason" = "L’administrateur de votre serveur d’accueil (%1$@) vous a déconnecté de votre compte %2$@ (%3$@)."; diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index ffc4b5184e..c94b41bedb 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -7725,8 +7725,8 @@ - (void)documentPickerPresenter:(MXKDocumentPickerPresenter *)presenter didPickD NSUInteger maxUploadFileSize = self.roomDataSource.mxSession.maxUploadSize; NSDictionary *fileAttributes = [NSFileManager.defaultManager attributesOfItemAtPath:url.path error:nil]; if (fileAttributes && fileAttributes.fileSize > maxUploadFileSize) { - [self showAlertWithTitle:@"The file you want to upload is too big." - message:[NSString stringWithFormat:@"\nThe file you want to upload is too big.\n\nIt mustn't weight more than %ldMB", maxUploadFileSize/(1024*1024)]]; + [self showAlertWithTitle:[VectorL10n fileUploadErrorTooLargeTitle] + message:[VectorL10n fileUploadErrorTooLargeMessage:[NSByteCountFormatter stringFromByteCount:maxUploadFileSize countStyle:NSByteCountFormatterCountStyleFile]]]; return; } From 90f1122f7525788cdbf6c9393f11ae0e05baed6d Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Mon, 3 Jun 2024 18:48:25 +0200 Subject: [PATCH 3/3] Check filesize limit before sending Image, Video or File --- .../MatrixKit/Models/Room/MXKRoomDataSource.h | 7 ++ .../MatrixKit/Models/Room/MXKRoomDataSource.m | 93 ++++++++++++++++++- Riot/Modules/Room/RoomViewController.m | 28 ++++-- 3 files changed, 113 insertions(+), 15 deletions(-) diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h index 87aabe50b3..1e7cd2cd0a 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h @@ -51,6 +51,13 @@ typedef enum : NSUInteger } MXKRoomDataSourceBubblesPagination; +// Check filesize before sending: make RoomDataSource errors public +typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { + MXKRoomDataSourceErrorResendGeneric = 10001, + MXKRoomDataSourceErrorResendInvalidMessageType = 10002, + MXKRoomDataSourceErrorResendInvalidLocalFilePath = 10003, + MXKRoomDataSourceErrorCantSendFileToBig = 10004, // Check filesize before sending: file to big error +}; #pragma mark - Cells identifiers diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m index 033aa93618..8399b4c2af 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m @@ -46,11 +46,12 @@ NSString * const MXKRoomDataSourceErrorDomain = @"kMXKRoomDataSourceErrorDomain"; -typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { - MXKRoomDataSourceErrorResendGeneric = 10001, - MXKRoomDataSourceErrorResendInvalidMessageType = 10002, - MXKRoomDataSourceErrorResendInvalidLocalFilePath = 10003, -}; +// Check filesize before sending: make RoomDataSource errors public +//typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { +// MXKRoomDataSourceErrorResendGeneric = 10001, +// MXKRoomDataSourceErrorResendInvalidMessageType = 10002, +// MXKRoomDataSourceErrorResendInvalidLocalFilePath = 10003, +//}; @interface MXKRoomDataSource () @@ -1923,6 +1924,67 @@ - (BOOL)canReplyToEventWithId:(NSString*)eventIdToReply return [self.room canReplyToEvent:eventToReply]; } +// Check filesize before sending: check file size before sending +- (BOOL)_isFilesizeOkToBeSent:(NSUInteger)filesize +{ + // Check maxUploadSize accepted by the home server before trying to upload. + NSUInteger maxUploadFileSize = self.mxSession.maxUploadSize; + if (filesize > maxUploadFileSize) + { + return NO; + } + else + { + return YES; + } +} + +- (BOOL)isFilesizeOkToBeSentForData:(NSData *)fileData +{ + return [self _isFilesizeOkToBeSent:fileData.length]; +} + +- (BOOL)isFilesizeOkToBeSentForLocalFileUrl:(NSURL *)localFileUrl +{ + NSDictionary *fileAttributes = [NSFileManager.defaultManager attributesOfItemAtPath:localFileUrl.path error:nil]; + if (fileAttributes) + { + return [self _isFilesizeOkToBeSent:fileAttributes.fileSize]; + } + else + { + return NO; + } +} + +- (BOOL)isFilesizeOkToBeSentForLocalAVAsset:(AVAsset *)asset +{ + // Check if asset points to a local file + if( ![asset isKindOfClass:AVURLAsset.class] ) + { + // If asset doesn't point to a local asset, we can't check size. + // Return YES to let the upload happens and get the result of the backend. + return YES; + } + + AVURLAsset *urlAsset = (AVURLAsset *)asset; + NSNumber *assetFilesize; + NSError *error; + + // Try to get asset filesize. + [urlAsset.URL getResourceValue:&assetFilesize forKey:NSURLFileSizeKey error:&error]; + + // If we can't check size, + if( error != NULL || assetFilesize == NULL ) + { + // return YES to let the upload happens and get the result of the backend. + return YES; + } + + return [self _isFilesizeOkToBeSent:assetFilesize.unsignedLongValue]; +} + + - (void)sendImage:(NSData *)imageData mimeType:(NSString *)mimetype success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure { UIImage *image = [UIImage imageWithData:imageData]; @@ -1944,6 +2006,13 @@ - (void)sendImage:(NSData *)imageData mimeType:(NSString *)mimetype success:(voi - (void)sendImageData:(NSData*)imageData withImageSize:(CGSize)imageSize mimeType:(NSString*)mimetype andThumbnail:(UIImage*)thumbnail success:(void (^)(NSString *eventId))success failure:(void (^)(NSError *error))failure { + // Check filesize before sending: check fielsize before trying to send file + if( ![self isFilesizeOkToBeSentForData:imageData] ) + { + failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorCantSendFileToBig userInfo:nil]); + return; + } + __block MXEvent *localEchoEvent = nil; [_room sendImage:imageData withImageSize:imageSize mimeType:mimetype andThumbnail:thumbnail threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure]; @@ -1964,6 +2033,13 @@ - (void)sendVideo:(NSURL *)videoLocalURL withThumbnail:(UIImage *)videoThumbnail - (void)sendVideoAsset:(AVAsset *)videoAsset withThumbnail:(UIImage *)videoThumbnail success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure { + // Check filesize before sending: check fielsize before trying to send file + if( ![self isFilesizeOkToBeSentForLocalAVAsset:videoAsset] ) + { + failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorCantSendFileToBig userInfo:nil]); + return; + } + __block MXEvent *localEchoEvent = nil; [_room sendVideoAsset:videoAsset withThumbnail:videoThumbnail threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure]; @@ -2013,6 +2089,13 @@ - (void)sendVoiceMessage:(NSURL *)audioFileLocalURL - (void)sendFile:(NSURL *)fileLocalURL mimeType:(NSString*)mimeType success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure { + // Check filesize before sending: check fielsize before trying to send file + if( ![self isFilesizeOkToBeSentForLocalFileUrl:fileLocalURL] ) + { + failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorCantSendFileToBig userInfo:nil]); + return; + } + __block MXEvent *localEchoEvent = nil; [_room sendFile:fileLocalURL mimeType:mimeType threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure]; diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index c94b41bedb..e429bb0a68 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -7721,15 +7721,6 @@ - (void)documentPickerPresenter:(MXKDocumentPickerPresenter *)presenter didPickD { self.documentPickerPresenter = nil; - // Check maxUploadSize accepted by the home server before trying to upload. - NSUInteger maxUploadFileSize = self.roomDataSource.mxSession.maxUploadSize; - NSDictionary *fileAttributes = [NSFileManager.defaultManager attributesOfItemAtPath:url.path error:nil]; - if (fileAttributes && fileAttributes.fileSize > maxUploadFileSize) { - [self showAlertWithTitle:[VectorL10n fileUploadErrorTooLargeTitle] - message:[VectorL10n fileUploadErrorTooLargeMessage:[NSByteCountFormatter stringFromByteCount:maxUploadFileSize countStyle:NSByteCountFormatterCountStyleFile]]]; - return; - } - MXKUTI *fileUTI = [[MXKUTI alloc] initWithLocalFileURL:url]; NSString *mimeType = fileUTI.mimeType; @@ -7756,6 +7747,17 @@ - (void)documentPickerPresenter:(MXKDocumentPickerPresenter *)presenter didPickD } } +// Check filesize before sending: if send file error is "File too big", display alert box to user +- (void)displayAlertIfErrorIsFileIsTooBig:(NSError *)error +{ + if( error.code == MXKRoomDataSourceErrorCantSendFileToBig ) + { + NSUInteger maxUploadFileSize = self.roomDataSource.mxSession.maxUploadSize; + [self showAlertWithTitle:[VectorL10n fileUploadErrorTooLargeTitle] + message:[VectorL10n fileUploadErrorTooLargeMessage:[NSByteCountFormatter stringFromByteCount:maxUploadFileSize countStyle:NSByteCountFormatterCountStyleFile]]]; + } +} + - (void)sendImage:(NSData *)imageData mimeType:(NSString *)mimeType { // Create before sending the message in case of a discussion (direct chat) MXWeakify(self); @@ -7767,7 +7769,9 @@ - (void)sendImage:(NSData *)imageData mimeType:(NSString *)mimeType { [self.roomDataSource sendImage:imageData mimeType:mimeType success:nil failure:^(NSError *error) { // Nothing to do. The image is marked as unsent in the room history by the datasource MXLogDebug(@"[MXKRoomViewController] sendImage failed."); - }]; + // Check filesize before sending: if error is "FileTooBig", display alert box. + [self displayAlertIfErrorIsFileIsTooBig:error]; + }]; } // Errors are handled at the request level. This should be improved in case of code rewriting. }]; @@ -7784,6 +7788,8 @@ - (void)sendVideo:(NSURL * _Nonnull)url { [(RoomDataSource*)self.roomDataSource sendVideo:url success:nil failure:^(NSError *error) { // Nothing to do. The video is marked as unsent in the room history by the datasource MXLogDebug(@"[MXKRoomViewController] sendVideo failed."); + // Check filesize before sending: if error is "FileTooBig", display alert box. + [self displayAlertIfErrorIsFileIsTooBig:error]; }]; } // Errors are handled at the request level. This should be improved in case of code rewriting. @@ -7801,6 +7807,8 @@ - (void)sendFile:(NSURL * _Nonnull)url mimeType:(NSString *)mimeType { [self.roomDataSource sendFile:url mimeType:mimeType success:nil failure:^(NSError *error) { // Nothing to do. The file is marked as unsent in the room history by the datasource MXLogDebug(@"[MXKRoomViewController] sendFile failed."); + // Check filesize before sending: if error is "FileTooBig", display alert box. + [self displayAlertIfErrorIsFileIsTooBig:error]; }]; } // Errors are handled at the request level. This should be improved in case of code rewriting.