From 50353d371f71ae18943425ab8369fd2ae5e56290 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Tue, 11 Dec 2018 15:38:10 +0300 Subject: [PATCH 01/28] update documentation link --- README.md | 4 +-- controller/editorcontroller.php | 2 +- lib/appconfig.php | 50 ++++++++++++++++----------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index b7c42d4a..918c1e39 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ After that find **ONLYOFFICE** in the list of available applications and install If the server with the Nextcloud installed does not have an Internet access, or if you need it for some other reason, the administrator can install the application manually. To start using ONLYOFFICE Document Server with Nextcloud, the following steps must be performed: -1. Go to the Nextcloud server _apps/_ directory (or some other directory [used](https://docs.nextcloud.com/server/13/admin_manual/installation/apps_management_installation.html#using-custom-app-directories)): +1. Go to the Nextcloud server _apps/_ directory (or some other directory [used](https://docs.nextcloud.com/server/latest/admin_manual/apps_management.html#using-custom-app-directories)): ``` cd apps/ ``` @@ -142,4 +142,4 @@ When the _Log-in credentials, save in session_ authentication type is used, the But if the encryption with the _per-user encryption keys_ (used by default in Nextcloud **Default encryption module** app) is enabled, ONLYOFFICE Document Server cannot open the encrypted files for editing and save them after the editing. The ONLYOFFICE section of the administrative settings page will display a notification about it. However if you set the encryption with the _master key_, ONLYOFFICE application will work as intended. -The instruction on enabling _master key_ based encryption is available in the official documentation on [Nextcloud](https://docs.nextcloud.com/server/13/admin_manual/configuration_files/encryption_configuration.html#occ-encryption-commands) websites. +The instruction on enabling _master key_ based encryption is available in the official documentation on [Nextcloud](https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/encryption_configuration.html#occ-encryption-commands) websites. diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index dcc85dd4..28bace65 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -638,7 +638,7 @@ private function getShare($token) { return [NULL, $this->trans->t("You do not have enough permissions to view the file")]; } - if ($share->getPassword() + if ($share->getPassword() && (!$this->session->exists("public_link_authenticated") || $this->session->get("public_link_authenticated") !== (string) $share->getId())) { return [NULL, $this->trans->t("You do not have enough permissions to view the file")]; diff --git a/lib/appconfig.php b/lib/appconfig.php index 67d8de7b..d5c19480 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -571,34 +571,34 @@ public function FormatsSetting() { */ private $formats = [ "csv" => [ "mime" => "text/csv", "type" => "spreadsheet", "edit" => true, "editable" => true ], - "doc" => [ "mime" => "application/msword", "type" => "text", "conv" => true ], - "docm" => [ "mime" => "application/vnd.ms-word.document.macroEnabled.12", "type" => "text", "conv" => true ], - "docx" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "type" => "text", "edit" => true, "def" => true ], - "dot" => [ "type" => "text", "conv" => true ], - "dotx" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template", "type" => "text", "conv" => true ], - "epub" => [ "mime" => "application/epub+zip", "type" => "text", "conv" => true ], - "htm" => [ "type" => "text", "conv" => true ], - "html" => [ "mime" => "text/html", "type" => "text", "conv" => true ], + "doc" => [ "mime" => "application/msword", "type" => "text", "conv" => true ], + "docm" => [ "mime" => "application/vnd.ms-word.document.macroEnabled.12", "type" => "text", "conv" => true ], + "docx" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "type" => "text", "edit" => true, "def" => true ], + "dot" => [ "type" => "text", "conv" => true ], + "dotx" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template", "type" => "text", "conv" => true ], + "epub" => [ "mime" => "application/epub+zip", "type" => "text", "conv" => true ], + "htm" => [ "type" => "text", "conv" => true ], + "html" => [ "mime" => "text/html", "type" => "text", "conv" => true ], "odp" => [ "mime" => "application/vnd.oasis.opendocument.presentation", "type" => "presentation", "conv" => true, "editable" => true ], "ods" => [ "mime" => "application/vnd.oasis.opendocument.spreadsheet", "type" => "spreadsheet", "conv" => true, "editable" => true ], "odt" => [ "mime" => "application/vnd.oasis.opendocument.text", "type" => "text", "conv" => true, "editable" => true ], - "pdf" => [ "mime" => "application/pdf", "type" => "text" ], - "pot" => [ "type" => "presentation", "conv" => true ], - "potm" => [ "mime" => "application/vnd.ms-powerpoint.template.macroEnabled.12", "type" => "presentation", "conv" => true ], - "potx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.template", "type" => "presentation", "conv" => true ], - "pps" => [ "type" => "presentation", "conv" => true ], - "ppsm" => [ "mime" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", "type" => "presentation", "conv" => true ], - "ppsx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow", "type" => "presentation", "conv" => true ], - "ppt" => [ "mime" => "application/vnd.ms-powerpoint", "type" => "presentation", "conv" => true ], - "pptm" => [ "mime" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12", "type" => "presentation", "conv" => true ], - "pptx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", "type" => "presentation", "edit" => true, "def" => true ], + "pdf" => [ "mime" => "application/pdf", "type" => "text" ], + "pot" => [ "type" => "presentation", "conv" => true ], + "potm" => [ "mime" => "application/vnd.ms-powerpoint.template.macroEnabled.12", "type" => "presentation", "conv" => true ], + "potx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.template", "type" => "presentation", "conv" => true ], + "pps" => [ "type" => "presentation", "conv" => true ], + "ppsm" => [ "mime" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", "type" => "presentation", "conv" => true ], + "ppsx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow", "type" => "presentation", "conv" => true ], + "ppt" => [ "mime" => "application/vnd.ms-powerpoint", "type" => "presentation", "conv" => true ], + "pptm" => [ "mime" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12", "type" => "presentation", "conv" => true ], + "pptx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", "type" => "presentation", "edit" => true, "def" => true ], "rtf" => [ "mime" => "text/rtf", "type" => "text", "conv" => true, "editable" => true ], "txt" => [ "mime" => "text/plain", "type" => "text", "edit" => true, "editable" => true ], - "xls" => [ "mime" => "application/vnd.ms-excel", "type" => "spreadsheet", "conv" => true ], - "xlsm" => [ "mime" => "application/vnd.ms-excel.sheet.macroEnabled.12", "type" => "spreadsheet", "conv" => true ], - "xlsx" => [ "mime" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "type" => "spreadsheet", "edit" => true, "def" => true ], - "xlt" => [ "type" => "spreadsheet", "conv" => true ], - "xltm" => [ "mime" => "application/vnd.ms-excel.template.macroEnabled.12", "type" => "spreadsheet", "conv" => true ], - "xltx" => [ "mime" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template", "type" => "spreadsheet", "conv" => true ] - ]; + "xls" => [ "mime" => "application/vnd.ms-excel", "type" => "spreadsheet", "conv" => true ], + "xlsm" => [ "mime" => "application/vnd.ms-excel.sheet.macroEnabled.12", "type" => "spreadsheet", "conv" => true ], + "xlsx" => [ "mime" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "type" => "spreadsheet", "edit" => true, "def" => true ], + "xlt" => [ "type" => "spreadsheet", "conv" => true ], + "xltm" => [ "mime" => "application/vnd.ms-excel.template.macroEnabled.12", "type" => "spreadsheet", "conv" => true ], + "xltx" => [ "mime" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template", "type" => "spreadsheet", "conv" => true ] + ]; } From 888d94e1c50a1eb4a5a01f7e6e5acf6ee52c5030 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Tue, 11 Dec 2018 15:49:08 +0300 Subject: [PATCH 02/28] 13 nextcloud not supported --- css/editor.css | 5 +---- css/main.css | 13 ++++++------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/css/editor.css b/css/editor.css index 399c8546..7706f044 100644 --- a/css/editor.css +++ b/css/editor.css @@ -37,10 +37,7 @@ .AscDesktopEditor #body-user #header { display: none; } -.AscDesktopEditor #body-user #content-wrapper /*13*/{ - padding-top: 0; -} -.AscDesktopEditor #body-user #content /*14*/{ +.AscDesktopEditor #body-user #content { min-height: 100%; padding-top: 0; } diff --git a/css/main.css b/css/main.css index c3ee427f..5caacd68 100644 --- a/css/main.css +++ b/css/main.css @@ -43,19 +43,18 @@ .AscDesktopEditor #body-user #header { display: none; } -.AscDesktopEditor #body-user #content-wrapper, /*13*/ -.AscDesktopEditor #body-user #content /*14*/{ +.AscDesktopEditor #body-user #content { padding-top: 0; } -.AscDesktopEditor #body-user #app-navigation, /*14*/ -.AscDesktopEditor #body-user #controls, /*14*/ +.AscDesktopEditor #body-user #app-navigation, +.AscDesktopEditor #body-user #controls, .AscDesktopEditor #body-user #app-sidebar { top: 0; } -.AscDesktopEditor #body-user #app-navigation /*14*/{ - height: 100%; /*14*/ +.AscDesktopEditor #body-user #app-navigation { + height: 100%; } -.AscDesktopEditor #body-user #app-sidebar /*14*/{ +.AscDesktopEditor #body-user #app-sidebar { height: 100vh; } .AscDesktopEditor #body-user table.multiselect thead { From 23ea17d291b066369339e1718d9f174f5d00574b Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Tue, 11 Dec 2018 16:09:26 +0300 Subject: [PATCH 03/28] getting file in shared folder by link --- controller/callbackcontroller.php | 10 +++++++++- controller/editorcontroller.php | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index 05f8e300..fdfe98f6 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -444,6 +444,8 @@ public function track($doc, $users, $key, $status, $url, $token) { break; } + $this->logger->debug("Track: " . $fileId . " status " . $status . " result " . $error, array("app" => $this->appName)); + return new JSONResponse(["error" => $error], Http::STATUS_OK); } @@ -462,6 +464,7 @@ private function getFile($userId, $fileId) { } $files = $this->root->getUserFolder($userId)->getById($fileId); + if (empty($files)) { $this->logger->error("Files not found: " . $fileId, array("app" => $this->appName)); return [NULL, new JSONResponse(["message" => $this->trans->t("Files not found")], Http::STATUS_NOT_FOUND)]; @@ -499,7 +502,12 @@ private function getFileByToken($fileId, $token) { } if ($node instanceof Folder) { - $file = $node->getById($fileId)[0]; + $file = $node->getById($fileId); + + if (empty($files)) { + return [NULL, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND)]; + } + $file = $files[0]; } else { $file = $node; } diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 28bace65..3927f513 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -576,6 +576,7 @@ private function getFile($userId, $fileId) { if (!$file->isReadable()) { return [NULL, $this->trans->t("You do not have enough permissions to view the file")]; } + return [$file, NULL]; } @@ -606,7 +607,12 @@ private function getFileByToken($fileId, $token) { } if ($node instanceof Folder) { - $file = $node->getById($fileId)[0]; + $files = $node->getById($fileId); + + if (empty($files)) { + return [NULL, $this->trans->t("File not found")]; + } + $file = $files[0]; } else { $file = $node; } From 38aedc86a6f2d63ffcc759ea0fed60af63e5fcc3 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Tue, 11 Dec 2018 17:28:05 +0300 Subject: [PATCH 04/28] hide download button (#32) --- controller/editorcontroller.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 3927f513..8cb0872c 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -499,6 +499,13 @@ public function config($fileId, $token = NULL, $desktop = false) { $folderLink = NULL; if (!empty($token)) { + if (method_exists($share, getHideDownload) && $share->getHideDownload()) { + $params["document"]["permissions"] = [ + "download" => false, + "print" => false + ]; + } + $node = $share->getNode(); if ($node instanceof Folder) { $sharedFolder = $node; From 2c9cb6955f3da8f35c970a012a8db7c840daa334 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Wed, 12 Dec 2018 11:46:03 +0300 Subject: [PATCH 05/28] fix php warning (#40) --- controller/editorcontroller.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 8cb0872c..fea8ba7d 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -565,7 +565,7 @@ public function config($fileId, $token = NULL, $desktop = false) { */ private function getFile($userId, $fileId) { if (empty($fileId)) { - return [NULL, $this->trans->t("FileId is empty")]; + return [NULL, $this->trans->t("FileId is empty"), NULL]; } if ($userId !== NULL) { @@ -576,15 +576,15 @@ private function getFile($userId, $fileId) { } if (empty($files)) { - return [NULL, $this->trans->t("File not found")]; + return [NULL, $this->trans->t("File not found"), NULL]; } $file = $files[0]; if (!$file->isReadable()) { - return [NULL, $this->trans->t("You do not have enough permissions to view the file")]; + return [NULL, $this->trans->t("You do not have enough permissions to view the file"), NULL]; } - return [$file, NULL]; + return [$file, NULL, NULL]; } /** @@ -599,25 +599,25 @@ private function getFileByToken($fileId, $token) { list ($share, $error) = $this->getShare($token); if (isset($error)) { - return [NULL, $error]; + return [NULL, $error, NULL]; } if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) { - return [NULL, $this->trans->t("You do not have enough permissions to view the file")]; + return [NULL, $this->trans->t("You do not have enough permissions to view the file"), NULL]; } try { $node = $share->getNode(); } catch (NotFoundException $e) { $this->logger->error("getFileByToken error: " . $e->getMessage(), array("app" => $this->appName)); - return [NULL, $this->trans->t("File not found")]; + return [NULL, $this->trans->t("File not found"), NULL]; } if ($node instanceof Folder) { $files = $node->getById($fileId); if (empty($files)) { - return [NULL, $this->trans->t("File not found")]; + return [NULL, $this->trans->t("File not found"), NULL]; } $file = $files[0]; } else { From 2356ae27cc2e482221579ff8f306f84d08583134 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Wed, 12 Dec 2018 16:15:58 +0300 Subject: [PATCH 06/28] fix public folder (#35) --- js/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index 5c75b82c..1cefde07 100644 --- a/js/main.js +++ b/js/main.js @@ -228,7 +228,7 @@ }; var initPage = function(){ - if ($("#isPublic").val() && !$("#dir").val().length) { + if ($("#isPublic").val() === "1" && !$("#filestable").length) { var fileName = $("#filename").val(); var extension = fileName.substr(fileName.lastIndexOf(".") + 1).toLowerCase(); From 013b9ff113142771e41c3bbc8de94f5d6c5ff55c Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Thu, 13 Dec 2018 11:50:00 +0300 Subject: [PATCH 07/28] fix php warning --- controller/settingscontroller.php | 1 + lib/appconfig.php | 3 +++ templates/settings.php | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index 917d4566..b3d0ed7e 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -156,6 +156,7 @@ public function SaveSettings($documentserver, $this->config->SetDocumentServerSecret($secret); $documentserver = $this->config->GetDocumentServerUrl(); + $error = NULL; if (!empty($documentserver)) { $error = $this->checkDocServiceUrl(); $this->config->SetSettingsError($error); diff --git a/lib/appconfig.php b/lib/appconfig.php index d5c19480..1e59ac9f 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -441,6 +441,9 @@ public function GetSameTab() { * @param array $value - same tab */ public function SetLimitGroups($groups) { + if (!is_array($limitGroups)) { + $limitGroups = array(); + } $value = json_encode($groups); $this->logger->info("Set groups: " . $value, array("app" => $this->appName)); diff --git a/templates/settings.php b/templates/settings.php index 1d9b210c..69b09339 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -82,7 +82,7 @@ checked="checked" /> + checked="checked" /> @@ -98,7 +98,7 @@ checked="checked" /> + checked="checked" /> From 4a884b611cfe4d364dc76bb63f83be950bc76f26 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Thu, 13 Dec 2018 16:54:52 +0300 Subject: [PATCH 08/28] check https --- controller/settingscontroller.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index b3d0ed7e..a842f8b2 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -207,10 +207,8 @@ public function GetSettings() { private function checkDocServiceUrl() { try { - $documentServerUrl = $this->config->GetDocumentServerUrl(); - if (substr($this->urlGenerator->getAbsoluteURL("/"), 0, strlen("https")) === "https" - && preg_match("/^https?:\/\//i", $documentServerUrl) - && substr($documentServerUrl, 0, strlen("https")) !== "https") { + if (preg_match("/^https:\/\//i", $this->urlGenerator->getAbsoluteURL("/")) + && preg_match("/^http:\/\//i", $this->config->GetDocumentServerUrl())) { throw new \Exception($this->trans->t("Mixed Active Content is not allowed. HTTPS address for Document Server is required.")); } From 751fbcf732e4c37168ae9328983093e2c6668267 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Thu, 10 Jan 2019 17:24:33 +0300 Subject: [PATCH 09/28] fix php warning (#51) --- lib/appconfig.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/appconfig.php b/lib/appconfig.php index 1e59ac9f..76c89579 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -438,11 +438,11 @@ public function GetSameTab() { /** * Save the list of groups * - * @param array $value - same tab + * @param array $groups - the list of groups */ public function SetLimitGroups($groups) { - if (!is_array($limitGroups)) { - $limitGroups = array(); + if (!is_array($groups)) { + $groups = array(); } $value = json_encode($groups); $this->logger->info("Set groups: " . $value, array("app" => $this->appName)); @@ -460,7 +460,11 @@ public function GetLimitGroups() { if (empty($value)) { return array(); } - return json_decode($value, true); + $groups = json_decode($value, true); + if (!is_array($groups)) { + $groups = array(); + } + return $groups; } /** From c805a44a0a74fb659f0aa1f4863f2db0acfb15a7 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Tue, 22 Jan 2019 18:21:38 +0300 Subject: [PATCH 10/28] 2019 --- appinfo/app.php | 2 +- appinfo/application.php | 2 +- appinfo/routes.php | 2 +- controller/callbackcontroller.php | 2 +- controller/editorcontroller.php | 2 +- controller/settingscontroller.php | 2 +- css/editor.css | 2 +- css/main.css | 2 +- css/settings.css | 2 +- js/desktop.js | 2 +- js/editor.js | 2 +- js/main.js | 2 +- js/settings.js | 2 +- lib/adminsection.php | 2 +- lib/adminsettings.php | 2 +- lib/appconfig.php | 2 +- lib/crypt.php | 2 +- lib/documentservice.php | 2 +- settings.php | 2 +- templates/editor.php | 2 +- templates/settings.php | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/appinfo/app.php b/appinfo/app.php index e39c69a6..e7d24801 100644 --- a/appinfo/app.php +++ b/appinfo/app.php @@ -1,7 +1,7 @@ Date: Thu, 14 Feb 2019 17:58:00 +0300 Subject: [PATCH 11/28] fix size on mobile (ONLYOFFICE/web-apps-pro@f560e6fd5c404bb1aa556826b0de44d2adebf5fe) --- js/editor.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/editor.js b/js/editor.js index 550c22a4..900100f4 100644 --- a/js/editor.js +++ b/js/editor.js @@ -99,6 +99,10 @@ }; var docEditor = new DocsAPI.DocEditor("iframeEditor", config); + + if (config.type === "mobile" && $("#app > iframe").css("position") === "fixed") { + $("#app > iframe").css("height", "calc(100% - 50px)") + } } } }); From 90630a04af02c302ffa1481a870918e68f1f29d1 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Thu, 28 Feb 2019 16:56:46 +0300 Subject: [PATCH 12/28] permissions modifyFilter --- controller/editorcontroller.php | 8 ++++++++ lib/appconfig.php | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index c479fcad..a5555bce 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -545,6 +545,14 @@ public function config($fileId, $token = NULL, $desktop = false) { $params = $this->setCustomization($params); + $permissions_modifyFilter = $this->config->getSystemValue($this->config->_permissions_modifyFilter); + if (isset($permissions_modifyFilter)) { + if (!array_key_exists("permissions", $params["document"])) { + $params["document"]["permissions"] = []; + } + $params["document"]["permissions"]["modifyFilter"] = $permissions_modifyFilter; + } + if (!empty($this->config->GetDocumentServerSecret())) { $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret()); $params["token"] = $token; diff --git a/lib/appconfig.php b/lib/appconfig.php index cda20740..d7b07aae 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -144,6 +144,13 @@ class AppConfig { */ private $_settingsError = "settings_error"; + /** + * The config key for the modifyFilter + * + * @var string + */ + public $_permissions_modifyFilter = "permissions_modifyFilter"; + /** * The config key for the customer * From 799e24a418e16622af349b4d5aa7a00d32ccf1cf Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Fri, 1 Mar 2019 15:40:29 +0300 Subject: [PATCH 13/28] using IClientService --- lib/documentservice.php | 72 +++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/lib/documentservice.php b/lib/documentservice.php index 4ca98297..fb609278 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -154,30 +154,30 @@ function SendRequestToConvertService($document_uri, $from_extension, $to_extensi $response_xml_data; $countTry = 0; - $opts = array("http" => array( - "method" => "POST", - "timeout" => "120", - "header"=> "Content-type: application/json\r\n", - "content" => json_encode($data) - ) - ); + $opts = array( + "timeout" => "120", + "headers" => [ + "Content-type" => "application/json" + ], + "body" => json_encode($data) + ); if (!empty($this->config->GetDocumentServerSecret())) { $params = [ "payload" => $data ]; $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret()); - $opts["http"]["header"] = $opts["http"]["header"] . $this->config->JwtHeader() . ": Bearer " . $token . "\r\n"; + $opts["headers"][$this->config->JwtHeader()] = "Bearer " . $token; $token = \Firebase\JWT\JWT::encode($data, $this->config->GetDocumentServerSecret()); $data["token"] = $token; - $opts["http"]["content"] = json_encode($data); + $opts["body"] = json_encode($data); } $ServiceConverterMaxTry = 3; while ($countTry < $ServiceConverterMaxTry) { $countTry = $countTry + 1; - $response_xml_data = $this->Request($urlToConverter, $opts); + $response_xml_data = $this->Request($urlToConverter, "post", $opts); if ($response_xml_data !== false) { break; } } @@ -265,12 +265,7 @@ function HealthcheckRequest() { $urlHealthcheck = $documentServerUrl . "healthcheck"; - $opts = array("http" => array( - "timeout" => "60" - ) - ); - - if (($response = $this->Request($urlHealthcheck, $opts)) === false) { + if (($response = $this->Request($urlHealthcheck)) === false) { throw new \Exception ($this->trans->t("Bad Request or timeout error")); } @@ -298,27 +293,26 @@ function CommandRequest($method) { "c" => $method ]; - $opts = array("http" => array( - "method" => "POST", - "timeout" => "60", - "header"=> "Content-type: application/json\r\n", - "content" => json_encode($data) - ) - ); + $opts = array( + "headers" => [ + "Content-type" => "application/json" + ], + "body" => json_encode($data) + ); if (!empty($this->config->GetDocumentServerSecret())) { $params = [ "payload" => $data ]; $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret()); - $opts["http"]["header"] = $opts["http"]["header"] . $this->config->JwtHeader() . ": Bearer " . $token . "\r\n"; + $opts["headers"][$this->config->JwtHeader()] = "Bearer " . $token; $token = \Firebase\JWT\JWT::encode($data, $this->config->GetDocumentServerSecret()); $data["token"] = $token; - $opts["http"]["content"] = json_encode($data); + $opts["body"] = json_encode($data); } - if (($response = $this->Request($urlCommand, $opts)) === false) { + if (($response = $this->Request($urlCommand, "post", $opts)) === false) { throw new \Exception ($this->trans->t("Bad Request or timeout error")); } @@ -364,24 +358,32 @@ function ProcessCommandServResponceError($errorCode) { * Request to Document Server with turn off verification * * @param string $url - request address - * @param array $opts - stream context options + * @param array $method - request method + * @param array $opts - request options * * @return string */ - public function Request($url, $opts = NULL) { + + public function Request($url, $method = "get", $opts = NULL) { + $httpClientService = \OC::$server->getHTTPClientService(); + $client = $httpClientService->newClient(); + if (NULL === $opts) { $opts = array(); } - if (substr($url, 0, strlen("https")) === "https" && $this->config->TurnOffVerification()) { - $opts["ssl"] = array( - "verify_peer" => false, - "verify_peer_name" => false - ); + $opts["verify"] = false; + } + if (!array_key_exists("timeout", $opts)) { + $opts["timeout"] = 60; } - $context = stream_context_create($opts); + if ($method === "post") { + $response = $client->post($url, $opts); + } else { + $response = $client->get($url, $opts); + } - return file_get_contents($url, false, $context); + return $response->getBody(); } } From 9534325df79c4017dcee1eb7322d8a0bffecaff6 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Fri, 1 Mar 2019 17:29:56 +0300 Subject: [PATCH 14/28] using instance's secret --- controller/settingscontroller.php | 2 -- lib/appconfig.php | 16 ++-------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index de7dd18c..ab5ce7a7 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -162,8 +162,6 @@ public function SaveSettings($documentserver, $this->config->SetSettingsError($error); } - $this->config->DropSKey(); - $this->config->SetDefaultFormats($defFormats); $this->config->SetEditableFormats($editFormats); $this->config->SetSameTab($sameTab); diff --git a/lib/appconfig.php b/lib/appconfig.php index d7b07aae..52a68123 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -86,7 +86,7 @@ class AppConfig { * * @var string */ - private $_cryptSecret = "skey"; + private $_cryptSecret = "secret"; /** * The config key for the default formats @@ -357,19 +357,7 @@ public function GetDocumentServerSecret() { * @return string */ public function GetSKey() { - $skey = $this->config->getAppValue($this->appName, $this->_cryptSecret, ""); - if (empty($skey)) { - $skey = number_format(round(microtime(true) * 1000), 0, ".", ""); - $this->config->setAppValue($this->appName, $this->_cryptSecret, $skey); - } - return $skey; - } - - /** - * Regenerate the secret key - */ - public function DropSKey() { - $this->config->setAppValue($this->appName, $this->_cryptSecret, ""); + return $this->config->getSystemValue($this->_cryptSecret, true); } /** From c323d04f40d93544039fb9250712f24ce1b9108c Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Mon, 4 Mar 2019 14:43:08 +0300 Subject: [PATCH 15/28] fix typo (23ea17d291b066369339e1718d9f174f5d00574b) --- README.md | 5 ----- controller/callbackcontroller.php | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index 918c1e39..5a2db709 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ This allows multiple users to collaborate in real time and to save back those ch You can also use our **[Docker installation](https://github.com/ONLYOFFICE/docker-onlyoffice-nextcloud)** to get installed and configured Document Server and Nextcloud installation with a couple of commands. - ## Installing ONLYOFFICE Document Server You will need an instance of ONLYOFFICE Document Server that is resolvable and connectable both from Nextcloud and any end clients (version 4.2.7 and later are supported for use with the app). @@ -25,7 +24,6 @@ Or you can use Document Server behind a proxy, please refer to [this article](ht The easiest way to start an instance of ONLYOFFICE Document Server is to use [Docker](https://github.com/ONLYOFFICE/Docker-DocumentServer). - ## Installing Nextcloud ONLYOFFICE integration app The Nextcloud administrator can install the integration app from the in-built application market. @@ -60,7 +58,6 @@ There are several ways to do that: 3. In Nextcloud open the `~/index.php/settings/apps?category=disabled` page with _Not enabled_ apps by administrator and click _Enable_ for the **ONLYOFFICE** application. - ## Configuring Nextcloud ONLYOFFICE integration app In Nextcloud open the `~/index.php/settings/admin/onlyoffice` page with administrative settings for **ONLYOFFICE** section. @@ -88,7 +85,6 @@ The **Open in ONLYOFFICE** action will be added to the file context menu. You can specify this action as default and it will be used when the file name is clicked for the selected file types. - ## How it works The ONLYOFFICE integration follows the API documented here https://api.onlyoffice.com/editors/basic: @@ -127,7 +123,6 @@ This method adds the copy of the file from the assets folder to the folder the u * Nextcloud downloads the new version of the document, replacing the old one. - ## Known issues * If the document is shared using the **Federated Cloud Sharing** app, the co-editing among the servers will not be avaialble. diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index adc5345f..a54a6bc5 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -502,7 +502,7 @@ private function getFileByToken($fileId, $token) { } if ($node instanceof Folder) { - $file = $node->getById($fileId); + $files = $node->getById($fileId); if (empty($files)) { return [NULL, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND)]; From 118f2d82ccf22d6ef94206b87cc612e629b7d7c9 Mon Sep 17 00:00:00 2001 From: Jos Poortvliet Date: Mon, 4 Mar 2019 14:47:44 +0100 Subject: [PATCH 16/28] remove 'organization' category While, I suppose, ONLYOFFICE can be used to organize things I just don't think it is a primary purpose that fits with the tasks, calendar or polls apps. And yes, a few other apps have to be removed there, too, I'm making a few PR's :D --- appinfo/info.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/appinfo/info.xml b/appinfo/info.xml index c7e8a278..f13f56e6 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -20,7 +20,6 @@ files integration office - organization tools https://www.onlyoffice.com https://github.com/ONLYOFFICE/onlyoffice-nextcloud/issues @@ -36,4 +35,4 @@ OCA\Onlyoffice\AdminSettings OCA\Onlyoffice\AdminSection - \ No newline at end of file + From 34a9648cda29e4c77ce9a99dac40cdfc74a5d59e Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Mon, 4 Mar 2019 17:41:11 +0300 Subject: [PATCH 17/28] change generate url --- js/editor.js | 5 ++++- js/main.js | 5 ++++- js/settings.js | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/js/editor.js b/js/editor.js index 900100f4..fcd938e3 100644 --- a/js/editor.js +++ b/js/editor.js @@ -51,7 +51,10 @@ return; } - var configUrl = OC.generateUrl("apps/onlyoffice/ajax/config/" + (fileId || 0)); + var configUrl = OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/config/{fileId}", + { + fileId: fileId || 0 + }); var params = []; if (fileToken) { diff --git a/js/main.js b/js/main.js index cee1ceb8..29f34d42 100644 --- a/js/main.js +++ b/js/main.js @@ -79,7 +79,10 @@ }); if ($("#isPublic").val()) { - url = OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/s/" + encodeURIComponent($("#sharingToken").val())) + "?fileId=" + fileId; + url = OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/s/" + encodeURIComponent($("#sharingToken").val()) + "?fileId={fileId}", + { + fileId: fileId + }); } if (winEditor && winEditor.location) { diff --git a/js/settings.js b/js/settings.js index 4562e81e..a8b48cb1 100644 --- a/js/settings.js +++ b/js/settings.js @@ -93,7 +93,7 @@ $.ajax({ method: "PUT", - url: OC.generateUrl("apps/onlyoffice/ajax/settings"), + url: OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/settings"), data: { documentserver: onlyofficeUrl, documentserverInternal: onlyofficeInternalUrl, From 51ea9f7ce6475f98fe0b8f327c451415e7fd49c8 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Mon, 4 Mar 2019 17:36:39 +0300 Subject: [PATCH 18/28] unknown user use token --- controller/editorcontroller.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index a5555bce..05c71684 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -576,14 +576,10 @@ private function getFile($userId, $fileId) { return [NULL, $this->trans->t("FileId is empty"), NULL]; } - if ($userId !== NULL) { - $files = $this->root->getUserFolder($userId)->getById($fileId); - } else { - $this->logger->debug("getFile by unknown user: " . $fileId, array("app" => $this->appName)); - $files = $this->root->getById($fileId); - } + $files = $this->root->getUserFolder($userId)->getById($fileId); if (empty($files)) { + $this->logger->info("Files not found: " . $fileId, array("app" => $this->appName)); return [NULL, $this->trans->t("File not found"), NULL]; } $file = $files[0]; @@ -625,6 +621,7 @@ private function getFileByToken($fileId, $token) { $files = $node->getById($fileId); if (empty($files)) { + $this->logger->info("Files not found: " . $fileId, array("app" => $this->appName)); return [NULL, $this->trans->t("File not found"), NULL]; } $file = $files[0]; From 7e8dcdef8a04b0138d669d3514213ffa23f8755d Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Tue, 5 Mar 2019 10:34:38 +0300 Subject: [PATCH 19/28] filePath as addition param (#66) --- controller/editorcontroller.php | 24 +++++++++++++++++++----- js/editor.js | 4 ++++ js/main.js | 12 +++++++----- templates/editor.php | 2 +- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 05c71684..952e086d 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -342,14 +342,15 @@ public function convert($fileId) { * * @param integer $fileId - file identifier * @param string $token - access token + * @param string $filePath - file path * * @return TemplateResponse|RedirectResponse * * @NoAdminRequired * @NoCSRFRequired */ - public function index($fileId, $token = NULL) { - $this->logger->debug("Open: " . $fileId, array("app" => $this->appName)); + public function index($fileId, $token = NULL, $filePath = NULL) { + $this->logger->debug("Open: " . $fileId . " " . $filePath, array("app" => $this->appName)); if (empty($token) && !$this->userSession->isLoggedIn()) { $redirectUrl = $this->urlGenerator->linkToRoute("core.login.showLoginForm", [ @@ -372,6 +373,7 @@ public function index($fileId, $token = NULL) { $params = [ "documentServerUrl" => $documentServerUrl, "fileId" => $fileId, + "filePath" => $filePath, "token" => $token ]; @@ -411,6 +413,7 @@ public function PublicPage($fileId, $token) { * Collecting the file parameters for the document service * * @param integer $fileId - file identifier + * @param string $filePath - file path * @param string $token - access token * @param bool $desktop - desktop label * @@ -419,7 +422,7 @@ public function PublicPage($fileId, $token) { * @NoAdminRequired * @PublicPage */ - public function config($fileId, $token = NULL, $desktop = false) { + public function config($fileId, $filePath = NULL, $token = NULL, $desktop = false) { if (empty($token) && !$this->config->isUserAllowedToUse()) { return ["error" => $this->trans->t("Not permitted")]; @@ -431,7 +434,7 @@ public function config($fileId, $token = NULL, $desktop = false) { $userId = $user->getUID(); } - list ($file, $error, $share) = empty($token) ? $this->getFile($userId, $fileId) : $this->getFileByToken($fileId, $token); + list ($file, $error, $share) = empty($token) ? $this->getFile($userId, $fileId, $filePath) : $this->getFileByToken($fileId, $token); if (isset($error)) { $this->logger->error("Config: " . $fileId . " " . $error, array("app" => $this->appName)); @@ -568,10 +571,11 @@ public function config($fileId, $token = NULL, $desktop = false) { * * @param string $userId - user identifier * @param integer $fileId - file identifier + * @param string $filePath - file path * * @return array */ - private function getFile($userId, $fileId) { + private function getFile($userId, $fileId, $filePath = NULL) { if (empty($fileId)) { return [NULL, $this->trans->t("FileId is empty"), NULL]; } @@ -582,8 +586,18 @@ private function getFile($userId, $fileId) { $this->logger->info("Files not found: " . $fileId, array("app" => $this->appName)); return [NULL, $this->trans->t("File not found"), NULL]; } + $file = $files[0]; + if (count($files) > 1 && !empty($filePath)) { + $filePath = "/" . $userId . "/files" . $filePath; + foreach ($files as $curFile) { + if ($curFile->getPath() === $filePath) { + $file = $curFile; + } + } + } + if (!$file->isReadable()) { return [NULL, $this->trans->t("You do not have enough permissions to view the file"), NULL]; } diff --git a/js/editor.js b/js/editor.js index fcd938e3..bc10d1e9 100644 --- a/js/editor.js +++ b/js/editor.js @@ -40,6 +40,7 @@ }; var fileId = $("#iframeEditor").data("id"); + var filePath = $("#iframeEditor").data("path"); var fileToken = $("#iframeEditor").data("token"); if (!fileId && !fileToken) { displayError(t(OCA.Onlyoffice.AppName, "FileId is empty")); @@ -57,6 +58,9 @@ }); var params = []; + if (filePath) { + params.push("filePath=" + encodeURIComponent(filePath)); + } if (fileToken) { params.push("token=" + encodeURIComponent(fileToken)); } diff --git a/js/main.js b/js/main.js index 29f34d42..19a43b6a 100644 --- a/js/main.js +++ b/js/main.js @@ -63,7 +63,7 @@ } fileList.add(response, { animate: true }); - OCA.Onlyoffice.OpenEditor(response.id, winEditor); + OCA.Onlyoffice.OpenEditor(response.id, dir, response.name, winEditor); OC.Notification.show(t(OCA.Onlyoffice.AppName, "File created"), { timeout: 3 @@ -72,10 +72,12 @@ ); }; - OCA.Onlyoffice.OpenEditor = function (fileId, winEditor) { - var url = OC.generateUrl("/apps/" + OCA.Onlyoffice.AppName + "/{fileId}", + OCA.Onlyoffice.OpenEditor = function (fileId, fileDir, fileName, winEditor) { + var filePath = fileDir.replace(new RegExp("\/$"), "") + "/" + fileName; + var url = OC.generateUrl("/apps/" + OCA.Onlyoffice.AppName + "/{fileId}?filePath={filePath}", { - fileId: fileId + fileId: fileId, + filePath: filePath }); if ($("#isPublic").val()) { @@ -96,7 +98,7 @@ OCA.Onlyoffice.FileClick = function (fileName, context) { var fileInfoModel = context.fileInfoModel || context.fileList.getModelForFile(fileName); - OCA.Onlyoffice.OpenEditor(fileInfoModel.id); + OCA.Onlyoffice.OpenEditor(fileInfoModel.id, context.dir, fileName); }; OCA.Onlyoffice.FileConvertClick = function (fileName, context) { diff --git a/templates/editor.php b/templates/editor.php index ac3de450..38deacc2 100644 --- a/templates/editor.php +++ b/templates/editor.php @@ -34,7 +34,7 @@
-
" data-token="">
+
" data-path="" data-token="">