diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index fe80f429..00000000 --- a/.gitmodules +++ /dev/null @@ -1,8 +0,0 @@ -[submodule "src/main/resources/app_data/document-templates"] - path = src/main/resources/app_data/document-templates - url = https://github.com/ONLYOFFICE/document-templates - branch = main/new -[submodule "src/main/resources/app_data/document-formats"] - path = src/main/resources/app_data/document-formats - url = https://github.com/ONLYOFFICE/document-formats - branch = master diff --git a/3rd-Party.license b/3rd-Party.license index 5569e79c..4a7309f6 100644 --- a/3rd-Party.license +++ b/3rd-Party.license @@ -1,18 +1,26 @@ Confluence ONLYOFFICE integration app uses code from the following 3rd party projects: -com.auth0.java-jwt - Java implementation of JSON Web Token (JWT) (https://github.com/auth0/java-jwt/blob/master/LICENSE) -License: MIT License -License File: com.auth0.java-jwt.license +com.atlassian.confluence.confluence - Confluence Core +License: Apache 2.0 +License File: com.atlassian.confluence.confluence.licence com.fasterxml.jackson.core.jackson-databind - General data-binding functionality for Jackson: works on core streaming API (https://github.com/FasterXML/jackson-databind/blob/2.16/LICENSE) -License: Apache License 2.0 +License: Apache 2.0 License File: com.fasterxml.jackson.core.jackson-databind.license +commons-io.commons-io - The Apache Commons IO library contains utility classes, stream implementations, file filters, file comparators, endian transformation classes, and much more. +License: Apache 2.0 +License File: commons-io.commons-io.license + javax.servlet-api - Java Servlet API (https://opensource.org/licenses/CDDL-1.0 https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) License: CDDL, GPL 2.0 License File: javax.servlet-api.license -JSON - JSON is a light-weight, language independent, data interchange format. See http://www.JSON.org/ The files in this package implement JSON encoders/decoders in Java. It also includes the capability to convert between JSON and XML, HTTP headers, Cookies, and CDL. This is a reference implementation. (http://json.org/license.html) -License: JSON -License File: JSON.license +org.apache.httpcomponents.httpclient - HTTPClient provides an efficient, up-to-date, and feature-rich package implementing the client side of the most recent HTTP standards and recommendations. +License: Apache 2.0 +License File: org.apache.httpcomponents.httpclient.license + +org.json.json - JSON is a light-weight, language independent, data interchange format. See http://www.JSON.org/ The files in this package implement JSON encoders/decoders in Java. It also includes the capability to convert between JSON and XML, HTTP headers, Cookies, and CDL. This is a reference implementation. (https://github.com/stleary/JSON-java/blob/master/LICENSE) +License: Public Domain +License File: org.json.json.license diff --git a/CHANGELOG.md b/CHANGELOG.md index f8fc1711..24d99516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Change Log +## 5.0.0 +## Added +- compatible with Confluence 8.8 +- core of the plugin has been moved to com.onlyoffice.docs-integration-sdk (https://github.com/ONLYOFFICE/docs-integration-sdk-java) +- improved connection settings validation +- improved history servlet security +- setting authorization header on settings page +- user image in editor +- filling pdf +- translations (zh_CN) + +## Changed +- improved date formatting in history changes +- default conversion format (from docxf to pdf instead oform) +- remove filling for oform + ## 4.4.0 ## Added - compatible with Confluence 8.6 diff --git a/README.md b/README.md index 6bdfb565..faa3138b 100644 --- a/README.md +++ b/README.md @@ -178,12 +178,18 @@ The table below will help you make the right choice. | Font and paragraph formatting | + | + | | Object insertion | + | + | | Transitions | + | + | +| Animations | + | + | | Presenter mode | + | + | | Notes | + | + | | **Form creator features** | **Community Edition** | **Enterprise Edition** | | Adding form fields | + | + | | Form preview | + | + | | Saving as PDF | + | + | +| **Working with PDF** | **Community Edition** | **Enterprise Edition** | +| Text annotations (highlight, underline, cross out) | + | + | +| Comments | + | + | +| Freehand drawings | + | + | +| Form filling | + | + | | | [Get it now](https://www.onlyoffice.com/download-docs.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubConfluence#docs-community) | [Start Free Trial](https://www.onlyoffice.com/download-docs.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubConfluence#docs-enterprise) | -\* If supported by DMS. \ No newline at end of file +\* If supported by DMS. diff --git a/licenses/3rd-Party.license b/licenses/3rd-Party.license index 5569e79c..4a7309f6 100644 --- a/licenses/3rd-Party.license +++ b/licenses/3rd-Party.license @@ -1,18 +1,26 @@ Confluence ONLYOFFICE integration app uses code from the following 3rd party projects: -com.auth0.java-jwt - Java implementation of JSON Web Token (JWT) (https://github.com/auth0/java-jwt/blob/master/LICENSE) -License: MIT License -License File: com.auth0.java-jwt.license +com.atlassian.confluence.confluence - Confluence Core +License: Apache 2.0 +License File: com.atlassian.confluence.confluence.licence com.fasterxml.jackson.core.jackson-databind - General data-binding functionality for Jackson: works on core streaming API (https://github.com/FasterXML/jackson-databind/blob/2.16/LICENSE) -License: Apache License 2.0 +License: Apache 2.0 License File: com.fasterxml.jackson.core.jackson-databind.license +commons-io.commons-io - The Apache Commons IO library contains utility classes, stream implementations, file filters, file comparators, endian transformation classes, and much more. +License: Apache 2.0 +License File: commons-io.commons-io.license + javax.servlet-api - Java Servlet API (https://opensource.org/licenses/CDDL-1.0 https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) License: CDDL, GPL 2.0 License File: javax.servlet-api.license -JSON - JSON is a light-weight, language independent, data interchange format. See http://www.JSON.org/ The files in this package implement JSON encoders/decoders in Java. It also includes the capability to convert between JSON and XML, HTTP headers, Cookies, and CDL. This is a reference implementation. (http://json.org/license.html) -License: JSON -License File: JSON.license +org.apache.httpcomponents.httpclient - HTTPClient provides an efficient, up-to-date, and feature-rich package implementing the client side of the most recent HTTP standards and recommendations. +License: Apache 2.0 +License File: org.apache.httpcomponents.httpclient.license + +org.json.json - JSON is a light-weight, language independent, data interchange format. See http://www.JSON.org/ The files in this package implement JSON encoders/decoders in Java. It also includes the capability to convert between JSON and XML, HTTP headers, Cookies, and CDL. This is a reference implementation. (https://github.com/stleary/JSON-java/blob/master/LICENSE) +License: Public Domain +License File: org.json.json.license diff --git a/licenses/com.atlassian.confluence.confluence.licence b/licenses/com.atlassian.confluence.confluence.licence new file mode 100644 index 00000000..7f8889ba --- /dev/null +++ b/licenses/com.atlassian.confluence.confluence.licence @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/licenses/com.auth0.java-jwt.license b/licenses/com.auth0.java-jwt.license deleted file mode 100644 index 72de587f..00000000 --- a/licenses/com.auth0.java-jwt.license +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Auth0, Inc. (http://auth0.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/licenses/commons-io.commons-io.license b/licenses/commons-io.commons-io.license new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/licenses/commons-io.commons-io.license @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/licenses/org.apache.httpcomponents.httpclient.license b/licenses/org.apache.httpcomponents.httpclient.license new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/licenses/org.apache.httpcomponents.httpclient.license @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/licenses/JSON.license b/licenses/org.json.json.license similarity index 100% rename from licenses/JSON.license rename to licenses/org.json.json.license diff --git a/pom.xml b/pom.xml index defbaeef..95d643b3 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ 4.0.0 onlyoffice onlyoffice-confluence-plugin - 4.4.0 + 5.0.0 Ascensio System SIA @@ -34,19 +34,32 @@ org.json json - 20230227 + 20231013 provided - - com.auth0 - java-jwt - 4.0.0 - com.fasterxml.jackson.core jackson-databind 2.13.4.2 + + com.onlyoffice + docs-integration-sdk + 1.1.2 + + + org.apache.httpcomponents + httpclient + 4.5.14 + provided + + + commons-io + commons-io + 2.13.0 + provided + + diff --git a/src/main/java/onlyoffice/OnlyOfficeAPIServlet.java b/src/main/java/onlyoffice/OnlyOfficeAPIServlet.java index 57a147d3..366545cc 100644 --- a/src/main/java/onlyoffice/OnlyOfficeAPIServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeAPIServlet.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,20 +22,24 @@ import com.atlassian.confluence.status.service.SystemInformationService; import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; import com.atlassian.confluence.user.ConfluenceUser; +import com.atlassian.confluence.user.UserAccessor; +import com.atlassian.confluence.user.actions.ProfilePictureInfo; +import com.atlassian.sal.api.user.UserKey; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.managers.document.DocumentManager; -import onlyoffice.managers.jwt.JwtManager; -import onlyoffice.managers.url.UrlManager; +import com.onlyoffice.manager.request.RequestManager; +import com.onlyoffice.manager.settings.SettingsManager; +import com.onlyoffice.manager.security.JwtManager; +import com.onlyoffice.model.common.User; +import com.onlyoffice.model.documenteditor.config.document.ReferenceData; +import onlyoffice.model.dto.UsersInfoRequest; +import onlyoffice.model.dto.UsersInfoResponse; +import onlyoffice.sdk.manager.document.DocumentManager; +import onlyoffice.sdk.manager.url.UrlManager; import onlyoffice.utils.attachment.AttachmentUtil; import onlyoffice.utils.parsing.ParsingUtil; import org.apache.commons.io.IOUtils; import org.apache.http.HttpEntity; -import org.apache.http.HttpException; -import org.apache.http.HttpStatus; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.json.JSONArray; @@ -50,6 +54,7 @@ import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Base64; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -59,24 +64,31 @@ public class OnlyOfficeAPIServlet extends HttpServlet { private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeAPIServlet"); private final SystemInformationService sysInfoService; + private final UserAccessor userAccessor; + private final SettingsManager settingsManager; private final JwtManager jwtManager; private final DocumentManager documentManager; private final AttachmentUtil attachmentUtil; private final ParsingUtil parsingUtil; private final UrlManager urlManager; - private final ConfigurationManager configurationManager; + private final RequestManager requestManager; - public OnlyOfficeAPIServlet(final SystemInformationService sysInfoService, final JwtManager jwtManager, + private final ObjectMapper objectMapper = new ObjectMapper(); + + public OnlyOfficeAPIServlet(final SystemInformationService sysInfoService, final UserAccessor userAccessor, + final SettingsManager settingsManager, final JwtManager jwtManager, final DocumentManager documentManager, final AttachmentUtil attachmentUtil, final ParsingUtil parsingUtil, final UrlManager urlManager, - final ConfigurationManager configurationManager) { + final RequestManager requestManager) { this.sysInfoService = sysInfoService; + this.userAccessor = userAccessor; + this.settingsManager = settingsManager; this.jwtManager = jwtManager; this.documentManager = documentManager; this.attachmentUtil = attachmentUtil; this.parsingUtil = parsingUtil; this.urlManager = urlManager; - this.configurationManager = configurationManager; + this.requestManager = requestManager; } @Override @@ -94,6 +106,9 @@ public void doPost(final HttpServletRequest request, final HttpServletResponse r case "reference-data": referenceData(request, response); break; + case "users-info": + usersInfo(request, response); + break; default: response.sendError(HttpServletResponse.SC_NOT_FOUND); return; @@ -134,30 +149,23 @@ private void saveAs(final HttpServletRequest request, final HttpServletResponse return; } - downloadUrl = urlManager.replaceDocEditorURLToInternal(downloadUrl); - - try (CloseableHttpClient httpClient = configurationManager.getHttpClient()) { - HttpGet httpGet = new HttpGet(downloadUrl); - - try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) { - int status = httpResponse.getStatusLine().getStatusCode(); - HttpEntity entity = httpResponse.getEntity(); + downloadUrl = urlManager.replaceToInnerDocumentServerUrl(downloadUrl); - if (status == HttpStatus.SC_OK) { - byte[] bytes = IOUtils.toByteArray(entity.getContent()); - InputStream inputStream = new ByteArrayInputStream(bytes); + requestManager.executeGetRequest(downloadUrl, new RequestManager.Callback() { + @Override + public Void doWork(final Object response) throws Exception { + byte[] bytes = IOUtils.toByteArray(((HttpEntity) response).getContent()); + InputStream inputStream = new ByteArrayInputStream(bytes); - log.info("size = " + bytes.length); + log.info("size = " + bytes.length); - String fileName = documentManager.getCorrectName(title, ext, pageId); - String mimeType = documentManager.getMimeType(fileName); + String fileName = attachmentUtil.getCorrectName(title, ext, pageId); + String mimeType = documentManager.getMimeType(fileName); - attachmentUtil.createNewAttachment(fileName, mimeType, inputStream, bytes.length, pageId, user); - } else { - throw new HttpException("Document Server returned code " + status); - } + attachmentUtil.createNewAttachment(fileName, mimeType, inputStream, bytes.length, pageId, user); + return null; } - } + }); } catch (Exception e) { throw new IOException(e.getMessage()); } @@ -188,16 +196,16 @@ private void attachmentData(final HttpServletRequest request, final HttpServletR if (attachmentUtil.checkAccess(attachmentId, user, false)) { Map data = new HashMap<>(); - String fileType = attachmentUtil.getFileExt(attachmentId); + String documentName = documentManager.getDocumentName(String.valueOf(attachmentId)); + String fileType = documentManager.getExtension(documentName); - if (bodyJson.has("command")) { + if (!bodyJson.get("command").equals(null)) { data.put("command", bodyJson.getString("command")); } data.put("fileType", fileType); - data.put("url", urlManager.getFileUri(attachmentId)); - if (jwtManager.jwtEnabled()) { - JSONObject dataJSON = new JSONObject(gson.toJson(data)); - data.put("token", jwtManager.createToken(dataJSON)); + data.put("url", urlManager.getFileUrl(String.valueOf(attachmentId))); + if (settingsManager.isSecurityEnabled()) { + data.put("token", jwtManager.createToken(data)); } responseJson.add(data); @@ -226,13 +234,14 @@ private void referenceData(final HttpServletRequest request, final HttpServletRe try { JSONObject bodyJson = new JSONObject(body); - JSONObject referenceData = new JSONObject(); + ReferenceData referenceData = new ReferenceData(); Long attachmentId = null; if (bodyJson.has("referenceData")) { - referenceData = bodyJson.getJSONObject("referenceData"); - if (referenceData.getString("instanceId").equals(sysInfoService.getConfluenceInfo().getBaseUrl())) { - attachmentId = referenceData.getLong("fileKey"); + String referenceDataString = bodyJson.getJSONObject("referenceData").toString(); + referenceData = objectMapper.readValue(referenceDataString, ReferenceData.class); + if (referenceData.getInstanceId().equals(sysInfoService.getConfluenceInfo().getBaseUrl())) { + attachmentId = Long.valueOf(referenceData.getFileKey()); } } @@ -246,8 +255,8 @@ private void referenceData(final HttpServletRequest request, final HttpServletRe attachment = attachmentUtil.getAttachmentByName(bodyJson.getString("path"), pageId); if (attachment != null) { attachmentId = attachment.getId(); - referenceData.put("fileKey", attachment.getId()); - referenceData.put("instanceId", sysInfoService.getConfluenceInfo().getBaseUrl()); + referenceData.setFileKey(String.valueOf(attachment.getId())); + referenceData.setInstanceId(sysInfoService.getConfluenceInfo().getBaseUrl()); } } } @@ -262,22 +271,83 @@ private void referenceData(final HttpServletRequest request, final HttpServletRe return; } - JSONObject responseJson = new JSONObject(); + Map responseMap = new HashMap<>(); - responseJson.put("fileType", attachmentUtil.getFileExt(attachmentId)); - responseJson.put("path", attachmentUtil.getFileName(attachmentId)); - responseJson.put("referenceData", referenceData); - responseJson.put("url", urlManager.getFileUri(attachmentId)); + String documentName = documentManager.getDocumentName(String.valueOf(attachmentId)); + String extension = documentManager.getExtension(documentName); - if (jwtManager.jwtEnabled()) { - responseJson.put("token", jwtManager.createToken(responseJson)); + responseMap.put("fileType", extension); + responseMap.put("path", documentName); + responseMap.put("referenceData", referenceData); + responseMap.put("url", urlManager.getFileUrl(String.valueOf(attachmentId))); + + if (settingsManager.isSecurityEnabled()) { + responseMap.put("token", jwtManager.createToken(responseMap)); } response.setContentType("application/json"); PrintWriter writer = response.getWriter(); - writer.write(responseJson.toString()); + writer.write(objectMapper.writeValueAsString(responseMap)); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } + + private void usersInfo(final HttpServletRequest request, final HttpServletResponse response) throws IOException { + ConfluenceUser currentUser = AuthenticatedUserThreadLocal.get(); + + if (currentUser == null) { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + UsersInfoRequest usersInfoRequest = new UsersInfoRequest(); + + try (InputStream requestStream = request.getInputStream()) { + String bodyString = parsingUtil.getBody(requestStream); + + if (bodyString.isEmpty()) { + throw new IllegalArgumentException("requestBody is empty"); + } + + usersInfoRequest = objectMapper.readValue(bodyString, UsersInfoRequest.class); + } catch (IOException e) { + throw e; + } + + List users = new ArrayList<>(); + + for (String userKeyString : usersInfoRequest.getIds()) { + UserKey userKey = new UserKey(userKeyString); + ConfluenceUser confluenceUser = userAccessor.getUserByKey(userKey); + + if (confluenceUser != null) { + User user = User.builder() + .id(confluenceUser.getKey().getStringValue()) + .name(confluenceUser.getFullName()) + .build(); + + ProfilePictureInfo profilePictureInfo = userAccessor.getUserProfilePicture(confluenceUser); + + if (profilePictureInfo != null && !profilePictureInfo.isDefault()) { + try (InputStream pictureInputStream = profilePictureInfo.getBytes()) { + byte[] pictureByteArray = IOUtils.toByteArray(pictureInputStream); + String pictureBase64 = Base64.getEncoder().encodeToString(pictureByteArray); + String contentType = profilePictureInfo.getContentType(); + + user.setImage("data:" + contentType + ";base64," + pictureBase64); + } + } + + users.add(user); + } + } + + UsersInfoResponse usersInfoResponse = new UsersInfoResponse(); + usersInfoResponse.setUsers(users); + + response.setContentType("application/json"); + PrintWriter writer = response.getWriter(); + writer.write(objectMapper.writeValueAsString(usersInfoResponse)); + } } diff --git a/src/main/java/onlyoffice/OnlyOfficeConfServlet.java b/src/main/java/onlyoffice/OnlyOfficeConfServlet.java index 89fa9483..13cbbeb8 100644 --- a/src/main/java/onlyoffice/OnlyOfficeConfServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeConfServlet.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,55 +21,54 @@ import com.atlassian.confluence.renderer.radeox.macros.MacroUtils; import com.atlassian.confluence.setup.settings.SettingsManager; import com.atlassian.confluence.util.velocity.VelocityUtils; -import com.atlassian.sal.api.pluginsettings.PluginSettings; -import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; import com.atlassian.sal.api.user.UserManager; import com.atlassian.spring.container.ContainerManager; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.managers.jwt.JwtManager; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onlyoffice.model.settings.Settings; +import com.onlyoffice.model.settings.SettingsConstants; +import com.onlyoffice.model.settings.security.Security; +import com.onlyoffice.model.settings.validation.ValidationResult; +import onlyoffice.sdk.manager.document.DocumentManager; +import onlyoffice.sdk.manager.url.UrlManager; +import onlyoffice.sdk.service.SettingsValidationService; import onlyoffice.utils.parsing.ParsingUtil; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.io.IOUtils; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import org.json.JSONArray; -import org.json.JSONObject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.beans.IntrospectionException; import java.io.IOException; import java.io.PrintWriter; -import java.io.StringWriter; import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; import java.util.Map; public class OnlyOfficeConfServlet extends HttpServlet { private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeConfServlet"); + private final ObjectMapper objectMapper = new ObjectMapper(); + private final long serialVersionUID = 1L; - private static final int ERROR_INVALID_TOKEN = 6; private final UserManager userManager; - private final PluginSettingsFactory pluginSettingsFactory; - private final JwtManager jwtManager; - private final ConfigurationManager configurationManager; + private final com.onlyoffice.manager.settings.SettingsManager settingsManager; + private final DocumentManager documentManager; private final ParsingUtil parsingUtil; + private final SettingsValidationService settingsValidationService; - public OnlyOfficeConfServlet(final UserManager userManager, final PluginSettingsFactory pluginSettingsFactory, - final JwtManager jwtManager, final ConfigurationManager configurationManager, - final ParsingUtil parsingUtil) { + public OnlyOfficeConfServlet(final UserManager userManager, + final com.onlyoffice.manager.settings.SettingsManager settingsManager, + final DocumentManager documentManager, final UrlManager urlManager, + final ParsingUtil parsingUtil, + final SettingsValidationService settingsValidationService) { this.userManager = userManager; - this.pluginSettingsFactory = pluginSettingsFactory; - this.jwtManager = jwtManager; - this.configurationManager = configurationManager; + this.settingsManager = settingsManager; + this.documentManager = documentManager; this.parsingUtil = parsingUtil; + this.settingsValidationService = settingsValidationService; } @Override @@ -83,58 +82,50 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re return; } - PluginSettings pluginSettings = pluginSettingsFactory.createGlobalSettings(); - String apiUrl = (String) pluginSettings.get("onlyoffice.apiUrl"); - String jwtSecret = (String) pluginSettings.get("onlyoffice.jwtSecret"); - String docInnerUrl = (String) pluginSettings.get("onlyoffice.docInnerUrl"); - String confUrl = (String) pluginSettings.get("onlyoffice.confUrl"); - Boolean verifyCertificate = configurationManager.getBooleanPluginSetting("verifyCertificate", false); - Boolean forceSave = configurationManager.forceSaveEnabled(); - Boolean chat = configurationManager.getBooleanPluginSetting("chat", true); - Boolean compactHeader = configurationManager.getBooleanPluginSetting("compactHeader", false); - Boolean feedback = configurationManager.getBooleanPluginSetting("feedback", false); - Boolean helpMenu = configurationManager.getBooleanPluginSetting("helpMenu", true); - Boolean toolbarNoTabs = configurationManager.getBooleanPluginSetting("toolbarNoTabs", false); - String reviewDisplay = configurationManager.getStringPluginSetting("reviewDisplay", "original"); - Boolean demo = configurationManager.demoEnabled(); - Boolean demoAvailable = configurationManager.demoAvailable(true); - Map defaultCustomizableEditingTypes = configurationManager.getCustomizableEditingTypes(); - - if (apiUrl == null || apiUrl.isEmpty()) { - apiUrl = ""; - } - if (jwtSecret == null || jwtSecret.isEmpty()) { - jwtSecret = ""; - } - if (docInnerUrl == null || docInnerUrl.isEmpty()) { - docInnerUrl = ""; - } - if (confUrl == null || confUrl.isEmpty()) { - confUrl = ""; - } + Boolean demoAvailable = settingsManager.isDemoAvailable(); + Map defaultCustomizableEditingTypes = documentManager.getLossyEditableMap(); response.setContentType("text/html;charset=UTF-8"); PrintWriter writer = response.getWriter(); Map contextMap = MacroUtils.defaultVelocityContext(); - contextMap.put("docserviceApiUrl", apiUrl); - contextMap.put("docserviceInnerUrl", docInnerUrl); - contextMap.put("docserviceConfUrl", confUrl); - contextMap.put("docserviceJwtSecret", jwtSecret); - contextMap.put("verifyCertificate", verifyCertificate); - contextMap.put("forceSave", forceSave); - contextMap.put("chat", chat); - contextMap.put("compactHeader", compactHeader); - contextMap.put("feedback", feedback); - contextMap.put("helpMenu", helpMenu); - contextMap.put("toolbarNoTabs", toolbarNoTabs); - contextMap.put("reviewDisplay", reviewDisplay); - contextMap.put("docserviceDemo", demo); - contextMap.put("docserviceDemoAvailable", demoAvailable); - contextMap.put("pathApiUrl", configurationManager.getProperty("files.docservice.url.api")); + contextMap.put("demoAvailable", demoAvailable); + contextMap.put("pathApiUrl", settingsManager.getDocsIntegrationSdkProperties().getDocumentServer().getApiUrl()); + + if (settingsManager.getSetting(SettingsConstants.LOSSY_EDIT) == null + || settingsManager.getSetting(SettingsConstants.LOSSY_EDIT).isEmpty()) { + defaultCustomizableEditingTypes.put("txt", true); + defaultCustomizableEditingTypes.put("csv", true); + } + contextMap.put("defaultCustomizableEditingTypes", defaultCustomizableEditingTypes); + try { + Map settings = settingsManager.getSettings(); + + if (settings.get("customization.review.reviewDisplay") == null + || settings.get("customization.review.reviewDisplay").isEmpty()) { + settings.put("customization.review.reviewDisplay", "ORIGINAL"); + } + + if (settings.get("customization.help") == null || settings.get("customization.help").isEmpty()) { + settings.put("customization.help", "true"); + } + + if (settings.get("customization.chat") == null || settings.get("customization.chat").isEmpty()) { + settings.put("customization.chat", "true"); + } + + contextMap.put("settings", settings); + } catch (IntrospectionException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + writer.write(getTemplate(contextMap)); } @@ -157,157 +148,39 @@ public void doPost(final HttpServletRequest request, final HttpServletResponse r return; } - String apiUrl; - String docInnerUrl; - String jwtSecret; - PluginSettings pluginSettings = pluginSettingsFactory.createGlobalSettings(); - try { - JSONObject jsonObj = new JSONObject(body); - - Boolean demo = jsonObj.getBoolean("demo"); - configurationManager.selectDemo(demo); - - if (configurationManager.demoActive()) { - apiUrl = configurationManager.getDemo("url"); - docInnerUrl = configurationManager.getDemo("url"); - } else { - apiUrl = appendSlash(jsonObj.getString("apiUrl")); - jwtSecret = jsonObj.getString("jwtSecret"); - docInnerUrl = appendSlash(jsonObj.getString("docInnerUrl")); - Boolean verifyCertificate = jsonObj.getBoolean("verifyCertificate"); - pluginSettings.put("onlyoffice.apiUrl", apiUrl); - pluginSettings.put("onlyoffice.jwtSecret", jwtSecret); - pluginSettings.put("onlyoffice.docInnerUrl", docInnerUrl); - pluginSettings.put("onlyoffice.verifyCertificate", verifyCertificate.toString()); - } - - String confUrl = appendSlash(jsonObj.getString("confUrl")); - Boolean forceSave = jsonObj.getBoolean("forceSave"); - Boolean chat = jsonObj.getBoolean("chat"); - Boolean compactHeader = jsonObj.getBoolean("compactHeader"); - Boolean feedback = jsonObj.getBoolean("feedback"); - Boolean helpMenu = jsonObj.getBoolean("helpMenu"); - Boolean toolbarNoTabs = jsonObj.getBoolean("toolbarNoTabs"); - String reviewDisplay = jsonObj.getString("reviewDisplay"); - JSONArray editingTypes = jsonObj.getJSONArray("editingTypes"); - - pluginSettings.put("onlyoffice.confUrl", confUrl); - pluginSettings.put("onlyoffice.forceSave", forceSave.toString()); - pluginSettings.put("onlyoffice.chat", chat.toString()); - pluginSettings.put("onlyoffice.compactHeader", compactHeader.toString()); - pluginSettings.put("onlyoffice.feedback", feedback.toString()); - pluginSettings.put("onlyoffice.helpMenu", helpMenu.toString()); - pluginSettings.put("onlyoffice.toolbarNoTabs", toolbarNoTabs.toString()); - pluginSettings.put("onlyoffice.reviewDisplay", reviewDisplay); - pluginSettings.put("onlyoffice.editingTypes", editingTypes.toString()); - - } catch (Exception ex) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - ex.printStackTrace(pw); - String error = ex.toString() + "\n" + sw.toString(); - log.error(error); - - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - response.getWriter().write("{\"success\": false, \"message\": \"jsonparse\"}"); - return; - } - - log.debug("Checking docserv url"); - if (!checkDocServUrl((docInnerUrl == null || docInnerUrl.isEmpty()) ? apiUrl : docInnerUrl)) { - response.getWriter().write("{\"success\": false, \"message\": \"docservunreachable\"}"); - return; - } - - try { - log.debug("Checking docserv commandservice"); - if (!checkDocServCommandService((docInnerUrl == null || docInnerUrl.isEmpty()) ? apiUrl : docInnerUrl)) { - response.getWriter().write("{\"success\": false, \"message\": \"docservcommand\"}"); - return; - } - } catch (SecurityException ex) { - response.getWriter().write("{\"success\": false, \"message\": \"jwterror\"}"); - return; - } - - response.getWriter().write("{\"success\": true}"); - } + Settings settings = objectMapper.readValue(body, Settings.class); - private String appendSlash(final String str) { - if (str == null || str.isEmpty() || str.endsWith("/")) { - return str; + if (settings.getDemo() != null && settings.getDemo()) { + settingsManager.enableDemo(); } else { - return str + "/"; + settingsManager.disableDemo(); } - } - private Boolean checkDocServUrl(final String url) { - try (CloseableHttpClient httpClient = configurationManager.getHttpClient()) { - HttpGet request = new HttpGet(url + "healthcheck"); - try (CloseableHttpResponse response = httpClient.execute(request)) { + if (settingsManager.isDemoActive()) { + Security security = settings.getSecurity(); + security.setKey(null); + security.setHeader(null); - String content = IOUtils.toString(response.getEntity().getContent(), "utf-8").trim(); - if (content.equalsIgnoreCase("true")) { - return true; - } - } - } catch (Exception e) { - log.debug("/healthcheck error: " + e.getMessage()); + settings.setUrl(null); + settings.setInnerUrl(null); + settings.setSecurity(security); } - return false; - } - - private Boolean checkDocServCommandService(final String url) throws SecurityException { - Integer errorCode = -1; - try (CloseableHttpClient httpClient = configurationManager.getHttpClient()) { - JSONObject body = new JSONObject(); - body.put("c", "version"); - - HttpPost request = new HttpPost(url + "coauthoring/CommandService.ashx"); - - if (jwtManager.jwtEnabled()) { - String token = jwtManager.createToken(body); - JSONObject payloadBody = new JSONObject(); - payloadBody.put("payload", body); - String headerToken = jwtManager.createToken(body); - body.put("token", token); - String header = jwtManager.getJwtHeader(); - request.setHeader(header, "Bearer " + headerToken); - } - - StringEntity requestEntity = new StringEntity(body.toString(), ContentType.APPLICATION_JSON); - request.setEntity(requestEntity); - request.setHeader("Accept", "application/json"); - - log.debug("Sending POST to Docserver: " + body.toString()); - try (CloseableHttpResponse response = httpClient.execute(request)) { - int status = response.getStatusLine().getStatusCode(); + try { + settingsManager.setSettings(settings); + } catch (IntrospectionException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } - if (status != HttpStatus.SC_OK) { - return false; - } else { - String content = IOUtils.toString(response.getEntity().getContent(), "utf-8"); - log.debug("/CommandService content: " + content); - JSONObject callBackJson = null; - callBackJson = new JSONObject(content); + Map validationResults = settingsValidationService.validateSettings(); - if (callBackJson.isNull("error")) { - return false; - } + Map responseMap = new HashMap<>(); + responseMap.put("validationResults", validationResults); - errorCode = callBackJson.getInt("error"); - } - } - } catch (Exception e) { - log.debug("/CommandService error: " + e.getMessage()); - return false; - } - - if (errorCode == ERROR_INVALID_TOKEN) { - throw new SecurityException(); - } else { - return errorCode == 0; - } + response.getWriter().write(objectMapper.writeValueAsString(responseMap)); } } diff --git a/src/main/java/onlyoffice/OnlyOfficeConvertServlet.java b/src/main/java/onlyoffice/OnlyOfficeConvertServlet.java index a88c5b25..c7eb63d6 100644 --- a/src/main/java/onlyoffice/OnlyOfficeConvertServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeConvertServlet.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,24 +18,24 @@ package onlyoffice; +import com.atlassian.confluence.languages.LocaleManager; import com.atlassian.confluence.pages.Attachment; import com.atlassian.confluence.pages.AttachmentManager; import com.atlassian.confluence.renderer.radeox.macros.MacroUtils; import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.confluence.util.velocity.VelocityUtils; +import com.onlyoffice.manager.request.RequestManager; +import com.onlyoffice.model.common.CommonResponse; +import com.onlyoffice.model.common.Format; +import com.onlyoffice.model.convertservice.ConvertRequest; +import com.onlyoffice.model.convertservice.ConvertResponse; +import com.onlyoffice.service.convert.ConvertService; import onlyoffice.managers.auth.AuthContext; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.managers.convert.ConvertManager; -import onlyoffice.managers.document.DocumentManager; +import onlyoffice.sdk.manager.document.DocumentManager; import onlyoffice.utils.attachment.AttachmentUtil; import org.apache.commons.io.IOUtils; import org.apache.http.HttpEntity; -import org.apache.http.HttpException; -import org.apache.http.HttpStatus; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.json.JSONObject; @@ -48,7 +48,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; -import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.util.Map; @@ -56,23 +55,25 @@ public class OnlyOfficeConvertServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeConvertServlet"); + private final LocaleManager localeManager; private final AttachmentManager attachmentManager; private final AttachmentUtil attachmentUtil; - private final ConvertManager convertManager; + private final ConvertService convertService; private final AuthContext authContext; private final DocumentManager documentManager; - private final ConfigurationManager configurationManager; + private final RequestManager requestManager; - public OnlyOfficeConvertServlet(final AttachmentManager attachmentManager, final AttachmentUtil attachmentUtil, - final ConvertManager convertManager, final AuthContext authContext, - final DocumentManager documentManager, - final ConfigurationManager configurationManager) { + public OnlyOfficeConvertServlet(final LocaleManager localeManager, final AttachmentManager attachmentManager, + final AttachmentUtil attachmentUtil, final ConvertService convertService, + final AuthContext authContext, final DocumentManager documentManager, + final RequestManager requestManager) { + this.localeManager = localeManager; this.attachmentManager = attachmentManager; this.attachmentUtil = attachmentUtil; - this.convertManager = convertManager; + this.convertService = convertService; this.authContext = authContext; this.documentManager = documentManager; - this.configurationManager = configurationManager; + this.requestManager = requestManager; } @Override @@ -94,8 +95,21 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re Map contextMap = MacroUtils.defaultVelocityContext(); Long pageId = attachment.getContainer().getId(); String fileName = attachment.getFileName(); - String ext = attachment.getFileExtension(); - String newExt = convertManager.getTargetExt(ext); + String newFileExtension = documentManager.getDefaultConvertExtension(fileName); + + String extension = documentManager.getExtension(fileName); + Format docx = documentManager.getFormats().stream() + .filter(format -> format.getName().equals("docx")) + .findFirst() + .get(); + + if (docx != null + && extension.equals(docx.getName()) + && docx.getConvert() != null + && docx.getConvert().contains("docxf")) { + newFileExtension = "docxf"; + } + String title = fileName.substring(0, fileName.lastIndexOf(".")); if (pageIdString != null && !pageIdString.isEmpty()) { @@ -108,7 +122,7 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re title = newTitle; } - String newName = documentManager.getCorrectName(title, newExt, pageId); + String newName = documentManager.getCorrectNewFileName(title, newFileExtension, pageId); contextMap.put("attachmentId", attachmentIdString); contextMap.put("oldName", fileName); @@ -132,69 +146,89 @@ public void doPost(final HttpServletRequest request, final HttpServletResponse r String errorMessage = null; JSONObject json = null; - try { - Long attachmentId = Long.parseLong(attachmentIdString); - log.info("attachmentId " + attachmentId); - Attachment attachment = attachmentManager.getAttachment(attachmentId); + Long attachmentId = Long.parseLong(attachmentIdString); + log.info("attachmentId " + attachmentId); - user = AuthenticatedUserThreadLocal.get(); - log.info("user " + user); + Attachment attachment = attachmentManager.getAttachment(attachmentId); - String fileName = attachment.getFileName(); - String ext = attachment.getFileExtension(); - String title = fileName.substring(0, fileName.lastIndexOf(".")); + user = AuthenticatedUserThreadLocal.get(); + log.info("user " + user); - String pageIdAsString = request.getParameter("pageId"); - String newTitle = request.getParameter("newTitle"); + String fileName = attachment.getFileName(); + String title = fileName.substring(0, fileName.lastIndexOf(".")); - if (newTitle != null && !newTitle.isEmpty()) { - title = newTitle; - } + String pageIdAsString = request.getParameter("pageId"); + String newTitle = request.getParameter("newTitle"); - Long pageId = null; - if (pageIdAsString != null && !pageIdAsString.isEmpty()) { - pageId = Long.parseLong(pageIdAsString); - } else { - pageId = attachment.getContainer().getId(); - } + if (newTitle != null && !newTitle.isEmpty()) { + title = newTitle; + } - String convertToExt = convertManager.getTargetExt(ext); - - if (attachmentUtil.checkAccess(attachmentId, user, false) - && attachmentUtil.checkAccessCreate(user, pageId)) { - if (convertToExt != null) { - json = convertManager.convert(attachmentId, ext, convertToExt, user, null); - - if (json.has("endConvert") && json.getBoolean("endConvert")) { - String newFileName = documentManager.getCorrectName(title, convertToExt, pageId); - Long newAttachmentId = savefile(attachment, json.getString("fileUrl"), newFileName, pageId); - json.put("attachmentId", newAttachmentId); - } else if (json.has("error")) { - errorMessage = "Unknown conversion error"; - } - } else { - errorMessage = "Files of " + ext + " format cannot be converted"; - } - } else { - log.error("access deny"); - errorMessage = "You don not have enough permission to convert the file"; - } - } catch (Exception ex) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - ex.printStackTrace(pw); - String error = ex.toString() + "\n" + sw.toString(); - log.error(error); - errorMessage = ex.toString(); + Long pageId = null; + if (pageIdAsString != null && !pageIdAsString.isEmpty()) { + pageId = Long.parseLong(pageIdAsString); + } else { + pageId = attachment.getContainer().getId(); + } + + String convertToExt = documentManager.getDefaultConvertExtension(fileName); + + String extension = documentManager.getExtension(fileName); + Format docx = documentManager.getFormats().stream() + .filter(format -> format.getName().equals("docx")) + .findFirst() + .get(); + + if (docx != null + && extension.equals(docx.getName()) + && docx.getConvert() != null + && docx.getConvert().contains("docxf")) { + convertToExt = "docxf"; + } + + if (!attachmentUtil.checkAccess(attachmentId, user, false) + || !attachmentUtil.checkAccessCreate(user, pageId)) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + return; + } + + if (convertToExt == null) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; } response.setContentType("application/json"); PrintWriter writer = response.getWriter(); - if (errorMessage != null) { - writer.write("{\"error\":\"" + errorMessage + "\"}"); - } else { + + try { + String region = localeManager.getLocale(user).toLanguageTag(); + + ConvertRequest convertRequest = ConvertRequest.builder() + .async(true) + .outputtype(convertToExt) + .region(region) + .build(); + + ConvertResponse convertResponse = convertService.processConvert(convertRequest, + String.valueOf(attachmentId)); + + json = new JSONObject(convertResponse); + + if (convertResponse.getEndConvert() != null && convertResponse.getEndConvert()) { + String newFileName = documentManager.getCorrectNewFileName(title, convertToExt, pageId); + Long newAttachmentId = savefile(attachment, convertResponse.getFileUrl(), newFileName, pageId); + json.put("attachmentId", newAttachmentId); + } + + writer.write(json.toString()); + } catch (IOException e) { + CommonResponse commonResponse = new CommonResponse(); + commonResponse.setError(CommonResponse.Error.CONNECTION); + json = new JSONObject(commonResponse); writer.write(json.toString()); + } catch (Exception e) { + throw new RuntimeException(e); } } @@ -202,33 +236,25 @@ private Long savefile(final Attachment attachment, final String fileUrl, final S throws Exception { log.info("downloadUri = " + fileUrl); - try (CloseableHttpClient httpClient = configurationManager.getHttpClient()) { - HttpGet request = new HttpGet(fileUrl); + return requestManager.executeGetRequest(fileUrl, new RequestManager.Callback() { + @Override + public Long doWork(final Object response) throws Exception { + byte[] bytes = IOUtils.toByteArray(((HttpEntity) response).getContent()); + InputStream inputStream = new ByteArrayInputStream(bytes); - try (CloseableHttpResponse response = httpClient.execute(request)) { + Attachment copy = attachment.copyLatestVersion(); - int status = response.getStatusLine().getStatusCode(); - HttpEntity entity = response.getEntity(); + copy.setContainer(attachmentUtil.getContainer(pageId)); + copy.setFileName(newName); + copy.setFileSize(bytes.length); + copy.setMediaType(documentManager.getMimeType(newName)); - if (status == HttpStatus.SC_OK) { - byte[] bytes = IOUtils.toByteArray(entity.getContent()); - InputStream inputStream = new ByteArrayInputStream(bytes); + attachmentManager.saveAttachment(copy, null, inputStream); + attachmentUtil.setCollaborativeEditingKey(copy.getLatestVersionId(), null); - Attachment copy = attachment.copyLatestVersion(); - - copy.setContainer(attachmentUtil.getContainer(pageId)); - copy.setFileName(newName); - copy.setFileSize(bytes.length); - copy.setMediaType(documentManager.getMimeType(newName)); - - attachmentManager.saveAttachment(copy, null, inputStream); - - return copy.getLatestVersionId(); - } else { - throw new HttpException("Document Server returned code " + status); - } + return copy.getLatestVersionId(); } - } + }); } } diff --git a/src/main/java/onlyoffice/OnlyOfficeEditorServlet.java b/src/main/java/onlyoffice/OnlyOfficeEditorServlet.java index e62980f8..d816d412 100644 --- a/src/main/java/onlyoffice/OnlyOfficeEditorServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeEditorServlet.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,21 +18,23 @@ package onlyoffice; +import com.atlassian.confluence.languages.LocaleManager; import com.atlassian.confluence.pages.BlogPost; import com.atlassian.confluence.renderer.radeox.macros.MacroUtils; import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.confluence.util.velocity.VelocityUtils; import com.atlassian.sal.api.message.I18nResolver; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onlyoffice.manager.settings.SettingsManager; +import com.onlyoffice.model.documenteditor.Config; +import com.onlyoffice.model.documenteditor.config.document.DocumentType; +import com.onlyoffice.model.documenteditor.config.editorconfig.Mode; +import com.onlyoffice.service.documenteditor.config.ConfigService; import onlyoffice.managers.auth.AuthContext; import com.atlassian.confluence.pages.Attachment; -import onlyoffice.managers.config.ConfigManager; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.managers.document.DocumentManager; -import onlyoffice.managers.url.UrlManager; -import onlyoffice.model.config.DocumentType; -import onlyoffice.model.config.Type; -import onlyoffice.model.config.editor.Mode; +import onlyoffice.sdk.manager.document.DocumentManager; +import onlyoffice.sdk.manager.url.UrlManager; import onlyoffice.utils.attachment.AttachmentUtil; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; @@ -44,33 +46,39 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.io.InputStream; import java.io.PrintWriter; import java.net.URLEncoder; import java.util.Map; +import static onlyoffice.sdk.manager.url.UrlManagerImpl.DOC_EDITOR_SERVLET; + public class OnlyOfficeEditorServlet extends HttpServlet { private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeEditorServlet"); private final long serialVersionUID = 1L; private final I18nResolver i18n; private final UrlManager urlManager; - private final ConfigurationManager configurationManager; private final AuthContext authContext; private final DocumentManager documentManager; private final AttachmentUtil attachmentUtil; - private final ConfigManager configManager; + private final ConfigService configService; + private final SettingsManager settingsManager; + + private final LocaleManager localeManager; - public OnlyOfficeEditorServlet(final I18nResolver i18n, final UrlManager urlManager, - final ConfigurationManager configurationManager, final AuthContext authContext, + public OnlyOfficeEditorServlet(final I18nResolver i18n, final UrlManager urlManager, final AuthContext authContext, final DocumentManager documentManager, final AttachmentUtil attachmentUtil, - final ConfigManager configManager) { + final ConfigService configService, final SettingsManager settingsManager, + final LocaleManager localeManager) { this.i18n = i18n; this.urlManager = urlManager; - this.configurationManager = configurationManager; this.authContext = authContext; this.documentManager = documentManager; this.attachmentUtil = attachmentUtil; - this.configManager = configManager; + this.configService = configService; + this.settingsManager = settingsManager; + this.localeManager = localeManager; } @Override @@ -80,8 +88,7 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re String attachmentIdString = request.getParameter("attachmentId"); String actionDataString = request.getParameter("actionData"); - String referer = request.getHeader("referer"); - + String modeString = request.getParameter("mode"); if (attachmentIdString == null || attachmentIdString.isEmpty()) { if (!authContext.checkUserAuthorization(request, response)) { return; @@ -97,10 +104,30 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re return; } - Long attachmentId = documentManager.createDemo(fileName, fileExt, Long.parseLong(pageId), user); - - response.sendRedirect(request.getContextPath() + "?attachmentId=" - + URLEncoder.encode(attachmentId.toString(), "UTF-8")); + String extension = fileExt == null + || !fileExt.equals("xlsx") + && !fileExt.equals("pptx") + && !fileExt.equals("docxf") + ? "docx" : fileExt.trim(); + + String name = fileName == null || fileName.equals("") + ? i18n.getText("onlyoffice.editor.dialog.filecreate." + extension) : fileName; + + name = attachmentUtil.getCorrectName(name, extension, Long.parseLong(pageId)); + String mimeType = documentManager.getMimeType(name); + InputStream newBlankFile = documentManager.getNewBlankFile(extension, localeManager.getLocale(user)); + + Attachment attachment = attachmentUtil.createNewAttachment( + name, + mimeType, + newBlankFile, + newBlankFile.available(), + Long.parseLong(pageId), + user + ); + + response.sendRedirect(request.getContextPath() + DOC_EDITOR_SERVLET + "?attachmentId=" + + URLEncoder.encode(String.valueOf(attachment.getId()), "UTF-8")); return; } } @@ -109,8 +136,8 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re Long attachmentId = Long.parseLong(attachmentIdString); Long pageId = attachmentUtil.getAttachmentPageId(attachmentId); Attachment attachment = attachmentUtil.getAttachment(attachmentId); - String extension = attachmentUtil.getFileExt(attachmentId); - DocumentType documentType = documentManager.getDocType(extension); + String fileName = documentManager.getDocumentName(String.valueOf(attachmentId)); + DocumentType documentType = documentManager.getDocumentType(fileName); if (attachment == null) { response.sendError(HttpServletResponse.SC_NOT_FOUND); @@ -123,8 +150,8 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re } Map context = MacroUtils.defaultVelocityContext(); - context.put("docserviceApiUrl", urlManager.getDocServiceApiUrl()); - context.put("docTitle", attachmentUtil.getFileName(attachmentId)); + context.put("docserviceApiUrl", urlManager.getDocumentServerApiUrl()); + context.put("docTitle", documentManager.getDocumentName(String.valueOf(attachmentId))); context.put("favicon", urlManager.getFaviconUrl(documentType)); context.put("pageId", pageId); context.put("pageTitle", attachmentUtil.getAttachmentPageTitle(attachmentId)); @@ -133,28 +160,45 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re context.put("isBlogPost", String.valueOf(attachmentUtil.getContainer(pageId) instanceof BlogPost)); if (documentType != null) { - Type type = documentManager.getEditorType(request.getHeader("USER-AGENT")); - JSONObject actionData = null; if (actionDataString != null && !actionDataString.isEmpty()) { actionData = new JSONObject(actionDataString); } - String config = configManager.createConfig(attachmentId, Mode.EDIT, type, actionData, referer); - context.put("configAsHtml", config); + Mode mode = Mode.EDIT; + + if (modeString != null && modeString.equals("view")) { + mode = Mode.VIEW; + } + + Config config = configService.createConfig( + attachmentId.toString(), + mode, + request.getHeader("USER-AGENT") + ); + + config.getEditorConfig().setLang(localeManager.getLocale(user).toLanguageTag()); + config.getEditorConfig().setActionLink(actionData); + + ObjectMapper mapper = new ObjectMapper(); + + context.put("configAsHtml", mapper.writeValueAsString(config)); context.put("historyInfoUriAsHtml", urlManager.getHistoryInfoUri(attachmentId)); context.put("historyDataUriAsHtml", urlManager.getHistoryDataUri(attachmentId)); context.put("attachmentDataAsHtml", urlManager.getAttachmentDataUri()); context.put("saveAsUriAsHtml", urlManager.getSaveAsUri()); context.put("referenceDataUriAsHtml", urlManager.getReferenceDataUri(pageId)); - context.put("insertImageTypesAsHtml", new JSONArray(documentManager.getInsertImageTypes()).toString()); - context.put("compareFileTypesAsHtml", new JSONArray(documentManager.getCompareFileTypes()).toString()); - context.put("mailMergeTypesAsHtml", new JSONArray(documentManager.getMailMergeTypes()).toString()); - context.put("demo", configurationManager.demoActive()); + context.put("insertImageTypesAsHtml", + new JSONArray(documentManager.getInsertImageExtensions()).toString()); + context.put("compareFileTypesAsHtml", + new JSONArray(documentManager.getCompareFileExtensions()).toString()); + context.put("mailMergeTypesAsHtml", new JSONArray(documentManager.getMailMergeExtensions()).toString()); + context.put("demo", settingsManager.isDemoActive()); + context.put("usersInfoUrlAsHtml", urlManager.getUsersInfoUrl()); } else { context.put("errorMessage", i18n.getText("onlyoffice.editor.message.error.unsupported") + "(." - + attachmentUtil.getFileExt(attachmentId) + ")"); + + documentManager.getExtension(fileName) + ")"); } response.setContentType("text/html;charset=UTF-8"); diff --git a/src/main/java/onlyoffice/OnlyOfficeFileProviderServlet.java b/src/main/java/onlyoffice/OnlyOfficeFileProviderServlet.java index f3df6e47..3ab76126 100644 --- a/src/main/java/onlyoffice/OnlyOfficeFileProviderServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeFileProviderServlet.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,9 @@ import com.atlassian.confluence.user.UserAccessor; import com.atlassian.sal.api.user.UserKey; import com.atlassian.spring.container.ContainerManager; -import onlyoffice.managers.jwt.JwtManager; + +import com.onlyoffice.manager.settings.SettingsManager; +import onlyoffice.sdk.manager.security.JwtManager; import onlyoffice.utils.attachment.AttachmentUtil; import org.json.JSONObject; @@ -40,19 +42,22 @@ public class OnlyOfficeFileProviderServlet extends HttpServlet { private final AttachmentUtil attachmentUtil; private final JwtManager jwtManager; + private final SettingsManager settingsManager; - public OnlyOfficeFileProviderServlet(final AttachmentUtil attachmentUtil, final JwtManager jwtManager) { + public OnlyOfficeFileProviderServlet(final AttachmentUtil attachmentUtil, final JwtManager jwtManager, + final SettingsManager settingsManager) { this.attachmentUtil = attachmentUtil; this.jwtManager = jwtManager; + this.settingsManager = settingsManager; } @Override public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { - if (jwtManager.jwtEnabled()) { - String jwth = jwtManager.getJwtHeader(); + if (settingsManager.isSecurityEnabled()) { + String jwth = settingsManager.getSecurityHeader(); String header = request.getHeader(jwth); - String authorizationPrefix = "Bearer "; + String authorizationPrefix = settingsManager.getSecurityPrefix(); String token = (header != null && header.startsWith(authorizationPrefix)) ? header.substring(authorizationPrefix.length()) : header; diff --git a/src/main/java/onlyoffice/OnlyOfficeFormatsServlet.java b/src/main/java/onlyoffice/OnlyOfficeFormatsServlet.java index bce10e48..3e40d6e4 100644 --- a/src/main/java/onlyoffice/OnlyOfficeFormatsServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeFormatsServlet.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,8 @@ package onlyoffice; import com.google.gson.Gson; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.model.Format; +import com.onlyoffice.model.common.Format; +import onlyoffice.sdk.manager.document.DocumentManager; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; @@ -36,15 +36,15 @@ public class OnlyOfficeFormatsServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeFormatsServlet"); - private final ConfigurationManager configurationManager; + private final DocumentManager documentManager; - public OnlyOfficeFormatsServlet(final ConfigurationManager configurationManager) { - this.configurationManager = configurationManager; + public OnlyOfficeFormatsServlet(final DocumentManager documentManager) { + this.documentManager = documentManager; } @Override public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException { - List supportedFormats = configurationManager.getSupportedFormats(); + List supportedFormats = documentManager.getFormats(); List result = new ArrayList<>(); for (Format format : supportedFormats) { diff --git a/src/main/java/onlyoffice/OnlyOfficeHistoryServlet.java b/src/main/java/onlyoffice/OnlyOfficeHistoryServlet.java index 286a7879..f12e9afd 100644 --- a/src/main/java/onlyoffice/OnlyOfficeHistoryServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeHistoryServlet.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,18 +26,22 @@ import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.confluence.user.ConfluenceUserPreferences; import com.atlassian.confluence.user.UserAccessor; -import com.atlassian.spring.container.ContainerManager; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; +import com.onlyoffice.model.common.Changes; +import com.onlyoffice.model.common.User; +import com.onlyoffice.model.documenteditor.HistoryData; +import com.onlyoffice.model.documenteditor.callback.History; +import com.onlyoffice.model.documenteditor.history.Version; +import com.onlyoffice.model.documenteditor.historydata.Previous; +import onlyoffice.sdk.manager.security.JwtManager; +import com.onlyoffice.manager.settings.SettingsManager; +import onlyoffice.sdk.manager.url.UrlManager; import onlyoffice.managers.auth.AuthContext; -import onlyoffice.managers.document.DocumentManager; -import onlyoffice.managers.jwt.JwtManager; -import onlyoffice.managers.url.UrlManager; +import onlyoffice.sdk.manager.document.DocumentManager; import onlyoffice.utils.attachment.AttachmentUtil; -import onlyoffice.utils.parsing.ParsingUtil; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import org.json.JSONException; -import org.json.JSONObject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -47,8 +51,12 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -60,26 +68,28 @@ public class OnlyOfficeHistoryServlet extends HttpServlet { private final LocaleManager localeManager; private final FormatSettingsManager formatSettingsManager; + private final UserAccessor userAccessor; private final AuthContext authContext; private final DocumentManager documentManager; private final AttachmentUtil attachmentUtil; private final UrlManager urlManager; + private final SettingsManager settingsManager; private final JwtManager jwtManager; - private final ParsingUtil parsingUtil; public OnlyOfficeHistoryServlet(final LocaleManager localeManager, - final FormatSettingsManager formatSettingsManager, + final FormatSettingsManager formatSettingsManager, final UserAccessor userAccessor, final AuthContext authContext, final DocumentManager documentManager, final AttachmentUtil attachmentUtil, final UrlManager urlManager, - final JwtManager jwtManager, final ParsingUtil parsingUtil) { + final SettingsManager settingsManager, final JwtManager jwtManager) { this.localeManager = localeManager; this.formatSettingsManager = formatSettingsManager; + this.userAccessor = userAccessor; this.authContext = authContext; this.documentManager = documentManager; this.attachmentUtil = attachmentUtil; this.urlManager = urlManager; + this.settingsManager = settingsManager; this.jwtManager = jwtManager; - this.parsingUtil = parsingUtil; } @Override @@ -109,8 +119,26 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re private void getAttachmentDiff(final HttpServletRequest request, final HttpServletResponse response) throws IOException { + if (settingsManager.isSecurityEnabled()) { + String securityHeader = settingsManager.getSecurityHeader(); + String bodySecurityHeader = request.getHeader(securityHeader); + String authorizationPrefix = settingsManager.getSecurityPrefix(); + String token = (bodySecurityHeader != null && bodySecurityHeader.startsWith(authorizationPrefix)) + ? bodySecurityHeader.substring(authorizationPrefix.length()) : bodySecurityHeader; + + if (token == null || token == "") { + throw new SecurityException("Expected JWT"); + } + + try { + String payload = jwtManager.verify(token); + } catch (Exception e) { + throw new SecurityException("JWT verification failed!"); + } + } + String vkey = request.getParameter("vkey"); - String attachmentIdString = documentManager.readHash(vkey); + String attachmentIdString = jwtManager.readHash(vkey); if (attachmentIdString.isEmpty()) { response.sendError(HttpServletResponse.SC_NOT_FOUND); @@ -122,15 +150,9 @@ private void getAttachmentDiff(final HttpServletRequest request, final HttpServl if (diff != null) { InputStream inputStream = attachmentUtil.getAttachmentData(diff.getId()); - String publicDocEditorUrl = urlManager.getPublicDocEditorUrl(); - - if (publicDocEditorUrl.endsWith("/")) { - publicDocEditorUrl = publicDocEditorUrl.substring(0, publicDocEditorUrl.length() - 1); - } response.setContentType(diff.getMediaType()); response.setContentLength(inputStream.available()); - response.addHeader("Access-Control-Allow-Origin", publicDocEditorUrl); byte[] buffer = new byte[BUFFER_SIZE]; @@ -151,7 +173,7 @@ private void getAttachmentHistoryInfo(final HttpServletRequest request, final Ht } String vkey = request.getParameter("vkey"); - String attachmentIdString = documentManager.readHash(vkey); + String attachmentIdString = jwtManager.readHash(vkey); if (attachmentIdString.isEmpty()) { response.sendError(HttpServletResponse.SC_NOT_FOUND); @@ -168,7 +190,6 @@ private void getAttachmentHistoryInfo(final HttpServletRequest request, final Ht List attachments = attachmentUtil.getAllVersions(attachmentId); if (attachments != null) { - UserAccessor userAccessor = (UserAccessor) ContainerManager.getComponent("userAccessor"); ConfluenceUserPreferences preferences = userAccessor.getConfluenceUserPreferences(user); DateFormatter dateFormatter = preferences.getDateFormatter(formatSettingsManager, localeManager); Gson gson = new Gson(); @@ -177,27 +198,28 @@ private void getAttachmentHistoryInfo(final HttpServletRequest request, final Ht Collections.reverse(attachments); List history = new ArrayList<>(); for (Attachment attachment : attachments) { - Version version = new Version(); - version.setVersion(attachment.getVersion()); - version.setKey(documentManager.getKeyOfFile(attachment.getId(), false)); - version.setCreated(dateFormatter.formatDateTime(attachment.getCreationDate())); - version.setUser(attachment.getCreator().getName(), attachment.getCreator().getFullName()); - - Attachment changes = attachmentUtil.getAttachmentChanges(attachment.getId()); - if (changes != null) { + Version version = Version.builder() + .version(String.valueOf(attachment.getVersion())) + .key(documentManager.getDocumentKey(String.valueOf(attachment.getId()), false)) + .created(dateFormatter.formatDateTime(attachment.getCreationDate())) + .user(User.builder() + .id(attachment.getCreator().getKey().getStringValue()) + .name(attachment.getCreator().getFullName()) + .build() + ) + .build(); + + Attachment changesAttachment = attachmentUtil.getAttachmentChanges(attachment.getId()); + if (changesAttachment != null) { if (prevVersion != null && (attachment.getVersion() - prevVersion.getVersion()) == 1) { - InputStream changesSteam = attachmentUtil.getAttachmentData(changes.getId()); - String changesString = parsingUtil.getBody(changesSteam); - JSONObject changesJSON = null; - try { - changesJSON = new JSONObject(changesString); - version.setServerVersion(changesJSON.getString("serverVersion")); - version.setChanges( - gson.fromJson(changesJSON.getJSONArray("changes").toString(), Object.class) - ); - } catch (JSONException e) { - throw new IOException(e.getMessage()); - } + InputStream changesSteam = attachmentUtil.getAttachmentData(changesAttachment.getId()); + + ObjectMapper mapper = new ObjectMapper(); + History changes = mapper.readValue(changesSteam, History.class); + changes.setChanges(formatChanges(changes.getChanges(), user)); + + version.setServerVersion(changes.getServerVersion()); + version.setChanges(changes.getChanges()); } else { attachmentUtil.removeAttachmentChanges(attachment.getId()); } @@ -220,6 +242,23 @@ private void getAttachmentHistoryInfo(final HttpServletRequest request, final Ht } } + private List formatChanges(final List changes, final ConfluenceUser user) { + ConfluenceUserPreferences preferences = userAccessor.getConfluenceUserPreferences(user); + DateFormatter dateFormatter = preferences.getDateFormatter(formatSettingsManager, localeManager); + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + for (Changes changesEntity : changes) { + try { + Date created = dateFormat.parse(changesEntity.getCreated()); + changesEntity.setCreated(dateFormatter.formatDateTime(created)); + } catch (ParseException e) { + log.error(e); + } + } + + return changes; + } + private void getAttachmentHistoryData(final HttpServletRequest request, final HttpServletResponse response) throws IOException { if (!authContext.checkUserAuthorization(request, response)) { @@ -227,7 +266,7 @@ private void getAttachmentHistoryData(final HttpServletRequest request, final Ht } String vkey = request.getParameter("vkey"); - String attachmentIdString = documentManager.readHash(vkey); + String attachmentIdString = jwtManager.readHash(vkey); String versionString = request.getParameter("version"); if (attachmentIdString.isEmpty() || versionString == null || versionString.isEmpty()) { @@ -248,25 +287,35 @@ private void getAttachmentHistoryData(final HttpServletRequest request, final Ht List attachments = attachmentUtil.getAllVersions(attachmentId); if (attachments != null) { Gson gson = new Gson(); - VersionData versionData = null; + HistoryData historyData = null; Attachment prevVersion = null; Collections.reverse(attachments); for (Attachment attachment : attachments) { if (attachment.getVersion() == version) { - versionData = new VersionData(); - versionData.setVersion(attachment.getVersion()); - versionData.setKey(documentManager.getKeyOfFile(attachment.getId(), false)); - versionData.setUrl(urlManager.getFileUri(attachment.getId())); - versionData.setFileType(attachment.getFileExtension()); + historyData = HistoryData.builder() + .version(String.valueOf(attachment.getVersion())) + .key(documentManager.getDocumentKey(String.valueOf(attachment.getId()), false)) + .url(urlManager.getFileUrl(String.valueOf(attachment.getId()))) + .fileType(attachment.getFileExtension()) + .build(); Attachment diff = attachmentUtil.getAttachmentDiff(attachment.getId()); if (prevVersion != null && diff != null) { boolean adjacentVersions = (attachment.getVersion() - prevVersion.getVersion()) == 1; if (adjacentVersions) { - versionData.setChangesUrl(urlManager.getAttachmentDiffUri(attachment.getId())); - versionData.setPrevious(documentManager.getKeyOfFile(prevVersion.getId(), false), - urlManager.getFileUri(prevVersion.getId()), prevVersion.getFileExtension()); + historyData.setChangesUrl(urlManager.getAttachmentDiffUri(attachment.getId())); + historyData.setPrevious(Previous.builder() + .key( + documentManager.getDocumentKey( + String.valueOf(prevVersion.getId()), + false + ) + ) + .url(urlManager.getFileUrl(String.valueOf(prevVersion.getId()))) + .fileType(prevVersion.getFileExtension()) + .build() + ); } } break; @@ -274,11 +323,10 @@ private void getAttachmentHistoryData(final HttpServletRequest request, final Ht prevVersion = attachment; } - if (versionData != null) { - if (jwtManager.jwtEnabled()) { + if (historyData != null) { + if (settingsManager.isSecurityEnabled()) { try { - JSONObject versionDataJSON = new JSONObject(gson.toJson(versionData)); - versionData.setToken(jwtManager.createToken(versionDataJSON)); + historyData.setToken(jwtManager.createToken(historyData)); } catch (Exception e) { throw new IOException(e.getMessage()); } @@ -286,7 +334,7 @@ private void getAttachmentHistoryData(final HttpServletRequest request, final Ht response.setContentType("application/json"); PrintWriter writer = response.getWriter(); - writer.write(gson.toJson(versionData)); + writer.write(gson.toJson(historyData)); } else { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; @@ -296,103 +344,4 @@ private void getAttachmentHistoryData(final HttpServletRequest request, final Ht return; } } - - public class Version { - private int version; - private String key; - private Object changes; - private String created; - private User user; - private String serverVersion; - - public Version() { - } - - public void setVersion(final int version) { - this.version = version; - } - - public void setKey(final String key) { - this.key = key; - } - - public void setChanges(final Object changes) { - this.changes = changes; - } - - public void setCreated(final String created) { - this.created = created; - } - - public void setUser(final String id, final String name) { - this.user = new User(id, name); - } - - public void setServerVersion(final String serverVersion) { - this.serverVersion = serverVersion; - } - - public class User { - private String id; - private String name; - - public User(final String id, final String name) { - this.id = id; - this.name = name; - } - } - } - - public class VersionData { - private int version; - private String key; - private String url; - private String fileType; - private String changesUrl; - private Previous previous; - private String token; - - public VersionData() { - } - - public void setVersion(final int version) { - this.version = version; - } - - public void setKey(final String key) { - this.key = key; - } - - public void setUrl(final String url) { - this.url = url; - } - - public void setFileType(final String fileType) { - this.fileType = fileType; - } - - public void setChangesUrl(final String changesUrl) { - this.changesUrl = changesUrl; - } - - public void setPrevious(final String key, final String url, final String fileType) { - this.previous = new Previous(key, url, fileType); - } - - public void setToken(final String token) { - this.token = token; - } - - public class Previous { - private String key; - private String url; - private String fileType; - - public Previous(final String key, final String url, final String fileType) { - this.key = key; - this.url = url; - this.fileType = fileType; - } - } - } } diff --git a/src/main/java/onlyoffice/OnlyOfficeSaveFileServlet.java b/src/main/java/onlyoffice/OnlyOfficeSaveFileServlet.java index 5e102fa2..7c5c25a8 100644 --- a/src/main/java/onlyoffice/OnlyOfficeSaveFileServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeSaveFileServlet.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,67 +18,48 @@ package onlyoffice; +import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.confluence.user.UserAccessor; import com.atlassian.sal.api.user.UserKey; import com.atlassian.spring.container.ContainerManager; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.managers.convert.ConvertManager; -import onlyoffice.managers.jwt.JwtManager; -import onlyoffice.managers.url.UrlManager; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onlyoffice.manager.settings.SettingsManager; +import com.onlyoffice.model.documenteditor.Callback; +import onlyoffice.sdk.manager.security.JwtManager; +import com.onlyoffice.service.documenteditor.callback.CallbackService; import onlyoffice.utils.attachment.AttachmentUtil; import onlyoffice.utils.parsing.ParsingUtil; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpEntity; -import org.apache.http.HttpException; -import org.apache.http.HttpStatus; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import org.json.JSONArray; import org.json.JSONObject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.ByteArrayInputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; -import java.io.StringWriter; public class OnlyOfficeSaveFileServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeSaveFileServlet"); - private static final int STATUS_EDITING = 1; - private static final int STATUS_MUST_SAVE = 2; - private static final int STATUS_CORRUPTED = 3; - private static final int STATUS_CLOSED = 4; - private static final int STATUS_FORCE_SAVE = 6; - private static final int STATUS_CORRUPTED_FORCE_SAVE = 7; - + private final SettingsManager settingsManager; private final JwtManager jwtManager; private final AttachmentUtil attachmentUtil; private final ParsingUtil parsingUtil; - private final UrlManager urlManager; - private final ConfigurationManager configurationManager; - private final ConvertManager convertManager; + private final CallbackService callbackService; - public OnlyOfficeSaveFileServlet(final JwtManager jwtManager, final AttachmentUtil attachmentUtil, - final ParsingUtil parsingUtil, final UrlManager urlManager, - final ConfigurationManager configurationManager, - final ConvertManager convertManager) { + public OnlyOfficeSaveFileServlet(final SettingsManager settingsManager, final JwtManager jwtManager, + final AttachmentUtil attachmentUtil, final ParsingUtil parsingUtil, + final CallbackService callbackService) { + this.settingsManager = settingsManager; this.jwtManager = jwtManager; this.attachmentUtil = attachmentUtil; this.parsingUtil = parsingUtil; - this.urlManager = urlManager; - this.configurationManager = configurationManager; - this.convertManager = convertManager; + this.callbackService = callbackService; } @Override @@ -108,6 +89,8 @@ public void doPost(final HttpServletRequest request, final HttpServletResponse r UserKey userKey = new UserKey(userKeyString); ConfluenceUser user = userAccessor.getUserByKey(userKey); + AuthenticatedUserThreadLocal.set(user); + Long attachmentId = Long.parseLong(attachmentIdString); if (attachmentUtil.getAttachment(attachmentId) == null) { @@ -117,8 +100,23 @@ public void doPost(final HttpServletRequest request, final HttpServletResponse r String error = ""; try { - processData(attachmentId, user, request); + InputStream requestStream = request.getInputStream(); + + String bodyString = parsingUtil.getBody(requestStream); + + if (bodyString.isEmpty()) { + throw new IllegalArgumentException("requestBody is empty"); + } + + ObjectMapper mapper = new ObjectMapper(); + Callback callback = mapper.readValue(bodyString, Callback.class); + + String authorizationHeader = request.getHeader(settingsManager.getSecurityHeader()); + callback = callbackService.verifyCallback(callback, authorizationHeader); + + callbackService.processCallback(callback, attachmentIdString); } catch (Exception e) { + log.error(e.getMessage(), e); error = e.getMessage(); } @@ -129,206 +127,5 @@ public void doPost(final HttpServletRequest request, final HttpServletResponse r response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); writer.write("{\"error\":1,\"message\":\"" + error + "\"}"); } - - log.info("error = " + error); - } - - private void processData(final Long attachmentId, final ConfluenceUser user, final HttpServletRequest request) - throws Exception { - log.info("attachmentId = " + attachmentId.toString()); - InputStream requestStream = request.getInputStream(); - - try { - String body = parsingUtil.getBody(requestStream); - log.info("body = " + body); - if (body.isEmpty()) { - throw new IllegalArgumentException("requestBody is empty"); - } - - JSONObject jsonObj = new JSONObject(body); - - if (jwtManager.jwtEnabled()) { - String token = jsonObj.optString("token"); - String payload = null; - Boolean inBody = true; - - if (token == null || token == "") { - String jwth = jwtManager.getJwtHeader(); - String header = (String) request.getHeader(jwth); - String authorizationPrefix = "Bearer "; - token = (header != null && header.startsWith(authorizationPrefix)) - ? header.substring(authorizationPrefix.length()) : header; - inBody = false; - } - - if (token == null || token == "") { - throw new SecurityException("Try save without JWT"); - } - - try { - payload = jwtManager.verify(token); - } catch (Exception e) { - throw new SecurityException("Try save with wrong JWT"); - } - - JSONObject bodyFromToken = new JSONObject(payload); - - if (inBody) { - jsonObj = bodyFromToken; - } else { - jsonObj = bodyFromToken.getJSONObject("payload"); - } - } - - long status = jsonObj.getLong("status"); - log.info("status = " + status); - log.info("user = " + user); - - if (status == STATUS_EDITING) { - if (jsonObj.has("actions")) { - JSONArray actions = jsonObj.getJSONArray("actions"); - if (actions.length() > 0) { - JSONObject action = (JSONObject) actions.get(0); - if (action.getLong("type") == 1) { - if (user == null || !attachmentUtil.checkAccess(attachmentId, user, true)) { - throw new SecurityException("Access denied. User " + user - + " don't have the appropriate permissions to edit this document."); - } - - if (attachmentUtil.getCollaborativeEditingKey(attachmentId) == null) { - String key = jsonObj.getString("key"); - attachmentUtil.setCollaborativeEditingKey(attachmentId, key); - } - } - } - } - } - - if (status == STATUS_MUST_SAVE || status == STATUS_CORRUPTED) { - if (user != null && attachmentUtil.checkAccess(attachmentId, user, true)) { - String fileType = jsonObj.getString("filetype"); - String downloadUrl = jsonObj.getString("url"); - downloadUrl = urlManager.replaceDocEditorURLToInternal(downloadUrl); - log.info("downloadUri = " + downloadUrl); - - JSONObject history = jsonObj.getJSONObject("history"); - String changesUrl = !jsonObj.isNull("changesurl") - ? urlManager.replaceDocEditorURLToInternal(jsonObj.getString("changesurl")) - : null; - log.info("changesUri = " + changesUrl); - - Boolean forceSaveVersion = - attachmentUtil.getPropertyAsBoolean(attachmentId, "onlyoffice-force-save"); - - attachmentUtil.setCollaborativeEditingKey(attachmentId, null); - - if (forceSaveVersion) { - saveAttachmentFromUrl(attachmentId, downloadUrl, fileType, user, false); - attachmentUtil.removeProperty(attachmentId, "onlyoffice-force-save"); - attachmentUtil.removeAttachmentChanges(attachmentId); - - File convertedFile = attachmentUtil.getConvertedFile(attachmentId); - if (convertedFile.exists()) { - convertedFile.delete(); - } - } else { - saveAttachmentFromUrl(attachmentId, downloadUrl, fileType, user, true); - } - - attachmentUtil.saveAttachmentChanges(attachmentId, history.toString(), changesUrl); - } else { - throw new SecurityException("Try save without access: " + user); - } - } - - if (status == STATUS_CLOSED) { - attachmentUtil.setCollaborativeEditingKey(attachmentId, null); - } - - if (status == STATUS_FORCE_SAVE || status == STATUS_CORRUPTED_FORCE_SAVE) { - if (user != null && attachmentUtil.checkAccess(attachmentId, user, true)) { - if (configurationManager.forceSaveEnabled()) { - String fileType = jsonObj.getString("filetype"); - String downloadUrl = jsonObj.getString("url"); - downloadUrl = urlManager.replaceDocEditorURLToInternal(downloadUrl); - log.info("downloadUri = " + downloadUrl); - - JSONObject history = jsonObj.getJSONObject("history"); - String changesUrl = !jsonObj.isNull("changesurl") - ? urlManager.replaceDocEditorURLToInternal(jsonObj.getString("changesurl")) - : null; - log.info("changesUri = " + downloadUrl); - - Boolean forceSaveVersion = - attachmentUtil.getPropertyAsBoolean(attachmentId, "onlyoffice-force-save"); - - if (forceSaveVersion) { - saveAttachmentFromUrl(attachmentId, downloadUrl, fileType, user, false); - attachmentUtil.removeAttachmentChanges(attachmentId); - } else { - String key = attachmentUtil.getCollaborativeEditingKey(attachmentId); - attachmentUtil.setCollaborativeEditingKey(attachmentId, null); - - saveAttachmentFromUrl(attachmentId, downloadUrl, fileType, user, true); - attachmentUtil.setCollaborativeEditingKey(attachmentId, key); - attachmentUtil.setProperty(attachmentId, "onlyoffice-force-save", "true"); - } - - attachmentUtil.saveAttachmentChanges(attachmentId, history.toString(), changesUrl); - - File convertedFile = attachmentUtil.getConvertedFile(attachmentId); - if (convertedFile.exists()) { - convertedFile.delete(); - } - } else { - log.info("Forcesave is disabled, ignoring forcesave request"); - } - } else { - throw new SecurityException("Try save without access: " + user); - } - } - } catch (Exception ex) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - ex.printStackTrace(pw); - String error = ex.toString() + "\n" + sw.toString(); - log.error(error); - - throw ex; - } - } - - private void saveAttachmentFromUrl(final Long attachmentId, final String downloadUrl, final String fileType, - final ConfluenceUser user, final boolean newVersion) throws Exception { - String attachmentExt = attachmentUtil.getFileExt(attachmentId); - String url = downloadUrl; - - if (!attachmentExt.equals(fileType)) { - JSONObject response = - convertManager.convert(attachmentId, fileType, attachmentExt, downloadUrl, null, false, null); - url = response.getString("fileUrl"); - } - - try (CloseableHttpClient httpClient = configurationManager.getHttpClient()) { - HttpGet request = new HttpGet(url); - - try (CloseableHttpResponse response = httpClient.execute(request)) { - int status = response.getStatusLine().getStatusCode(); - HttpEntity entity = response.getEntity(); - - if (status == HttpStatus.SC_OK) { - byte[] bytes = IOUtils.toByteArray(entity.getContent()); - InputStream inputStream = new ByteArrayInputStream(bytes); - - if (newVersion) { - attachmentUtil.saveAttachmentAsNewVersion(attachmentId, inputStream, bytes.length, user); - } else { - attachmentUtil.updateAttachment(attachmentId, inputStream, bytes.length, user); - } - } else { - throw new HttpException("Document Server returned code " + status); - } - } - } } } diff --git a/src/main/java/onlyoffice/OnlyOfficeTestServlet.java b/src/main/java/onlyoffice/OnlyOfficeTestServlet.java new file mode 100644 index 00000000..df709f27 --- /dev/null +++ b/src/main/java/onlyoffice/OnlyOfficeTestServlet.java @@ -0,0 +1,73 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package onlyoffice; + +import com.onlyoffice.manager.settings.SettingsManager; +import onlyoffice.sdk.manager.security.JwtManager; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class OnlyOfficeTestServlet extends HttpServlet { + private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeTestServlet"); + private static final long serialVersionUID = 1L; + + private final JwtManager jwtManager; + private final SettingsManager settingsManager; + + public OnlyOfficeTestServlet(final JwtManager jwtManager, final SettingsManager settingsManager) { + this.jwtManager = jwtManager; + this.settingsManager = settingsManager; + } + + @Override + public void doGet(final HttpServletRequest request, final HttpServletResponse response) + throws ServletException, IOException { + if (settingsManager.isSecurityEnabled()) { + String jwth = settingsManager.getSecurityHeader(); + String header = request.getHeader(jwth); + String authorizationPrefix = settingsManager.getSecurityPrefix(); + String token = (header != null && header.startsWith(authorizationPrefix)) + ? header.substring(authorizationPrefix.length()) : header; + + if (token == null || token == "") { + throw new SecurityException("Expected JWT"); + } + + try { + String payload = jwtManager.verify(token); + } catch (Exception e) { + throw new SecurityException("JWT verification failed!"); + } + } + + String message = "Test file for conversion"; + + response.setContentType("text/plain"); + response.setContentLength(message.getBytes("UTF-8").length); + response.setHeader("Content-Disposition", "attachment; filename=test.txt"); + + response.getWriter().write(message); + } +} diff --git a/src/main/java/onlyoffice/action/DownloadAsAction.java b/src/main/java/onlyoffice/action/DownloadAsAction.java index 922f4d86..2324841f 100644 --- a/src/main/java/onlyoffice/action/DownloadAsAction.java +++ b/src/main/java/onlyoffice/action/DownloadAsAction.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,33 +19,53 @@ package onlyoffice.action; import com.atlassian.confluence.core.ConfluenceActionSupport; +import com.atlassian.confluence.languages.LocaleManager; import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; import com.atlassian.core.filters.ServletContextThreadLocal; import com.atlassian.xwork.HttpMethod; +import com.atlassian.xwork.ParameterSafe; import com.atlassian.xwork.PermittedMethods; -import onlyoffice.managers.convert.ConvertManager; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onlyoffice.model.common.CommonResponse; +import com.onlyoffice.model.convertservice.ConvertRequest; +import com.onlyoffice.model.convertservice.ConvertResponse; +import com.onlyoffice.service.convert.ConvertService; +import onlyoffice.sdk.manager.document.DocumentManager; +import onlyoffice.sdk.manager.url.UrlManager; import onlyoffice.utils.attachment.AttachmentUtil; import com.atlassian.confluence.user.ConfluenceUser; import org.apache.commons.lang3.StringUtils; -import org.json.JSONObject; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.io.PrintWriter; import java.util.List; public class DownloadAsAction extends ConfluenceActionSupport { + private final Logger log = LogManager.getLogger("onlyoffice.action.DownloadAsAction"); + private AttachmentUtil attachmentUtil; - private ConvertManager convertManager; + private ConvertService convertService; + private DocumentManager documentManager; + private final LocaleManager localeManager; + private final UrlManager urlManager; private String attachmentId; private String fileName; private String targetFileType; private static final char[] INVALID_CHARS; - public DownloadAsAction(final AttachmentUtil attachmentUtil, final ConvertManager convertManager) { + public DownloadAsAction(final AttachmentUtil attachmentUtil, final ConvertService convertService, + final LocaleManager localeManager, final DocumentManager documentManager, + final UrlManager urlManager) { this.attachmentUtil = attachmentUtil; - this.convertManager = convertManager; + this.convertService = convertService; + this.documentManager = documentManager; + this.localeManager = localeManager; + this.urlManager = urlManager; } @PermittedMethods({ HttpMethod.GET }) @@ -58,7 +78,6 @@ public void validate() { super.validate(); Long attachmentId = Long.parseLong(this.attachmentId); - String ext = attachmentUtil.getFileExt(attachmentId); if (!attachmentUtil.checkAccess(attachmentId, getAuthenticatedUser(), false)) { addActionError(getText("onlyoffice.connector.dialog.conversion.message.error.permission")); @@ -82,9 +101,11 @@ public void validate() { return; } - if (convertManager.getTargetExtList(ext) == null - || convertManager.getTargetExtList(ext).isEmpty() - || !convertManager.getTargetExtList(ext).contains(targetFileType) + String documentName = documentManager.getDocumentName(String.valueOf(attachmentId)); + + if (documentManager.getConvertExtensionList(documentName) == null + || documentManager.getConvertExtensionList(documentName).isEmpty() + || !documentManager.getConvertExtensionList(documentName).contains(targetFileType) ) { addActionError(getText("onlyoffice.connector.error.Unknown")); ServletContextThreadLocal.getResponse().setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE); @@ -94,33 +115,67 @@ public void validate() { @PermittedMethods({ HttpMethod.POST }) public String execute() throws Exception { Long attachmentId = Long.parseLong(this.attachmentId); - String ext = attachmentUtil.getFileExt(attachmentId); - String targetExt = convertManager.getTargetExt(ext); + String fileName = documentManager.getDocumentName(String.valueOf(attachmentId)); + String targetExt = documentManager.getDefaultConvertExtension(fileName); if (!this.targetFileType.isEmpty()) { targetExt = this.targetFileType; } ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + String region = localeManager.getLocale(user).toLanguageTag(); + + ConvertRequest convertRequest = ConvertRequest.builder() + .async(true) + .outputtype(targetExt) + .region(region) + .build(); - JSONObject convertResult = - convertManager.convert(attachmentId, ext, targetExt, user, this.fileName + "." + targetExt); HttpServletResponse response = ServletContextThreadLocal.getResponse(); response.setContentType("application/json"); PrintWriter writer = response.getWriter(); - writer.write(convertResult.toString()); + ObjectMapper mapper = new ObjectMapper(); + + try { + ConvertResponse convertResponse = convertService.processConvert(convertRequest, this.attachmentId); + + if (convertResponse.getEndConvert() != null && convertResponse.getEndConvert()) { + String fileUrl = convertResponse.getFileUrl(); + + String documentServerUrl = urlManager.getDocumentServerUrl(); + String innerDocumentServerUrl = urlManager.getInnerDocumentServerUrl(); + + if (!documentServerUrl.equals(innerDocumentServerUrl)) { + fileUrl = fileUrl.replace(innerDocumentServerUrl, documentServerUrl); + } + + convertResponse.setFileUrl(fileUrl); + } + + writer.write(mapper.writeValueAsString(convertResponse)); + } catch (IOException e) { + log.error(e.getMessage(), e); + + CommonResponse commonResponse = new CommonResponse(); + commonResponse.setError(CommonResponse.Error.CONNECTION); + writer.write(mapper.writeValueAsString(commonResponse)); + } + response.setStatus(HttpServletResponse.SC_OK); return "none"; } + @ParameterSafe public void setAttachmentId(final String attachmentId) { this.attachmentId = attachmentId; } + @ParameterSafe public void setFileName(final String fileName) { this.fileName = fileName; } + @ParameterSafe public void setTargetFileType(final String targetFileType) { this.targetFileType = targetFileType; } @@ -130,23 +185,26 @@ public String getAttachmentId() { } public String getFileName() { - Long attachmentId = Long.parseLong(this.attachmentId); - String fileName = attachmentUtil.getFileName(attachmentId); + String fileName = documentManager.getDocumentName(this.attachmentId); - return fileName.substring(0, fileName.lastIndexOf(".")); + return documentManager.getBaseName(fileName); } public String getFileType() { - Long attachmentId = Long.parseLong(this.attachmentId); - return attachmentUtil.getFileExt(attachmentId); + String fileName = documentManager.getDocumentName(this.attachmentId); + + return documentManager.getExtension(fileName); } public String getTargetFileType() { - return convertManager.getTargetExt(getFileType()); + return documentManager.getDefaultConvertExtension(getFileName()); } public List getTargetFileTypeList() { - return convertManager.getTargetExtList(getFileType()); + Long attachmentId = Long.parseLong(this.attachmentId); + String fileName = documentManager.getDocumentName(String.valueOf(attachmentId)); + + return documentManager.getConvertExtensionList(fileName); } static { diff --git a/src/main/java/onlyoffice/conditions/IsOfficeFileAttachment.java b/src/main/java/onlyoffice/conditions/IsOfficeFileAttachment.java index 82b08188..7ccba64e 100644 --- a/src/main/java/onlyoffice/conditions/IsOfficeFileAttachment.java +++ b/src/main/java/onlyoffice/conditions/IsOfficeFileAttachment.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.plugin.PluginParseException; import com.atlassian.plugin.web.Condition; -import onlyoffice.managers.document.DocumentManager; +import com.onlyoffice.manager.document.DocumentManager; import onlyoffice.utils.attachment.AttachmentUtil; import java.util.Map; @@ -62,21 +62,23 @@ public boolean shouldDisplay(final Map context) { ConfluenceUser user = AuthenticatedUserThreadLocal.get(); boolean accessEdit = attachmentUtil.checkAccess(attachment, user, true); boolean accessView = attachmentUtil.checkAccess(attachment, user, false); - String ext = attachment.getFileExtension(); + String fileName = attachment.getFileName(); if (forEdit) { if (form) { - if (accessEdit && documentManager.isFillForm(ext)) { + if (accessEdit && documentManager.isFillable(fileName)) { return true; } } else { - if (accessEdit && documentManager.isEditable(ext)) { + if (accessEdit && documentManager.isEditable(fileName)) { return true; } } } else { - if (accessView && documentManager.isViewable(ext) - && !(accessEdit && (documentManager.isEditable(ext) || documentManager.isFillForm(ext)))) { + if (accessView + && documentManager.isViewable(fileName) + && !(accessEdit && documentManager.isEditable(fileName)) + ) { return true; } } diff --git a/src/main/java/onlyoffice/conditions/IsOfficeFileConvertAttachment.java b/src/main/java/onlyoffice/conditions/IsOfficeFileConvertAttachment.java index 140bb73f..43912bb0 100644 --- a/src/main/java/onlyoffice/conditions/IsOfficeFileConvertAttachment.java +++ b/src/main/java/onlyoffice/conditions/IsOfficeFileConvertAttachment.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,8 +23,7 @@ import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.plugin.PluginParseException; import com.atlassian.plugin.web.Condition; -import onlyoffice.managers.convert.ConvertManager; -import onlyoffice.managers.document.DocumentManager; +import onlyoffice.sdk.manager.document.DocumentManager; import onlyoffice.utils.attachment.AttachmentUtil; import java.util.Map; @@ -32,16 +31,12 @@ public class IsOfficeFileConvertAttachment implements Condition { private boolean form; - - private final DocumentManager documentManager; private final AttachmentUtil attachmentUtil; - private final ConvertManager convertManager; + private final DocumentManager documentManager; - public IsOfficeFileConvertAttachment(final DocumentManager documentManager, final AttachmentUtil attachmentUtil, - final ConvertManager convertManager) { - this.documentManager = documentManager; + public IsOfficeFileConvertAttachment(final AttachmentUtil attachmentUtil, final DocumentManager documentManager) { this.attachmentUtil = attachmentUtil; - this.convertManager = convertManager; + this.documentManager = documentManager; } public void init(final Map params) throws PluginParseException { @@ -65,7 +60,7 @@ public boolean shouldDisplay(final Map context) { ConfluenceUser user = AuthenticatedUserThreadLocal.get(); boolean accessEdit = attachmentUtil.checkAccess(attachment, user, true); - if (!accessEdit || convertManager.getTargetExt(ext) == null || ext.equals("docx")) { + if (!accessEdit || documentManager.getDefaultConvertExtension(attachment.getFileName()) == null) { return false; } diff --git a/src/main/java/onlyoffice/conditions/IsOfficeFileDownloadAsAttachment.java b/src/main/java/onlyoffice/conditions/IsOfficeFileDownloadAsAttachment.java index a4e867fb..99335145 100644 --- a/src/main/java/onlyoffice/conditions/IsOfficeFileDownloadAsAttachment.java +++ b/src/main/java/onlyoffice/conditions/IsOfficeFileDownloadAsAttachment.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,8 +23,7 @@ import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.plugin.PluginParseException; import com.atlassian.plugin.web.Condition; -import onlyoffice.managers.convert.ConvertManager; -import onlyoffice.managers.document.DocumentManager; +import onlyoffice.sdk.manager.document.DocumentManager; import onlyoffice.utils.attachment.AttachmentUtil; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; @@ -32,16 +31,13 @@ import java.util.Map; public class IsOfficeFileDownloadAsAttachment implements Condition { - - private final DocumentManager documentManager; private final AttachmentUtil attachmentUtil; - private final ConvertManager convertManager; + private final DocumentManager documentManager; - public IsOfficeFileDownloadAsAttachment(final DocumentManager documentManager, final AttachmentUtil attachmentUtil, - final ConvertManager convertManager) { - this.documentManager = documentManager; + public IsOfficeFileDownloadAsAttachment(final AttachmentUtil attachmentUtil, + final DocumentManager documentManager) { this.attachmentUtil = attachmentUtil; - this.convertManager = convertManager; + this.documentManager = documentManager; } private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeSaveFileServlet"); @@ -57,9 +53,7 @@ public boolean shouldDisplay(final Map map) { return false; } - String ext = attachment.getFileExtension(); - - if (attachment.getFileSize() > documentManager.getConvertationFileSizeMax()) { + if (attachment.getFileSize() > documentManager.getMaxConversionFileSize()) { return false; } @@ -67,7 +61,7 @@ public boolean shouldDisplay(final Map map) { boolean access = attachmentUtil.checkAccess(attachment, user, false); return access - && convertManager.getTargetExtList(ext) != null - && convertManager.getTargetExtList(ext).size() > 0; + && documentManager.getConvertExtensionList(attachment.getFileName()) != null + && documentManager.getConvertExtensionList(attachment.getFileName()).size() > 0; } } diff --git a/src/main/java/onlyoffice/conditions/IsOfficePageAttachments.java b/src/main/java/onlyoffice/conditions/IsOfficePageAttachments.java index 6e91f96a..9b023c24 100644 --- a/src/main/java/onlyoffice/conditions/IsOfficePageAttachments.java +++ b/src/main/java/onlyoffice/conditions/IsOfficePageAttachments.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/main/java/onlyoffice/conditions/confluence/previews/plugin/OnlyofficeButton.java b/src/main/java/onlyoffice/conditions/confluence/previews/plugin/OnlyofficeButton.java index d733a350..6e9e81f5 100644 --- a/src/main/java/onlyoffice/conditions/confluence/previews/plugin/OnlyofficeButton.java +++ b/src/main/java/onlyoffice/conditions/confluence/previews/plugin/OnlyofficeButton.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ import com.atlassian.confluence.pages.AttachmentManager; import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; import com.atlassian.confluence.user.ConfluenceUser; -import onlyoffice.managers.document.DocumentManager; +import com.onlyoffice.manager.document.DocumentManager; import onlyoffice.utils.attachment.AttachmentUtil; import onlyoffice.utils.parsing.ParsingUtil; import org.json.JSONObject; @@ -65,15 +65,16 @@ public void doPost(final HttpServletRequest request, final HttpServletResponse r boolean accessEdit = attachmentUtil.checkAccess(attachment, user, true); boolean accessView = attachmentUtil.checkAccess(attachment, user, false); - String ext = attachment.getFileExtension(); + String fileName = attachment.getFileName(); String access = null; - if (accessEdit && documentManager.isEditable(ext)) { + if (accessEdit && documentManager.isEditable(fileName)) { access = "edit"; - } else if (accessEdit && documentManager.isFillForm(ext)) { + } else if (accessEdit && documentManager.isFillable(fileName)) { access = "fillform"; - } else if (accessView && documentManager.isViewable(ext) - && !(accessEdit && (documentManager.isEditable(ext) || documentManager.isFillForm(ext)))) { + } else if (accessView && documentManager.isViewable(fileName) + && !(accessEdit + && (documentManager.isEditable(fileName) || documentManager.isFillable(fileName)))) { access = "view"; } diff --git a/src/main/java/onlyoffice/macro/OnlyOfficePreviewMacro.java b/src/main/java/onlyoffice/macro/OnlyOfficePreviewMacro.java index c5502627..7d264da2 100644 --- a/src/main/java/onlyoffice/macro/OnlyOfficePreviewMacro.java +++ b/src/main/java/onlyoffice/macro/OnlyOfficePreviewMacro.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import com.atlassian.confluence.content.render.xhtml.ConversionContext; import com.atlassian.confluence.core.ContentEntityObject; +import com.atlassian.confluence.languages.LocaleManager; import com.atlassian.confluence.macro.Macro; import com.atlassian.confluence.macro.EditorImagePlaceholder; import com.atlassian.confluence.macro.ResourceAware; @@ -32,14 +33,17 @@ import com.atlassian.confluence.pages.AttachmentManager; import com.atlassian.confluence.plugin.services.VelocityHelperService; import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; +import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.confluence.util.HtmlUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onlyoffice.manager.document.DocumentManager; +import com.onlyoffice.manager.url.UrlManager; +import com.onlyoffice.model.documenteditor.Config; +import com.onlyoffice.model.documenteditor.config.document.DocumentType; +import com.onlyoffice.model.documenteditor.config.document.Type; +import com.onlyoffice.model.documenteditor.config.editorconfig.Mode; +import com.onlyoffice.service.documenteditor.config.ConfigService; import onlyoffice.macro.components.ContentResolver; -import onlyoffice.managers.config.ConfigManager; -import onlyoffice.managers.document.DocumentManager; -import onlyoffice.managers.url.UrlManager; -import onlyoffice.model.config.DocumentType; -import onlyoffice.model.config.Type; -import onlyoffice.model.config.editor.Mode; import onlyoffice.utils.attachment.AttachmentUtil; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; @@ -61,23 +65,25 @@ public class OnlyOfficePreviewMacro implements Macro, EditorImagePlaceholder, Re private final AttachmentManager attachmentManager; private final VelocityHelperService velocityHelperService; private final ContentResolver contentResolver; - private final ConfigManager configManager; + private final LocaleManager localeManager; private final UrlManager urlManager; - private final DocumentManager documentManager; private final AttachmentUtil attachmentUtil; + private final ConfigService configSevice; + private final DocumentManager documentManager; public OnlyOfficePreviewMacro(final AttachmentManager attachmentManager, final VelocityHelperService velocityHelperService, - final ContentResolver contentResolver, - final ConfigManager configManager, final UrlManager urlManager, - final DocumentManager documentManager, final AttachmentUtil attachmentUtil) { + final ContentResolver contentResolver, final LocaleManager localeManager, + final UrlManager urlManager, final AttachmentUtil attachmentUtil, + final ConfigService configSevice, final DocumentManager documentManager) { this.attachmentManager = attachmentManager; this.velocityHelperService = velocityHelperService; this.contentResolver = contentResolver; - this.configManager = configManager; + this.localeManager = localeManager; this.urlManager = urlManager; - this.documentManager = documentManager; this.attachmentUtil = attachmentUtil; + this.configSevice = configSevice; + this.documentManager = documentManager; } @Override @@ -103,37 +109,37 @@ public String execute(final Map args, final String s, final Conv width = normalizeSize((width == null) ? DEFAULT_WIDTH : width); height = normalizeSize((height == null) ? DEFAULT_HEIGHT : height); + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + try { - String config = configManager.createConfig( - attachment.getId(), - Mode.VIEW, - Type.EMBEDDED, - null, - null, - width, - height - ); - - String extension = attachmentUtil.getFileExt(attachment.getId()); + Config config = configSevice.createConfig(String.valueOf(attachment.getId()), Mode.EDIT, Type.EMBEDDED); + + config.setWidth(width); + config.setHeight(height); + config.getEditorConfig().setLang(localeManager.getLocale(user).toLanguageTag()); + + String fileName = attachment.getFileName(); String action = ""; final boolean isPreview = conversionContext.getOutputType().equals("preview"); - if (attachmentUtil.checkAccess(attachment.getId(), AuthenticatedUserThreadLocal.get(), true) + if (attachmentUtil.checkAccess(attachment.getId(), user, true) && !isPreview) { - if (documentManager.isEditable(extension)) { + if (documentManager.isEditable(fileName)) { action = "edit"; - } else if (documentManager.isFillForm(extension)) { + } else if (documentManager.isFillable(fileName)) { action = "fill"; } } + ObjectMapper mapper = new ObjectMapper(); + final Map context = this.velocityHelperService.createDefaultVelocityContext(); context.put("id", System.currentTimeMillis()); context.put("attachmentId", attachment.getId()); context.put("action", action); - context.put("docServiceApiUrl", urlManager.getDocServiceApiUrl()); - context.put("configAsHtml", config); + context.put("docServiceApiUrl", urlManager.getDocumentServerApiUrl()); + context.put("configAsHtml", mapper.writeValueAsString(config)); return this.velocityHelperService.getRenderedTemplate("templates/preview.vm", context); } catch (Exception e) { @@ -175,8 +181,8 @@ public ImagePlaceholder getImagePlaceholder(final Map args, int dotIdx = name.lastIndexOf(DOT_INDEX); if (dotIdx != -1) { String fileExt = name.substring(dotIdx + 1).toLowerCase(); - if (documentManager.getDocType(fileExt) != null) { - documentType = documentManager.getDocType(fileExt).name().toLowerCase(); + if (documentManager.getDocumentType(name) != null) { + documentType = documentManager.getDocumentType(name).name().toLowerCase(); if (fileExt.equals("oform")) { documentType = "form"; } diff --git a/src/main/java/onlyoffice/macro/components/ContentResolver.java b/src/main/java/onlyoffice/macro/components/ContentResolver.java index ae667aef..4079ed8e 100644 --- a/src/main/java/onlyoffice/macro/components/ContentResolver.java +++ b/src/main/java/onlyoffice/macro/components/ContentResolver.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/main/java/onlyoffice/macro/components/DefaultContentResolver.java b/src/main/java/onlyoffice/macro/components/DefaultContentResolver.java index 1235a653..bc52ffc1 100644 --- a/src/main/java/onlyoffice/macro/components/DefaultContentResolver.java +++ b/src/main/java/onlyoffice/macro/components/DefaultContentResolver.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/main/java/onlyoffice/managers/auth/AuthContext.java b/src/main/java/onlyoffice/managers/auth/AuthContext.java index 7c2b0fed..b550a9b0 100644 --- a/src/main/java/onlyoffice/managers/auth/AuthContext.java +++ b/src/main/java/onlyoffice/managers/auth/AuthContext.java @@ -1,3 +1,21 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + package onlyoffice.managers.auth; import javax.servlet.http.HttpServletRequest; diff --git a/src/main/java/onlyoffice/managers/auth/AuthContextImpl.java b/src/main/java/onlyoffice/managers/auth/AuthContextImpl.java index 29595252..11e61f29 100644 --- a/src/main/java/onlyoffice/managers/auth/AuthContextImpl.java +++ b/src/main/java/onlyoffice/managers/auth/AuthContextImpl.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/main/java/onlyoffice/managers/config/ConfigManager.java b/src/main/java/onlyoffice/managers/config/ConfigManager.java deleted file mode 100644 index ad40d420..00000000 --- a/src/main/java/onlyoffice/managers/config/ConfigManager.java +++ /dev/null @@ -1,14 +0,0 @@ -package onlyoffice.managers.config; - -import onlyoffice.model.config.Type; -import onlyoffice.model.config.editor.Mode; -import org.json.JSONObject; - -import java.io.Serializable; - -public interface ConfigManager extends Serializable { - String createConfig(Long attachmentId, Mode mode, Type type, JSONObject actionLink, String referer) - throws Exception; - String createConfig(Long attachmentId, Mode mode, Type type, JSONObject actionLink, String referer, - String width, String height) throws Exception; -} diff --git a/src/main/java/onlyoffice/managers/config/ConfigManagerImpl.java b/src/main/java/onlyoffice/managers/config/ConfigManagerImpl.java deleted file mode 100644 index 7a34b470..00000000 --- a/src/main/java/onlyoffice/managers/config/ConfigManagerImpl.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.managers.config; - -import com.atlassian.confluence.languages.LocaleManager; -import com.atlassian.confluence.status.service.SystemInformationService; -import com.google.gson.Gson; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.managers.document.DocumentManager; -import onlyoffice.managers.jwt.JwtManager; -import onlyoffice.managers.url.UrlManager; -import onlyoffice.model.config.Config; -import onlyoffice.model.config.Type; -import onlyoffice.model.config.editor.Mode; -import onlyoffice.utils.attachment.AttachmentUtil; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.json.JSONObject; - -public class ConfigManagerImpl implements ConfigManager { - private final Logger log = LogManager.getLogger("onlyoffice.ConfigManagerImpl"); - - private final LocaleManager localeManager; - private final SystemInformationService sysInfoService; - - private final DocumentManager documentManager; - private final AttachmentUtil attachmentUtil; - private final UrlManager urlManager; - private final ConfigurationManager configurationManager; - private final JwtManager jwtManager; - - public ConfigManagerImpl(final LocaleManager localeManager, final SystemInformationService sysInfoService, - final DocumentManager documentManager, final AttachmentUtil attachmentUtil, - final UrlManager urlManager, final ConfigurationManager configurationManager, - final JwtManager jwtManager) { - this.localeManager = localeManager; - this.sysInfoService = sysInfoService; - this.documentManager = documentManager; - this.attachmentUtil = attachmentUtil; - this.urlManager = urlManager; - this.configurationManager = configurationManager; - this.jwtManager = jwtManager; - - } - - public String createConfig(final Long attachmentId, final Mode mode, final Type type, final JSONObject actionLink, - final String referer) - throws Exception { - return this.createConfig(attachmentId, mode, type, actionLink, referer, null, null); - } - - public String createConfig(final Long attachmentId, final Mode mode, final Type type, final JSONObject actionLink, - final String referer, final String width, final String height) throws Exception { - Gson gson = new Gson(); - - Config config = new Config( - localeManager, - documentManager, - attachmentUtil, - urlManager, - configurationManager, - attachmentId, - mode, - type, - actionLink, - referer, - sysInfoService.getConfluenceInfo().getBaseUrl() - ); - - if (width != null) { - config.setWidth(width); - } - - if (height != null) { - config.setHeight(height); - } - - if (jwtManager.jwtEnabled()) { - config.setToken(jwtManager.createToken(config)); - } - - return gson.toJson(config); - } -} diff --git a/src/main/java/onlyoffice/managers/configuration/ConfigurationManager.java b/src/main/java/onlyoffice/managers/configuration/ConfigurationManager.java deleted file mode 100644 index 4d18f508..00000000 --- a/src/main/java/onlyoffice/managers/configuration/ConfigurationManager.java +++ /dev/null @@ -1,38 +0,0 @@ -package onlyoffice.managers.configuration; - -import onlyoffice.model.Format; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.IOException; -import java.io.Serializable; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -public interface ConfigurationManager extends Serializable { - Properties getProperties() throws IOException; - - String getProperty(String propertyName); - - boolean forceSaveEnabled(); - - boolean selectDemo(Boolean demo); - - Boolean demoEnabled(); - - Boolean demoAvailable(Boolean forActivate); - - Boolean demoActive(); - - String getDemo(String key); - - Boolean getBooleanPluginSetting(String key, Boolean defaultValue); - - String getStringPluginSetting(String key, String defaultValue); - - Map getCustomizableEditingTypes(); - - CloseableHttpClient getHttpClient() throws Exception; - - List getSupportedFormats(); -} diff --git a/src/main/java/onlyoffice/managers/configuration/ConfigurationManagerImpl.java b/src/main/java/onlyoffice/managers/configuration/ConfigurationManagerImpl.java deleted file mode 100644 index acdd8cf4..00000000 --- a/src/main/java/onlyoffice/managers/configuration/ConfigurationManagerImpl.java +++ /dev/null @@ -1,244 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.managers.configuration; - -import com.atlassian.sal.api.pluginsettings.PluginSettings; -import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import onlyoffice.model.Format; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.ssl.SSLContextBuilder; -import org.apache.http.ssl.TrustStrategy; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLSession; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.TimeUnit; - -public class ConfigurationManagerImpl implements ConfigurationManager { - private final Logger log = LogManager.getLogger("onlyoffice.managers.configuration.ConfigurationManager"); - private final PluginSettings pluginSettings; - - private final String configurationPath = "onlyoffice-config.properties"; - private final String formatsPath = "app_data/document-formats/onlyoffice-docs-formats.json"; - private final String pluginDemoName = "onlyoffice.demo"; - private final String pluginDemoNameStart = "onlyoffice.demoStart"; - - private Map demoData; - private List supportedFormats; - - public ConfigurationManagerImpl(final PluginSettingsFactory pluginSettingsFactory) { - pluginSettings = pluginSettingsFactory.createGlobalSettings(); - - demoData = new HashMap(); - demoData.put("url", "https://onlinedocs.onlyoffice.com/"); - demoData.put("header", "AuthorizationJWT"); - demoData.put("secret", "sn2puSUF7muF5Jas"); - demoData.put("trial", "30"); - - InputStream inputStream = getClass().getClassLoader().getResourceAsStream(formatsPath); - - ObjectMapper objectMapper = new ObjectMapper(); - try { - supportedFormats = objectMapper.readValue(inputStream, new TypeReference>() { }); - } catch (IOException e) { - log.error(e.getMessage(), e); - } - } - - public Properties getProperties() throws IOException { - Properties properties = new Properties(); - InputStream inputStream = getClass().getClassLoader().getResourceAsStream(configurationPath); - if (inputStream != null) { - properties.load(inputStream); - } - return properties; - } - - public String getProperty(final String propertyName) { - try { - Properties properties = getProperties(); - String property = properties.getProperty(propertyName); - return property; - } catch (IOException e) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - e.printStackTrace(pw); - log.error(e.toString() + "\n" + sw.toString()); - return null; - } - } - - public boolean forceSaveEnabled() { - String forceSave = (String) pluginSettings.get("onlyoffice.forceSave"); - if (forceSave == null || forceSave.isEmpty()) { - return false; - } - return Boolean.parseBoolean(forceSave); - } - - public boolean selectDemo(final Boolean demo) { - pluginSettings.put(pluginDemoName, demo.toString()); - if (demo) { - String demoStart = (String) pluginSettings.get(pluginDemoNameStart); - if (demoStart == null || demoStart.isEmpty()) { - DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); - Date date = new Date(); - pluginSettings.put(pluginDemoNameStart, dateFormat.format(date)); - } - return true; - } - return false; - } - - public Boolean demoEnabled() { - String demo = (String) pluginSettings.get(pluginDemoName); - if (demo == null || demo.isEmpty()) { - return false; - } - return Boolean.parseBoolean(demo); - } - - public Boolean demoAvailable(final Boolean forActivate) { - String demoStart = (String) pluginSettings.get(pluginDemoNameStart); - if (demoStart != null && !demoStart.isEmpty()) { - DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); - try { - Calendar date = Calendar.getInstance(); - date.setTime(dateFormat.parse(demoStart)); - date.add(Calendar.DATE, Integer.parseInt(demoData.get("trial"))); - - return date.after(Calendar.getInstance()); - } catch (ParseException e) { - e.printStackTrace(); - } - } - return forActivate; - } - - public Boolean demoActive() { - return demoEnabled() && demoAvailable(false); - } - - public String getDemo(final String key) { - return demoData.get(key); - } - - public Boolean getBooleanPluginSetting(final String key, final Boolean defaultValue) { - String setting = (String) pluginSettings.get("onlyoffice." + key); - if (setting == null || setting.isEmpty()) { - return defaultValue; - } - return Boolean.parseBoolean(setting); - } - - public String getStringPluginSetting(final String key, final String defaultValue) { - String setting = (String) pluginSettings.get("onlyoffice." + key); - if (setting == null || setting.isEmpty()) { - return defaultValue; - } - return setting; - } - - public Map getCustomizableEditingTypes() { - Map customizableEditingTypes = new HashMap<>(); - List editingTypes; - - String editingTypesString = (String) pluginSettings.get("onlyoffice.editingTypes"); - - if (editingTypesString != null && !editingTypesString.isEmpty()) { - editingTypes = Arrays.asList( - editingTypesString.substring(1, editingTypesString.length() - 1).replace("\"", "").split(",")); - } else { - editingTypes = Arrays.asList("csv", "txt"); - } - - List formats = this.getSupportedFormats(); - - for (Format format : formats) { - if (format.getActions().contains("lossy-edit")) { - customizableEditingTypes.put(format.getName(), editingTypes.contains(format.getName())); - } - } - - return customizableEditingTypes; - } - - public CloseableHttpClient getHttpClient() throws Exception { - Integer timeout = (int) TimeUnit.SECONDS.toMillis(Long.parseLong(getProperty("timeout"))); - RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout).setSocketTimeout(timeout).build(); - - CloseableHttpClient httpClient; - - if (getBooleanPluginSetting("verifyCertificate", false) && !demoActive()) { - SSLContextBuilder builder = new SSLContextBuilder(); - - builder.loadTrustMaterial(null, new TrustStrategy() { - @Override - public boolean isTrusted(final X509Certificate[] chain, final String authType) - throws CertificateException { - return true; - } - }); - - SSLConnectionSocketFactory sslConnectionSocketFactory = - new SSLConnectionSocketFactory(builder.build(), new HostnameVerifier() { - @Override - public boolean verify(final String hostname, final SSLSession session) { - return true; - } - }); - - httpClient = - HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).setDefaultRequestConfig(config) - .build(); - } else { - httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).build(); - } - - return httpClient; - } - - public List getSupportedFormats() { - return supportedFormats; - } -} - diff --git a/src/main/java/onlyoffice/managers/convert/ConvertManager.java b/src/main/java/onlyoffice/managers/convert/ConvertManager.java deleted file mode 100644 index a466aeb2..00000000 --- a/src/main/java/onlyoffice/managers/convert/ConvertManager.java +++ /dev/null @@ -1,18 +0,0 @@ -package onlyoffice.managers.convert; - -import com.atlassian.confluence.user.ConfluenceUser; -import org.json.JSONObject; -import java.util.List; -import java.io.Serializable; - -public interface ConvertManager extends Serializable { - JSONObject convert(Long attachmentId, String ext, String convertToExt, ConfluenceUser user, - String title) throws Exception; - - JSONObject convert(Long attachmentId, String currentExt, String convertToExt, String url, String region, - boolean async, String title) throws Exception; - - String getTargetExt(String ext); - - List getTargetExtList(String ext); -} diff --git a/src/main/java/onlyoffice/managers/convert/ConvertManagerImpl.java b/src/main/java/onlyoffice/managers/convert/ConvertManagerImpl.java deleted file mode 100644 index c38e6597..00000000 --- a/src/main/java/onlyoffice/managers/convert/ConvertManagerImpl.java +++ /dev/null @@ -1,186 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.managers.convert; - -import com.atlassian.confluence.languages.LocaleManager; -import com.atlassian.confluence.user.ConfluenceUser; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.managers.document.DocumentManager; -import onlyoffice.managers.jwt.JwtManager; -import onlyoffice.managers.url.UrlManager; -import onlyoffice.model.Format; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpStatus; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.json.JSONObject; - -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; - -public class ConvertManagerImpl implements ConvertManager { - private final Logger log = LogManager.getLogger("onlyoffice.managers.convert.ConvertManager"); - - private static final int NOT_REACHED_STATUS = -10; - - private final LocaleManager localeManager; - private final UrlManager urlManager; - private final JwtManager jwtManager; - private final ConfigurationManager configurationManager; - private final DocumentManager documentManager; - - public ConvertManagerImpl(final UrlManager urlManager, final JwtManager jwtManager, - final ConfigurationManager configurationManager, - final DocumentManager documentManager, final LocaleManager localeManager) { - this.urlManager = urlManager; - this.jwtManager = jwtManager; - this.configurationManager = configurationManager; - this.documentManager = documentManager; - this.localeManager = localeManager; - } - - public JSONObject convert(final Long attachmentId, final String ext, final String convertToExt, - final ConfluenceUser user, final String title) throws Exception { - String url = urlManager.getFileUri(attachmentId); - String region = localeManager.getLocale(user).toLanguageTag(); - return convert(attachmentId, ext, convertToExt, url, region, true, title); - } - - public JSONObject convert(final Long attachmentId, final String currentExt, final String convertToExt, - final String url, final String region, final boolean async, - final String title) throws Exception { - try (CloseableHttpClient httpClient = configurationManager.getHttpClient()) { - JSONObject body = new JSONObject(); - body.put("async", async); - body.put("embeddedfonts", true); - body.put("filetype", currentExt); - body.put("outputtype", convertToExt); - body.put("key", documentManager.getKeyOfFile(attachmentId, false)); - body.put("url", url); - body.put("region", region); - body.put("title", title); - - if (Arrays.asList("bmp", "gif", "jpg", "png").contains(convertToExt)) { - JSONObject thumbnail = new JSONObject(); - thumbnail.put("first", false); - body.put("thumbnail", thumbnail); - } - - StringEntity requestEntity = new StringEntity(body.toString(), ContentType.APPLICATION_JSON); - String conversionServiceUrl = urlManager.getInnerDocEditorUrl() + configurationManager - .getProperties() - .getProperty("files.docservice.url.convert"); - - HttpPost request = new HttpPost(conversionServiceUrl); - request.setEntity(requestEntity); - request.setHeader("Accept", "application/json"); - - if (jwtManager.jwtEnabled()) { - String token = jwtManager.createToken(body); - JSONObject payloadBody = new JSONObject(); - payloadBody.put("payload", body); - String headerToken = jwtManager.createToken(body); - body.put("token", token); - String header = jwtManager.getJwtHeader(); - request.setHeader(header, "Bearer " + headerToken); - } - - log.debug("Sending POST to Docserver: " + body.toString()); - JSONObject callBackJson = new JSONObject(); - - try (CloseableHttpResponse response = httpClient.execute(request)) { - int status = response.getStatusLine().getStatusCode(); - - if (status != HttpStatus.SC_OK) { - log.error("Conversion service returned code " + status + ". URL: " + conversionServiceUrl); - callBackJson.put("error", NOT_REACHED_STATUS); - } else { - InputStream is = response.getEntity().getContent(); - String content = IOUtils.toString(is, StandardCharsets.UTF_8); - - log.debug("Docserver returned: " + content); - - try { - callBackJson = new JSONObject(content); - } catch (Exception e) { - throw new Exception("Couldn't convert JSON from docserver: " + e.getMessage()); - } - } - - return callBackJson; - } - } - } - - public String getTargetExt(final String ext) { - List supportedFormats = configurationManager.getSupportedFormats(); - - for (Format format : supportedFormats) { - if (format.getName().equals(ext)) { - switch (format.getType()) { - case WORD: - if (format.getName().equals("docxf") && format.getConvert().contains("oform")) { - return "oform"; - } - if (format.getName().equals("docx") && format.getConvert().contains("docxf")) { - return "docxf"; - } - if (format.getConvert().contains("docx")) { - return "docx"; - } - break; - case CELL: - if (format.getConvert().contains("xlsx")) { - return "xlsx"; - } - break; - case SLIDE: - if (format.getConvert().contains("pptx")) { - return "pptx"; - } - break; - default: - break; - } - } - } - - return null; - } - - public List getTargetExtList(final String ext) { - List supportedFormats = configurationManager.getSupportedFormats(); - - for (Format format : supportedFormats) { - if (format.getName().equals(ext)) { - return format.getConvert(); - } - } - - return null; - } - -} diff --git a/src/main/java/onlyoffice/managers/document/DocumentManager.java b/src/main/java/onlyoffice/managers/document/DocumentManager.java deleted file mode 100644 index 5e826f99..00000000 --- a/src/main/java/onlyoffice/managers/document/DocumentManager.java +++ /dev/null @@ -1,43 +0,0 @@ -package onlyoffice.managers.document; - -import com.atlassian.confluence.user.ConfluenceUser; -import onlyoffice.model.config.DocumentType; -import onlyoffice.model.config.Type; - -import java.io.IOException; -import java.io.Serializable; -import java.util.List; - -public interface DocumentManager extends Serializable { - long getMaxFileSize(); - - long getConvertationFileSizeMax(); - - String getKeyOfFile(Long attachmentId, boolean embedded); - - String createHash(String str); - - String readHash(String base64); - - String getCorrectName(String fileName, String fileExt, Long pageID); - - Long createDemo(String fileName, String fileExt, Long pageID, ConfluenceUser user) throws IOException; - - DocumentType getDocType(String ext); - - Type getEditorType(String userAgent); - - String getMimeType(String name); - - boolean isEditable(String fileExtension); - - boolean isFillForm(String fileExtension); - - boolean isViewable(String fileExtension); - - List getInsertImageTypes(); - - List getCompareFileTypes(); - - List getMailMergeTypes(); -} diff --git a/src/main/java/onlyoffice/managers/document/DocumentManagerImpl.java b/src/main/java/onlyoffice/managers/document/DocumentManagerImpl.java deleted file mode 100644 index cd89cf26..00000000 --- a/src/main/java/onlyoffice/managers/document/DocumentManagerImpl.java +++ /dev/null @@ -1,332 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.managers.document; - - -import com.atlassian.confluence.core.ContentEntityManager; -import com.atlassian.confluence.core.ContentEntityObject; -import com.atlassian.confluence.languages.LocaleManager; -import com.atlassian.confluence.pages.Attachment; -import com.atlassian.confluence.pages.AttachmentManager; -import com.atlassian.confluence.user.ConfluenceUser; -import com.atlassian.plugin.PluginAccessor; -import com.atlassian.sal.api.message.I18nResolver; -import com.atlassian.spring.container.ContainerManager; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.model.Format; -import onlyoffice.model.config.DocumentType; -import onlyoffice.model.config.Type; -import onlyoffice.utils.attachment.AttachmentUtil; -import org.apache.commons.codec.binary.Hex; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.MessageDigest; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Base64; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -public class DocumentManagerImpl implements DocumentManager { - private final Logger log = LogManager.getLogger("onlyoffice.managers.document.DocumentManager"); - private static final String USER_AGENT_MOBILE = "android|avantgo|playbook|blackberry|blazer|compal|elaine|fennec" - + "|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone" - + "|p(ixi|re)\\/|plucker|pocket|psp|symbian|treo|up\\.(browser|link)|vodafone|wap" - + "|windows (ce|phone)|xda|xiino"; - private static final int DEFAULT_MAX_FILE_SIZE = 5242880; - private static final int MAX_KEY_LENGTH = 20; - - private final I18nResolver i18nResolver; - private final ConfigurationManager configurationManager; - private final AttachmentUtil attachmentUtil; - - public DocumentManagerImpl(final I18nResolver i18nResolver, final ConfigurationManager configurationManager, - final AttachmentUtil attachmentUtil) { - this.i18nResolver = i18nResolver; - this.configurationManager = configurationManager; - this.attachmentUtil = attachmentUtil; - } - - public long getMaxFileSize() { - long size; - try { - String filesizeMax = configurationManager.getProperty("filesize-max"); - size = Long.parseLong(filesizeMax); - } catch (Exception ex) { - size = 0; - } - - return size > 0 ? size : DEFAULT_MAX_FILE_SIZE; - } - - public String getKeyOfFile(final Long attachmentId, final boolean embedded) { - String key = attachmentUtil.getCollaborativeEditingKey(attachmentId); - if (key == null) { - String hashCode = attachmentUtil.getHashCode(attachmentId); - key = generateRevisionId(hashCode); - } - - return embedded ? key + "_embedded" : key; - } - - public long getConvertationFileSizeMax() { - long size; - try { - String filesizeMax = configurationManager.getProperty("convertation-filesize-max"); - size = Long.parseLong(filesizeMax); - } catch (Exception ex) { - size = 0; - } - - return size > 0 ? size : DEFAULT_MAX_FILE_SIZE; - } - - private String generateRevisionId(final String expectedKey) { - String result = expectedKey; - - if (result.length() > MAX_KEY_LENGTH) { - result = Integer.toString(result.hashCode()); - } - String key = result.replace("[^0-9-.a-zA-Z_=]", "_"); - key = key.substring(0, Math.min(key.length(), MAX_KEY_LENGTH)); - log.info("key = " + key); - return key; - } - - public String createHash(final String str) { - try { - String secret = configurationManager.getProperty("files.docservice.secret"); - - String payload = getHashHex(str + secret) + "?" + str; - - String base64 = Base64.getEncoder().encodeToString(payload.getBytes("UTF-8")); - return base64; - } catch (Exception ex) { - log.error(ex); - } - return ""; - } - - public String readHash(final String base64) { - try { - String str = new String(Base64.getDecoder().decode(base64), "UTF-8"); - - String secret = configurationManager.getProperty("files.docservice.secret"); - - String[] payloadParts = str.split("\\?"); - - String payload = getHashHex(payloadParts[1] + secret); - if (payload.equals(payloadParts[0])) { - return payloadParts[1]; - } - } catch (Exception ex) { - log.error(ex); - } - return ""; - } - - private String getHashHex(final String str) { - try { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] digest = md.digest(str.getBytes()); - String hex = Hex.encodeHexString(digest); - - return hex; - } catch (Exception ex) { - log.error(ex); - } - return ""; - } - - public String getCorrectName(final String fileName, final String fileExt, final Long pageID) { - ContentEntityManager contentEntityManager = - (ContentEntityManager) ContainerManager.getComponent("contentEntityManager"); - AttachmentManager attachmentManager = (AttachmentManager) ContainerManager.getComponent("attachmentManager"); - ContentEntityObject contentEntityObject = contentEntityManager.getById(pageID); - - List attachments = attachmentManager.getLatestVersionsOfAttachments(contentEntityObject); - String name = (fileName + "." + fileExt).replaceAll("[*?:\"<>/|\\\\]", "_"); - int count = 0; - Boolean flag = true; - - while (flag) { - flag = false; - for (Attachment attachment : attachments) { - if (attachment.getFileName().equals(name)) { - count++; - name = fileName + " (" + count + ")." + fileExt; - flag = true; - break; - } - } - } - - return name; - } - - private InputStream getDemoFile(final ConfluenceUser user, final String fileExt) { - LocaleManager localeManager = (LocaleManager) ContainerManager.getComponent("localeManager"); - PluginAccessor pluginAccessor = (PluginAccessor) ContainerManager.getComponent("pluginAccessor"); - - String pathToDemoFile = "app_data/document-templates/" + localeManager - .getLocale(user) - .toString() - .replace("_", "-"); - - if (pluginAccessor.getDynamicResourceAsStream(pathToDemoFile) == null) { - pathToDemoFile = "app_data/en-US"; - } - - return pluginAccessor.getDynamicResourceAsStream(pathToDemoFile + "/new." + fileExt); - } - - public Long createDemo(final String fileName, final String fileExt, final Long pageId, final ConfluenceUser user) - throws - IOException { - String extension = - fileExt == null || !fileExt.equals("xlsx") && !fileExt.equals("pptx") && !fileExt.equals("docxf") - ? "docx" : fileExt.trim(); - String name = fileName == null || fileName.equals("") - ? i18nResolver.getText("onlyoffice.editor.dialog.filecreate." + extension) : fileName; - - InputStream demoFile = getDemoFile(user, extension); - - name = getCorrectName(name, extension, pageId); - String mimeType = getMimeType(name); - - Attachment attachment = - attachmentUtil.createNewAttachment(name, mimeType, demoFile, demoFile.available(), pageId, user); - - return attachment.getContentId().asLong(); - } - - public DocumentType getDocType(final String ext) { - List supportedFormats = configurationManager.getSupportedFormats(); - - for (Format format : supportedFormats) { - if (format.getName().equals(ext)) { - - return format.getType(); - } - } - - return null; - } - - public String getMimeType(final String name) { - Path path = new File(name).toPath(); - String mimeType = null; - try { - mimeType = Files.probeContentType(path); - } catch (IOException e) { - log.error(e.getMessage(), e); - } - return mimeType != null ? mimeType : "application/octet-stream"; - } - - public Type getEditorType(final String userAgent) { - Pattern pattern = Pattern.compile(USER_AGENT_MOBILE, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); - if (userAgent != null && pattern.matcher(userAgent).find()) { - return Type.MOBILE; - } else { - return Type.DESKTOP; - } - } - - public boolean isEditable(final String ext) { - List supportedFormats = configurationManager.getSupportedFormats(); - - for (Format format : supportedFormats) { - if (format.getName().equals(ext) && format.getActions().contains("edit")) { - return true; - } - } - - Map customizableEditingTypes = configurationManager.getCustomizableEditingTypes(); - - for (Map.Entry customizableEditingType : customizableEditingTypes.entrySet()) { - if (customizableEditingType.getKey().equals(ext) && customizableEditingType.getValue()) { - return true; - } - } - - return false; - } - - public boolean isFillForm(final String ext) { - List supportedFormats = configurationManager.getSupportedFormats(); - - for (Format format : supportedFormats) { - if (format.getName().equals(ext) && format.getActions().contains("fill")) { - return true; - } - } - - return false; - } - - public boolean isViewable(final String fileExtension) { - List supportedFormats = configurationManager.getSupportedFormats(); - - for (Format format : supportedFormats) { - if (format.getName().equals(fileExtension) && format.getActions().contains("view")) { - return true; - } - } - - return false; - } - - public List getInsertImageTypes() { - return Arrays.asList("bmp", "gif", "jpeg", "jpg", "png"); - } - - public List getCompareFileTypes() { - List supportedFormats = configurationManager.getSupportedFormats(); - List result = new ArrayList<>(); - - for (Format format : supportedFormats) { - if (format.getType().equals(DocumentType.WORD)) { - result.add(format.getName()); - } - } - - return result; - } - - public List getMailMergeTypes() { - List supportedFormats = configurationManager.getSupportedFormats(); - List result = new ArrayList<>(); - - for (Format format : supportedFormats) { - if (format.getType().equals(DocumentType.CELL)) { - result.add(format.getName()); - } - } - - return result; - } -} diff --git a/src/main/java/onlyoffice/managers/jwt/JwtManager.java b/src/main/java/onlyoffice/managers/jwt/JwtManager.java deleted file mode 100644 index fb87286d..00000000 --- a/src/main/java/onlyoffice/managers/jwt/JwtManager.java +++ /dev/null @@ -1,23 +0,0 @@ -package onlyoffice.managers.jwt; - -import org.json.JSONObject; - -import java.io.Serializable; -import java.util.Map; - -public interface JwtManager extends Serializable { - - String createToken(Object payload) throws Exception; - - String createToken(JSONObject payload) throws Exception; - - String verify(String token); - - String createInternalToken(Map payloadMap); - - String verifyInternalToken(String token); - - Boolean jwtEnabled(); - - String getJwtHeader(); -} diff --git a/src/main/java/onlyoffice/managers/jwt/JwtManagerImpl.java b/src/main/java/onlyoffice/managers/jwt/JwtManagerImpl.java deleted file mode 100644 index ae9c0f27..00000000 --- a/src/main/java/onlyoffice/managers/jwt/JwtManagerImpl.java +++ /dev/null @@ -1,136 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.managers.jwt; - -import com.atlassian.config.ApplicationConfiguration; -import com.atlassian.sal.api.pluginsettings.PluginSettings; -import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; -import com.auth0.jwt.JWT; -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.fasterxml.jackson.databind.ObjectMapper; -import onlyoffice.managers.configuration.ConfigurationManager; -import org.json.JSONObject; - -import java.util.Base64; -import java.util.Map; -import java.util.Random; - -public class JwtManagerImpl implements JwtManager { - - private static final long ACCEPT_LEEWAY = 3; - private static final int PLUGIN_SECRET_LENGTH = 32; - - private final ApplicationConfiguration applicationConfiguration; - private final ConfigurationManager configurationManager; - private final PluginSettings settings; - - public JwtManagerImpl(final PluginSettingsFactory pluginSettingsFactory, - final ApplicationConfiguration applicationConfiguration, - final ConfigurationManager configurationManager) { - settings = pluginSettingsFactory.createGlobalSettings(); - this.applicationConfiguration = applicationConfiguration; - this.configurationManager = configurationManager; - } - - public String createToken(final Object payload) { - ObjectMapper objectMapper = new ObjectMapper(); - Map payloadMap = objectMapper.convertValue(payload, Map.class); - - return createToken(payloadMap, getJwtSecret()); - } - - public String createToken(final JSONObject payload) throws Exception { - ObjectMapper objectMapper = new ObjectMapper(); - Map payloadMap = objectMapper.readValue(payload.toString(), Map.class); - - return createToken(payloadMap, getJwtSecret()); - } - - public String verify(final String token) { - return verifyToken(token, getJwtSecret()); - } - - public String createInternalToken(final Map payloadMap) { - return createToken(payloadMap, getPluginSecret()); - } - - public String verifyInternalToken(final String token) { - return verifyToken(token, getPluginSecret()); - } - - public Boolean jwtEnabled() { - return configurationManager.demoActive() || settings.get("onlyoffice.jwtSecret") != null - && !((String) settings.get("onlyoffice.jwtSecret")).isEmpty(); - } - - public String getJwtHeader() { - String header = configurationManager.demoActive() - ? configurationManager - .getDemo("header") : (String) applicationConfiguration.getProperty("onlyoffice.jwt.header"); - return header == null || header.isEmpty() ? "Authorization" : header; - } - - private String getJwtSecret() { - return configurationManager.demoActive() - ? configurationManager.getDemo("secret") : (String) settings.get("onlyoffice.jwtSecret"); - } - - private String createToken(final Map payloadMap, final String key) { - Algorithm algorithm = Algorithm.HMAC256(key); - - String token = JWT.create() - .withPayload(payloadMap) - .sign(algorithm); - - return token; - } - - private String verifyToken(final String token, final String key) { - Algorithm algorithm = Algorithm.HMAC256(key); - Base64.Decoder decoder = Base64.getUrlDecoder(); - - DecodedJWT jwt = JWT.require(algorithm) - .acceptLeeway(ACCEPT_LEEWAY) - .build() - .verify(token); - - return new String(decoder.decode(jwt.getPayload())); - } - - private String getPluginSecret() { - if (settings.get("onlyoffice.plugin-secret") == null || settings.get("onlyoffice.plugin-secret").equals("")) { - Random random = new Random(); - char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray(); - - char[] randBuffer = new char[PLUGIN_SECRET_LENGTH]; - for (int i = 0; i < randBuffer.length; i++) { - randBuffer[i] = numbersAndLetters[random.nextInt(numbersAndLetters.length)]; - } - - String secret = new String(randBuffer); - - settings.put("onlyoffice.plugin-secret", secret); - - return secret; - } else { - return (String) settings.get("onlyoffice.plugin-secret"); - } - } -} diff --git a/src/main/java/onlyoffice/managers/url/UrlManager.java b/src/main/java/onlyoffice/managers/url/UrlManager.java deleted file mode 100644 index de89e877..00000000 --- a/src/main/java/onlyoffice/managers/url/UrlManager.java +++ /dev/null @@ -1,37 +0,0 @@ -package onlyoffice.managers.url; - -import onlyoffice.model.config.DocumentType; - -import java.io.Serializable; - -public interface UrlManager extends Serializable { - String getPublicDocEditorUrl(); - - String getInnerDocEditorUrl(); - - String getFileUri(Long attachmentId); - - String getAttachmentDiffUri(Long attachmentId); - - String getHistoryInfoUri(Long attachmentId); - - String getHistoryDataUri(Long attachmentId); - - String getAttachmentDataUri(); - - String getSaveAsUri(); - - String getReferenceDataUri(Long pageId); - - String getCallbackUrl(Long attachmentId); - - String getGobackUrl(Long attachmentId, String referer); - - String getCreateUri(Long pageId, String ext); - - String replaceDocEditorURLToInternal(String url); - - String getDocServiceApiUrl(); - - String getFaviconUrl(DocumentType documentType); -} diff --git a/src/main/java/onlyoffice/managers/url/UrlManagerImpl.java b/src/main/java/onlyoffice/managers/url/UrlManagerImpl.java deleted file mode 100644 index 3bd4db02..00000000 --- a/src/main/java/onlyoffice/managers/url/UrlManagerImpl.java +++ /dev/null @@ -1,238 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.managers.url; - -import com.atlassian.confluence.pages.Attachment; -import com.atlassian.confluence.pages.AttachmentManager; -import com.atlassian.plugin.webresource.UrlMode; -import com.atlassian.plugin.webresource.WebResourceUrlProvider; -import com.atlassian.confluence.setup.settings.SettingsManager; -import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; -import com.atlassian.confluence.user.ConfluenceUser; -import com.atlassian.confluence.util.GeneralUtil; -import com.atlassian.sal.api.pluginsettings.PluginSettings; -import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; -import com.atlassian.spring.container.ContainerManager; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.managers.document.DocumentManager; -import onlyoffice.model.config.DocumentType; -import onlyoffice.managers.jwt.JwtManager; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; - -import java.util.HashMap; -import java.util.Map; - -public class UrlManagerImpl implements UrlManager { - private final Logger log = LogManager.getLogger("onlyoffice.managers.url.UrlManager"); - private final String docEditorServlet = "plugins/servlet/onlyoffice/doceditor"; - private final String callbackServlet = "plugins/servlet/onlyoffice/save"; - private final String historyServlet = "plugins/servlet/onlyoffice/history"; - private final String fileProviderServlet = "plugins/servlet/onlyoffice/file-provider"; - private final String apiServlet = "plugins/servlet/onlyoffice/api"; - - private final WebResourceUrlProvider webResourceUrlProvider; - private final SettingsManager settingsManager; - private final PluginSettings pluginSettings; - private final ConfigurationManager configurationManager; - private final DocumentManager documentManager; - private final JwtManager jwtManager; - - public UrlManagerImpl(final WebResourceUrlProvider webResourceUrlProvider, - final PluginSettingsFactory pluginSettingsFactory, final SettingsManager settingsManager, - final ConfigurationManager configurationManager, final DocumentManager documentManager, - final JwtManager jwtManager) { - this.webResourceUrlProvider = webResourceUrlProvider; this.settingsManager = settingsManager; - this.configurationManager = configurationManager; - this.documentManager = documentManager; - this.jwtManager = jwtManager; - pluginSettings = pluginSettingsFactory.createGlobalSettings(); - } - - public String getPublicDocEditorUrl() { - String url = ""; - if (configurationManager.demoActive()) { - url = configurationManager.getDemo("url"); - } else { - url = (String) pluginSettings.get("onlyoffice.apiUrl"); - } - return (url == null || url.isEmpty()) ? "" : url; - } - - - public String getInnerDocEditorUrl() { - String url = (String) pluginSettings.get("onlyoffice.docInnerUrl"); - if (url == null || url.isEmpty() || configurationManager.demoActive()) { - return getPublicDocEditorUrl(); - } else { - return url; - } - } - - public String getFileUri(final Long attachmentId) { - ConfluenceUser user = AuthenticatedUserThreadLocal.get(); - - Map params = new HashMap<>(); - - if (user != null) { - params.put("userKey", user.getKey().getStringValue()); - } - params.put("attachmentId", attachmentId.toString()); - params.put("action", "download"); - - String fileUri = - getConfluenceBaseUrl() + fileProviderServlet + "?token=" + jwtManager.createInternalToken(params); - - return fileUri; - } - - public String getAttachmentDiffUri(final Long attachmentId) { - String hash = documentManager.createHash(Long.toString(attachmentId)); - String diffAttachmentUrl = - getConfluenceBaseUrl() + historyServlet + "?type=diff&vkey=" + GeneralUtil.urlEncode(hash); - - return diffAttachmentUrl; - } - - public String getHistoryInfoUri(final Long attachmentId) { - String hash = documentManager.createHash(Long.toString(attachmentId)); - String historyInfoUri = - getConfluenceBaseUrl() + historyServlet + "?type=info&vkey=" + GeneralUtil.urlEncode(hash); - - return historyInfoUri; - } - - public String getHistoryDataUri(final Long attachmentId) { - String hash = documentManager.createHash(Long.toString(attachmentId)); - String historyDataUri = - getConfluenceBaseUrl() + historyServlet + "?type=data&vkey=" + GeneralUtil.urlEncode(hash); - - return historyDataUri; - } - - public String getAttachmentDataUri() { - String attachmentDataUri = getConfluenceBaseUrl() + apiServlet + "?type=attachment-data"; - - return attachmentDataUri; - } - - public String getSaveAsUri() { - String saveAsUri = getConfluenceBaseUrl() + apiServlet + "?type=save-as"; - - return saveAsUri; - } - - public String getReferenceDataUri(final Long pageId) { - String referenceDataUri = getConfluenceBaseUrl() + apiServlet + "?type=reference-data&pageId=" + pageId; - - return referenceDataUri; - } - - public String getCallbackUrl(final Long attachmentId) { - ConfluenceUser user = AuthenticatedUserThreadLocal.get(); - - Map params = new HashMap<>(); - params.put("userKey", user.getKey().getStringValue()); - params.put("attachmentId", attachmentId.toString()); - params.put("action", "callback"); - - String callbackUrl = - getConfluenceBaseUrl() + callbackServlet + "?token=" + jwtManager.createInternalToken(params); - log.info("callbackUrl " + callbackUrl); - - return callbackUrl; - } - - public String getGobackUrl(final Long attachmentId, final String referer) { - String gobackUrl = ""; - - if (referer != null && referer.contains("/display/")) { - gobackUrl = referer; - } else { - String viewPageAttachments = "/pages/viewpageattachments.action?pageId="; - AttachmentManager attachmentManager = - (AttachmentManager) ContainerManager.getComponent("attachmentManager"); - Attachment attachment = attachmentManager.getAttachment(attachmentId); - gobackUrl = settingsManager.getGlobalSettings().getBaseUrl() + viewPageAttachments - + attachment.getContainer().getContentId().asLong(); - } - - log.info("gobackUrl = " + gobackUrl); - - return gobackUrl; - } - - public String getCreateUri(final Long pageId, final String ext) { - - String targetExt = "docx"; - - switch (documentManager.getDocType(ext)) { - case WORD: - targetExt = ext.equals("docxf") ? "docxf" : "docx"; - break; - case CELL: - targetExt = "xlsx"; - break; - case SLIDE: - targetExt = "pptx"; - break; - default: - } - - return getConfluenceBaseUrl() + docEditorServlet + "?pageId=" + pageId + "&fileExt=" + targetExt; - } - - private String getConfluenceBaseUrl() { - String url = (String) pluginSettings.get("onlyoffice.confUrl"); - if (url == null || url.isEmpty()) { - return settingsManager.getGlobalSettings().getBaseUrl() + "/"; - } else { - return url; - } - } - - public String replaceDocEditorURLToInternal(final String url) { - String innerDocEditorUrl = getInnerDocEditorUrl(); - String publicDocEditorUrl = getPublicDocEditorUrl(); - String result = url; - - if (!publicDocEditorUrl.equals(innerDocEditorUrl) && !configurationManager.demoActive()) { - result = result.replace(publicDocEditorUrl, innerDocEditorUrl); - } - return result; - } - - public String getDocServiceApiUrl() { - return getPublicDocEditorUrl() + configurationManager.getProperty("files.docservice.url.api"); - } - - public String getFaviconUrl(final DocumentType documentType) { - String nameIcon = "word"; - - if (documentType != null) { - nameIcon = documentType.name().toLowerCase(); - } - - return webResourceUrlProvider.getStaticPluginResourceUrl( - "onlyoffice.onlyoffice-confluence-plugin:onlyoffice-confluence-plugin-resources-editor", - nameIcon + ".ico", - UrlMode.ABSOLUTE - ); - } -} diff --git a/src/main/java/onlyoffice/model/Format.java b/src/main/java/onlyoffice/model/Format.java deleted file mode 100644 index d99b824c..00000000 --- a/src/main/java/onlyoffice/model/Format.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.model; - -import onlyoffice.model.config.DocumentType; - -import java.util.List; - -public class Format { - private String name; - private DocumentType type; - private List actions; - private List convert; - private List mime; - - public String getName() { - return name; - } - - public DocumentType getType() { - return type; - } - - public List getActions() { - return actions; - } - - public List getConvert() { - return convert; - } - - public List getMime() { - return mime; - } - - public void setName(final String name) { - this.name = name; - } - - public void setType(final DocumentType type) { - this.type = type; - } - - public void setAction(final List actions) { - this.actions = actions; - } - - public void setConvert(final List convert) { - this.convert = convert; - } - - public void setMime(final List mime) { - this.mime = mime; - } - -} diff --git a/src/main/java/onlyoffice/model/config/Config.java b/src/main/java/onlyoffice/model/config/Config.java deleted file mode 100644 index f5f69bdf..00000000 --- a/src/main/java/onlyoffice/model/config/Config.java +++ /dev/null @@ -1,114 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.model.config; - -import com.atlassian.confluence.languages.LocaleManager; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.managers.document.DocumentManager; -import onlyoffice.managers.url.UrlManager; -import onlyoffice.model.config.document.Document; -import onlyoffice.model.config.editor.EditorConfig; -import onlyoffice.model.config.editor.Mode; -import onlyoffice.utils.attachment.AttachmentUtil; -import org.json.JSONObject; - -public class Config { - private Type type; - private DocumentType documentType; - private EditorConfig editorConfig; - private Document document; - private String token; - private String height = "100%"; - private String width = "100%"; - - public Config(final LocaleManager localeManager, final DocumentManager documentManager, - final AttachmentUtil attachmentUtil, final UrlManager urlManager, - final ConfigurationManager configurationManager, final Long attachmentId, final Mode mode, - final Type type, final JSONObject actionLink, final String referer, final String instanceId) { - this.type = type; - this.documentType = documentManager.getDocType(attachmentUtil.getFileExt(attachmentId)); - this.document = new Document(documentManager, attachmentUtil, urlManager, attachmentId, type, instanceId); - this.editorConfig = new EditorConfig( - localeManager, - attachmentUtil, - urlManager, - configurationManager, - attachmentId, - mode, - actionLink, - referer - ); - } - - public String getToken() { - return token; - } - - public void setToken(final String token) { - this.token = token; - } - - public String getHeight() { - return height; - } - - public void setHeight(final String height) { - this.height = height; - } - - public String getWidth() { - return width; - } - - public void setWidth(final String width) { - this.width = width; - } - - public Type getType() { - return type; - } - - public void setType(final Type type) { - this.type = type; - } - - public DocumentType getDocumentType() { - return documentType; - } - - public void setDocumentType(final DocumentType documentType) { - this.documentType = documentType; - } - - public EditorConfig getEditorConfig() { - return editorConfig; - } - - public void setEditorConfig(final EditorConfig editorConfig) { - this.editorConfig = editorConfig; - } - - public Document getDocument() { - return document; - } - - public void setDocument(final Document document) { - this.document = document; - } -} diff --git a/src/main/java/onlyoffice/model/config/document/Document.java b/src/main/java/onlyoffice/model/config/document/Document.java deleted file mode 100644 index cfb4cf2a..00000000 --- a/src/main/java/onlyoffice/model/config/document/Document.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.model.config.document; - -import onlyoffice.managers.document.DocumentManager; -import onlyoffice.managers.url.UrlManager; -import onlyoffice.model.config.Type; -import onlyoffice.utils.attachment.AttachmentUtil; - -public class Document { - private String key; - private String title; - private String url; - private String fileType; - private Permissions permissions; - private ReferenceData referenceData; - - public Document(final DocumentManager documentManager, final AttachmentUtil attachmentUtil, - final UrlManager urlManager, final Long attachmentId, final Type type, final String instanceId) { - key = documentManager.getKeyOfFile(attachmentId, type.equals(Type.EMBEDDED)); - title = attachmentUtil.getFileName(attachmentId); - fileType = attachmentUtil.getFileExt(attachmentId); - url = urlManager.getFileUri(attachmentId); - permissions = new Permissions(documentManager, attachmentUtil, attachmentId); - referenceData = new ReferenceData(attachmentId, instanceId); - } - - public String getKey() { - return key; - } - - public void setKey(final String key) { - this.key = key; - } - - public String getTitle() { - return title; - } - - public void setTitle(final String title) { - this.title = title; - } - - public String getUrl() { - return url; - } - - public void setUrl(final String url) { - this.url = url; - } - - public String getFileType() { - return fileType; - } - - public void setFileType(final String fileType) { - this.fileType = fileType; - } - - public Permissions getPermissions() { - return permissions; - } - - public void setPermissions(final Permissions permissions) { - this.permissions = permissions; - } -} diff --git a/src/main/java/onlyoffice/model/config/document/Permissions.java b/src/main/java/onlyoffice/model/config/document/Permissions.java deleted file mode 100644 index b37b9c48..00000000 --- a/src/main/java/onlyoffice/model/config/document/Permissions.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.model.config.document; - -import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; -import onlyoffice.managers.document.DocumentManager; -import onlyoffice.utils.attachment.AttachmentUtil; - -public class Permissions { - private boolean edit; - - public Permissions(final DocumentManager documentManager, final AttachmentUtil attachmentUtil, - final Long attachmentId) { - String fileExt = attachmentUtil.getFileExt(attachmentId); - boolean isEditable = documentManager.isEditable(fileExt) || documentManager.isFillForm(fileExt); - edit = attachmentUtil.checkAccess(attachmentId, AuthenticatedUserThreadLocal.get(), true) && isEditable; - } - - public boolean isEdit() { - return edit; - } - - public void setEdit(final boolean edit) { - this.edit = edit; - } -} diff --git a/src/main/java/onlyoffice/model/config/document/ReferenceData.java b/src/main/java/onlyoffice/model/config/document/ReferenceData.java deleted file mode 100644 index 352e7f40..00000000 --- a/src/main/java/onlyoffice/model/config/document/ReferenceData.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.model.config.document; - -public class ReferenceData { - private long fileKey; - private String instanceId; - - public ReferenceData(final long fileKey, final String instanceId) { - this.fileKey = fileKey; - this.instanceId = instanceId; - } - - public long getFileKey() { - return fileKey; - } - - public void setFileKey(final long fileKey) { - this.fileKey = fileKey; - } - - public String getInstanceId() { - return instanceId; - } - - public void setInstanceId(final String instanceId) { - this.instanceId = instanceId; - } -} diff --git a/src/main/java/onlyoffice/model/config/editor/Customization.java b/src/main/java/onlyoffice/model/config/editor/Customization.java deleted file mode 100644 index 20ec88fe..00000000 --- a/src/main/java/onlyoffice/model/config/editor/Customization.java +++ /dev/null @@ -1,120 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package onlyoffice.model.config.editor; - -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.managers.url.UrlManager; - -public class Customization { - private boolean forcesave; - private boolean chat; - private boolean compactHeader; - private boolean feedback; - private boolean help; - private boolean toolbarNoTabs; - private ReviewDisplay reviewDisplay; - private Goback goback; - - public Customization(final UrlManager urlManager, final ConfigurationManager configurationManager, - final Long attachmentId, final String referer) { - this.forcesave = configurationManager.forceSaveEnabled(); - this.chat = configurationManager.getBooleanPluginSetting("chat", true); - this.compactHeader = configurationManager.getBooleanPluginSetting("compactHeader", false); - this.feedback = configurationManager.getBooleanPluginSetting("feedback", false); - this.help = configurationManager.getBooleanPluginSetting("helpMenu", true); - this.toolbarNoTabs = configurationManager.getBooleanPluginSetting("toolbarNoTabs", false); - if (!configurationManager.getStringPluginSetting("reviewDisplay", "original").equals("original")) { - switch (configurationManager.getStringPluginSetting("reviewDisplay", "original")) { - case "markup": - this.reviewDisplay = ReviewDisplay.MARKUP; - break; - case "final": - this.reviewDisplay = ReviewDisplay.FINAL; - break; - case "original": - default: - this.reviewDisplay = ReviewDisplay.ORIGINAL; - } - } - this.goback = new Goback(urlManager, attachmentId, referer); - } - - public boolean isForcesave() { - return forcesave; - } - - public void setForcesave(final boolean forcesave) { - this.forcesave = forcesave; - } - - public boolean isChat() { - return chat; - } - - public void setChat(final boolean chat) { - this.chat = chat; - } - - public boolean isCompactHeader() { - return compactHeader; - } - - public void setCompactHeader(final boolean compactHeader) { - this.compactHeader = compactHeader; - } - - public boolean isFeedback() { - return feedback; - } - - public void setFeedback(final boolean feedback) { - this.feedback = feedback; - } - - public boolean isHelp() { - return help; - } - - public void setHelp(final boolean help) { - this.help = help; - } - - public boolean isToolbarNoTabs() { - return toolbarNoTabs; - } - - public void setToolbarNoTabs(final boolean toolbarNoTabs) { - this.toolbarNoTabs = toolbarNoTabs; - } - - public ReviewDisplay getReviewDisplay() { - return reviewDisplay; - } - - public void setReviewDisplay(final ReviewDisplay reviewDisplay) { - this.reviewDisplay = reviewDisplay; - } - - public Goback getGoback() { - return goback; - } - - public void setGoback(final Goback goback) { - this.goback = goback; - } -} diff --git a/src/main/java/onlyoffice/model/config/editor/EditorConfig.java b/src/main/java/onlyoffice/model/config/editor/EditorConfig.java deleted file mode 100644 index 081273b1..00000000 --- a/src/main/java/onlyoffice/model/config/editor/EditorConfig.java +++ /dev/null @@ -1,118 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.model.config.editor; - -import com.atlassian.confluence.languages.LocaleManager; -import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; -import com.atlassian.confluence.user.ConfluenceUser; -import onlyoffice.managers.configuration.ConfigurationManager; -import onlyoffice.managers.url.UrlManager; -import onlyoffice.utils.attachment.AttachmentUtil; -import org.json.JSONObject; - -public class EditorConfig { - private Mode mode; - private String createUrl; - private String callbackUrl; - private String lang; - private JSONObject actionLink; - private Customization customization; - private User user; - - public EditorConfig(final LocaleManager localeManager, final AttachmentUtil attachmentUtil, - final UrlManager urlManager, final ConfigurationManager configurationManager, - final Long attachmentId, final Mode mode, final JSONObject actionLink, final String referer) { - ConfluenceUser user = AuthenticatedUserThreadLocal.get(); - Long pageId = attachmentUtil.getAttachmentPageId(attachmentId); - String fileExt = attachmentUtil.getFileExt(attachmentId); - - this.mode = mode; - this.actionLink = actionLink; - this.lang = localeManager.getLocale(user).toLanguageTag(); - this.customization = new Customization(urlManager, configurationManager, attachmentId, referer); - - if (user != null) { - this.user = new User(user); - } - - if (attachmentUtil.checkAccessCreate(user, pageId)) { - this.createUrl = urlManager.getCreateUri(pageId, fileExt); - } - - if (attachmentUtil.checkAccess(attachmentId, user, true)) { - this.callbackUrl = urlManager.getCallbackUrl(attachmentId); - } - } - - public Mode getMode() { - return mode; - } - - public void setMode(final Mode mode) { - this.mode = mode; - } - - public String getCreateUrl() { - return createUrl; - } - - public void setCreateUrl(final String createUrl) { - this.createUrl = createUrl; - } - - public String getCallbackUrl() { - return callbackUrl; - } - - public void setCallbackUrl(final String callbackUrl) { - this.callbackUrl = callbackUrl; - } - - public String getLang() { - return lang; - } - - public void setLang(final String lang) { - this.lang = lang; - } - - public JSONObject getActionLink() { - return actionLink; - } - - public void setActionLink(final JSONObject actionLink) { - this.actionLink = actionLink; - } - - public Customization getCustomization() { - return customization; - } - - public void setCustomization(final Customization customization) { - this.customization = customization; - } - - public User getUser() { - return user; - } - - public void setUser(final User user) { - this.user = user; - } -} diff --git a/src/main/java/onlyoffice/model/config/editor/User.java b/src/main/java/onlyoffice/model/config/editor/User.java deleted file mode 100644 index 21852e7f..00000000 --- a/src/main/java/onlyoffice/model/config/editor/User.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * - * (c) Copyright Ascensio System SIA 2023 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package onlyoffice.model.config.editor; - -import com.atlassian.confluence.user.ConfluenceUser; - -public class User { - private String id; - private String name; - - public User(final ConfluenceUser user) { - this.id = user.getName(); - this.name = user.getFullName(); - } - - public String getId() { - return id; - } - - public String getName() { - return name; - } - - public void setId(final String id) { - this.id = id; - } - - public void setName(final String name) { - this.name = name; - } -} diff --git a/src/main/java/onlyoffice/model/config/editor/ReviewDisplay.java b/src/main/java/onlyoffice/model/dto/UsersInfoRequest.java similarity index 62% rename from src/main/java/onlyoffice/model/config/editor/ReviewDisplay.java rename to src/main/java/onlyoffice/model/dto/UsersInfoRequest.java index be09896d..928795a8 100644 --- a/src/main/java/onlyoffice/model/config/editor/ReviewDisplay.java +++ b/src/main/java/onlyoffice/model/dto/UsersInfoRequest.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,18 @@ * */ -package onlyoffice.model.config.editor; +package onlyoffice.model.dto; -import com.google.gson.annotations.SerializedName; +import java.util.ArrayList; +import java.util.List; +public class UsersInfoRequest { + private List ids = new ArrayList<>(); -public enum ReviewDisplay { - @SerializedName("markup") - MARKUP, - @SerializedName("final") - FINAL, - @SerializedName("original") - ORIGINAL + public List getIds() { + return ids; + } + + public void setIds(final List ids) { + this.ids = ids; + } } diff --git a/src/main/java/onlyoffice/model/config/DocumentType.java b/src/main/java/onlyoffice/model/dto/UsersInfoResponse.java similarity index 58% rename from src/main/java/onlyoffice/model/config/DocumentType.java rename to src/main/java/onlyoffice/model/dto/UsersInfoResponse.java index ebb0a343..ea27fdcb 100644 --- a/src/main/java/onlyoffice/model/config/DocumentType.java +++ b/src/main/java/onlyoffice/model/dto/UsersInfoResponse.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,20 @@ * */ -package onlyoffice.model.config; +package onlyoffice.model.dto; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.gson.annotations.SerializedName; +import com.onlyoffice.model.common.User; -public enum DocumentType { - @JsonProperty("word") - @SerializedName("word") - WORD, - @JsonProperty("cell") - @SerializedName("cell") - CELL, - @JsonProperty("slide") - @SerializedName("slide") - SLIDE +import java.util.List; + +public class UsersInfoResponse { + private List users; + + public List getUsers() { + return users; + } + + public void setUsers(final List users) { + this.users = users; + } } diff --git a/src/main/java/onlyoffice/model/config/editor/Mode.java b/src/main/java/onlyoffice/sdk/manager/document/DocumentManager.java similarity index 66% rename from src/main/java/onlyoffice/model/config/editor/Mode.java rename to src/main/java/onlyoffice/sdk/manager/document/DocumentManager.java index 2d5d7dad..7d5b5263 100644 --- a/src/main/java/onlyoffice/model/config/editor/Mode.java +++ b/src/main/java/onlyoffice/sdk/manager/document/DocumentManager.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,9 @@ * */ -package onlyoffice.model.config.editor; +package onlyoffice.sdk.manager.document; -import com.google.gson.annotations.SerializedName; - -public enum Mode { - @SerializedName("view") - VIEW, - @SerializedName("edit") - EDIT +public interface DocumentManager extends com.onlyoffice.manager.document.DocumentManager { + String getCorrectNewFileName(String fileName, String fileExt, Long pageID); + String getMimeType(String name); } diff --git a/src/main/java/onlyoffice/sdk/manager/document/DocumentManagerImpl.java b/src/main/java/onlyoffice/sdk/manager/document/DocumentManagerImpl.java new file mode 100644 index 00000000..fc78d941 --- /dev/null +++ b/src/main/java/onlyoffice/sdk/manager/document/DocumentManagerImpl.java @@ -0,0 +1,128 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package onlyoffice.sdk.manager.document; + +import com.atlassian.confluence.core.ContentEntityManager; +import com.atlassian.confluence.core.ContentEntityObject; +import com.atlassian.confluence.pages.Attachment; +import com.atlassian.confluence.pages.AttachmentManager; +import com.atlassian.spring.container.ContainerManager; +import com.onlyoffice.manager.document.DefaultDocumentManager; +import com.onlyoffice.manager.settings.SettingsManager; +import onlyoffice.utils.attachment.AttachmentUtil; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +public class DocumentManagerImpl extends DefaultDocumentManager implements DocumentManager { + private final Logger log = LogManager.getLogger("onlyoffice.sdk.manager.document.DocumentManagerImpl"); + private static final int MAX_KEY_LENGTH = 20; + + private final AttachmentUtil attachmentUtil; + private final AttachmentManager attachmentManager; + + public DocumentManagerImpl(final SettingsManager settingsManager, final AttachmentUtil attachmentUtil, + final AttachmentManager attachmentManager) { + super(settingsManager); + this.attachmentUtil = attachmentUtil; + this.attachmentManager = attachmentManager; + } + + @Override + public String getDocumentKey(final String fileId, final boolean embedded) { + Long attachmentId = Long.parseLong(fileId); + String key = attachmentUtil.getCollaborativeEditingKey(attachmentId); + if (key == null) { + String hashCode = attachmentUtil.getHashCode(attachmentId); + key = generateRevisionId(hashCode); + } + + return embedded ? key + "_embedded" : key; + } + + @Override + public String getDocumentName(final String fileId) { + Long attachmentId = Long.parseLong(fileId); + + Attachment attachment = attachmentManager.getAttachment(attachmentId); + + if (attachment != null) { + return attachment.getFileName(); + } + + return null; + } + + @Override + public String getCorrectNewFileName(final String fileName, final String fileExtension, final Long pageID) { + ContentEntityManager contentEntityManager = + (ContentEntityManager) ContainerManager.getComponent("contentEntityManager"); + AttachmentManager attachmentManager = (AttachmentManager) ContainerManager.getComponent("attachmentManager"); + ContentEntityObject contentEntityObject = contentEntityManager.getById(pageID); + + List attachments = attachmentManager.getLatestVersionsOfAttachments(contentEntityObject); + String name = (fileName + "." + fileExtension).replaceAll("[*?:\"<>/|\\\\]", "_"); + int count = 0; + Boolean flag = true; + + while (flag) { + flag = false; + for (Attachment attachment : attachments) { + if (attachment.getFileName().equals(name)) { + count++; + name = fileName + " (" + count + ")." + fileExtension; + flag = true; + break; + } + } + } + + return name; + } + + @Override + public String getMimeType(final String name) { + Path path = new File(name).toPath(); + String mimeType = null; + try { + mimeType = Files.probeContentType(path); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + return mimeType != null ? mimeType : "application/octet-stream"; + } + + private String generateRevisionId(final String expectedKey) { + String result = expectedKey; + + if (result.length() > MAX_KEY_LENGTH) { + result = Integer.toString(result.hashCode()); + } + String key = result.replace("[^0-9-.a-zA-Z_=]", "_"); + key = key.substring(0, Math.min(key.length(), MAX_KEY_LENGTH)); + log.info("key = " + key); + return key; + } + +} diff --git a/src/main/java/onlyoffice/sdk/manager/security/JwtManager.java b/src/main/java/onlyoffice/sdk/manager/security/JwtManager.java new file mode 100644 index 00000000..109994b9 --- /dev/null +++ b/src/main/java/onlyoffice/sdk/manager/security/JwtManager.java @@ -0,0 +1,28 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package onlyoffice.sdk.manager.security; + +import java.util.Map; + +public interface JwtManager extends com.onlyoffice.manager.security.JwtManager { + String createInternalToken(Map payloadMap); + String verifyInternalToken(String token); + String createHash(String str); + String readHash(String base64); +} diff --git a/src/main/java/onlyoffice/sdk/manager/security/JwtManagerImpl.java b/src/main/java/onlyoffice/sdk/manager/security/JwtManagerImpl.java new file mode 100644 index 00000000..41caac38 --- /dev/null +++ b/src/main/java/onlyoffice/sdk/manager/security/JwtManagerImpl.java @@ -0,0 +1,115 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package onlyoffice.sdk.manager.security; + +import com.atlassian.sal.api.pluginsettings.PluginSettings; +import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; +import com.onlyoffice.manager.security.DefaultJwtManager; +import org.apache.commons.codec.binary.Hex; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +import java.security.MessageDigest; +import java.util.Base64; +import java.util.Map; +import java.util.Random; + +public class JwtManagerImpl extends DefaultJwtManager implements JwtManager { + private final Logger log = LogManager.getLogger("onlyoffice.sdk.manager.security.JwtManagerImpl"); + private static final int PLUGIN_SECRET_LENGTH = 32; + private static final String FILES_CONFLUENCE_SECRET = "Vskoproizvolny Salt par Chivreski"; + private final PluginSettings pluginSettings; + + public JwtManagerImpl(final PluginSettingsFactory pluginSettingsFactory, + final com.onlyoffice.manager.settings.SettingsManager settingsManagerSdk) { + super(settingsManagerSdk); + this.pluginSettings = pluginSettingsFactory.createGlobalSettings(); + } + + + public String createInternalToken(final Map payloadMap) { + return super.createToken(payloadMap, getPluginSecret()); + } + + public String verifyInternalToken(final String token) { + return verifyToken(token, getPluginSecret()); + } + + public String createHash(final String str) { + try { + String payload = getHashHex(str + FILES_CONFLUENCE_SECRET) + "?" + str; + + String base64 = Base64.getEncoder().encodeToString(payload.getBytes("UTF-8")); + return base64; + } catch (Exception ex) { + log.error(ex); + } + return ""; + } + + public String readHash(final String base64) { + try { + String str = new String(Base64.getDecoder().decode(base64), "UTF-8"); + + String[] payloadParts = str.split("\\?"); + + String payload = getHashHex(payloadParts[1] + FILES_CONFLUENCE_SECRET); + if (payload.equals(payloadParts[0])) { + return payloadParts[1]; + } + } catch (Exception ex) { + log.error(ex); + } + return ""; + } + + private String getHashHex(final String str) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] digest = md.digest(str.getBytes()); + String hex = Hex.encodeHexString(digest); + + return hex; + } catch (Exception ex) { + log.error(ex); + } + return ""; + } + + private String getPluginSecret() { + if (pluginSettings.get("onlyoffice.plugin-secret") == null + || pluginSettings.get("onlyoffice.plugin-secret").equals("")) { + Random random = new Random(); + char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray(); + + char[] randBuffer = new char[PLUGIN_SECRET_LENGTH]; + for (int i = 0; i < randBuffer.length; i++) { + randBuffer[i] = numbersAndLetters[random.nextInt(numbersAndLetters.length)]; + } + + String secret = new String(randBuffer); + + pluginSettings.put("onlyoffice.plugin-secret", secret); + + return secret; + } else { + return (String) pluginSettings.get("onlyoffice.plugin-secret"); + } + } +} diff --git a/src/main/java/onlyoffice/sdk/manager/settings/SettingsManagerImpl.java b/src/main/java/onlyoffice/sdk/manager/settings/SettingsManagerImpl.java new file mode 100644 index 00000000..5fb47cac --- /dev/null +++ b/src/main/java/onlyoffice/sdk/manager/settings/SettingsManagerImpl.java @@ -0,0 +1,43 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package onlyoffice.sdk.manager.settings; + +import com.atlassian.sal.api.pluginsettings.PluginSettings; +import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; +import com.onlyoffice.manager.settings.DefaultSettingsManager; + +public class SettingsManagerImpl extends DefaultSettingsManager { + private static final String SETTINGS_PREFIX = "onlyoffice."; + + private final PluginSettings pluginSettings; + + public SettingsManagerImpl(final PluginSettingsFactory pluginSettingsFactory) { + this.pluginSettings = pluginSettingsFactory.createGlobalSettings(); + } + + @Override + public String getSetting(final String name) { + return (String) pluginSettings.get(SETTINGS_PREFIX + name); + } + + @Override + public void setSetting(final String name, final String value) { + pluginSettings.put(SETTINGS_PREFIX + name, value); + } +} diff --git a/src/main/java/onlyoffice/model/config/editor/Goback.java b/src/main/java/onlyoffice/sdk/manager/url/UrlManager.java similarity index 50% rename from src/main/java/onlyoffice/model/config/editor/Goback.java rename to src/main/java/onlyoffice/sdk/manager/url/UrlManager.java index f095d40a..50f4d52d 100644 --- a/src/main/java/onlyoffice/model/config/editor/Goback.java +++ b/src/main/java/onlyoffice/sdk/manager/url/UrlManager.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,22 +16,17 @@ * */ -package onlyoffice.model.config.editor; +package onlyoffice.sdk.manager.url; -import onlyoffice.managers.url.UrlManager; +import com.onlyoffice.model.documenteditor.config.document.DocumentType; -public class Goback { - private String url; - - public Goback(final UrlManager urlManager, final Long attachmentId, final String referer) { - this.url = urlManager.getGobackUrl(attachmentId, referer); - } - - public String getUrl() { - return url; - } - - public void setUrl(final String url) { - this.url = url; - } +public interface UrlManager extends com.onlyoffice.manager.url.UrlManager { + String getAttachmentDiffUri(Long attachmentId); + String getHistoryInfoUri(Long attachmentId); + String getHistoryDataUri(Long attachmentId); + String getAttachmentDataUri(); + String getSaveAsUri(); + String getReferenceDataUri(Long pageId); + String getFaviconUrl(DocumentType documentType); + String getUsersInfoUrl(); } diff --git a/src/main/java/onlyoffice/sdk/manager/url/UrlManagerImpl.java b/src/main/java/onlyoffice/sdk/manager/url/UrlManagerImpl.java new file mode 100644 index 00000000..b28a5ab6 --- /dev/null +++ b/src/main/java/onlyoffice/sdk/manager/url/UrlManagerImpl.java @@ -0,0 +1,208 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package onlyoffice.sdk.manager.url; + +import com.atlassian.confluence.pages.Attachment; +import com.atlassian.confluence.pages.AttachmentManager; +import com.atlassian.confluence.setup.settings.SettingsManager; +import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; +import com.atlassian.confluence.user.ConfluenceUser; +import com.atlassian.confluence.util.GeneralUtil; +import com.atlassian.plugin.webresource.UrlMode; +import com.atlassian.plugin.webresource.WebResourceUrlProvider; +import com.atlassian.spring.container.ContainerManager; +import com.onlyoffice.manager.document.DocumentManager; +import com.onlyoffice.manager.url.DefaultUrlManager; +import com.onlyoffice.model.documenteditor.config.document.DocumentType; +import com.onlyoffice.model.settings.SettingsConstants; +import onlyoffice.sdk.manager.security.JwtManager; +import onlyoffice.utils.attachment.AttachmentUtil; + +import java.util.HashMap; +import java.util.Map; + +public class UrlManagerImpl extends DefaultUrlManager implements UrlManager { + + public static final String API_SERVLET = "/plugins/servlet/onlyoffice/api"; + public static final String DOC_EDITOR_SERVLET = "/plugins/servlet/onlyoffice/doceditor"; + public static final String FILE_PROVIDER_SERVLET = "/plugins/servlet/onlyoffice/file-provider"; + public static final String CALLBACK_SERVLET = "/plugins/servlet/onlyoffice/save"; + public static final String HISTORY_SERVLET = "/plugins/servlet/onlyoffice/history"; + + private final WebResourceUrlProvider webResourceUrlProvider; + private final SettingsManager settingsManager; + + private final JwtManager jwtManager; + private final AttachmentUtil attachmentUtil; + private final DocumentManager documentManager; + + public UrlManagerImpl(final WebResourceUrlProvider webResourceUrlProvider, final SettingsManager settingsManager, + final JwtManager jwtManager, final AttachmentUtil attachmentUtil, + final DocumentManager documentManager, + final com.onlyoffice.manager.settings.SettingsManager settingsManagerSdk) { + super(settingsManagerSdk); + this.webResourceUrlProvider = webResourceUrlProvider; + this.settingsManager = settingsManager; + this.jwtManager = jwtManager; + this.attachmentUtil = attachmentUtil; + this.documentManager = documentManager; + } + + @Override + public String getFileUrl(final String fileId) { + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + + Map params = new HashMap<>(); + + if (user != null) { + params.put("userKey", user.getKey().getStringValue()); + } + params.put("attachmentId", fileId); + params.put("action", "download"); + + String fileUri = + getConfluenceBaseUrl(true) + FILE_PROVIDER_SERVLET + "?token=" + jwtManager.createInternalToken(params); + + return fileUri; + } + + @Override + public String getCallbackUrl(final String fileId) { + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + + Map params = new HashMap<>(); + params.put("userKey", user.getKey().getStringValue()); + params.put("attachmentId", fileId); + params.put("action", "callback"); + + String callbackUrl = getConfluenceBaseUrl(true) + + CALLBACK_SERVLET + + "?token=" + + jwtManager.createInternalToken(params); + + return callbackUrl; + } + + @Override + public String getGobackUrl(final String fileId) { + String viewPageAttachments = "/pages/viewpageattachments.action?pageId="; + AttachmentManager attachmentManager = + (AttachmentManager) ContainerManager.getComponent("attachmentManager"); + Attachment attachment = attachmentManager.getAttachment(Long.parseLong(fileId)); + return settingsManager.getGlobalSettings().getBaseUrl() + + viewPageAttachments + + attachment.getContainer().getContentId().asLong(); + } + + @Override + public String getCreateUrl(final String fileId) { + Long pageId = attachmentUtil.getAttachmentPageId(Long.parseLong(fileId)); + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + + if (attachmentUtil.checkAccessCreate(user, pageId)) { + String fileName = documentManager.getDocumentName(fileId); + String extension = documentManager.getExtension(fileName); + DocumentType documentType = documentManager.getDocumentType(fileName); + + if (!extension.equals("docxf")) { + extension = documentManager.getDefaultExtension(documentType); + } + + return getConfluenceBaseUrl(false) + DOC_EDITOR_SERVLET + "?pageId=" + pageId + "&fileExt=" + extension; + } else { + return null; + } + } + + @Override + public String getTestConvertUrl(final String url) { + return getConfluenceBaseUrl(true) + "/plugins/servlet/onlyoffice/test"; + } + + public String getAttachmentDiffUri(final Long attachmentId) { + String hash = jwtManager.createHash(Long.toString(attachmentId)); + String diffAttachmentUrl = + getConfluenceBaseUrl(true) + HISTORY_SERVLET + "?type=diff&vkey=" + GeneralUtil.urlEncode(hash); + + return diffAttachmentUrl; + } + + public String getHistoryInfoUri(final Long attachmentId) { + String hash = jwtManager.createHash(Long.toString(attachmentId)); + String historyInfoUri = + getConfluenceBaseUrl(false) + HISTORY_SERVLET + "?type=info&vkey=" + GeneralUtil.urlEncode(hash); + + return historyInfoUri; + } + + public String getHistoryDataUri(final Long attachmentId) { + String hash = jwtManager.createHash(Long.toString(attachmentId)); + String historyDataUri = + getConfluenceBaseUrl(false) + HISTORY_SERVLET + "?type=data&vkey=" + GeneralUtil.urlEncode(hash); + + return historyDataUri; + } + public String getAttachmentDataUri() { + String attachmentDataUri = getConfluenceBaseUrl(false) + API_SERVLET + "?type=attachment-data"; + + return attachmentDataUri; + } + + public String getSaveAsUri() { + String saveAsUri = getConfluenceBaseUrl(false) + API_SERVLET + "?type=save-as"; + + return saveAsUri; + } + + public String getReferenceDataUri(final Long pageId) { + String referenceDataUri = getConfluenceBaseUrl(false) + API_SERVLET + "?type=reference-data&pageId=" + pageId; + + return referenceDataUri; + } + + public String getFaviconUrl(final DocumentType documentType) { + String nameIcon = "word"; + + if (documentType != null) { + nameIcon = documentType.name().toLowerCase(); + } + + return webResourceUrlProvider.getStaticPluginResourceUrl( + "onlyoffice.onlyoffice-confluence-plugin:onlyoffice-confluence-plugin-resources-editor", + nameIcon + ".ico", + UrlMode.ABSOLUTE + ); + } + + public String getUsersInfoUrl() { + String usersInfoUrl = getConfluenceBaseUrl(false) + API_SERVLET + "?type=users-info"; + + return usersInfoUrl; + } + + private String getConfluenceBaseUrl(final Boolean inner) { + String productInnerUrl = getSettingsManager().getSetting(SettingsConstants.PRODUCT_INNER_URL); + + if (inner && productInnerUrl != null && !productInnerUrl.isEmpty()) { + return sanitizeUrl(productInnerUrl); + } else { + return sanitizeUrl(settingsManager.getGlobalSettings().getBaseUrl()); + } + } +} diff --git a/src/main/java/onlyoffice/sdk/service/CallbackServiceImpl.java b/src/main/java/onlyoffice/sdk/service/CallbackServiceImpl.java new file mode 100644 index 00000000..2a9a96c7 --- /dev/null +++ b/src/main/java/onlyoffice/sdk/service/CallbackServiceImpl.java @@ -0,0 +1,249 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package onlyoffice.sdk.service; + +import com.atlassian.confluence.pages.Attachment; +import com.atlassian.confluence.pages.AttachmentManager; +import com.atlassian.confluence.pages.persistence.dao.AttachmentDao; +import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; +import com.atlassian.confluence.user.ConfluenceUser; +import com.atlassian.sal.api.transaction.TransactionCallback; +import com.atlassian.sal.api.transaction.TransactionTemplate; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onlyoffice.manager.request.RequestManager; +import com.onlyoffice.manager.security.JwtManager; +import com.onlyoffice.manager.settings.SettingsManager; + +import com.onlyoffice.model.convertservice.ConvertRequest; +import com.onlyoffice.model.convertservice.ConvertResponse; +import com.onlyoffice.model.documenteditor.Callback; +import com.onlyoffice.model.documenteditor.callback.Action; +import com.onlyoffice.model.documenteditor.callback.History; +import com.onlyoffice.model.documenteditor.callback.action.Type; +import com.onlyoffice.service.documenteditor.callback.DefaultCallbackService; +import com.onlyoffice.service.convert.ConvertService; +import onlyoffice.sdk.manager.document.DocumentManager; +import onlyoffice.sdk.manager.url.UrlManager; +import onlyoffice.utils.attachment.AttachmentUtil; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpEntity; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +public class CallbackServiceImpl extends DefaultCallbackService { + private final AttachmentUtil attachmentUtil; + private final ConvertService convertService; + private final RequestManager requestManager; + private final TransactionTemplate transactionTemplate; + private final AttachmentManager attachmentManager; + private final SettingsManager settingsManager; + private final UrlManager urlManager; + private final DocumentManager documentManager; + + public CallbackServiceImpl(final JwtManager jwtManager, final AttachmentUtil attachmentUtil, + final ConvertService convertService, final RequestManager requestManager, + final SettingsManager settingsManager, final TransactionTemplate transactionTemplate, + final AttachmentManager attachmentManager, final UrlManager urlManager, + final DocumentManager documentManager) { + super(jwtManager, settingsManager); + this.settingsManager = settingsManager; + this.attachmentUtil = attachmentUtil; + this.convertService = convertService; + this.requestManager = requestManager; + this.urlManager = urlManager; + this.transactionTemplate = transactionTemplate; + this.attachmentManager = attachmentManager; + this.documentManager = documentManager; + } + + public void handlerEditing(final Callback callback, final String fileId) throws Exception { + if (callback.getActions() != null) { + List actions = callback.getActions(); + if (actions.size() > 0) { + Action action = actions.get(0); + if (action.getType().equals(Type.CONNECTED)) { + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + + if (user == null || !attachmentUtil.checkAccess(Long.valueOf(fileId), user, true)) { + throw new SecurityException("Access denied. User " + user + + " don't have the appropriate permissions to edit this document."); + } + + if (attachmentUtil.getCollaborativeEditingKey(Long.valueOf(fileId)) == null) { + String key = callback.getKey(); + attachmentUtil.setCollaborativeEditingKey(Long.valueOf(fileId), key); + } + } + } + } + } + + public void handlerSave(final Callback callback, final String fileId) throws Exception { + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + if (user != null && attachmentUtil.checkAccess(Long.valueOf(fileId), user, true)) { + String fileType = callback.getFiletype(); + String downloadUrl = callback.getUrl(); + History history = callback.getHistory(); + String changesUrl = callback.getChangesurl(); + + Boolean forceSaveVersion = + attachmentUtil.getPropertyAsBoolean(Long.valueOf(fileId), "onlyoffice-force-save"); + + attachmentUtil.setCollaborativeEditingKey(Long.valueOf(fileId), null); + + if (forceSaveVersion) { + saveAttachmentFromUrl(Long.valueOf(fileId), downloadUrl, fileType, user, false); + attachmentUtil.removeProperty(Long.valueOf(fileId), "onlyoffice-force-save"); + attachmentUtil.removeAttachmentChanges(Long.valueOf(fileId)); + + File convertedFile = attachmentUtil.getConvertedFile(Long.valueOf(fileId)); + if (convertedFile.exists()) { + convertedFile.delete(); + } + } else { + saveAttachmentFromUrl(Long.valueOf(fileId), downloadUrl, fileType, user, true); + } + + ObjectMapper mapper = new ObjectMapper(); + + saveAttachmentChanges(Long.valueOf(fileId), mapper.writeValueAsString(history), changesUrl); + } else { + throw new SecurityException("Try save without access: " + user); + } + } + + public void handlerForcesave(final Callback callback, final String fileId) throws Exception { + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + if (user != null && attachmentUtil.checkAccess(Long.valueOf(fileId), user, true)) { + if (settingsManager.getSettingBoolean("customization.forcesave", false)) { + String fileType = callback.getFiletype(); + String downloadUrl = callback.getUrl(); + History history = callback.getHistory(); + String changesUrl = callback.getChangesurl(); + + Boolean forceSaveVersion = + attachmentUtil.getPropertyAsBoolean(Long.valueOf(fileId), "onlyoffice-force-save"); + + if (forceSaveVersion) { + saveAttachmentFromUrl(Long.valueOf(fileId), downloadUrl, fileType, user, false); + attachmentUtil.removeAttachmentChanges(Long.valueOf(fileId)); + } else { + String key = attachmentUtil.getCollaborativeEditingKey(Long.valueOf(fileId)); + attachmentUtil.setCollaborativeEditingKey(Long.valueOf(fileId), null); + + saveAttachmentFromUrl(Long.valueOf(fileId), downloadUrl, fileType, user, true); + attachmentUtil.setCollaborativeEditingKey(Long.valueOf(fileId), key); + attachmentUtil.setProperty(Long.valueOf(fileId), "onlyoffice-force-save", "true"); + } + + ObjectMapper mapper = new ObjectMapper(); + + saveAttachmentChanges(Long.valueOf(fileId), mapper.writeValueAsString(history), + changesUrl); + + File convertedFile = attachmentUtil.getConvertedFile(Long.valueOf(fileId)); + if (convertedFile.exists()) { + convertedFile.delete(); + } + } + } else { + throw new SecurityException("Try save without access: " + user); + } + } + + private void saveAttachmentFromUrl(final Long attachmentId, final String downloadUrl, final String fileType, + final ConfluenceUser user, final boolean newVersion) throws Exception { + String documentName = documentManager.getDocumentName(String.valueOf(attachmentId)); + String extension = documentManager.getExtension(documentName); + String url = urlManager.replaceToInnerDocumentServerUrl(downloadUrl); + + ConvertRequest convertRequest = ConvertRequest.builder() + .outputtype(extension) + .url(url) + .build(); + + if (!extension.equals(fileType)) { + ConvertResponse convertResponse = convertService.processConvert(convertRequest, + String.valueOf(attachmentId)); + url = convertResponse.getFileUrl(); + } + + requestManager.executeGetRequest(url, new RequestManager.Callback() { + @Override + public Void doWork(final Object response) throws Exception { + byte[] bytes = IOUtils.toByteArray(((HttpEntity) response).getContent()); + InputStream inputStream = new ByteArrayInputStream(bytes); + + if (newVersion) { + attachmentUtil.saveAttachmentAsNewVersion(attachmentId, inputStream, bytes.length, user); + } else { + attachmentUtil.updateAttachment(attachmentId, inputStream, bytes.length, user); + } + + return null; + } + }); + } + + private void saveAttachmentChanges(final Long attachmentId, final String history, final String changesUrl) + throws Exception { + Attachment attachment = attachmentManager.getAttachment(attachmentId); + + if (history != null && !history.isEmpty() && changesUrl != null && !changesUrl.isEmpty()) { + InputStream changesStream = new ByteArrayInputStream(history.getBytes(StandardCharsets.UTF_8)); + Attachment changes = + new Attachment("onlyoffice-changes.json", "application/json", changesStream.available(), ""); + changes.setContainer(attachment.getContainer()); + changes.setHidden(true); + + String innerChangesUrl = urlManager.replaceToInnerDocumentServerUrl(changesUrl); + requestManager.executeGetRequest(innerChangesUrl, new RequestManager.Callback() { + @Override + public Void doWork(final Object response) throws Exception { + byte[] bytes = IOUtils.toByteArray(((HttpEntity) response).getContent()); + InputStream streamDiff = new ByteArrayInputStream(bytes); + + Attachment diff = new Attachment("onlyoffice-diff.zip", "application/zip", bytes.length, ""); + diff.setContainer(attachment.getContainer()); + diff.setHidden(true); + + attachment.addAttachment(changes); + attachment.addAttachment(diff); + + AttachmentDao attDao = attachmentManager.getAttachmentDao(); + Object result = transactionTemplate.execute(new TransactionCallback() { + @Override + public Object doInTransaction() { + attDao.saveNewAttachment(changes, changesStream); + attDao.saveNewAttachment(diff, streamDiff); + attDao.updateAttachment(attachment); + return null; + } + }); + + return null; + } + }); + } + } +} diff --git a/src/main/java/onlyoffice/sdk/service/ConfigServiceImpl.java b/src/main/java/onlyoffice/sdk/service/ConfigServiceImpl.java new file mode 100644 index 00000000..fe4c9328 --- /dev/null +++ b/src/main/java/onlyoffice/sdk/service/ConfigServiceImpl.java @@ -0,0 +1,87 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package onlyoffice.sdk.service; + +import com.atlassian.confluence.status.service.SystemInformationService; +import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; +import com.atlassian.confluence.user.ConfluenceUser; +import com.onlyoffice.manager.security.JwtManager; +import com.onlyoffice.manager.settings.SettingsManager; +import com.onlyoffice.manager.url.UrlManager; +import com.onlyoffice.model.common.User; +import com.onlyoffice.model.documenteditor.config.document.Permissions; +import com.onlyoffice.model.documenteditor.config.document.ReferenceData; +import com.onlyoffice.service.documenteditor.config.DefaultConfigService; +import com.onlyoffice.manager.document.DocumentManager; +import onlyoffice.utils.attachment.AttachmentUtil; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +public class ConfigServiceImpl extends DefaultConfigService { + + private final Logger log = LogManager.getLogger("onlyoffice.ConfigServiceImpl"); + private final SystemInformationService sysInfoService; + + private AttachmentUtil attachmentUtil; + + public ConfigServiceImpl(final DocumentManager documentManager, final UrlManager urlManager, + final JwtManager jwtManager, final SystemInformationService sysInfoService, + final AttachmentUtil attachmentUtil, final SettingsManager settingsManager) { + super(documentManager, urlManager, jwtManager, settingsManager); + this.sysInfoService = sysInfoService; + this.attachmentUtil = attachmentUtil; + } + + @Override + public ReferenceData getReferenceData(final String fileId) { + return ReferenceData.builder() + .fileKey(fileId) + .instanceId(sysInfoService.getConfluenceInfo().getBaseUrl()) + .build(); + } + + @Override + public Permissions getPermissions(final String fileId) { + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + String fileName = getDocumentManager().getDocumentName(fileId); + + Boolean editPermission = attachmentUtil.checkAccess(Long.parseLong(fileId), user, true); + Boolean isEditable = super.getDocumentManager().isEditable(fileName); + Boolean isFillable = super.getDocumentManager().isFillable(fileName); + + return Permissions.builder() + .edit(editPermission && isEditable) + .fillForms(editPermission && isFillable) + .build(); + } + + @Override + public User getUser() { + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + + if (user != null) { + return User.builder() + .id(user.getKey().getStringValue()) + .name(user.getFullName()) + .build(); + } else { + return super.getUser(); + } + } +} diff --git a/src/main/java/onlyoffice/model/config/Type.java b/src/main/java/onlyoffice/sdk/service/SettingsValidationService.java similarity index 63% rename from src/main/java/onlyoffice/model/config/Type.java rename to src/main/java/onlyoffice/sdk/service/SettingsValidationService.java index 33c31c8a..75909c95 100644 --- a/src/main/java/onlyoffice/model/config/Type.java +++ b/src/main/java/onlyoffice/sdk/service/SettingsValidationService.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,12 @@ * */ -package onlyoffice.model.config; +package onlyoffice.sdk.service; -import com.google.gson.annotations.SerializedName; +import com.onlyoffice.model.settings.validation.ValidationResult; -public enum Type { - @SerializedName("desktop") - DESKTOP, - @SerializedName("mobile") - MOBILE, - @SerializedName("embedded") - EMBEDDED +import java.util.Map; + +public interface SettingsValidationService extends com.onlyoffice.service.settings.SettingsValidationService { + Map validateSettings(); } diff --git a/src/main/java/onlyoffice/sdk/service/SettingsValidationServiceImpl.java b/src/main/java/onlyoffice/sdk/service/SettingsValidationServiceImpl.java new file mode 100644 index 00000000..93f6c238 --- /dev/null +++ b/src/main/java/onlyoffice/sdk/service/SettingsValidationServiceImpl.java @@ -0,0 +1,140 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package onlyoffice.sdk.service; + +import com.atlassian.sal.api.message.I18nResolver; +import com.onlyoffice.manager.request.RequestManager; +import com.onlyoffice.manager.settings.SettingsManager; +import com.onlyoffice.manager.url.UrlManager; +import com.onlyoffice.model.common.CommonResponse; +import com.onlyoffice.model.settings.validation.ValidationResult; +import com.onlyoffice.model.settings.validation.status.Status; +import com.onlyoffice.service.settings.DefaultSettingsValidationService; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +import java.util.HashMap; +import java.util.Map; + +public class SettingsValidationServiceImpl extends DefaultSettingsValidationService + implements SettingsValidationService { + private final Logger log = LogManager.getLogger("onlyoffice.ValidationSettingsServiceImpl"); + + private final I18nResolver i18n; + + public SettingsValidationServiceImpl(final I18nResolver i18n, final RequestManager requestManager, + final UrlManager urlManager, final SettingsManager settingsManager) { + super(requestManager, urlManager, settingsManager); + this.i18n = i18n; + } + + @Override + public Map validateSettings() { + Map result = new HashMap<>(); + + try { + result.put( + "documentServer", + checkDocumentServer() + ); + } catch (Exception e) { + log.error(e.getMessage(), e); + + result.put( + "documentServer", + ValidationResult.builder() + .status(Status.FAILED) + .error(CommonResponse.Error.CONNECTION) + .build() + ); + } + + try { + result.put( + "commandService", + checkCommandService() + ); + } catch (Exception e) { + log.error(e.getMessage(), e); + + result.put( + "commandService", + ValidationResult.builder() + .status(Status.FAILED) + .error(CommonResponse.Error.CONNECTION) + .build() + ); + } + + try { + result.put( + "convertService", + checkConvertService() + ); + } catch (Exception e) { + log.error(e.getMessage(), e); + + result.put( + "convertService", + ValidationResult.builder() + .status(Status.FAILED) + .error(CommonResponse.Error.CONNECTION) + .build() + ); + } + + if (result.get("documentServer").getStatus().equals(Status.FAILED)) { + result.get("documentServer") + .setMessage( + i18n.getText( + "onlyoffice.server.common.error." + result.get("documentServer") + .getError() + .toString() + .toLowerCase() + ) + ); + } + + if (result.get("commandService").getStatus().equals(Status.FAILED)) { + result.get("commandService") + .setMessage( + i18n.getText( + "onlyoffice.service.command.error." + result.get("commandService") + .getError() + .toString() + .toLowerCase() + ) + ); + } + + if (result.get("convertService").getStatus().equals(Status.FAILED)) { + result.get("convertService") + .setMessage( + i18n.getText( + "onlyoffice.service.convert.error." + result.get("convertService") + .getError() + .toString() + .toLowerCase() + ) + ); + } + + return result; + } +} diff --git a/src/main/java/onlyoffice/utils/attachment/AttachmentUtil.java b/src/main/java/onlyoffice/utils/attachment/AttachmentUtil.java index b92f3a38..56c200e3 100644 --- a/src/main/java/onlyoffice/utils/attachment/AttachmentUtil.java +++ b/src/main/java/onlyoffice/utils/attachment/AttachmentUtil.java @@ -1,3 +1,21 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + package onlyoffice.utils.attachment; import com.atlassian.confluence.core.ContentEntityObject; @@ -27,18 +45,12 @@ void saveAttachmentAsNewVersion(Long attachmentId, InputStream attachmentData, i void updateAttachment(Long attachmentId, InputStream attachmentData, int size, ConfluenceUser user); - void saveAttachmentChanges(Long attachmentId, String history, String changesUrl) throws Exception; - void removeAttachmentChanges(Long attachmentId); InputStream getAttachmentData(Long attachmentId); String getMediaType(Long attachmentId); - String getFileName(Long attachmentId); - - String getFileExt(Long attachmentId); - String getHashCode(Long attachmentId); String getCollaborativeEditingKey(Long attachmentId); @@ -75,4 +87,6 @@ Attachment createNewAttachment(String title, String mimeType, InputStream file, File getConvertedFile(Long attachmentId); ContentEntityObject getContainer(Long containerId); + + String getCorrectName(String fileName, String fileExt, Long pageID); } diff --git a/src/main/java/onlyoffice/utils/attachment/AttachmentUtilImpl.java b/src/main/java/onlyoffice/utils/attachment/AttachmentUtilImpl.java index c29a935c..28b8d5dd 100644 --- a/src/main/java/onlyoffice/utils/attachment/AttachmentUtilImpl.java +++ b/src/main/java/onlyoffice/utils/attachment/AttachmentUtilImpl.java @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,22 +35,12 @@ import com.atlassian.sal.api.transaction.TransactionTemplate; import com.atlassian.spring.container.ContainerManager; import com.atlassian.user.User; -import onlyoffice.managers.configuration.ConfigurationManager; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpEntity; -import org.apache.http.HttpException; -import org.apache.http.HttpStatus; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.nio.charset.StandardCharsets; import java.util.Calendar; import java.util.Date; import java.util.List; @@ -65,14 +55,10 @@ public class AttachmentUtilImpl implements AttachmentUtil { private final PageManager pageManager; private final BootstrapManager bootstrapManager; - private final ConfigurationManager configurationManager; - public AttachmentUtilImpl(final AttachmentManager attachmentManager, final TransactionTemplate transactionTemplate, - final ConfigurationManager configurationManager, final PageManager pageManager, - final BootstrapManager bootstrapManager) { + final PageManager pageManager, final BootstrapManager bootstrapManager) { this.attachmentManager = attachmentManager; this.transactionTemplate = transactionTemplate; - this.configurationManager = configurationManager; this.pageManager = pageManager; this.bootstrapManager = bootstrapManager; } @@ -166,53 +152,6 @@ public Object doInTransaction() { }); } - public void saveAttachmentChanges(final Long attachmentId, final String history, final String changesUrl) - throws Exception { - Attachment attachment = attachmentManager.getAttachment(attachmentId); - - if (history != null && !history.isEmpty() && changesUrl != null && !changesUrl.isEmpty()) { - InputStream changesStream = new ByteArrayInputStream(history.getBytes(StandardCharsets.UTF_8)); - Attachment changes = - new Attachment("onlyoffice-changes.json", "application/json", changesStream.available(), ""); - changes.setContainer(attachment.getContainer()); - changes.setHidden(true); - - try (CloseableHttpClient httpClient = configurationManager.getHttpClient()) { - HttpGet request = new HttpGet(changesUrl); - - try (CloseableHttpResponse response = httpClient.execute(request)) { - int status = response.getStatusLine().getStatusCode(); - HttpEntity entity = response.getEntity(); - - if (status == HttpStatus.SC_OK) { - byte[] bytes = IOUtils.toByteArray(entity.getContent()); - InputStream streamDiff = new ByteArrayInputStream(bytes); - - Attachment diff = new Attachment("onlyoffice-diff.zip", "application/zip", bytes.length, ""); - diff.setContainer(attachment.getContainer()); - diff.setHidden(true); - - attachment.addAttachment(changes); - attachment.addAttachment(diff); - - AttachmentDao attDao = attachmentManager.getAttachmentDao(); - Object result = transactionTemplate.execute(new TransactionCallback() { - @Override - public Object doInTransaction() { - attDao.saveNewAttachment(changes, changesStream); - attDao.saveNewAttachment(diff, streamDiff); - attDao.updateAttachment(attachment); - return null; - } - }); - } else { - throw new HttpException("Docserver returned code " + status); - } - } - } - } - } - public void removeAttachmentChanges(final Long attachmentId) { Attachment changes = getAttachmentChanges(attachmentId); Attachment diff = getAttachmentDiff(attachmentId); @@ -242,16 +181,6 @@ public String getMediaType(final Long attachmentId) { return attachment.getMediaType(); } - public String getFileName(final Long attachmentId) { - Attachment attachment = attachmentManager.getAttachment(attachmentId); - return attachment.getFileName(); - } - - public String getFileExt(final Long attachmentId) { - String fileName = getFileName(attachmentId); - return fileName.substring(fileName.lastIndexOf(".") + 1).trim().toLowerCase(); - } - public String getHashCode(final Long attachmentId) { Attachment attachment = attachmentManager.getAttachment(attachmentId); int hashCode = attachment.hashCode(); @@ -421,4 +350,30 @@ public ContentEntityObject getContainer(final Long containerId) { return container; } + + public String getCorrectName(final String fileName, final String fileExt, final Long pageID) { + ContentEntityManager contentEntityManager = + (ContentEntityManager) ContainerManager.getComponent("contentEntityManager"); + AttachmentManager attachmentManager = (AttachmentManager) ContainerManager.getComponent("attachmentManager"); + ContentEntityObject contentEntityObject = contentEntityManager.getById(pageID); + + List attachments = attachmentManager.getLatestVersionsOfAttachments(contentEntityObject); + String name = (fileName + "." + fileExt).replaceAll("[*?:\"<>/|\\\\]", "_"); + int count = 0; + Boolean flag = true; + + while (flag) { + flag = false; + for (Attachment attachment : attachments) { + if (attachment.getFileName().equals(name)) { + count++; + name = fileName + " (" + count + ")." + fileExt; + flag = true; + break; + } + } + } + + return name; + } } diff --git a/src/main/java/onlyoffice/utils/parsing/ParsingUtil.java b/src/main/java/onlyoffice/utils/parsing/ParsingUtil.java index e81171fc..b4a9f19d 100644 --- a/src/main/java/onlyoffice/utils/parsing/ParsingUtil.java +++ b/src/main/java/onlyoffice/utils/parsing/ParsingUtil.java @@ -1,3 +1,21 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + package onlyoffice.utils.parsing; import java.io.InputStream; diff --git a/src/main/java/onlyoffice/utils/parsing/ParsingUtilImpl.java b/src/main/java/onlyoffice/utils/parsing/ParsingUtilImpl.java index 3e8bf310..b3ebc9c9 100644 --- a/src/main/java/onlyoffice/utils/parsing/ParsingUtilImpl.java +++ b/src/main/java/onlyoffice/utils/parsing/ParsingUtilImpl.java @@ -1,3 +1,21 @@ +/** + * + * (c) Copyright Ascensio System SIA 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + package onlyoffice.utils.parsing; import java.io.InputStream; diff --git a/src/main/resources/app_data/document-formats b/src/main/resources/app_data/document-formats deleted file mode 160000 index 6c4927a0..00000000 --- a/src/main/resources/app_data/document-formats +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6c4927a0d153350202492e6f6b5e434faf1e80d2 diff --git a/src/main/resources/app_data/document-templates b/src/main/resources/app_data/document-templates deleted file mode 160000 index f00ab3a3..00000000 --- a/src/main/resources/app_data/document-templates +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f00ab3a3efe6e2f8542ba026d1fc1d72df7dfd5f diff --git a/src/main/resources/atlassian-plugin-marketing.xml b/src/main/resources/atlassian-plugin-marketing.xml index f5ca4727..88779511 100644 --- a/src/main/resources/atlassian-plugin-marketing.xml +++ b/src/main/resources/atlassian-plugin-marketing.xml @@ -1,6 +1,6 @@ - + diff --git a/src/main/resources/atlassian-plugin.xml b/src/main/resources/atlassian-plugin.xml index d402f3b6..add92ced 100644 --- a/src/main/resources/atlassian-plugin.xml +++ b/src/main/resources/atlassian-plugin.xml @@ -29,6 +29,12 @@ + com.atlassian.auiplugin:ajs + com.atlassian.auiplugin:aui-spinner + + + + @@ -154,7 +160,7 @@ Link and text for this link used to open the document which is available for preview only.