diff --git a/Common/config/default.json b/Common/config/default.json index 93dc6c1e0..3d4df8d26 100644 --- a/Common/config/default.json +++ b/Common/config/default.json @@ -76,8 +76,12 @@ }, "services": { "CoAuthoring": { + "ssl" :{ + "key" : "", + "cert" : "" + }, "server": { - "port": 8000, + "port": 7084, "workerpercpu": 1, "mode": "development", "limits_tempfile_upload": 104857600, @@ -119,11 +123,11 @@ "limits_image_types_upload": "jpg;jpeg;jpe;png;gif;bmp" }, "sql": { - "type": "postgres", + "type": "mysql", "tableChanges": "doc_changes", "tableResult": "task_result", "dbHost": "localhost", - "dbPort": 5432, + "dbPort": 7306, "dbName": "onlyoffice", "dbUser": "onlyoffice", "dbPass": "onlyoffice", @@ -215,7 +219,7 @@ "autostart": [] }, "editor":{ - "spellcheckerUrl": "", + "spellcheckerUrl": "/spellchecker", "reconnection":{ "attempts": 50, "delay": "2s" @@ -296,8 +300,12 @@ "silent": true }, "SpellChecker": { + "ssl" :{ + "key" : "", + "cert" : "" + }, "server": { - "port": 8080, + "port": 7085, "mode": "development" } } diff --git a/Common/config/log4js/logconfig.json b/Common/config/log4js/logconfig.json new file mode 100644 index 000000000..a76d9e918 --- /dev/null +++ b/Common/config/log4js/logconfig.json @@ -0,0 +1,15 @@ +{ + "appenders": { + "default": { + "type": "file", + "filename": "../onlyoffice.log", + "layout": { + "type": "pattern", + "pattern": "[%d] [%p] %c - %.10000m" + } + } + }, + "categories": { + "default": { "appenders": [ "default" ], "level": "WARN" } + } +} diff --git a/Common/config/onlyofficeconfig.json b/Common/config/onlyofficeconfig.json new file mode 100644 index 000000000..4f85bd77a --- /dev/null +++ b/Common/config/onlyofficeconfig.json @@ -0,0 +1,70 @@ +{ + "log": { + "filePath": "../documentserver/server/Common/config/log4js/logconfig.json" + }, + "storage": { + "fs": { + "folderPath": "../documentserver/App_Data/cache/files" + } + }, + "services": { + "CoAuthoring": { + "server": { + "static_content": { + "/fonts": { + "path": "../documentserver/fonts", + "options": {"maxAge": "7d"} + }, + "/sdkjs": { + "path": "../documentserver/sdkjs", + "options": {"maxAge": "7d"} + }, + "/web-apps": { + "path": "../documentserver/web-apps", + "options": {"maxAge": "7d"} + }, + "/sdkjs-plugins": { + "path": "../documentserver/sdkjs-plugins", + "options": {"maxAge": "7d"} + }, + "/App_Data": { + "path": "../documentserver/App_Data", + "options": {"maxAge": "7d"} + } + } + }, + "utils": { + "utils_common_fontdir": "/usr/share/fonts" + }, + "request-filtering-agent" : { + "allowPrivateIPAddress": true, + "allowMetaIPAddress": true + }, + "sockjs": { + "sockjs_url": "../documentserver/web-apps/vendor/sockjs/sockjs.min.js" + } + } + }, + "license": { + "license_file": "./../documentserver/license.lic", + "warning_limit_percents": 70, + "packageType": 0 + }, + "FileConverter": { + "converter": { + "fontDir": "/usr/share/fonts", + "presentationThemesDir": "../documentserver/sdkjs/slide/themes", + "x2tPath": "../documentserver/server/FileConverter/bin/x2t", + "docbuilderPath": "../documentserver/server/FileConverter/bin/docbuilder", + "docbuilderAllFontsPath": "../documentserver/App_Data/docbuilder/AllFonts.js" + } + }, + "FileStorage": { + "directory": "../documentserver/App_Data" + }, + "SpellChecker": { + "server": { + "dictDir": "../documentserver/server/SpellChecker/dictionaries" + } + } +} \ No newline at end of file diff --git a/Common/sources/constants.js b/Common/sources/constants.js index f976ed9a9..2705388d7 100644 --- a/Common/sources/constants.js +++ b/Common/sources/constants.js @@ -70,7 +70,7 @@ exports.LICENSE_RESULT = { ExpiredLimited: 11 }; -exports.LICENSE_CONNECTIONS = 20; +exports.LICENSE_CONNECTIONS = 99999; exports.LICENSE_EXPIRE_USERS_ONE_DAY = 24 * 60 * 60; // day in seconds exports.AVS_OFFICESTUDIO_FILE_UNKNOWN = 0x0000; diff --git a/DocService/sources/server.js b/DocService/sources/server.js index b623759c2..e18e562a4 100644 --- a/DocService/sources/server.js +++ b/DocService/sources/server.js @@ -42,6 +42,7 @@ const fs = require('fs'); const express = require('express'); const http = require('http'); +const https = require('https'); const urlModule = require('url'); const path = require('path'); const bodyParser = require("body-parser"); @@ -55,7 +56,19 @@ const utils = require('./../../Common/sources/utils'); const commonDefines = require('./../../Common/sources/commondefines'); const configStorage = configCommon.get('storage'); const app = express(); -const server = http.createServer(app); + +let server = null; + +if (config.has('ssl')) { + const privateKey = fs.readFileSync(config.get('ssl.key')).toString(); + const certificateKey = fs.readFileSync(config.get('ssl.cert')).toString(); + //See detailed options format here: http://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener + const options = {key: privateKey, cert: certificateKey}; + + server = https.createServer(options, app); +} else { + server = http.createServer(app); +} let licenseInfo, updatePluginsTime, userPlugins, pluginsLoaded; diff --git a/SpellChecker/sources/server.js b/SpellChecker/sources/server.js index 61bd8080e..756a45961 100644 --- a/SpellChecker/sources/server.js +++ b/SpellChecker/sources/server.js @@ -93,9 +93,9 @@ if (cluster.isMaster) { if (config.has('ssl')) { const privateKey = fs.readFileSync(config.get('ssl.key')).toString(); const certificateKey = fs.readFileSync(config.get('ssl.cert')).toString(); - const trustedCertificate = fs.readFileSync(config.get('ssl.ca')).toString(); + //See detailed options format here: http://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener - const options = {key: privateKey, cert: certificateKey, ca: [trustedCertificate]}; + const options = {key: privateKey, cert: certificateKey}; server = https.createServer(options, app); } else { diff --git a/bin/createdb.sql b/bin/createdb.sql new file mode 100644 index 000000000..32551c816 --- /dev/null +++ b/bin/createdb.sql @@ -0,0 +1,77 @@ + +-- +-- Create schema onlyoffice +-- +CREATE DATABASE IF NOT EXISTS onlyoffice DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; +--CREATE USER IF NOT EXISTS 'onlyoffice' IDENTIFIED BY 'onlyoffice'; +--grant all on onlyoffice.* to 'onlyoffice' identified by 'onlyoffice'; +GRANT ALL PRIVILEGES ON onlyoffice.* TO 'zimbra'; +FLUSH PRIVILEGES; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + + + +USE onlyoffice; + +-- +-- Definition of table `doc_changes` +-- + +CREATE TABLE IF NOT EXISTS `doc_changes` ( + `id` varchar(255) NOT NULL, + `change_id` int(10) unsigned NOT NULL, + `user_id` varchar(255) NOT NULL, + `user_id_original` varchar(255) NOT NULL, + `user_name` varchar(255) NOT NULL, + `change_data` longtext NOT NULL, + `change_date` datetime NOT NULL, + PRIMARY KEY (`id`,`change_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `doc_changes` +-- + +/*!40000 ALTER TABLE `doc_changes` DISABLE KEYS */; +/*!40000 ALTER TABLE `doc_changes` ENABLE KEYS */; + +-- +-- Definition of table `task_result` +-- + +CREATE TABLE IF NOT EXISTS `task_result` ( + `id` varchar(255) NOT NULL, + `status` tinyint(3) NOT NULL, + `status_info` int(10) NOT NULL, + `last_open_date` datetime NOT NULL, + `user_index` int(10) unsigned NOT NULL DEFAULT 1, + `change_id` int(10) unsigned NOT NULL DEFAULT 0, + `callback` longtext NOT NULL, + `baseurl` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `task_result` +-- + +/*!40000 ALTER TABLE `task_result` DISABLE KEYS */; +/*!40000 ALTER TABLE `task_result` ENABLE KEYS */; + + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; diff --git a/bin/jq b/bin/jq new file mode 100644 index 000000000..f48b0ca92 Binary files /dev/null and b/bin/jq differ diff --git a/bin/process_id.json b/bin/process_id.json new file mode 100644 index 000000000..867ad39fa --- /dev/null +++ b/bin/process_id.json @@ -0,0 +1,5 @@ +{ + "docservice": -1, + "spellchecker": -1, + "converter" : -1 +} diff --git a/bin/zmonlyofficeconfig b/bin/zmonlyofficeconfig new file mode 100644 index 000000000..2e9f77156 --- /dev/null +++ b/bin/zmonlyofficeconfig @@ -0,0 +1,256 @@ +#!/bin/bash +# +# ***** BEGIN LICENSE BLOCK ***** +# Zimbra Collaboration Suite Server +# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2021 Synacor, Inc. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software Foundation, +# version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. +# You should have received a copy of the GNU General Public License along with this program. +# If not, see . +# ***** END LICENSE BLOCK ***** +# + +source /opt/zimbra/bin/zmshutil || exit 1 +zmsetvars + +zmjq="/opt/zimbra/onlyoffice/bin/jq" + +defaultjson_path="/opt/zimbra/onlyoffice/documentserver/server/Common/config/default.json" +mysql_port=7306 +zimbra_mysql_user="zimbra" +zimbra_mysql_password="" +server_crt="/opt/zimbra/ssl/zimbra/server/server.crt" +server_key="/opt/zimbra/ssl/zimbra/server/server.key" + +STATUS=0 + +document_editing_JWT_secret="" + +usage() { + echo "" + echo "Invalid argument. Allowed :" + echo "new Configure Onlyoffice on the server" + echo "update-jwt-secret arg0 Update Onlyoffice server's jwt secret with the passed value" + echo "update-db Update Onlyoffice server's DB connection details from config" + echo "" + exit +} + +generate_random() +{ + length=8 + digits=({2..9}) + lower=({a..k} {m..n} {p..z}) + upper=({A..N} {P..Z}) + CharArray=(${digits[*]} ${lower[*]} ${upper[*]}) + ArrayLength=${#CharArray[*]} + password="" + for i in `seq 1 $length` + do + index=$(($RANDOM%$ArrayLength)) + char=${CharArray[$index]} + password=${password}${char} + done + echo $password + +} + +update_db_config() +{ + #port + config_mysql_port=$(su - zimbra -c "zmlocalconfig -x -s mysql_port") + if [ ! -z "$config_mysql_port" ]; then + IFS='=' + read -ra arr <<< "$config_mysql_port" + mysql_port=$(echo "${arr[1]}" | xargs) + + fi + + + content=$(${zmjq} --argjson mysql_port "$mysql_port" '.services.CoAuthoring.sql.dbPort=$mysql_port' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + + #user + config_mysql_user=$(su - zimbra -c "zmlocalconfig -x -s zimbra_mysql_user") + if [ ! -z "$config_mysql_user" ]; then + IFS='=' + read -ra arr <<< "$config_mysql_user" + zimbra_mysql_user=$(echo "${arr[1]}" | xargs) + + fi + + content=$(${zmjq} --arg zimbra_mysql_user "$zimbra_mysql_user" '.services.CoAuthoring.sql.dbUser=$zimbra_mysql_user' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + + #password + config_mysql_pass=$(su - zimbra -c "zmlocalconfig -x -s zimbra_mysql_password") + if [ ! -z "$config_mysql_pass" ]; then + IFS='=' + read -ra arr <<< "$config_mysql_pass" + zimbra_mysql_password=$(echo "${arr[1]}" | xargs) + + fi + + content=$(${zmjq} --arg zimbra_mysql_password "$zimbra_mysql_password" '.services.CoAuthoring.sql.dbPass=$zimbra_mysql_password' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + +} + +update_certificate_path() +{ + content=$(${zmjq} --arg server_crt "$server_crt" '.services.CoAuthoring.ssl.cert=$server_crt' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + + content=$(${zmjq} --arg server_crt "$server_crt" '.SpellChecker.ssl.cert=$server_crt' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + + content=$(${zmjq} --arg server_key "$server_key" '.services.CoAuthoring.ssl.key=$server_key' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + + content=$(${zmjq} --arg server_key "$server_key" '.SpellChecker.ssl.key=$server_key' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} +} + +update_token_config() +{ + + content=$(${zmjq} '.services.CoAuthoring.token.enable.browser=true' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + + content=$(${zmjq} '.services.CoAuthoring.token.enable.request.inbox=true' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + + content=$(${zmjq} '.services.CoAuthoring.token.enable.request.outbox=true' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + + content=$(${zmjq} '.services.CoAuthoring.requestDefaults.rejectUnauthorized=false' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + +} + +update_jwt_config() +{ + jwtsecret=$1 + cmd="su - zimbra -c \"zmprov -m -l mcf zimbraDocumentEditingJwtSecret ${jwtsecret}\"" + eval "$cmd" + RC=$? + if [ $RC -ne "0" ]; then + STATUS=$R + echo "Updating zimbraDocumentEditingJwtSecret faced problem." + fi + + #update the default.json + content=$(${zmjq} --arg jwtsecret "$jwtsecret" '.services.CoAuthoring.secret.browser.string=$jwtsecret' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + + content=$(${zmjq} --arg jwtsecret "$jwtsecret" '.services.CoAuthoring.secret.inbox.string=$jwtsecret' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + + content=$(${zmjq} --arg jwtsecret "$jwtsecret" '.services.CoAuthoring.secret.outbox.string=$jwtsecret' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} + + content=$(${zmjq} --arg jwtsecret "$jwtsecret" '.services.CoAuthoring.secret.session.string=$jwtsecret' ${defaultjson_path}) + echo "${content}" > ${defaultjson_path} +} + +set_jwt_secret() +{ + if [ -z "$1" ]; then + echo "Setting Random Secret..." + jwtsecret=$(generate_random) + update_jwt_config $jwtsecret + else + jwtsecret=$1 + update_jwt_config $jwtsecret + fi +} + +generate_fonts_data() +{ + mkdir -p /opt/zimbra/onlyoffice/documentserver/fonts + + fonts_gen=$(LD_LIBRARY_PATH=/opt/zimbra/onlyoffice/documentserver/server/FileConverter/bin /opt/zimbra/onlyoffice/documentserver/server/tools/allfontsgen \ + --input="/opt/zimbra/onlyoffice/documentserver/core-fonts" \ + --allfonts-web="/opt/zimbra/onlyoffice/documentserver/sdkjs/common/AllFonts.js" \ + --allfonts="/opt/zimbra/onlyoffice/documentserver/server/FileConverter/bin/AllFonts.js" \ + --images="/opt/zimbra/onlyoffice/documentserver/sdkjs/common/Images" \ + --selection="/opt/zimbra/onlyoffice/documentserver/server/FileConverter/bin/font_selection.bin" \ + --output-web="/opt/zimbra/onlyoffice/documentserver/fonts" \ + --use-system="true") + R=$? + if [ $R -ne "0" ]; then + STATUS=$R + echo "Error while generating fonts. ${fonts_gen}" + fi + +} + +generate_presentation_themes() +{ + presentation_themes_gen=$(LD_LIBRARY_PATH=/opt/zimbra/onlyoffice/documentserver/server/FileConverter/bin /opt/zimbra/onlyoffice/documentserver/server/tools/allthemesgen \ + --converter-dir="/opt/zimbra/onlyoffice/documentserver/server/FileConverter/bin"\ + --src="/opt/zimbra/onlyoffice/documentserver/sdkjs/slide/themes"\ + --output="/opt/zimbra/onlyoffice/documentserver/sdkjs/common/Images") + R=$? + if [ $R -ne "0" ]; then + STATUS=$R + echo "Error while generating presentation themes. ${presentation_themes_gen}" + fi +} + +type="$1" +if [ "$#" -eq 0 ]; then + type="new" +fi + + +case "$type" in + new) + + jwtsecret=$(su - zimbra -c "zmprov -m -l getConfig zimbraDocumentEditingJwtSecret") + if [ -z "$jwtsecret" ]; then + echo "JWT Secret not set." + set_jwt_secret + else + IFS=':' + read -ra arr <<< "$jwtsecret" + document_editing_JWT_secret=$(echo "${arr[1]}" | xargs) + update_jwt_config $document_editing_JWT_secret + fi + + update_certificate_path + update_token_config + update_db_config + generate_fonts_data + generate_presentation_themes + echo "Onlyoffice configuration done." + exit $STATUS + ;; + + update-jwt-secret) + + if [ "$#" -ne 2 ]; then + usage + exit 1 + fi + jwtsecret="$2" + + update_jwt_config $jwtsecret + exit $STATUS + ;; + + update-db ) + update_db_config + exit $STATUS + ;; + *) + usage + exit 1 + ;; +esac