From 969b4f991ece3962ed2c7f3753ebc010fecb4749 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 30 Oct 2022 13:36:08 -0400 Subject: [PATCH 1/3] Create Profile\Attachment\Upload module class - Add missing response type in AjaxUpload initializition --- src/Module/Profile/Attachment/Upload.php | 169 +++++++++++++++++++ static/routes.config.php | 19 ++- view/js/filebrowser.js | 3 +- view/theme/frio/js/filebrowser.js | 5 +- view/theme/smoothly/templates/jot-header.tpl | 2 +- 5 files changed, 185 insertions(+), 13 deletions(-) create mode 100644 src/Module/Profile/Attachment/Upload.php diff --git a/src/Module/Profile/Attachment/Upload.php b/src/Module/Profile/Attachment/Upload.php new file mode 100644 index 000000000..0624ea5a3 --- /dev/null +++ b/src/Module/Profile/Attachment/Upload.php @@ -0,0 +1,169 @@ +. + * + */ + +namespace Friendica\Module\Profile\Attachment; + +use Friendica\App; +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\L10n; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Database\Database; +use Friendica\Model\Attach; +use Friendica\Model\User; +use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; +use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Util\Profiler; +use Friendica\Util\Strings; +use Psr\Log\LoggerInterface; + +/** + * Asynchronous attachment upload module + * + * Only used as the target action of the AjaxUpload Javascript library + */ +class Upload extends \Friendica\BaseModule +{ + /** @var Database */ + private $database; + + /** @var IHandleUserSessions */ + private $userSession; + + /** @var IManageConfigValues */ + private $config; + + /** @var SystemMessages */ + private $systemMessages; + + /** @var bool */ + private $isJson; + + public function __construct(SystemMessages $systemMessages, IManageConfigValues $config, IHandleUserSessions $userSession, Database $database, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->database = $database; + $this->userSession = $userSession; + $this->config = $config; + $this->systemMessages = $systemMessages; + } + + protected function post(array $request = []) + { + if ($this->isJson = !empty($request['response']) && $request['response'] == 'json') { + $this->response->setType(Response::TYPE_JSON, 'application/json'); + } + + $nick = $this->parameters['nickname']; + $owner = User::getOwnerDataByNick($nick); + if (!$owner) { + $this->logger->warning('owner is not a valid record:', ['owner' => $owner, 'nick' => $nick]); + return $this->return(401, $this->t('Invalid request.')); + } + + $can_post = false; + $contact_id = 0; + $page_owner_uid = $owner['uid']; + $community_page = $owner['page-flags'] == User::PAGE_FLAGS_COMMUNITY; + + if ($this->userSession->getLocalUserId() && $this->userSession->getLocalUserId() == $page_owner_uid) { + $can_post = true; + } elseif ($community_page && !empty($this->userSession->getRemoteContactID($page_owner_uid))) { + $contact_id = $this->userSession->getRemoteContactID($page_owner_uid); + $can_post = $this->database->exists('contact', ['blocked' => false, 'pending' => false, 'id' => $contact_id, 'uid' => $page_owner_uid]); + } + + if (!$can_post) { + $this->logger->warning('User does not have required permissions', ['contact_id' => $contact_id, 'page_owner_uid' => $page_owner_uid]); + return $this->return(403, $this->t('Permission denied.'), true); + } + + if (empty($_FILES['userfile'])) { + $this->logger->warning('No file uploaded (empty userfile)'); + return $this->return(401, $this->t('Invalid request.'), true); + } + + $tempFileName = $_FILES['userfile']['tmp_name']; + $fileName = basename($_FILES['userfile']['name']); + $fileSize = intval($_FILES['userfile']['size']); + $maxFileSize = $this->config->get('system', 'maxfilesize'); + + /* + * Found html code written in text field of form, when trying to upload a + * file with filesize greater than upload_max_filesize. Cause is unknown. + * Then Filesize gets <= 0. + */ + if ($fileSize <= 0) { + @unlink($tempFileName); + $msg = $this->t('Sorry, maybe your upload is bigger than the PHP configuration allows') . '
' . $this->t('Or - did you try to upload an empty file?'); + $this->logger->warning($msg, ['fileSize' => $fileSize]); + return $this->return(401, $msg, true); + } + + if ($maxFileSize && $fileSize > $maxFileSize) { + @unlink($tempFileName); + $msg = $this->t('File exceeds size limit of %s', Strings::formatBytes($maxFileSize)); + $this->logger->warning($msg, ['fileSize' => $fileSize]); + return $this->return(401, $msg); + } + + $newid = Attach::storeFile($tempFileName, $page_owner_uid, $fileName, '<' . $owner['id'] . '>'); + + @unlink($tempFileName); + + if ($newid === false) { + $msg = $this->t('File upload failed.'); + $this->logger->warning($msg); + return $this->return(500, $msg); + } + + if ($this->isJson) { + $content = json_encode(['ok' => true, 'id' => $newid], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + } else { + $content = "\n\n" . '[attachment]' . $newid . '[/attachment]' . "\n"; + } + + return $this->response->addContent($content); + } + + /** + * @param int $httpCode + * @param string $message + * @param bool $systemMessage + * @return void + * @throws InternalServerErrorException + */ + private function return(int $httpCode, string $message, bool $systemMessage = false): void + { + $this->response->setStatus($httpCode, $message); + + if ($this->isJson) { + $this->response->addContent(json_encode(['error' => $message], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); + } else { + if ($systemMessage) { + $this->systemMessages->addNotice($message); + } + + $this->response->addContent($message); + } + } +} diff --git a/static/routes.config.php b/static/routes.config.php index b27a70c69..1b0f68026 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -31,15 +31,16 @@ use Friendica\App\Router as R; use Friendica\Module; $profileRoutes = [ - '' => [Module\Profile\Index::class, [R::GET]], - '/profile' => [Module\Profile\Profile::class, [R::GET]], - '/schedule' => [Module\Profile\Schedule::class, [R::GET, R::POST]], - '/contacts/common' => [Module\Profile\Common::class, [R::GET]], - '/contacts[/{type}]' => [Module\Profile\Contacts::class, [R::GET]], - '/status[/{category}[/{date1}[/{date2}]]]' => [Module\Profile\Status::class, [R::GET]], - '/media' => [Module\Profile\Media::class, [R::GET]], - '/unkmail' => [Module\Profile\UnkMail::class, [R::GET, R::POST]], - '/photos/upload' => [Module\Profile\Photos\Upload::class, [ R::POST]], + '' => [Module\Profile\Index::class, [R::GET]], + '/attachment/upload' => [Module\Profile\Attachment\Upload::class, [ R::POST]], + '/profile' => [Module\Profile\Profile::class, [R::GET]], + '/schedule' => [Module\Profile\Schedule::class, [R::GET, R::POST]], + '/contacts/common' => [Module\Profile\Common::class, [R::GET]], + '/contacts[/{type}]' => [Module\Profile\Contacts::class, [R::GET]], + '/status[/{category}[/{date1}[/{date2}]]]' => [Module\Profile\Status::class, [R::GET]], + '/media' => [Module\Profile\Media::class, [R::GET]], + '/unkmail' => [Module\Profile\UnkMail::class, [R::GET, R::POST]], + '/photos/upload' => [Module\Profile\Photos\Upload::class, [ R::POST]], ]; $apiRoutes = [ diff --git a/view/js/filebrowser.js b/view/js/filebrowser.js index 33d06e708..e5bd2730c 100644 --- a/view/js/filebrowser.js +++ b/view/js/filebrowser.js @@ -123,8 +123,9 @@ var FileBrowser = { if ($("#upload-file").length) var file_uploader = new window.AjaxUpload( 'upload-file', - { action: 'wall_attach/'+FileBrowser.nickname+'?response=json', + { action: 'profile/' + FileBrowser.nickname + '/attachment/upload?response=json', name: 'userfile', + responseType: 'json', onSubmit: function(file,ext) { $('#profile-rotator').show(); $(".error").addClass('hidden'); }, onComplete: function(file,response) { if (response['error']!= undefined) { diff --git a/view/theme/frio/js/filebrowser.js b/view/theme/frio/js/filebrowser.js index 3cdd03e1a..67d3b7923 100644 --- a/view/theme/frio/js/filebrowser.js +++ b/view/theme/frio/js/filebrowser.js @@ -203,8 +203,9 @@ var FileBrowser = { if ($("#upload-file").length) { //AjaxUpload for files var file_uploader = new window.AjaxUpload("upload-file", { - action: "wall_attach/" + FileBrowser.nickname + "?response=json", + action: "profile/" + FileBrowser.nickname + "/attachment/upload?response=json", name: "userfile", + responseType: "json", onSubmit: function (file, ext) { $(".fbrowser-content").hide(); $(".fbrowser .profile-rotator-wrapper").show(); @@ -214,7 +215,7 @@ var FileBrowser = { if (response["error"] != undefined) { $(".error span").html(response["error"]); $(".error").removeClass("hidden"); - $("#profile-rotator").hide(); + $(".fbrowser .profile-rotator-wrapper").hide(); $(".fbrowser-content").show(); return; } diff --git a/view/theme/smoothly/templates/jot-header.tpl b/view/theme/smoothly/templates/jot-header.tpl index 71b877179..cfd21035d 100644 --- a/view/theme/smoothly/templates/jot-header.tpl +++ b/view/theme/smoothly/templates/jot-header.tpl @@ -75,7 +75,7 @@ function enableOnUser(){ var file_uploader = new window.AjaxUpload( 'wall-file-upload', - { action: 'wall_attach/{{$nickname}}', + { action: 'profile/{{$nickname}}/attachment/upload', name: 'userfile', onSubmit: function(file,ext) { $('#profile-rotator').show(); }, onComplete: function(file,response) { From 4d3c0e1c57d3d4b3d23b53007b200e544d7e03e0 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 30 Oct 2022 13:39:38 -0400 Subject: [PATCH 2/3] Remove mod/wall_upload.php file --- mod/wall_attach.php | 142 -------------------------------------------- 1 file changed, 142 deletions(-) delete mode 100644 mod/wall_attach.php diff --git a/mod/wall_attach.php b/mod/wall_attach.php deleted file mode 100644 index 289c024df..000000000 --- a/mod/wall_attach.php +++ /dev/null @@ -1,142 +0,0 @@ -. - * - */ - -use Friendica\App; -use Friendica\Core\Logger; -use Friendica\Core\System; -use Friendica\Database\DBA; -use Friendica\DI; -use Friendica\Model\Attach; -use Friendica\Model\User; -use Friendica\Util\Strings; - -function wall_attach_post(App $a) -{ - $isJson = (!empty($_GET['response']) && $_GET['response'] == 'json'); - - if (DI::args()->getArgc() > 1) { - $nick = DI::args()->getArgv()[1]; - $owner = User::getOwnerDataByNick($nick); - if (!DBA::isResult($owner)) { - Logger::warning('owner is not a valid record:', ['owner' => $owner, 'nick' => $nick]); - if ($isJson) { - System::jsonExit(['error' => DI::l10n()->t('Invalid request.')]); - } - return; - } - } else { - Logger::warning('Argument count is zero or one (invalid)'); - if ($isJson) { - System::jsonExit(['error' => DI::l10n()->t('Invalid request.')]); - } - - return; - } - - $can_post = false; - - $page_owner_uid = $owner['uid']; - $page_owner_cid = $owner['id']; - $community_page = $owner['page-flags'] == User::PAGE_FLAGS_COMMUNITY; - - if (DI::userSession()->getLocalUserId() && (DI::userSession()->getLocalUserId() == $page_owner_uid)) { - $can_post = true; - } elseif ($community_page && !empty(DI::userSession()->getRemoteContactID($page_owner_uid))) { - $contact_id = DI::userSession()->getRemoteContactID($page_owner_uid); - $can_post = DBA::exists('contact', ['blocked' => false, 'pending' => false, 'id' => $contact_id, 'uid' => $page_owner_uid]); - } - - if (!$can_post) { - Logger::warning('User does not have required permissions', ['contact_id' => $contact_id, 'page_owner_uid' => $page_owner_uid]); - if ($isJson) { - System::jsonExit(['error' => DI::l10n()->t('Permission denied.')]); - } - DI::sysmsg()->addNotice(DI::l10n()->t('Permission denied.')); - System::exit(); - } - - if (empty($_FILES['userfile'])) { - Logger::warning('No file uploaded (empty userfile)'); - if ($isJson) { - System::jsonExit(['error' => DI::l10n()->t('Invalid request.')]); - } - System::exit(); - } - - $tempFileName = $_FILES['userfile']['tmp_name']; - $fileName = basename($_FILES['userfile']['name']); - $fileSize = intval($_FILES['userfile']['size']); - $maxFileSize = DI::config()->get('system', 'maxfilesize'); - - /* - * Found html code written in text field of form, when trying to upload a - * file with filesize greater than upload_max_filesize. Cause is unknown. - * Then Filesize gets <= 0. - */ - if ($fileSize <= 0) { - $msg = DI::l10n()->t('Sorry, maybe your upload is bigger than the PHP configuration allows') . '
' . DI::l10n()->t('Or - did you try to upload an empty file?'); - Logger::warning($msg, ['fileSize' => $fileSize]); - @unlink($tempFileName); - if ($isJson) { - System::jsonExit(['error' => $msg]); - } else { - DI::sysmsg()->addNotice($msg); - } - System::exit(); - } - - if ($maxFileSize && $fileSize > $maxFileSize) { - $msg = DI::l10n()->t('File exceeds size limit of %s', Strings::formatBytes($maxFileSize)); - Logger::warning($msg, ['fileSize' => $fileSize]); - @unlink($tempFileName); - if ($isJson) { - System::jsonExit(['error' => $msg]); - } else { - echo $msg . '
'; - } - System::exit(); - } - - $newid = Attach::storeFile($tempFileName, $page_owner_uid, $fileName, '<' . $page_owner_cid . '>'); - - @unlink($tempFileName); - - if ($newid === false) { - $msg = DI::l10n()->t('File upload failed.'); - Logger::warning($msg); - if ($isJson) { - System::jsonExit(['error' => $msg]); - } else { - echo $msg . '
'; - } - System::exit(); - } - - if ($isJson) { - System::jsonExit(['ok' => true, 'id' => $newid]); - } - - $lf = "\n"; - - echo $lf . $lf . '[attachment]' . $newid . '[/attachment]' . $lf; - System::exit(); - // NOTREACHED -} From e9e7a73a63ca660d1e586883157933d957d9d952 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 30 Oct 2022 13:39:56 -0400 Subject: [PATCH 3/3] Update main translation file after changing strings --- view/lang/C/messages.po | 82 ++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index d263d22e0..9c561f161 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2022.12-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-10-30 14:22-0400\n" +"POT-Creation-Date: 2022-10-31 14:54-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -124,24 +124,23 @@ msgstr "" #: mod/photos.php:159 mod/photos.php:886 mod/repair_ostatus.php:31 #: mod/settings.php:40 mod/settings.php:50 mod/settings.php:156 #: mod/suggest.php:34 mod/uimport.php:33 mod/unfollow.php:35 -#: mod/unfollow.php:50 mod/unfollow.php:82 mod/wall_attach.php:70 -#: mod/wall_attach.php:72 src/Module/Attach.php:56 src/Module/BaseApi.php:94 -#: src/Module/BaseNotifications.php:98 src/Module/Contact/Advanced.php:60 -#: src/Module/Delegation.php:118 src/Module/FollowConfirm.php:38 -#: src/Module/FriendSuggest.php:57 src/Module/Group.php:40 -#: src/Module/Group.php:83 src/Module/Invite.php:42 src/Module/Invite.php:131 -#: src/Module/Notifications/Notification.php:76 +#: mod/unfollow.php:50 mod/unfollow.php:82 src/Module/Attach.php:56 +#: src/Module/BaseApi.php:94 src/Module/BaseNotifications.php:98 +#: src/Module/Contact/Advanced.php:60 src/Module/Delegation.php:118 +#: src/Module/FollowConfirm.php:38 src/Module/FriendSuggest.php:57 +#: src/Module/Group.php:40 src/Module/Group.php:83 src/Module/Invite.php:42 +#: src/Module/Invite.php:131 src/Module/Notifications/Notification.php:76 #: src/Module/Notifications/Notification.php:107 -#: src/Module/Profile/Common.php:55 src/Module/Profile/Contacts.php:55 -#: src/Module/Profile/Photos/Upload.php:108 src/Module/Profile/Schedule.php:39 -#: src/Module/Profile/Schedule.php:56 src/Module/Profile/UnkMail.php:69 -#: src/Module/Profile/UnkMail.php:121 src/Module/Profile/UnkMail.php:132 -#: src/Module/Register.php:77 src/Module/Register.php:90 -#: src/Module/Register.php:206 src/Module/Register.php:245 -#: src/Module/Search/Directory.php:37 src/Module/Settings/Account.php:50 -#: src/Module/Settings/Account.php:410 src/Module/Settings/Delegation.php:41 -#: src/Module/Settings/Delegation.php:69 src/Module/Settings/Display.php:41 -#: src/Module/Settings/Display.php:119 +#: src/Module/Profile/Attachment/Upload.php:97 src/Module/Profile/Common.php:55 +#: src/Module/Profile/Contacts.php:55 src/Module/Profile/Photos/Upload.php:108 +#: src/Module/Profile/Schedule.php:39 src/Module/Profile/Schedule.php:56 +#: src/Module/Profile/UnkMail.php:69 src/Module/Profile/UnkMail.php:121 +#: src/Module/Profile/UnkMail.php:132 src/Module/Register.php:77 +#: src/Module/Register.php:90 src/Module/Register.php:206 +#: src/Module/Register.php:245 src/Module/Search/Directory.php:37 +#: src/Module/Settings/Account.php:50 src/Module/Settings/Account.php:410 +#: src/Module/Settings/Delegation.php:41 src/Module/Settings/Delegation.php:69 +#: src/Module/Settings/Display.php:41 src/Module/Settings/Display.php:119 #: src/Module/Settings/Profile/Photo/Crop.php:165 #: src/Module/Settings/Profile/Photo/Index.php:111 #: src/Module/Settings/UserExport.php:84 src/Module/Settings/UserExport.php:118 @@ -1504,29 +1503,6 @@ msgstr "" msgid "Unable to unfollow this contact, please contact your administrator" msgstr "" -#: mod/wall_attach.php:41 mod/wall_attach.php:48 mod/wall_attach.php:79 -#: src/Module/Profile/Photos/Upload.php:113 -#: src/Module/Profile/Photos/Upload.php:162 -msgid "Invalid request." -msgstr "" - -#: mod/wall_attach.php:95 -msgid "Sorry, maybe your upload is bigger than the PHP configuration allows" -msgstr "" - -#: mod/wall_attach.php:95 -msgid "Or - did you try to upload an empty file?" -msgstr "" - -#: mod/wall_attach.php:107 -#, php-format -msgid "File exceeds size limit of %s" -msgstr "" - -#: mod/wall_attach.php:123 -msgid "File upload failed." -msgstr "" - #: src/App.php:490 msgid "No system theme config value set." msgstr "" @@ -8314,6 +8290,30 @@ msgstr "" msgid "Invalid photo with id %s." msgstr "" +#: src/Module/Profile/Attachment/Upload.php:80 +#: src/Module/Profile/Attachment/Upload.php:102 +#: src/Module/Profile/Photos/Upload.php:113 +#: src/Module/Profile/Photos/Upload.php:162 +msgid "Invalid request." +msgstr "" + +#: src/Module/Profile/Attachment/Upload.php:117 +msgid "Sorry, maybe your upload is bigger than the PHP configuration allows" +msgstr "" + +#: src/Module/Profile/Attachment/Upload.php:117 +msgid "Or - did you try to upload an empty file?" +msgstr "" + +#: src/Module/Profile/Attachment/Upload.php:124 +#, php-format +msgid "File exceeds size limit of %s" +msgstr "" + +#: src/Module/Profile/Attachment/Upload.php:134 +msgid "File upload failed." +msgstr "" + #: src/Module/Profile/Contacts.php:119 msgid "No contacts." msgstr ""