├── .github └── workflows │ ├── codeql.yaml │ ├── damengDatabaseTests.yml │ ├── mssqlDatabaseTests.yml │ ├── mysqlDatabaseTests.yml │ ├── oracleDatabaseTests.yml │ ├── postgreDatabaseTests.yml │ └── unitTests.yml ├── .gitignore ├── .travis.yml ├── 3DPARTY.md ├── 3d-party-lic-report ├── json2md.js └── license-report-config.json ├── 3rd-Party.txt ├── CHANGELOG.md ├── Common ├── config │ ├── default.json │ ├── development-linux.json │ ├── development-mac.json │ ├── development-windows.json │ ├── log4js │ │ ├── development.json │ │ └── production.json │ ├── production-linux.json │ └── production-windows.json ├── npm-shrinkwrap.json ├── package.json └── sources │ ├── activeMQCore.js │ ├── commondefines.js │ ├── constants.js │ ├── formatchecker.js │ ├── license.js │ ├── logger.js │ ├── mailService.js │ ├── notificationService.js │ ├── operationContext.js │ ├── rabbitMQCore.js │ ├── statsdclient.js │ ├── storage-base.js │ ├── storage-fs.js │ ├── storage-s3.js │ ├── taskqueueRabbitMQ.js │ ├── tenantManager.js │ └── utils.js ├── DocService ├── npm-shrinkwrap.json ├── package.json ├── public │ └── healthcheck.docx └── sources │ ├── DocsCoServer.js │ ├── canvasservice.js │ ├── changes2forgotten.js │ ├── converterservice.js │ ├── database.js │ ├── databaseConnectors │ ├── baseConnector.js │ ├── connectorUtilities.js │ ├── damengConnector.js │ ├── mssqlConnector.js │ ├── mysqlConnector.js │ ├── oracleConnector.js │ └── postgreConnector.js │ ├── editorDataMemory.js │ ├── fileuploaderservice.js │ ├── gc.js │ ├── pubsubRabbitMQ.js │ ├── routes │ └── static.js │ ├── server.js │ ├── shutdown.js │ ├── taskresult.js │ ├── utilsDocService.js │ └── wopiClient.js ├── FileConverter ├── npm-shrinkwrap.json ├── package.json └── sources │ ├── converter.js │ └── convertermaster.js ├── Gruntfile.js ├── LICENSE.txt ├── Makefile ├── Metrics ├── config │ └── config.js ├── npm-shrinkwrap.json └── package.json ├── Readme.md ├── SpellChecker ├── npm-shrinkwrap.json ├── package.json └── sources │ ├── languages.js │ ├── server.js │ └── spellCheck.js ├── branding ├── info │ ├── img │ │ ├── favicon.ico │ │ ├── icon-cross.png │ │ └── logo.png │ └── index.html └── welcome │ ├── img │ ├── favicon.ico │ ├── icon-cross.png │ └── icon-done.png │ └── index.html ├── license ├── Backbone.license ├── Bootstrap.license ├── Hunspell.license ├── Megapixel.license ├── NodeHun.license ├── PerfectScrollbar.license ├── RequireJS.license ├── SocketIO.license ├── Underscore.license ├── XRegExp.license ├── jQuery.browser.license ├── jQuery.license ├── less.license └── requirejs-text.license ├── npm-shrinkwrap.json ├── package.json ├── schema ├── dameng │ ├── createdb.sql │ └── removetbl.sql ├── json-api │ └── opening-file.json ├── mssql │ ├── createdb.sql │ └── removetbl.sql ├── mysql │ ├── createdb.sql │ ├── removetbl.sql │ └── upgrade │ │ ├── upgradev630.sql │ │ ├── upgradev710.sql │ │ └── upgradev720.sql ├── oracle │ ├── createdb.sql │ └── removetbl.sql └── postgresql │ ├── createdb.sql │ ├── removetbl.sql │ └── upgrade │ ├── upgradev630.sql │ ├── upgradev710.sql │ └── upgradev720.sql └── tests ├── env-setup.js ├── integration ├── databaseTests │ └── baseConnector.tests.js └── withServerInstance │ ├── forgottenFilesCommnads.tests.js │ └── storage.tests.js ├── jest.config.js ├── perf ├── checkFileExpire.js ├── convertImageToPng.js └── fixImageExifRotation.js └── unit ├── mailService.tests.js ├── sample.tests.js └── utils.tests.js /.github/workflows/codeql.yaml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | - 'hotfix/**' 8 | - 'release/**' 9 | paths-ignore: 10 | - '**/README.md' 11 | - '**/LICENSE' 12 | - '.github/**' 13 | 14 | schedule: 15 | - cron: '0 0 * * 6' 16 | 17 | jobs: 18 | analyze: 19 | name: Analyze 20 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} 21 | timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} 22 | permissions: 23 | actions: read 24 | contents: read 25 | security-events: write 26 | 27 | strategy: 28 | fail-fast: false 29 | matrix: 30 | language: [ 'javascript-typescript' ] 31 | 32 | steps: 33 | - name: Checkout repository 34 | uses: actions/checkout@v4 35 | 36 | # Initializes the CodeQL tools for scanning. 37 | - name: Initialize CodeQL 38 | uses: github/codeql-action/init@v3 39 | with: 40 | languages: ${{ matrix.language }} 41 | 42 | - name: Autobuild 43 | uses: github/codeql-action/autobuild@v3 44 | 45 | 46 | - name: Perform CodeQL Analysis 47 | uses: github/codeql-action/analyze@v3 48 | with: 49 | category: "/language:${{matrix.language}}" 50 | -------------------------------------------------------------------------------- /.github/workflows/damengDatabaseTests.yml: -------------------------------------------------------------------------------- 1 | name: Dameng database tests 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | paths: 7 | - 'tests/integration/databaseTests/**' 8 | - 'DocService/sources/databaseConnectors/baseConnector.js' 9 | - 'DocService/sources/databaseConnectors/damengConnector.js' 10 | jobs: 11 | dameng-tests: 12 | name: Dameng 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Run dameng DB docker container 17 | run: docker run --name dameng -p 5236:5236 -e PAGE_SIZE=16 -e LD_LIBRARY_PATH=/opt/dmdbms/bin -e INSTANCE_NAME=dm8_01 -d danilaworker/damengdb:8.1.2 18 | 19 | - name: Check out repository code 20 | uses: actions/checkout@v3 21 | 22 | - name: Caching dependencies 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: '16' 26 | cache: 'npm' 27 | cache-dependency-path: | 28 | ./npm-shrinkwrap.json 29 | ./Common/npm-shrinkwrap.json 30 | ./DocService/npm-shrinkwrap.json 31 | 32 | - name: Install modules 33 | run: | 34 | npm ci 35 | npm --prefix Common ci 36 | npm --prefix DocService ci 37 | 38 | - name: Await database service to finish startup 39 | run: sleep 15 40 | 41 | - name: Creating service DB configuration 42 | run: | 43 | echo '{"services": {"CoAuthoring": {"sql": {"type": "dameng", "dbHost": "127.0.0.1", "dbPort": 5236, "dbUser": "SYSDBA", "dbPass": "SYSDBA001"}}}}' >> Common/config/local.json 44 | 45 | - name: Creating schema 46 | run: | 47 | docker cp ./schema/dameng/createdb.sql dameng:/ 48 | docker exec dameng bash -c "cat /createdb.sql | /opt/dmdbms/bin/disql SYSDBA/SYSDBA001:5236" 49 | 50 | - name: Run Jest 51 | run: npm run "integration database tests" 52 | -------------------------------------------------------------------------------- /.github/workflows/mssqlDatabaseTests.yml: -------------------------------------------------------------------------------- 1 | name: MSSQL database tests 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | paths: 7 | - 'tests/integration/databaseTests/**' 8 | - 'DocService/sources/databaseConnectors/baseConnector.js' 9 | - 'DocService/sources/databaseConnectors/mssqlConnector.js' 10 | jobs: 11 | mssql-tests: 12 | name: MSSQL 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Run MSSQL DB docker container 17 | run: docker run --name mssql -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=onlYoff1ce" -p 8080:1433 -d mcr.microsoft.com/mssql/server:2022-latest 18 | 19 | - name: Check out repository code 20 | uses: actions/checkout@v3 21 | 22 | - name: Caching dependencies 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: '16' 26 | cache: 'npm' 27 | cache-dependency-path: | 28 | ./npm-shrinkwrap.json 29 | ./Common/npm-shrinkwrap.json 30 | ./DocService/npm-shrinkwrap.json 31 | 32 | - name: Install modules 33 | run: | 34 | npm ci 35 | npm --prefix Common ci 36 | npm --prefix DocService ci 37 | 38 | - name: Creating service DB configuration 39 | run: | 40 | echo '{"services": {"CoAuthoring": {"sql": {"type": "mssql", "dbHost": "localhost", "dbPort": 8080, "dbUser": "sa", "dbPass": "onlYoff1ce"}}}}' >> Common/config/local.json 41 | 42 | - name: Await database service to finish startup 43 | run: sleep 5 44 | 45 | - name: Creating schema 46 | run: | 47 | docker cp ./schema/mssql/createdb.sql mssql:/ 48 | docker exec mssql /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P onlYoff1ce -Q "CREATE DATABASE onlyoffice;" 49 | docker exec mssql /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P onlYoff1ce -d onlyoffice -i /createdb.sql 50 | 51 | - name: Run Jest 52 | run: npm run "integration database tests" 53 | -------------------------------------------------------------------------------- /.github/workflows/mysqlDatabaseTests.yml: -------------------------------------------------------------------------------- 1 | name: MYSQL database tests 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | paths: 7 | - 'tests/integration/databaseTests/**' 8 | - 'DocService/sources/databaseConnectors/baseConnector.js' 9 | - 'DocService/sources/databaseConnectors/mysqlConnector.js' 10 | jobs: 11 | mysql-tests: 12 | name: MYSQL 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Run Mysql DB docker container 17 | run: docker run --name mysql -p 8080:3306 -p 8081:33060 -e MYSQL_HOST=127.0.0.1 -e MYSQL_ROOT_PASSWORD=onlyoffice -e MYSQL_DATABASE=onlyoffice -d mysql:latest 18 | 19 | - name: Check out repository code 20 | uses: actions/checkout@v3 21 | 22 | - name: Caching dependencies 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: '16' 26 | cache: 'npm' 27 | cache-dependency-path: | 28 | ./npm-shrinkwrap.json 29 | ./Common/npm-shrinkwrap.json 30 | ./DocService/npm-shrinkwrap.json 31 | 32 | - name: Install modules 33 | run: | 34 | npm ci 35 | npm --prefix Common ci 36 | npm --prefix DocService ci 37 | 38 | - name: Creating service DB configuration 39 | run: | 40 | echo '{"services": {"CoAuthoring": {"sql": {"type": "mysql", "dbHost": "127.0.0.1", "dbPort": "8080", "dbUser": "root", "dbPass": "onlyoffice"}}}}' >> Common/config/local.json 41 | 42 | - name : Creating schema 43 | run: | 44 | docker cp ./schema/mysql/createdb.sql mysql:/ 45 | docker exec mysql mysql -h 127.0.0.1 -u root --password=onlyoffice -D onlyoffice -e 'source /createdb.sql' 46 | 47 | - name: Run Jest 48 | run: npm run "integration database tests" 49 | -------------------------------------------------------------------------------- /.github/workflows/oracleDatabaseTests.yml: -------------------------------------------------------------------------------- 1 | name: Oracle database tests 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | paths: 7 | - 'tests/integration/databaseTests/**' 8 | - 'DocService/sources/databaseConnectors/baseConnector.js' 9 | - 'DocService/sources/databaseConnectors/oracleConnector.js' 10 | jobs: 11 | oracle-tests: 12 | name: Oracle 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Run Oracle DB docker container 17 | run: docker run --name oracle -p 8080:1521 -p 8081:5500 -e ORACLE_PASSWORD=admin -e APP_USER=onlyoffice -e APP_USER_PASSWORD=onlyoffice -d gvenzl/oracle-xe:21-slim 18 | 19 | - name: Check out repository code 20 | uses: actions/checkout@v3 21 | 22 | - name: Caching dependencies 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: '16' 26 | cache: 'npm' 27 | cache-dependency-path: | 28 | ./npm-shrinkwrap.json 29 | ./Common/npm-shrinkwrap.json 30 | ./DocService/npm-shrinkwrap.json 31 | 32 | - name: Install modules 33 | run: | 34 | npm ci 35 | npm --prefix Common ci 36 | npm --prefix DocService ci 37 | 38 | - name: Creating service DB configuration 39 | run: | 40 | echo '{"services": {"CoAuthoring": {"sql": {"type": "oracle", "dbHost": "127.0.0.1", "dbPort": "8080", "dbUser": "onlyoffice", "dbPass": "onlyoffice", "dbName": "xepdb1"}}}}' >> Common/config/local.json 41 | 42 | - name: Await database service to finish startup 43 | run: sleep 15 44 | 45 | - name: Creating schema 46 | run: | 47 | docker cp ./schema/oracle/createdb.sql oracle:/ 48 | docker exec oracle sqlplus -s onlyoffice/onlyoffice@//localhost/xepdb1 @/createdb.sql 49 | 50 | - name: Run Jest 51 | run: npm run "integration database tests" 52 | -------------------------------------------------------------------------------- /.github/workflows/postgreDatabaseTests.yml: -------------------------------------------------------------------------------- 1 | name: Postgre database tests 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | paths: 7 | - 'tests/integration/databaseTests/**' 8 | - 'DocService/sources/databaseConnectors/baseConnector.js' 9 | - 'DocService/sources/databaseConnectors/postgreConnector.js' 10 | jobs: 11 | postgres-tests: 12 | name: Postgres 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Run Postgres DB docker container 17 | run: docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=onlyoffice -e POSTGRES_USER=onlyoffice -e POSTGRES_DB=onlyoffice -d postgres:latest 18 | 19 | - name: Check out repository code 20 | uses: actions/checkout@v3 21 | 22 | - name: Caching dependencies 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: '16' 26 | cache: 'npm' 27 | cache-dependency-path: | 28 | ./npm-shrinkwrap.json 29 | ./Common/npm-shrinkwrap.json 30 | ./DocService/npm-shrinkwrap.json 31 | 32 | - name: Install modules 33 | run: | 34 | npm ci 35 | npm --prefix Common ci 36 | npm --prefix DocService ci 37 | 38 | - name: Creating service DB configuration 39 | run: | 40 | echo '{"services": {"CoAuthoring": {"sql": {"dbHost": "127.0.0.1"}}}}' >> Common/config/local.json 41 | 42 | - name: Creating schema 43 | run: | 44 | docker cp ./schema/postgresql/createdb.sql postgres:/ 45 | docker exec postgres psql -d onlyoffice -U onlyoffice -a -f /createdb.sql 46 | 47 | - name: Run Jest 48 | run: npm run "integration database tests" 49 | -------------------------------------------------------------------------------- /.github/workflows/unitTests.yml: -------------------------------------------------------------------------------- 1 | name: Service unit tests 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | paths: 7 | - '**.js' 8 | - '!tests/integration/**' 9 | - '!DocService/sources/databaseConnectors/**' 10 | jobs: 11 | unit-tests: 12 | name: Service unit tests 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Check out repository code 17 | uses: actions/checkout@v3 18 | 19 | - name: Caching dependencies 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: '16' 23 | cache: 'npm' 24 | cache-dependency-path: | 25 | ./npm-shrinkwrap.json 26 | ./Common/npm-shrinkwrap.json 27 | ./DocService/npm-shrinkwrap.json 28 | 29 | - name: Install modules 30 | run: | 31 | npm ci 32 | npm --prefix Common ci 33 | npm --prefix DocService ci 34 | 35 | - name: Run Jest 36 | run: npm run "unit tests" 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | Common/config/local.json 3 | license.lic 4 | App_Data/ 5 | */node_modules 6 | FileConverter/bin 7 | DocService/npm-debug.log 8 | build 9 | node_modules 10 | /Gruntfile.js.out 11 | local-development-*.json 12 | *.pyc 13 | run-develop-local.py -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: node_js 3 | node_js: 4 | - '6' 5 | before_install: npm install -g grunt-cli 6 | script: 7 | - make 8 | matrix: 9 | allow_failures: 10 | - node_js: '6' -------------------------------------------------------------------------------- /3DPARTY.md: -------------------------------------------------------------------------------- 1 | 2 | ## Third-party 3 | 4 | - @aws-sdk/client-s3 3.637.0 ([Apache-2.0](https://raw.githubusercontent.com/aws/aws-sdk-js-v3/main/LICENSE)) 5 | - @aws-sdk/node-http-handler 3.374.0 ([Apache-2.0](https://raw.githubusercontent.com/aws/aws-sdk-js-v3/main/LICENSE)) 6 | - @aws-sdk/s3-request-presigner 3.370.0 ([Apache-2.0](https://raw.githubusercontent.com/aws/aws-sdk-js-v3/main/LICENSE)) 7 | - amqplib 0.8.0 ([MIT](https://raw.githubusercontent.com/amqp-node/amqplib/main/LICENSE)) 8 | - co 4.6.0 ([MIT](https://raw.githubusercontent.com/tj/co/master/LICENSE)) 9 | - config 2.0.1 ([MIT](https://raw.githubusercontent.com/node-config/node-config/master/LICENSE)) 10 | - content-disposition 0.5.3 ([MIT](https://raw.githubusercontent.com/jshttp/content-disposition/master/LICENSE)) 11 | - dnscache 1.0.1 ([BSD](https://raw.githubusercontent.com/yahoo/dnscache/master/LICENSE)) 12 | - escape-string-regexp 1.0.5 ([MIT](https://raw.githubusercontent.com/sindresorhus/escape-string-regexp/main/license)) 13 | - forwarded 0.1.2 ([MIT](https://raw.githubusercontent.com/jshttp/forwarded/master/LICENSE)) 14 | - ipaddr.js 1.8.1 ([MIT](https://raw.githubusercontent.com/whitequark/ipaddr.js/main/LICENSE)) 15 | - jsonwebtoken 9.0.0 ([MIT](https://raw.githubusercontent.com/auth0/node-jsonwebtoken/master/LICENSE)) 16 | - log4js 6.4.1 ([Apache-2.0](https://raw.githubusercontent.com/log4js-node/log4js-node/master/LICENSE)) 17 | - mime 2.3.1 ([MIT](https://raw.githubusercontent.com/broofa/mime/main/LICENSE)) 18 | - ms 2.1.1 ([MIT](https://raw.githubusercontent.com/vercel/ms/main/license.md)) 19 | - node-cache 4.2.1 ([MIT](https://raw.githubusercontent.com/node-cache/node-cache/master/LICENSE)) 20 | - node-statsd 0.1.1 ([MIT](https://raw.githubusercontent.com/sivy/node-statsd/master/LICENSE)) 21 | - nodemailer 6.9.13 ([MIT-0](https://raw.githubusercontent.com/nodemailer/nodemailer/master/LICENSE)) 22 | - request 2.88.0 ([Apache-2.0](https://raw.githubusercontent.com/request/request/master/LICENSE)) 23 | - request-filtering-agent 1.0.5 ([MIT](https://raw.githubusercontent.com/azu/request-filtering-agent/master/LICENSE)) 24 | - rhea 1.0.24 ([Apache-2.0](https://raw.githubusercontent.com/amqp/rhea/main/LICENSE)) 25 | - uri-js 4.2.2 ([BSD-2-Clause](https://raw.githubusercontent.com/garycourt/uri-js/master/LICENSE)) 26 | - win-ca 3.5.0 ([MIT](https://raw.githubusercontent.com/ukoloff/win-ca/master/LICENSE)) 27 | - ajv 8.9.0 ([MIT](https://raw.githubusercontent.com/ajv-validator/ajv/master/LICENSE)) 28 | - apicache 1.6.3 ([MIT](https://raw.githubusercontent.com/kwhitley/apicache/master/LICENSE)) 29 | - base64-stream 1.0.0 ([MIT](https://github.com/mazira/base64-stream?tab=readme-ov-file#license)) 30 | - body-parser 1.20.1 ([MIT](https://raw.githubusercontent.com/expressjs/body-parser/master/LICENSE)) 31 | - bottleneck 2.19.5 ([MIT](https://raw.githubusercontent.com/SGrondin/bottleneck/master/LICENSE)) 32 | - bytes 3.0.0 ([MIT](https://raw.githubusercontent.com/visionmedia/bytes.js/master/LICENSE)) 33 | - co 4.6.0 ([MIT](https://raw.githubusercontent.com/tj/co/master/LICENSE)) 34 | - config 2.0.1 ([MIT](https://raw.githubusercontent.com/node-config/node-config/master/LICENSE)) 35 | - cron 1.5.0 ([MIT](https://raw.githubusercontent.com/kelektiv/node-cron/main/LICENSE)) 36 | - deep-equal 1.0.1 ([MIT](https://raw.githubusercontent.com/inspect-js/node-deep-equal/main/LICENSE)) 37 | - dmdb 1.0.14280 ([none](https://www.npmjs.com/package/dmdb)) 38 | - ejs 3.1.10 ([Apache-2.0](https://raw.githubusercontent.com/mde/ejs/main/LICENSE)) 39 | - exif-parser 0.1.12 ([MIT](https://raw.githubusercontent.com/bwindels/exif-parser/master/LICENSE.md)) 40 | - express 4.19.2 ([MIT](https://raw.githubusercontent.com/expressjs/express/master/LICENSE)) 41 | - fakeredis 2.0.0 ([MIT](https://github.com/hdachev/fakeredis?tab=readme-ov-file#license)) 42 | - ioredis 5.3.1 ([MIT](https://raw.githubusercontent.com/redis/ioredis/main/LICENSE)) 43 | - jimp 0.22.10 ([MIT](https://raw.githubusercontent.com/jimp-dev/jimp/main/LICENSE)) 44 | - jsonwebtoken 9.0.0 ([MIT](https://raw.githubusercontent.com/auth0/node-jsonwebtoken/master/LICENSE)) 45 | - jwa 1.1.6 ([MIT](https://raw.githubusercontent.com/auth0/node-jwa/master/LICENSE)) 46 | - mime 2.3.1 ([MIT](https://raw.githubusercontent.com/broofa/mime/main/LICENSE)) 47 | - mime-db 1.49.0 ([MIT](https://raw.githubusercontent.com/jshttp/mime-db/master/LICENSE)) 48 | - ms 2.1.1 ([MIT](https://raw.githubusercontent.com/vercel/ms/master/license.md)) 49 | - mssql 9.1.1 ([MIT](https://raw.githubusercontent.com/tediousjs/node-mssql/master/LICENSE.md)) 50 | - multer 1.4.3 ([MIT](https://raw.githubusercontent.com/expressjs/multer/master/LICENSE)) 51 | - multi-integer-range 4.0.7 ([MIT](https://raw.githubusercontent.com/smikitky/node-multi-integer-range/master/LICENSE)) 52 | - multiparty 4.2.1 ([MIT](https://raw.githubusercontent.com/pillarjs/multiparty/master/LICENSE)) 53 | - mysql2 3.9.8 ([MIT](https://raw.githubusercontent.com/sidorares/node-mysql2/master/License)) 54 | - oracledb 6.3.0 ([(Apache-2.0 OR UPL-1.0)](https://raw.githubusercontent.com/oracle/node-oracledb/main/LICENSE.txt)) 55 | - pg 8.11.3 ([MIT](https://raw.githubusercontent.com/brianc/node-postgres/master/LICENSE)) 56 | - redis 4.6.11 ([MIT](https://raw.githubusercontent.com/redis/node-redis/master/LICENSE)) 57 | - retry 0.12.0 ([MIT](https://raw.githubusercontent.com/tim-kos/node-retry/master/License)) 58 | - socket.io 4.8.1 ([MIT](https://raw.githubusercontent.com/socketio/socket.io/main/LICENSE)) 59 | - underscore 1.13.1 ([MIT](https://raw.githubusercontent.com/jashkenas/underscore/master/LICENSE)) 60 | - utf7 1.0.2 ([BSD](https://www.npmjs.com/package/utf7)) 61 | - windows-locale 1.0.1 ([MIT](https://raw.githubusercontent.com/TiagoDanin/Windows-Locale/master/LICENSE)) 62 | - xmlbuilder2 3.0.2 ([MIT](https://raw.githubusercontent.com/oozcitak/xmlbuilder2/master/LICENSE)) 63 | - @expo/spawn-async 1.7.2 ([MIT](https://raw.githubusercontent.com/TritonDataCenter/node-spawn-async/master/LICENSE)) 64 | - bytes 3.0.0 ([MIT](https://raw.githubusercontent.com/visionmedia/bytes.js/master/LICENSE)) 65 | - co 4.6.0 ([MIT](https://raw.githubusercontent.com/tj/co/master/LICENSE)) 66 | - config 2.0.1 ([MIT](https://github.com/node-config/node-config/blob/master/LICENSE)) 67 | - lcid 3.1.1 ([MIT](https://raw.githubusercontent.com/sindresorhus/lcid/main/license)) 68 | - statsd 0.8.4 ([MIT](https://raw.githubusercontent.com/statsd/statsd/master/LICENSE)) 69 | -------------------------------------------------------------------------------- /3d-party-lic-report/json2md.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | const { readFile, writeFile } = require("node:fs/promises"); 35 | 36 | async function startTest() { 37 | let args = process.argv.slice(2); 38 | if (args.length < 1) { 39 | console.error('missing arguments.USAGE: json2md.js [output.md] [input.json]'); 40 | return; 41 | } 42 | console.info("3d license report start"); 43 | let outputMd = ''; 44 | let outputFlag = 'a'; 45 | let outputPath = args[0]; 46 | let inputPath = args[1]; 47 | 48 | if (inputPath) { 49 | let licensesText = await readFile(inputPath, 'utf-8'); 50 | let licensesJson = JSON.parse(licensesText); 51 | console.info("3d license report license count: %d", licensesJson.length); 52 | 53 | for (const element of licensesJson) { 54 | let name = element['name']; 55 | let installedVersion = element['installedVersion']; 56 | let licenseType = element['licenseType']; 57 | let licenseFileLink = element['licenseFileLink']; 58 | outputMd += `- ${name} ${installedVersion} ([${licenseType}](${licenseFileLink}))\n` 59 | } 60 | } else { 61 | outputMd = '\n## Third-party\n\n'; 62 | outputFlag = 'w'; 63 | } 64 | 65 | await writeFile(outputPath, outputMd, {flag: outputFlag}, 'utf-8'); 66 | console.info("3d license report end"); 67 | } 68 | 69 | startTest().catch((err) => { 70 | console.error(err.stack); 71 | }).finally(() => { 72 | process.exit(0); 73 | }); -------------------------------------------------------------------------------- /3d-party-lic-report/license-report-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "fields": [ 3 | "name", 4 | "licenseType", 5 | "link", 6 | "installedVersion" 7 | ] 8 | } -------------------------------------------------------------------------------- /3rd-Party.txt: -------------------------------------------------------------------------------- 1 | ONLYOFFICE DocumentServer uses code from the following 3rd party projects. 2 | 3 | 1. Bootstrap - Bootstrap is a free collection of tools for creating websites and web applications. It contains HTML and CSS-based design templates for typography, forms, buttons, navigation and other interface components, as well as optional JavaScript extensions. 4 | 5 | URL: http://getbootstrap.com 6 | License: Apache License Version 2.0 7 | License File: license/Bootstrap.license 8 | 9 | 10 | 2. RequireJS - RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments, like Rhino and Node. Using a modular script loader like RequireJS will improve the speed and quality of your code. 11 | 12 | URL: http://requirejs.org/ 13 | License: The "New" BSD License, MIT License 14 | License File: license/RequireJS.license 15 | 16 | 17 | 3. jQuery - jQuery is a fast, small, and feature-rich JavaScript library. 18 | 19 | URL: https://jquery.org 20 | License: MIT License 21 | License File: license/jQuery.license 22 | 23 | 24 | 4. Megapixel - MFixes iOS6 Safari's image file rendering issue for large size image (over mega-pixel), which causes unexpected subsampling when drawing it in canvas. 25 | 26 | URL: https://github.com/stomita/ios-imagefile-megapixel 27 | License: MIT License 28 | License File: license/Megapixel.license 29 | 30 | 31 | 5. SocketIO - WebSocket emulation - Javascript client 32 | 33 | URL: https://socket.io 34 | License: MIT License 35 | License File: license/SocketIO.license 36 | 37 | 38 | 6. Underscore - Underscore is a utility-belt library for JavaScript that provides a lot of the functional programming support that you would expect in Prototype.js (or Ruby), but without extending any of the built-in JavaScript objects. It's the tie to go along with jQuery's tux, and Backbone.js's suspenders. 39 | 40 | URL: https://github.com/jashkenas/underscore/ 41 | License: MIT License 42 | License File: license/Underscore.license 43 | 44 | 45 | 7. XRegExp - XRegExp is an open source (MIT License) JavaScript library that provides augmented and extensible regular expressions. You get new syntax, flags, and methods beyond what browsers support natively. XRegExp is also a regex utility belt with tools to make your client-side grepping simpler and more powerful, while freeing you from worrying about pesky cross-browser inconsistencies and the dubious lastIndex property. 46 | 47 | URL: http://xregexp.com/ 48 | License: MIT License 49 | License File: license/XRegExp.license 50 | 51 | 52 | 8. ZeroClipboard - The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface. 53 | 54 | URL: http://zeroclipboard.org 55 | License: MIT License 56 | License File: license/ZeroClipboard.license 57 | 58 | 59 | 9. Hunspell - Hunspell is the spell checker of LibreOffice, OpenOffice.org, Mozilla Firefox 3 & Thunderbird, Google Chrome, and it is also used by proprietary software packages, like Mac OS X, InDesign, memoQ, Opera and SDL Trados. 60 | 61 | URL: http://sourceforge.net/projects/hunspell/ 62 | License: MPL 1.1/GPL 2.0/LGPL 2.1 63 | License File: license/Hunspell.license 64 | 65 | 66 | 10. NodeHun - The Hunspell binding for nodejs that exposes as much of hunspell as possible and also adds new features. 67 | 68 | URL: https://npmjs.org/package/nodehun 69 | License: MIT License 70 | License File: license/NodeHun.license 71 | 72 | 73 | 11. Backbone - Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface. 74 | 75 | URL: http://backbonejs.org/ 76 | License: MIT License 77 | License File: license/Backbone.license 78 | 79 | 80 | 12. jQuery.browser - A jQuery plugin for browser detection. 81 | 82 | URL: http://api.jquery.com/jquery.browser/ 83 | License: MIT License 84 | License File: license/jQuery.browser.license 85 | 86 | 87 | 13. PerfectScrollbar - Tiny but perfect jQuery scrollbar plugin. 88 | 89 | URL: http://noraesae.github.com/perfect-scrollbar/ 90 | License: MIT License 91 | License File: license/PerfectScrollbar.license 92 | 93 | 94 | 14. jsrsasign - The 'jsrsasign' (RSA-Sign JavaScript Library) is a open source free pure JavaScript implementation of PKCS#1 v2.1 RSASSA-PKCS1-v1_5 RSA signing and validation algorithm. 95 | 96 | URL: http://kjur.github.io/jsrsasign/ 97 | License: MIT License 98 | License File: license/jsrsasign.license 99 | 100 | 101 | 15. less - Less is a CSS pre-processor 102 | 103 | URL: http://lesscss.org/ 104 | License: Apache 2 License 105 | License File: license/less.license 106 | 107 | 108 | 16. requirejs-text - A RequireJS/AMD loader plugin for loading text resources 109 | 110 | URL: http://lesscss.org/ 111 | License: MIT License 112 | License File: license/requirejs-text.license -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change log 2 | ## develop 3 | ### Back-end 4 | * 5 | 6 | ## 5.1.1 7 | ### Back-end 8 | * Add reconnection.attempts, reconnection.delay options to config - applicable for editor-server connection 9 | * Add sockjs config section for testing purposes 10 | * Fix inconsistent database status after files assemble in case of rapid open/close connection 11 | -------------------------------------------------------------------------------- /Common/config/development-linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "filePath": "../Common/config/log4js/development.json" 4 | }, 5 | "storage": { 6 | "fs": { 7 | "folderPath": "../App_Data" 8 | } 9 | }, 10 | "wopi": { 11 | "enable": true 12 | }, 13 | "services": { 14 | "CoAuthoring": { 15 | "server": { 16 | "port": 8000, 17 | "static_content": { 18 | "/fonts": { 19 | "path": "../../fonts" 20 | }, 21 | "/sdkjs": { 22 | "path": "../../sdkjs" 23 | }, 24 | "/web-apps": { 25 | "path": "../../web-apps" 26 | }, 27 | "/sdkjs-plugins": { 28 | "path": "../../sdkjs-plugins" 29 | }, 30 | "/dictionaries": { 31 | "path": "../../dictionaries" 32 | }, 33 | "/welcome": { 34 | "path": "../branding/welcome" 35 | }, 36 | "/info": { 37 | "path": "../branding/info" 38 | } 39 | } 40 | }, 41 | "utils": { 42 | "utils_common_fontdir": "/usr/share/fonts" 43 | }, 44 | "request-filtering-agent" : { 45 | "allowPrivateIPAddress": true, 46 | "allowMetaIPAddress": true 47 | }, 48 | "sockjs": { 49 | "sockjs_url": "/web-apps/vendor/sockjs/sockjs.min.js" 50 | }, 51 | "socketio": { 52 | "connection": { 53 | "pingTimeout": 86400000, 54 | "pingInterval": 86400000 55 | } 56 | } 57 | } 58 | }, 59 | "license": { 60 | "license_file": "./../license.lic", 61 | "warning_limit_percents": 70, 62 | "packageType": 0 63 | }, 64 | "FileConverter": { 65 | "converter": { 66 | "fontDir": "/usr/share/fonts", 67 | "presentationThemesDir": "../../sdkjs/slide/themes", 68 | "x2tPath": "../FileConverter/bin/x2t", 69 | "docbuilderPath": "../FileConverter/bin/docbuilder" 70 | } 71 | }, 72 | "SpellChecker": { 73 | "server": { 74 | "dictDir": "../../dictionaries" 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Common/config/development-mac.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "filePath": "../Common/config/log4js/development.json" 4 | }, 5 | "storage": { 6 | "fs": { 7 | "folderPath": "../App_Data" 8 | } 9 | }, 10 | "wopi": { 11 | "enable": true 12 | }, 13 | "services": { 14 | "CoAuthoring": { 15 | "server": { 16 | "port": 8000, 17 | "static_content": { 18 | "/fonts": { 19 | "path": "../../fonts" 20 | }, 21 | "/sdkjs": { 22 | "path": "../../sdkjs" 23 | }, 24 | "/web-apps": { 25 | "path": "../../web-apps" 26 | }, 27 | "/sdkjs-plugins": { 28 | "path": "../../sdkjs-plugins" 29 | }, 30 | "/dictionaries": { 31 | "path": "../../dictionaries" 32 | }, 33 | "/welcome": { 34 | "path": "../branding/welcome" 35 | }, 36 | "/info": { 37 | "path": "../branding/info" 38 | } 39 | } 40 | }, 41 | "utils": { 42 | "utils_common_fontdir": "/Library/Fonts" 43 | }, 44 | "sql": { 45 | "type": "mysql", 46 | "dbPort": 3306, 47 | "dbUser": "root", 48 | "dbPass": "onlyoffice" 49 | }, 50 | "request-filtering-agent" : { 51 | "allowPrivateIPAddress": true, 52 | "allowMetaIPAddress": true 53 | }, 54 | "sockjs": { 55 | "sockjs_url": "/web-apps/vendor/sockjs/sockjs.min.js" 56 | }, 57 | "socketio": { 58 | "connection": { 59 | "pingTimeout": 86400000, 60 | "pingInterval": 86400000 61 | } 62 | } 63 | } 64 | }, 65 | "license": { 66 | "license_file": "./../license.lic", 67 | "warning_limit_percents": 70, 68 | "packageType": 0 69 | }, 70 | "FileConverter": { 71 | "converter": { 72 | "fontDir": "", 73 | "presentationThemesDir": "../../sdkjs/slide/themes", 74 | "x2tPath": "../FileConverter/bin/x2t", 75 | "docbuilderPath": "../FileConverter/Bin/docbuilder", 76 | "errorfiles": "error" 77 | } 78 | }, 79 | "SpellChecker": { 80 | "server": { 81 | "dictDir": "../../dictionaries" 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /Common/config/development-windows.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "filePath": "../Common/config/log4js/development.json" 4 | }, 5 | "storage": { 6 | "fs": { 7 | "folderPath": "../App_Data" 8 | } 9 | }, 10 | "wopi": { 11 | "enable": true 12 | }, 13 | "services": { 14 | "CoAuthoring": { 15 | "server": { 16 | "port": 8000, 17 | "static_content": { 18 | "/fonts": { 19 | "path": "../../fonts" 20 | }, 21 | "/sdkjs": { 22 | "path": "../../sdkjs" 23 | }, 24 | "/web-apps": { 25 | "path": "../../web-apps" 26 | }, 27 | "/sdkjs-plugins": { 28 | "path": "../../sdkjs-plugins" 29 | }, 30 | "/dictionaries": { 31 | "path": "../../dictionaries" 32 | }, 33 | "/welcome": { 34 | "path": "../branding/welcome" 35 | }, 36 | "/info": { 37 | "path": "../branding/info" 38 | } 39 | } 40 | }, 41 | "utils": { 42 | "utils_common_fontdir": "C:\\Windows\\Fonts" 43 | }, 44 | "sql": { 45 | "type": "mysql", 46 | "dbPort": 3306, 47 | "dbUser": "root", 48 | "dbPass": "onlyoffice" 49 | }, 50 | "request-filtering-agent" : { 51 | "allowPrivateIPAddress": true, 52 | "allowMetaIPAddress": true 53 | }, 54 | "sockjs": { 55 | "sockjs_url": "/web-apps/vendor/sockjs/sockjs.min.js" 56 | }, 57 | "socketio": { 58 | "connection": { 59 | "pingTimeout": 86400000, 60 | "pingInterval": 86400000 61 | } 62 | } 63 | } 64 | }, 65 | "license": { 66 | "license_file": "./../license.lic", 67 | "warning_limit_percents": 70, 68 | "packageType": 0 69 | }, 70 | "FileConverter": { 71 | "converter": { 72 | "fontDir": "", 73 | "presentationThemesDir": "../../sdkjs/slide/themes", 74 | "x2tPath": "../FileConverter/Bin/x2t.exe", 75 | "docbuilderPath": "../FileConverter/Bin/docbuilder.exe", 76 | "errorfiles": "error" 77 | } 78 | }, 79 | "SpellChecker": { 80 | "server": { 81 | "dictDir": "../../dictionaries" 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /Common/config/log4js/development.json: -------------------------------------------------------------------------------- 1 | { 2 | "appenders": { 3 | "default": { 4 | "type": "console", 5 | "layout": { 6 | "type": "pattern", 7 | "pattern": "%[[%d] [%p] [%X{TENANT}] [%X{DOCID}] [%X{USERID}] %c -%] %.10000m" 8 | } 9 | } 10 | }, 11 | "categories": { 12 | "default": { "appenders": [ "default" ], "level": "ALL" } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Common/config/log4js/production.json: -------------------------------------------------------------------------------- 1 | { 2 | "appenders": { 3 | "default": { 4 | "type": "console", 5 | "layout": { 6 | "type": "pattern", 7 | "pattern": "[%d] [%p] [%X{TENANT}] [%X{DOCID}] [%X{USERID}] %c - %.10000m" 8 | } 9 | } 10 | }, 11 | "categories": { 12 | "default": { "appenders": [ "default" ], "level": "WARN" } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Common/config/production-linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "filePath": "/etc/onlyoffice/documentserver/log4js/production.json" 4 | }, 5 | "storage": { 6 | "fs": { 7 | "folderPath": "/var/lib/onlyoffice/documentserver/App_Data/cache/files" 8 | } 9 | }, 10 | "wopi": { 11 | "htmlTemplate" : "/var/www/onlyoffice/documentserver/web-apps/apps/api/wopi" 12 | }, 13 | "services": { 14 | "CoAuthoring": { 15 | "server": { 16 | "newFileTemplate" : "/var/www/onlyoffice/documentserver/document-templates/new", 17 | "static_content": { 18 | "/fonts": { 19 | "path": "/var/www/onlyoffice/documentserver/fonts", 20 | "options": {"maxAge": "7d"} 21 | }, 22 | "/sdkjs": { 23 | "path": "/var/www/onlyoffice/documentserver/sdkjs", 24 | "options": {"maxAge": "7d"} 25 | }, 26 | "/web-apps": { 27 | "path": "/var/www/onlyoffice/documentserver/web-apps", 28 | "options": {"maxAge": "7d"} 29 | }, 30 | "/welcome": { 31 | "path": "/var/www/onlyoffice/documentserver/server/welcome", 32 | "options": {"maxAge": "7d"} 33 | }, 34 | "/info": { 35 | "path": "/var/www/onlyoffice/documentserver/server/info", 36 | "options": {"maxAge": "7d"} 37 | }, 38 | "/sdkjs-plugins": { 39 | "path": "/var/www/onlyoffice/documentserver/sdkjs-plugins", 40 | "options": {"maxAge": "7d"} 41 | }, 42 | "/dictionaries": { 43 | "path": "/var/www/onlyoffice/documentserver/dictionaries", 44 | "options": {"maxAge": "7d"} 45 | } 46 | } 47 | }, 48 | "utils": { 49 | "utils_common_fontdir": "/usr/share/fonts" 50 | }, 51 | "sockjs": { 52 | "sockjs_url": "/web-apps/vendor/sockjs/sockjs.min.js" 53 | } 54 | } 55 | }, 56 | "license": { 57 | "license_file": "/var/www/onlyoffice/documentserver/../Data/license.lic", 58 | "warning_limit_percents": 70, 59 | "packageType": 0 60 | }, 61 | "FileConverter": { 62 | "converter": { 63 | "fontDir": "/usr/share/fonts", 64 | "presentationThemesDir": "/var/www/onlyoffice/documentserver/sdkjs/slide/themes", 65 | "x2tPath": "/var/www/onlyoffice/documentserver/server/FileConverter/bin/x2t", 66 | "docbuilderPath": "/var/www/onlyoffice/documentserver/server/FileConverter/bin/docbuilder" 67 | } 68 | }, 69 | "SpellChecker": { 70 | "server": { 71 | "dictDir": "/var/www/onlyoffice/documentserver/dictionaries" 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Common/config/production-windows.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "filePath": "../../config/log4js/production.json" 4 | }, 5 | "storage": { 6 | "fs": { 7 | "folderPath": "../App_Data/cache/files" 8 | } 9 | }, 10 | "services": { 11 | "CoAuthoring": { 12 | "server": { 13 | "static_content": { 14 | "/fonts": { 15 | "path": "../../fonts", 16 | "options": {"maxAge": "7d"} 17 | }, 18 | "/sdkjs": { 19 | "path": "../../sdkjs", 20 | "options": {"maxAge": "7d"} 21 | }, 22 | "/web-apps": { 23 | "path": "../../web-apps", 24 | "options": {"maxAge": "7d"} 25 | }, 26 | "/sdkjs-plugins": { 27 | "path": "../../sdkjs-plugins", 28 | "options": {"maxAge": "7d"} 29 | }, 30 | "/dictionaries": { 31 | "path": "../../dictionaries", 32 | "options": {"maxAge": "7d"} 33 | }, 34 | "/welcome": { 35 | "path": "../welcome", 36 | "options": {"maxAge": "7d"} 37 | }, 38 | "/info": { 39 | "path": "../info", 40 | "options": {"maxAge": "7d"} 41 | } 42 | } 43 | }, 44 | "utils": { 45 | "utils_common_fontdir": "C:\\Windows\\Fonts" 46 | }, 47 | "sockjs": { 48 | "sockjs_url": "/web-apps/vendor/sockjs/sockjs.min.js" 49 | } 50 | } 51 | }, 52 | "license": { 53 | "license_file": "./../license.lic", 54 | "warning_limit_percents": 70, 55 | "packageType": 0 56 | }, 57 | "FileConverter": { 58 | "converter": { 59 | "fontDir": "", 60 | "presentationThemesDir": "../../sdkjs/slide/themes", 61 | "x2tPath": "../FileConverter/bin/x2t.exe", 62 | "docbuilderPath": "../FileConverter/bin/docbuilder.exe" 63 | } 64 | }, 65 | "SpellChecker": { 66 | "server": { 67 | "dictDir": "../../dictionaries" 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "common", 3 | "version": "1.0.1", 4 | "homepage": "https://www.onlyoffice.com", 5 | "private": true, 6 | "dependencies": { 7 | "@aws-sdk/client-s3": "3.637.0", 8 | "@aws-sdk/node-http-handler": "3.374.0", 9 | "@aws-sdk/s3-request-presigner": "3.370.0", 10 | "amqplib": "0.8.0", 11 | "co": "4.6.0", 12 | "config": "2.0.1", 13 | "content-disposition": "0.5.3", 14 | "dnscache": "1.0.1", 15 | "escape-string-regexp": "1.0.5", 16 | "forwarded": "0.1.2", 17 | "ipaddr.js": "1.8.1", 18 | "jsonwebtoken": "9.0.0", 19 | "log4js": "6.4.1", 20 | "mime": "2.3.1", 21 | "ms": "2.1.1", 22 | "node-cache": "4.2.1", 23 | "node-statsd": "0.1.1", 24 | "nodemailer": "6.9.13", 25 | "request": "2.88.0", 26 | "request-filtering-agent": "1.0.5", 27 | "rhea": "1.0.24", 28 | "uri-js": "4.2.2", 29 | "win-ca": "3.5.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Common/sources/activeMQCore.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | var config = require('config'); 35 | var container = require('rhea'); 36 | var logger = require('./logger'); 37 | const operationContext = require('./operationContext'); 38 | 39 | const cfgRabbitSocketOptions = config.get('activemq.connectOptions'); 40 | 41 | var RECONNECT_TIMEOUT = 1000; 42 | 43 | function connetPromise(closeCallback) { 44 | return new Promise(function(resolve, reject) { 45 | //todo use built-in reconnect logic 46 | function startConnect() { 47 | let onDisconnected = function() { 48 | if (isConnected) { 49 | closeCallback(); 50 | } else { 51 | setTimeout(startConnect, RECONNECT_TIMEOUT); 52 | } 53 | } 54 | let conn = container.create_container().connect(cfgRabbitSocketOptions); 55 | let isConnected = false; 56 | conn.on('connection_open', function(context) { 57 | operationContext.global.logger.debug('[AMQP] connected'); 58 | isConnected = true; 59 | resolve(conn); 60 | }); 61 | conn.on('connection_error', function(context) { 62 | operationContext.global.logger.debug('[AMQP] connection_error %s', context.error && context.error); 63 | }); 64 | conn.on('connection_close', function(context) { 65 | operationContext.global.logger.debug('[AMQP] conn close'); 66 | if (onDisconnected) { 67 | onDisconnected(); 68 | onDisconnected = null; 69 | } 70 | }); 71 | conn.on('disconnected', function(context) { 72 | operationContext.global.logger.error('[AMQP] disconnected %s', context.error && context.error.stack); 73 | if (onDisconnected) { 74 | onDisconnected(); 75 | onDisconnected = null; 76 | } 77 | }); 78 | } 79 | 80 | startConnect(); 81 | }); 82 | } 83 | function openSenderPromise(conn, options) { 84 | return new Promise(function(resolve, reject) { 85 | resolve(conn.open_sender(options)); 86 | }); 87 | } 88 | function openReceiverPromise(conn, options) { 89 | return new Promise(function(resolve, reject) { 90 | resolve(conn.open_receiver(options)); 91 | }); 92 | } 93 | function closePromise(conn) { 94 | return new Promise(function(resolve, reject) { 95 | conn.close(); 96 | resolve(); 97 | }); 98 | } 99 | 100 | module.exports.connetPromise = connetPromise; 101 | module.exports.openSenderPromise = openSenderPromise; 102 | module.exports.openReceiverPromise = openReceiverPromise; 103 | module.exports.closePromise = closePromise; 104 | module.exports.RECONNECT_TIMEOUT = RECONNECT_TIMEOUT; 105 | -------------------------------------------------------------------------------- /Common/sources/license.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | const constants = require('./constants'); 36 | 37 | const buildDate = '6/29/2016'; 38 | const oBuildDate = new Date(buildDate); 39 | 40 | exports.readLicense = async function () { 41 | const c_LR = constants.LICENSE_RESULT; 42 | var now = new Date(); 43 | var startDate = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));//first day of current month 44 | return [{ 45 | count: 1, 46 | type: c_LR.Success, 47 | packageType: constants.PACKAGE_TYPE_OS, 48 | mode: constants.LICENSE_MODE.None, 49 | branding: false, 50 | connections: constants.LICENSE_CONNECTIONS, 51 | connectionsView: constants.LICENSE_CONNECTIONS, 52 | customization: false, 53 | advancedApi: false, 54 | usersCount: 0, 55 | usersViewCount: 0, 56 | usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY, 57 | hasLicense: false, 58 | buildDate: oBuildDate, 59 | startDate: startDate, 60 | endDate: null, 61 | customerId: "", 62 | alias: "", 63 | multitenancy: false 64 | }, null]; 65 | }; 66 | 67 | exports.packageType = constants.PACKAGE_TYPE_OS; 68 | -------------------------------------------------------------------------------- /Common/sources/logger.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | var config = require('config'); 36 | var util = require('util'); 37 | 38 | var log4js = require('log4js'); 39 | 40 | // https://stackoverflow.com/a/36643588 41 | var dateToJSONWithTZ = function (d) { 42 | var timezoneOffsetInHours = -(d.getTimezoneOffset() / 60); //UTC minus local time 43 | var sign = timezoneOffsetInHours >= 0 ? '+' : '-'; 44 | var leadingZero = (Math.abs(timezoneOffsetInHours) < 10) ? '0' : ''; 45 | 46 | //It's a bit unfortunate that we need to construct a new Date instance 47 | //(we don't want _d_ Date instance to be modified) 48 | var correctedDate = new Date(d.getFullYear(), d.getMonth(), 49 | d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), 50 | d.getMilliseconds()); 51 | correctedDate.setHours(d.getHours() + timezoneOffsetInHours); 52 | var iso = correctedDate.toISOString().replace('Z', ''); 53 | return iso + sign + leadingZero + Math.abs(timezoneOffsetInHours).toString() + ':00'; 54 | }; 55 | 56 | log4js.addLayout('json', function(config) { 57 | return function(logEvent) { 58 | logEvent['startTime'] = dateToJSONWithTZ(logEvent['startTime']); 59 | logEvent['message'] = util.format(...logEvent['data']); 60 | delete logEvent['data']; 61 | return JSON.stringify(logEvent); 62 | } 63 | }); 64 | 65 | log4js.configure(config.get('log.filePath')); 66 | 67 | var logger = log4js.getLogger('nodeJS'); 68 | 69 | if (config.get('log.options.replaceConsole')) { 70 | console.log = logger.info.bind(logger); 71 | console.info = logger.info.bind(logger); 72 | console.warn = logger.warn.bind(logger); 73 | console.error = logger.error.bind(logger); 74 | console.debug = logger.debug.bind(logger); 75 | } 76 | exports.getLogger = function (){ 77 | return log4js.getLogger.apply(log4js, Array.prototype.slice.call(arguments)); 78 | }; 79 | exports.trace = function (){ 80 | return logger.trace.apply(logger, Array.prototype.slice.call(arguments)); 81 | }; 82 | exports.debug = function (){ 83 | return logger.debug.apply(logger, Array.prototype.slice.call(arguments)); 84 | }; 85 | exports.info = function (){ 86 | return logger.info.apply(logger, Array.prototype.slice.call(arguments)); 87 | }; 88 | exports.warn = function (){ 89 | return logger.warn.apply(logger, Array.prototype.slice.call(arguments)); 90 | }; 91 | exports.error = function (){ 92 | return logger.error.apply(logger, Array.prototype.slice.call(arguments)); 93 | }; 94 | exports.fatal = function (){ 95 | return logger.fatal.apply(logger, Array.prototype.slice.call(arguments)); 96 | }; 97 | exports.shutdown = function (callback) { 98 | return log4js.shutdown(callback); 99 | }; 100 | -------------------------------------------------------------------------------- /Common/sources/mailService.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2023 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | const config = require('config'); 36 | const nodemailer = require('nodemailer'); 37 | 38 | const cfgConnection = config.get('email.connectionConfiguration'); 39 | 40 | const connectionDefaultSettings = { 41 | pool: true, 42 | socketTimeout: 1000 * 60 * 2, 43 | connectionTimeout: 1000 * 60 * 2, 44 | maxConnections: 10 45 | }; 46 | // Connection settings could be overridden by config, so user can configure transporter anyhow. 47 | const settings = Object.assign(connectionDefaultSettings, cfgConnection); 48 | const smtpTransporters = new Map(); 49 | 50 | function createTransporter(ctx, host, port, auth, messageCommonParameters = {}) { 51 | const server = { 52 | host, 53 | port, 54 | auth, 55 | secure: port === 465 56 | }; 57 | const transport = Object.assign({}, server, settings); 58 | 59 | try { 60 | if (smtpTransporters.has(`${host}:${auth.user}`)) { 61 | return; 62 | } 63 | 64 | const transporter = nodemailer.createTransport(transport, messageCommonParameters); 65 | smtpTransporters.set(`${host}:${auth.user}`, transporter); 66 | } catch (error) { 67 | ctx.logger.error('Mail service smtp transporter creation error: %o\nWith parameters: \n\thost - %s, \n\tport - %d, \n\tauth = %o', error.stack, host, port, auth); 68 | } 69 | } 70 | 71 | async function send(host, userLogin, mailObject) { 72 | const transporter = smtpTransporters.get(`${host}:${userLogin}`); 73 | if (!transporter) { 74 | throw new Error(`MailService: no transporter exists for host "${host}" and user "${userLogin}"`); 75 | } 76 | 77 | return transporter.sendMail(mailObject); 78 | } 79 | 80 | function deleteTransporter(ctx, host, userLogin) { 81 | const transporter = smtpTransporters.get(`${host}:${userLogin}`); 82 | if (!transporter) { 83 | ctx.logger.error(`MailService: no transporter exists for host "${host}" and user "${userLogin}"`); 84 | return; 85 | } 86 | 87 | transporter.close(); 88 | smtpTransporters.delete(`${host}:${userLogin}`); 89 | } 90 | 91 | function transportersRelease() { 92 | smtpTransporters.forEach(transporter => transporter.close()); 93 | smtpTransporters.clear(); 94 | } 95 | 96 | module.exports = { 97 | createTransporter, 98 | send, 99 | deleteTransporter, 100 | transportersRelease 101 | }; 102 | 103 | -------------------------------------------------------------------------------- /Common/sources/notificationService.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2023 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | const util = require('util'); 35 | const config = require('config'); 36 | const ms = require('ms'); 37 | 38 | const mailService = require('./mailService'); 39 | 40 | const cfgMailServer = config.get('email.smtpServerConfiguration'); 41 | const cfgMailMessageDefaults = config.get('email.contactDefaults'); 42 | const cfgEditorDataStorage = config.get('services.CoAuthoring.server.editorDataStorage'); 43 | const cfgEditorStatStorage = config.get('services.CoAuthoring.server.editorStatStorage'); 44 | const editorStatStorage = require('./../../DocService/sources/' + (cfgEditorStatStorage || cfgEditorDataStorage)); 45 | 46 | const editorStat = editorStatStorage.EditorStat ? new editorStatStorage.EditorStat() : new editorStatStorage(); 47 | const notificationTypes = { 48 | LICENSE_EXPIRATION_WARNING: 'licenseExpirationWarning', 49 | LICENSE_EXPIRATION_ERROR: 'licenseExpirationError', 50 | LICENSE_LIMIT_EDIT: 'licenseLimitEdit', 51 | LICENSE_LIMIT_LIVE_VIEWER: 'licenseLimitLiveViewer' 52 | }; 53 | 54 | class TransportInterface { 55 | async send(ctx, message) {} 56 | contentGeneration(title, message) {} 57 | } 58 | 59 | class MailTransport extends TransportInterface { 60 | host = cfgMailServer.host; 61 | port = cfgMailServer.port; 62 | auth = cfgMailServer.auth; 63 | 64 | constructor(ctx) { 65 | super(); 66 | 67 | mailService.createTransporter(ctx, this.host, this.port, this.auth, cfgMailMessageDefaults); 68 | } 69 | 70 | async send(ctx, message) { 71 | ctx.logger.debug('Notification service: MailTransport send %j', message); 72 | return mailService.send(this.host, this.auth.user, message); 73 | } 74 | 75 | contentGeneration(title, message) { 76 | return { 77 | subject: title, 78 | text: message 79 | }; 80 | } 81 | } 82 | 83 | // TODO: 84 | class TelegramTransport extends TransportInterface { 85 | constructor(ctx) { 86 | super(); 87 | } 88 | } 89 | 90 | class Transport { 91 | transport = new TransportInterface(); 92 | 93 | constructor(ctx, transportName) { 94 | this.name = transportName; 95 | 96 | switch (transportName) { 97 | case 'email': 98 | this.transport = new MailTransport(ctx); 99 | break; 100 | case 'telegram': 101 | this.transport = new TelegramTransport(ctx); 102 | break 103 | default: 104 | ctx.logger.warn(`Notification service: error: transport method "${transportName}" not implemented`); 105 | } 106 | } 107 | } 108 | 109 | async function notify(ctx, notificationType, title, message, opt_cacheKey = undefined) { 110 | const tenRule = ctx.getCfg(`notification.rules.${notificationType}`, config.get(`notification.rules.${notificationType}`)); 111 | if (tenRule?.enable) { 112 | ctx.logger.debug('Notification service: notify "%s"', notificationType); 113 | let checkRes = await checkRulePolicies(ctx, notificationType, tenRule, opt_cacheKey); 114 | if (checkRes) { 115 | await notifyRule(ctx, tenRule, title, message); 116 | } 117 | } 118 | } 119 | 120 | async function checkRulePolicies(ctx, notificationType, tenRule, opt_cacheKey) { 121 | const { repeatInterval } = tenRule.policies; 122 | //decrease repeatInterval by 1% to avoid race condition if timeout=repeatInterval 123 | let ttl = Math.floor(ms(repeatInterval) * 0.99 / 1000); 124 | let isLock = false; 125 | //todo for compatibility remove if after 8.2 126 | if (editorStat?.lockNotification) { 127 | isLock = await editorStat.lockNotification(ctx, opt_cacheKey || notificationType, ttl); 128 | } 129 | if (!isLock) { 130 | ctx.logger.debug(`Notification service: skip rule "%s" due to repeat interval = %s`, notificationType, repeatInterval); 131 | } 132 | return isLock; 133 | } 134 | 135 | async function notifyRule(ctx, tenRule, title, message) { 136 | const transportObjects = tenRule.transportType.map(transport => new Transport(ctx, transport)); 137 | for (const transportObject of transportObjects) { 138 | try { 139 | const mail = transportObject.transport.contentGeneration(title, message); 140 | await transportObject.transport.send(ctx, mail); 141 | } catch (error) { 142 | ctx.logger.error('Notification service: error: %s', error.stack); 143 | } 144 | } 145 | } 146 | 147 | module.exports = { 148 | notificationTypes, 149 | notify 150 | }; 151 | -------------------------------------------------------------------------------- /Common/sources/operationContext.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | const utils = require('./utils'); 36 | const logger = require('./logger'); 37 | const constants = require('./constants'); 38 | const tenantManager = require('./tenantManager'); 39 | 40 | function Context(){ 41 | this.logger = logger.getLogger('nodeJS'); 42 | this.initDefault(); 43 | } 44 | Context.prototype.init = function(tenant, docId, userId, opt_shardKey, opt_WopiSrc) { 45 | this.setTenant(tenant); 46 | this.setDocId(docId); 47 | this.setUserId(userId); 48 | this.setShardKey(opt_shardKey); 49 | this.setWopiSrc(opt_WopiSrc); 50 | 51 | this.config = null; 52 | this.secret = null; 53 | this.license = null; 54 | }; 55 | Context.prototype.initDefault = function() { 56 | this.init(tenantManager.getDefautTenant(), constants.DEFAULT_DOC_ID, constants.DEFAULT_USER_ID, undefined); 57 | }; 58 | Context.prototype.initFromConnection = function(conn) { 59 | let tenant = tenantManager.getTenantByConnection(this, conn); 60 | let docId = conn.docid; 61 | if (!docId) { 62 | let handshake = conn.handshake; 63 | const docIdParsed = constants.DOC_ID_SOCKET_PATTERN.exec(handshake.url); 64 | if (docIdParsed && 1 < docIdParsed.length) { 65 | docId = docIdParsed[1]; 66 | } 67 | } 68 | let userId = conn.user?.id; 69 | let shardKey = utils.getShardKeyByConnection(this, conn); 70 | let wopiSrc = utils.getWopiSrcByConnection(this, conn); 71 | this.init(tenant, docId || this.docId, userId || this.userId, shardKey, wopiSrc); 72 | }; 73 | Context.prototype.initFromRequest = function(req) { 74 | let tenant = tenantManager.getTenantByRequest(this, req); 75 | let shardKey = utils.getShardKeyByRequest(this, req); 76 | let wopiSrc = utils.getWopiSrcByRequest(this, req); 77 | this.init(tenant, this.docId, this.userId, shardKey, wopiSrc); 78 | }; 79 | Context.prototype.initFromTaskQueueData = function(task) { 80 | let ctx = task.getCtx(); 81 | this.init(ctx.tenant, ctx.docId, ctx.userId, ctx.shardKey, ctx.wopiSrc); 82 | }; 83 | Context.prototype.initFromPubSub = function(data) { 84 | let ctx = data.ctx; 85 | this.init(ctx.tenant, ctx.docId, ctx.userId, ctx.shardKey, ctx.wopiSrc); 86 | }; 87 | Context.prototype.initTenantCache = async function() { 88 | this.config = await tenantManager.getTenantConfig(this); 89 | //todo license and secret 90 | }; 91 | 92 | Context.prototype.setTenant = function(tenant) { 93 | this.tenant = tenant; 94 | this.logger.addContext('TENANT', tenant); 95 | }; 96 | Context.prototype.setDocId = function(docId) { 97 | this.docId = docId; 98 | this.logger.addContext('DOCID', docId); 99 | }; 100 | Context.prototype.setUserId = function(userId) { 101 | this.userId = userId; 102 | this.logger.addContext('USERID', userId); 103 | }; 104 | Context.prototype.setShardKey = function(shardKey) { 105 | this.shardKey = shardKey; 106 | }; 107 | Context.prototype.setWopiSrc = function(wopiSrc) { 108 | this.wopiSrc = wopiSrc; 109 | }; 110 | Context.prototype.toJSON = function() { 111 | return { 112 | tenant: this.tenant, 113 | docId: this.docId, 114 | userId: this.userId, 115 | shardKey: this.shardKey, 116 | wopiSrc: this.wopiSrc 117 | } 118 | }; 119 | Context.prototype.getCfg = function(property, defaultValue) { 120 | if (this.config){ 121 | return getImpl(this.config, property) ?? defaultValue; 122 | } 123 | return defaultValue; 124 | }; 125 | 126 | /** 127 | * Underlying get mechanism 128 | * 129 | * @private 130 | * @method getImpl 131 | * @param object {object} - Object to get the property for 132 | * @param property {string | array[string]} - The property name to get (as an array or '.' delimited string) 133 | * @return value {*} - Property value, including undefined if not defined. 134 | */ 135 | function getImpl(object, property) { 136 | //from https://github.com/node-config/node-config/blob/a8b91ac86b499d11b90974a2c9915ce31266044a/lib/config.js#L137 137 | var t = this, 138 | elems = Array.isArray(property) ? property : property.split('.'), 139 | name = elems[0], 140 | value = object[name]; 141 | if (elems.length <= 1) { 142 | return value; 143 | } 144 | // Note that typeof null === 'object' 145 | if (value === null || typeof value !== 'object') { 146 | return undefined; 147 | } 148 | return getImpl(value, elems.slice(1)); 149 | }; 150 | 151 | exports.Context = Context; 152 | exports.global = new Context(); 153 | -------------------------------------------------------------------------------- /Common/sources/rabbitMQCore.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | var config = require('config'); 35 | var amqp = require('amqplib/callback_api'); 36 | var logger = require('./logger'); 37 | const operationContext = require('./operationContext'); 38 | 39 | var cfgRabbitUrl = config.get('rabbitmq.url'); 40 | var cfgRabbitSocketOptions = config.get('rabbitmq.socketOptions'); 41 | 42 | var RECONNECT_TIMEOUT = 1000; 43 | 44 | function connetPromise(closeCallback) { 45 | return new Promise(function(resolve, reject) { 46 | function startConnect() { 47 | amqp.connect(cfgRabbitUrl, cfgRabbitSocketOptions, function(err, conn) { 48 | if (null != err) { 49 | operationContext.global.logger.error('[AMQP] %s', err.stack); 50 | setTimeout(startConnect, RECONNECT_TIMEOUT); 51 | } else { 52 | conn.on('error', function(err) { 53 | operationContext.global.logger.error('[AMQP] conn error', err.stack); 54 | }); 55 | var closeEventCallback = function() { 56 | //in some case receive multiple close events 57 | conn.removeListener('close', closeEventCallback); 58 | operationContext.global.logger.debug('[AMQP] conn close'); 59 | closeCallback(); 60 | }; 61 | conn.on('close', closeEventCallback); 62 | operationContext.global.logger.debug('[AMQP] connected'); 63 | resolve(conn); 64 | } 65 | }); 66 | } 67 | startConnect(); 68 | }); 69 | } 70 | function createChannelPromise(conn) { 71 | return new Promise(function(resolve, reject) { 72 | conn.createChannel(function(err, channel) { 73 | if (null != err) { 74 | reject(err); 75 | } else { 76 | resolve(channel); 77 | } 78 | }); 79 | }); 80 | } 81 | function createConfirmChannelPromise(conn) { 82 | return new Promise(function(resolve, reject) { 83 | conn.createConfirmChannel(function(err, channel) { 84 | if (null != err) { 85 | reject(err); 86 | } else { 87 | resolve(channel); 88 | } 89 | }); 90 | }); 91 | } 92 | function assertExchangePromise(channel, exchange, type, options) { 93 | return new Promise(function(resolve, reject) { 94 | channel.assertExchange(exchange, type, options, function(err, ok) { 95 | if (null != err) { 96 | reject(err); 97 | } else { 98 | resolve(ok.exchange); 99 | } 100 | }); 101 | }); 102 | } 103 | function assertQueuePromise(channel, queue, options) { 104 | return new Promise(function(resolve, reject) { 105 | channel.assertQueue(queue, options, function(err, ok) { 106 | if (null != err) { 107 | reject(err); 108 | } else { 109 | resolve(ok.queue); 110 | } 111 | }); 112 | }); 113 | } 114 | function consumePromise(channel, queue, messageCallback, options) { 115 | return new Promise(function(resolve, reject) { 116 | channel.consume(queue, messageCallback, options, function(err, ok) { 117 | if (null != err) { 118 | reject(err); 119 | } else { 120 | resolve(ok); 121 | } 122 | }); 123 | }); 124 | } 125 | function closePromise(conn) { 126 | return new Promise(function(resolve, reject) { 127 | conn.close(function(err) { 128 | if (err) { 129 | reject(err); 130 | } else { 131 | resolve(); 132 | } 133 | }); 134 | }); 135 | } 136 | 137 | module.exports.connetPromise = connetPromise; 138 | module.exports.createChannelPromise = createChannelPromise; 139 | module.exports.createConfirmChannelPromise = createConfirmChannelPromise; 140 | module.exports.assertExchangePromise = assertExchangePromise; 141 | module.exports.assertQueuePromise = assertQueuePromise; 142 | module.exports.consumePromise = consumePromise; 143 | module.exports.closePromise = closePromise; 144 | module.exports.RECONNECT_TIMEOUT = RECONNECT_TIMEOUT; 145 | -------------------------------------------------------------------------------- /Common/sources/statsdclient.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | var statsD = require('node-statsd'); 36 | var configStatsD = require('config').get('statsd'); 37 | 38 | var cfgStatsDUseMetrics = configStatsD.get('useMetrics'); 39 | var cfgStatsDHost = configStatsD.get('host'); 40 | var cfgStatsDPort = configStatsD.get('port'); 41 | var cfgStatsDPrefix = configStatsD.get('prefix'); 42 | 43 | var clientStatsD = null; 44 | if(cfgStatsDUseMetrics) { 45 | clientStatsD = new statsD({host: cfgStatsDHost, port:cfgStatsDPort, prefix: cfgStatsDPrefix}); 46 | } 47 | 48 | exports.getClient = function() { 49 | return clientStatsD; 50 | }; 51 | -------------------------------------------------------------------------------- /DocService/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coauthoring", 3 | "version": "1.0.1", 4 | "homepage": "https://www.onlyoffice.com", 5 | "private": true, 6 | "bin": { 7 | "docservice": "sources/server.js", 8 | "gc": "sources/gc.js", 9 | "prepare4shutdown": "sources/shutdown.js" 10 | }, 11 | "dependencies": { 12 | "ajv": "8.9.0", 13 | "apicache": "1.6.3", 14 | "base64-stream": "1.0.0", 15 | "body-parser": "1.20.1", 16 | "bottleneck": "2.19.5", 17 | "bytes": "3.0.0", 18 | "co": "4.6.0", 19 | "config": "2.0.1", 20 | "cron": "1.5.0", 21 | "deep-equal": "1.0.1", 22 | "dmdb": "1.0.14280", 23 | "ejs": "3.1.10", 24 | "exif-parser": "0.1.12", 25 | "express": "4.19.2", 26 | "fakeredis": "2.0.0", 27 | "ioredis": "5.3.1", 28 | "jimp": "0.22.10", 29 | "jsonwebtoken": "9.0.0", 30 | "jwa": "1.1.6", 31 | "mime": "2.3.1", 32 | "mime-db": "1.49.0", 33 | "ms": "2.1.1", 34 | "mssql": "9.1.1", 35 | "multer": "1.4.3", 36 | "multi-integer-range": "4.0.7", 37 | "multiparty": "4.2.1", 38 | "mysql2": "3.9.8", 39 | "oracledb": "6.3.0", 40 | "pg": "8.11.3", 41 | "redis": "4.6.11", 42 | "retry": "0.12.0", 43 | "socket.io": "4.8.1", 44 | "underscore": "1.13.1", 45 | "utf7": "1.0.2", 46 | "windows-locale": "1.0.1", 47 | "xmlbuilder2": "3.0.2" 48 | }, 49 | "pkg": { 50 | "scripts": [ 51 | "./sources/editorDataMemory.js", 52 | "./sources/editorDataRedis.js", 53 | "./sources/pubsubRabbitMQ.js", 54 | "../Common/sources/storage-fs.js", 55 | "../Common/sources/storage-s3.js" 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /DocService/public/healthcheck.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ONLYOFFICE/server/4933ff7a1aed0c999a621b8bee2e154a8a914930/DocService/public/healthcheck.docx -------------------------------------------------------------------------------- /DocService/sources/database.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | var mongoDB = require('mongodb'); 36 | var config = require('./config.json'); 37 | var _errorConnection = true; 38 | 39 | var logger = require('./../../Common/sources/logger'); 40 | 41 | function CreateDbClient(){ 42 | return new mongoDB.Db(config['mongodb']['database'], new mongoDB.Server(config['mongodb']['host'], config['mongodb']['port'], {auto_reconnect: true}), {safe:false}); 43 | } 44 | exports.insert = function (_collectionName, _newElement) { 45 | var _db = CreateDbClient(); 46 | if (!_db) { 47 | logger.error ("Error _db"); 48 | return; 49 | } 50 | 51 | _db.open (function (err, db) { 52 | if (!err) { 53 | // open collection. If it doesn't exist, it will be created 54 | db.collection(_collectionName, function(err, collection) { 55 | if (!err) { 56 | collection.insert (_newElement); 57 | } else { 58 | logger.error ("Error collection"); 59 | return; 60 | } 61 | 62 | db.close(); 63 | }); 64 | } else { 65 | logger.error ("Error open database"); 66 | } 67 | }); 68 | }; 69 | exports.remove = function (_collectionName, _removeElements) { 70 | var _db = CreateDbClient(); 71 | if (!_db) { 72 | logger.error ("Error _db"); 73 | return; 74 | } 75 | 76 | // Opening the database 77 | _db.open (function (err, db) { 78 | if (!err) { 79 | // open collection. If it doesn't exist, it will be created 80 | db.collection(_collectionName, function(err, collection) { 81 | if (!err) { 82 | collection.remove (_removeElements, function(err, collection) { 83 | logger.info ("All elements remove"); 84 | }); 85 | } else { 86 | logger.error ("Error collection"); 87 | return; 88 | } 89 | 90 | db.close(); 91 | }); 92 | } else { 93 | logger.error ("Error open database"); 94 | } 95 | }); 96 | }; 97 | exports.load = function (_collectionName, callbackFunction) { 98 | var _db = CreateDbClient(); 99 | if (!_db) { 100 | logger.error ("Error _db"); 101 | return callbackFunction (null); 102 | } 103 | 104 | var result = []; 105 | 106 | // opening database 107 | _db.open (function (err, db) { 108 | // open collection. If it doesn't exist, it will be created 109 | db.collection(_collectionName, function(err, collection) { 110 | // Get all elements of a collection with find() 111 | collection.find(function(err, cursor) { 112 | cursor.each(function(err, item) { 113 | // Null denotes the last element 114 | if (item != null) { 115 | if (!result.hasOwnProperty (item.docid)) 116 | result[item.docid] = [item]; 117 | else 118 | result[item.docid].push(item); 119 | } else 120 | callbackFunction (result); 121 | }); 122 | 123 | db.close(); 124 | }); 125 | }); 126 | }); 127 | }; -------------------------------------------------------------------------------- /DocService/sources/databaseConnectors/mysqlConnector.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | const mysql = require('mysql2/promise'); 36 | const connectorUtilities = require('./connectorUtilities'); 37 | const config = require('config'); 38 | 39 | const configSql = config.get('services.CoAuthoring.sql'); 40 | const cfgTableResult = configSql.get('tableResult'); 41 | 42 | const connectionConfiguration = { 43 | host : configSql.get('dbHost'), 44 | port : parseInt(configSql.get('dbPort')), 45 | user : configSql.get('dbUser'), 46 | password : configSql.get('dbPass'), 47 | database : configSql.get('dbName'), 48 | charset : configSql.get('charset'), 49 | connectionLimit : configSql.get('connectionlimit'), 50 | timezone : 'Z', 51 | flags : '-FOUND_ROWS' 52 | }; 53 | 54 | const additionalOptions = configSql.get('mysqlExtraOptions'); 55 | const configuration = Object.assign({}, connectionConfiguration, additionalOptions); 56 | let queryTimeout = undefined; 57 | if (configuration.queryTimeout) { 58 | queryTimeout = configuration.queryTimeout; 59 | delete configuration.queryTimeout; 60 | } 61 | 62 | const pool = mysql.createPool(configuration); 63 | 64 | function sqlQuery(ctx, sqlCommand, callbackFunction, opt_noModifyRes = false, opt_noLog = false, opt_values = []) { 65 | return executeQuery(ctx, sqlCommand, opt_values, opt_noModifyRes, opt_noLog).then( 66 | result => callbackFunction?.(null, result), 67 | error => callbackFunction?.(error) 68 | ); 69 | } 70 | 71 | async function executeQuery(ctx, sqlCommand, values = [], noModifyRes = false, noLog = false) { 72 | let connection = null; 73 | try { 74 | connection = await pool.getConnection(); 75 | 76 | const result = await connection.query({ sql: sqlCommand, timeout: queryTimeout, values }); 77 | 78 | let output; 79 | if (!noModifyRes) { 80 | output = result[0]?.affectedRows ? { affectedRows: result[0].affectedRows } : result[0]; 81 | } else { 82 | output = result[0]; 83 | } 84 | 85 | return output ?? { rows: [], affectedRows: 0 }; 86 | } catch (error) { 87 | if (!noLog) { 88 | ctx.logger.error(`sqlQuery() error while executing query: ${sqlCommand}\n${error.stack}`); 89 | } 90 | 91 | throw error; 92 | } finally { 93 | if (connection) { 94 | try { 95 | // Put the connection back in the pool 96 | connection.release(); 97 | } catch (error) { 98 | if (!noLog) { 99 | ctx.logger.error(`connection.release() error while executing query: ${sqlCommand}\n${error.stack}`); 100 | } 101 | } 102 | } 103 | } 104 | } 105 | 106 | async function closePool() { 107 | return await pool.end(); 108 | } 109 | 110 | function addSqlParameter(parameter, accumulatedArray) { 111 | accumulatedArray.push(parameter); 112 | return '?'; 113 | } 114 | 115 | function concatParams(firstParameter, secondParameter) { 116 | return `CONCAT(COALESCE(${firstParameter}, ''), COALESCE(${secondParameter}, ''))`; 117 | } 118 | 119 | async function upsert(ctx, task) { 120 | task.completeDefaults(); 121 | const dateNow = new Date(); 122 | 123 | let cbInsert = task.callback; 124 | if (task.callback) { 125 | const userCallback = new connectorUtilities.UserCallback(); 126 | userCallback.fromValues(task.userIndex, task.callback); 127 | cbInsert = userCallback.toSQLInsert(); 128 | } 129 | 130 | const values = []; 131 | const valuesPlaceholder = [ 132 | addSqlParameter(task.tenant, values), 133 | addSqlParameter(task.key, values), 134 | addSqlParameter(task.status, values), 135 | addSqlParameter(task.statusInfo, values), 136 | addSqlParameter(dateNow, values), 137 | addSqlParameter(task.userIndex, values), 138 | addSqlParameter(task.changeId, values), 139 | addSqlParameter(cbInsert, values), 140 | addSqlParameter(task.baseurl, values) 141 | ]; 142 | 143 | let updateStatement = `last_open_date = ${addSqlParameter(dateNow, values)}`; 144 | if (task.callback) { 145 | let callbackPlaceholder = addSqlParameter(JSON.stringify(task.callback), values); 146 | updateStatement += `, callback = CONCAT(callback , '${connectorUtilities.UserCallback.prototype.delimiter}{"userIndex":' , (user_index + 1) , ',"callback":', ${callbackPlaceholder}, '}')`; 147 | } 148 | 149 | if (task.baseurl) { 150 | let baseUrlPlaceholder = addSqlParameter(task.baseurl, values); 151 | updateStatement += `, baseurl = ${baseUrlPlaceholder}`; 152 | } 153 | 154 | updateStatement += ', user_index = LAST_INSERT_ID(user_index + 1);'; 155 | 156 | const sqlCommand = `INSERT INTO ${cfgTableResult} (tenant, id, status, status_info, last_open_date, user_index, change_id, callback, baseurl) `+ 157 | `VALUES (${valuesPlaceholder.join(', ')}) ` + 158 | `ON DUPLICATE KEY UPDATE ${updateStatement}`; 159 | 160 | const result = await executeQuery(ctx, sqlCommand, values, true); 161 | const insertId = result.affectedRows === 1 ? task.userIndex : result.insertId; 162 | //if CLIENT_FOUND_ROWS don't specify 1 row is inserted , 2 row is updated, and 0 row is set to its current values 163 | //http://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html 164 | const isInsert = result.affectedRows === 1; 165 | 166 | return { isInsert, insertId }; 167 | } 168 | 169 | module.exports.sqlQuery = sqlQuery; 170 | module.exports.closePool = closePool; 171 | module.exports.addSqlParameter = addSqlParameter; 172 | module.exports.concatParams = concatParams; 173 | module.exports.upsert = upsert; 174 | -------------------------------------------------------------------------------- /DocService/sources/routes/static.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2023 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | const express = require('express'); 35 | const config = require("config"); 36 | const operationContext = require('./../../../Common/sources/operationContext'); 37 | const utils = require('./../../../Common/sources/utils'); 38 | const storage = require('./../../../Common/sources/storage-base'); 39 | const urlModule = require("url"); 40 | const path = require("path"); 41 | const mime = require("mime"); 42 | 43 | const cfgStaticContent = config.has('services.CoAuthoring.server.static_content') ? config.get('services.CoAuthoring.server.static_content') : {}; 44 | const cfgCacheStorage = config.get('storage'); 45 | const cfgPersistentStorage = utils.deepMergeObjects({}, cfgCacheStorage, config.get('persistentStorage')); 46 | const cfgForgottenFiles = config.get('services.CoAuthoring.server.forgottenfiles'); 47 | const cfgErrorFiles = config.get('FileConverter.converter.errorfiles'); 48 | 49 | const router = express.Router(); 50 | 51 | function initCacheRouter(cfgStorage, routs) { 52 | const bucketName = cfgStorage.bucketName; 53 | const storageFolderName = cfgStorage.storageFolderName; 54 | const folderPath = cfgStorage.fs.folderPath; 55 | routs.forEach((rout) => { 56 | //special dirs are empty by default 57 | if (!rout) { 58 | return; 59 | } 60 | let rootPath = path.join(folderPath, rout); 61 | router.use(`/${bucketName}/${storageFolderName}/${rout}`, (req, res, next) => { 62 | const index = req.url.lastIndexOf('/'); 63 | if ('GET' === req.method && index > 0) { 64 | let sendFileOptions = { 65 | root: rootPath, dotfiles: 'deny', headers: { 66 | 'Content-Disposition': 'attachment' 67 | } 68 | }; 69 | const urlParsed = urlModule.parse(req.url); 70 | if (urlParsed && urlParsed.pathname) { 71 | const filename = decodeURIComponent(path.basename(urlParsed.pathname)); 72 | sendFileOptions.headers['Content-Type'] = mime.getType(filename); 73 | } 74 | const realUrl = decodeURI(req.url.substring(0, index)); 75 | res.sendFile(realUrl, sendFileOptions, (err) => { 76 | if (err) { 77 | operationContext.global.logger.error(err); 78 | res.status(400).end(); 79 | } 80 | }); 81 | } else { 82 | res.sendStatus(404); 83 | } 84 | }); 85 | }); 86 | } 87 | 88 | for (let i in cfgStaticContent) { 89 | if (cfgStaticContent.hasOwnProperty(i)) { 90 | router.use(i, express.static(cfgStaticContent[i]['path'], cfgStaticContent[i]['options'])); 91 | } 92 | } 93 | if (storage.needServeStatic()) { 94 | initCacheRouter(cfgCacheStorage, [cfgCacheStorage.cacheFolderName]); 95 | } 96 | if (storage.needServeStatic(cfgForgottenFiles)) { 97 | let persistentRouts = [cfgForgottenFiles, cfgErrorFiles]; 98 | persistentRouts.filter((rout) => {return rout && rout.length > 0;}); 99 | if (persistentRouts.length > 0) { 100 | initCacheRouter(cfgPersistentStorage, [cfgForgottenFiles, cfgErrorFiles]); 101 | } 102 | } 103 | 104 | module.exports = router; 105 | -------------------------------------------------------------------------------- /DocService/sources/shutdown.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | var config = require('config'); 35 | var configCoAuthoring = config.get('services.CoAuthoring'); 36 | var co = require('co'); 37 | var logger = require('./../../Common/sources/logger'); 38 | var pubsubService = require('./pubsubRabbitMQ'); 39 | const sqlBase = require('./databaseConnectors/baseConnector'); 40 | var commonDefines = require('./../../Common/sources/commondefines'); 41 | var constants = require('./../../Common/sources/constants'); 42 | var utils = require('./../../Common/sources/utils'); 43 | 44 | var cfgRedisPrefix = configCoAuthoring.get('redis.prefix'); 45 | var redisKeyShutdown = cfgRedisPrefix + constants.REDIS_KEY_SHUTDOWN; 46 | 47 | var WAIT_TIMEOUT = 30000; 48 | var LOOP_TIMEOUT = 1000; 49 | var EXEC_TIMEOUT = WAIT_TIMEOUT + utils.getConvertionTimeout(undefined); 50 | 51 | exports.shutdown = function(ctx, editorStat, status) { 52 | return co(function*() { 53 | var res = true; 54 | try { 55 | ctx.logger.debug('shutdown start:' + EXEC_TIMEOUT); 56 | 57 | //redisKeyShutdown is not a simple counter, so it doesn't get decremented by a build that started before Shutdown started 58 | //reset redisKeyShutdown just in case the previous run didn't finish 59 | yield editorStat.cleanupShutdown(redisKeyShutdown); 60 | 61 | var pubsub = new pubsubService(); 62 | yield pubsub.initPromise(); 63 | //inner ping to update presence 64 | ctx.logger.debug('shutdown pubsub shutdown message'); 65 | yield pubsub.publish(JSON.stringify({type: commonDefines.c_oPublishType.shutdown, ctx: ctx, status: status})); 66 | //wait while pubsub deliver and start conversion 67 | ctx.logger.debug('shutdown start wait pubsub deliver'); 68 | var startTime = new Date().getTime(); 69 | var isStartWait = true; 70 | while (true) { 71 | var curTime = new Date().getTime() - startTime; 72 | if (isStartWait && curTime >= WAIT_TIMEOUT) { 73 | isStartWait = false; 74 | ctx.logger.debug('shutdown stop wait pubsub deliver'); 75 | } else if (curTime >= EXEC_TIMEOUT) { 76 | res = false; 77 | ctx.logger.debug('shutdown timeout'); 78 | break; 79 | } 80 | var remainingFiles = yield editorStat.getShutdownCount(redisKeyShutdown); 81 | let inSavingStatus = yield sqlBase.getCountWithStatus(ctx, commonDefines.FileStatus.SaveVersion, EXEC_TIMEOUT); 82 | ctx.logger.debug('shutdown remaining files editorStat:%d, db:%d', remainingFiles, inSavingStatus); 83 | if (!isStartWait && (remainingFiles + inSavingStatus) <= 0) { 84 | break; 85 | } 86 | yield utils.sleep(LOOP_TIMEOUT); 87 | } 88 | //todo need to check the queues, because there may be long conversions running before Shutdown 89 | //clean up 90 | yield editorStat.cleanupShutdown(redisKeyShutdown); 91 | yield pubsub.close(); 92 | 93 | ctx.logger.debug('shutdown end'); 94 | } catch (e) { 95 | res = false; 96 | ctx.logger.error('shutdown error: %s', e.stack); 97 | } 98 | return res; 99 | }); 100 | }; 101 | -------------------------------------------------------------------------------- /DocService/sources/utilsDocService.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | const util = require("util"); 36 | const config = require('config'); 37 | const exifParser = require('exif-parser'); 38 | //set global window to fix issue https://github.com/photopea/UTIF.js/issues/130 39 | if (!global.window) { 40 | global.window = global; 41 | } 42 | const Jimp = require('jimp'); 43 | const locale = require('windows-locale'); 44 | const ms = require('ms'); 45 | 46 | const tenantManager = require('../../Common/sources/tenantManager'); 47 | const { notificationTypes, ...notificationService } = require('../../Common/sources/notificationService'); 48 | 49 | const cfgStartNotifyFrom = ms(config.get('license.warning_license_expiration')); 50 | const cfgNotificationRuleLicenseExpirationWarning = config.get('notification.rules.licenseExpirationWarning.template'); 51 | const cfgNotificationRuleLicenseExpirationError = config.get('notification.rules.licenseExpirationError.template'); 52 | 53 | async function fixImageExifRotation(ctx, buffer) { 54 | if (!buffer) { 55 | return buffer; 56 | } 57 | //todo move to DocService dir common 58 | try { 59 | let parser = exifParser.create(buffer); 60 | let exif = parser.parse(); 61 | if (exif.tags?.Orientation > 1) { 62 | ctx.logger.debug('fixImageExifRotation remove exif and rotate:%j', exif); 63 | buffer = convertImageTo(ctx, buffer, Jimp.AUTO); 64 | } 65 | } catch (e) { 66 | ctx.logger.debug('fixImageExifRotation error:%s', e.stack); 67 | } 68 | return buffer; 69 | } 70 | async function convertImageToPng(ctx, buffer) { 71 | return await convertImageTo(ctx, buffer, Jimp.MIME_PNG); 72 | } 73 | async function convertImageTo(ctx, buffer, mime) { 74 | try { 75 | ctx.logger.debug('convertImageTo %s', mime); 76 | let image = await Jimp.read(buffer); 77 | //remove exif 78 | image.bitmap.exifBuffer = undefined; 79 | //set jpeg and png quality 80 | //https://www.imagemagick.org/script/command-line-options.php#quality 81 | image.quality(90); 82 | image.deflateLevel(7); 83 | buffer = await image.getBufferAsync(mime); 84 | } catch (e) { 85 | ctx.logger.debug('convertImageTo error:%s', e.stack); 86 | } 87 | return buffer; 88 | } 89 | /** 90 | * 91 | * @param {string} lang 92 | * @returns {number | undefined} 93 | */ 94 | function localeToLCID(lang) { 95 | let elem = locale[lang && lang.toLowerCase()]; 96 | return elem && elem.id; 97 | } 98 | 99 | function humanFriendlyExpirationTime(endTime) { 100 | const month = [ 101 | 'January', 102 | 'February', 103 | 'March', 104 | 'April', 105 | 'May', 106 | 'June', 107 | 'July', 108 | 'August', 109 | 'September', 110 | 'October', 111 | 'November', 112 | 'December' 113 | ]; 114 | 115 | return `${month[endTime.getUTCMonth()]} ${endTime.getUTCDate()}, ${endTime.getUTCFullYear()}` 116 | } 117 | 118 | /** 119 | * Notify server user about license expiration via configured notification transports. 120 | * @param {Context} ctx Context. 121 | * @param {Date} endDate Date of expiration. 122 | * @returns {undefined} 123 | */ 124 | async function notifyLicenseExpiration(ctx, endDate) { 125 | if (!endDate) { 126 | ctx.logger.warn('notifyLicenseExpiration(): expiration date is not defined'); 127 | return; 128 | } 129 | 130 | const currentDate = new Date(); 131 | if (currentDate.getTime() >= endDate.getTime() - cfgStartNotifyFrom) { 132 | //todo remove stub for "new Date(1)" and "setMonth + 1" in license.js; bug 70676 133 | if (endDate.getUTCFullYear() < 2000) { 134 | endDate = currentDate; 135 | } 136 | const formattedExpirationTime = humanFriendlyExpirationTime(endDate); 137 | const applicationName = (process.env.APPLICATION_NAME || "").toUpperCase(); 138 | if (endDate <= currentDate) { 139 | const tenNotificationRuleLicenseExpirationError = ctx.getCfg('notification.rules.licenseExpirationError.template', cfgNotificationRuleLicenseExpirationError); 140 | const title = util.format(tenNotificationRuleLicenseExpirationError.title, applicationName); 141 | const message = util.format(tenNotificationRuleLicenseExpirationError.body, formattedExpirationTime); 142 | ctx.logger.error(message); 143 | await notificationService.notify(ctx, notificationTypes.LICENSE_EXPIRATION_ERROR, title, message); 144 | } else { 145 | const tenNotificationRuleLicenseExpirationWarning = ctx.getCfg('notification.rules.licenseExpirationWarning.template', cfgNotificationRuleLicenseExpirationWarning); 146 | const title = util.format(tenNotificationRuleLicenseExpirationWarning.title, applicationName); 147 | const message = util.format(tenNotificationRuleLicenseExpirationWarning.body, formattedExpirationTime); 148 | ctx.logger.warn(message); 149 | await notificationService.notify(ctx, notificationTypes.LICENSE_EXPIRATION_WARNING, title, message); 150 | } 151 | } 152 | } 153 | 154 | module.exports.fixImageExifRotation = fixImageExifRotation; 155 | module.exports.convertImageToPng = convertImageToPng; 156 | module.exports.localeToLCID = localeToLCID; 157 | module.exports.notifyLicenseExpiration = notifyLicenseExpiration; 158 | -------------------------------------------------------------------------------- /FileConverter/npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fileconverter", 3 | "version": "1.0.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@expo/spawn-async": { 8 | "version": "1.7.2", 9 | "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.7.2.tgz", 10 | "integrity": "sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==", 11 | "requires": { 12 | "cross-spawn": "^7.0.3" 13 | } 14 | }, 15 | "bytes": { 16 | "version": "3.0.0", 17 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 18 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 19 | }, 20 | "co": { 21 | "version": "4.6.0", 22 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 23 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" 24 | }, 25 | "config": { 26 | "version": "2.0.1", 27 | "resolved": "https://registry.npmjs.org/config/-/config-2.0.1.tgz", 28 | "integrity": "sha512-aTaviJnC8ZjQYx8kQf4u6tWqIxWolyQQ3LqXgnCLAsIb78JrUshHG0YuzIarzTaVVe1Pazms3TXImfYra8UsyQ==", 29 | "requires": { 30 | "json5": "^1.0.1" 31 | } 32 | }, 33 | "cross-spawn": { 34 | "version": "7.0.6", 35 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 36 | "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 37 | "requires": { 38 | "path-key": "^3.1.0", 39 | "shebang-command": "^2.0.0", 40 | "which": "^2.0.1" 41 | } 42 | }, 43 | "invert-kv": { 44 | "version": "3.0.1", 45 | "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-3.0.1.tgz", 46 | "integrity": "sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==" 47 | }, 48 | "isexe": { 49 | "version": "2.0.0", 50 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 51 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" 52 | }, 53 | "json5": { 54 | "version": "1.0.2", 55 | "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", 56 | "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", 57 | "requires": { 58 | "minimist": "^1.2.0" 59 | } 60 | }, 61 | "lcid": { 62 | "version": "3.1.1", 63 | "resolved": "https://registry.npmjs.org/lcid/-/lcid-3.1.1.tgz", 64 | "integrity": "sha512-M6T051+5QCGLBQb8id3hdvIW8+zeFV2FyBGFS9IEK5H9Wt4MueD4bW1eWikpHgZp+5xR3l5c8pZUkQsIA0BFZg==", 65 | "requires": { 66 | "invert-kv": "^3.0.0" 67 | } 68 | }, 69 | "minimist": { 70 | "version": "1.2.7", 71 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", 72 | "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" 73 | }, 74 | "path-key": { 75 | "version": "3.1.1", 76 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 77 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" 78 | }, 79 | "shebang-command": { 80 | "version": "2.0.0", 81 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 82 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 83 | "requires": { 84 | "shebang-regex": "^3.0.0" 85 | } 86 | }, 87 | "shebang-regex": { 88 | "version": "3.0.0", 89 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 90 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" 91 | }, 92 | "which": { 93 | "version": "2.0.2", 94 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 95 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 96 | "requires": { 97 | "isexe": "^2.0.0" 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /FileConverter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fileconverter", 3 | "version": "1.0.1", 4 | "homepage": "https://www.onlyoffice.com", 5 | "private": true, 6 | "bin": "sources/convertermaster.js", 7 | "dependencies": { 8 | "@expo/spawn-async": "1.7.2", 9 | "bytes": "3.0.0", 10 | "co": "4.6.0", 11 | "config": "2.0.1", 12 | "lcid": "3.1.1" 13 | }, 14 | "pkg": { 15 | "scripts": [ 16 | "../Common/sources/storage-fs.js", 17 | "../Common/sources/storage-s3.js", 18 | "../DocService/sources/editorDataMemory.js", 19 | "../DocService/sources/editorDataRedis.js" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FileConverter/sources/convertermaster.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | const cluster = require('cluster'); 36 | const logger = require('./../../Common/sources/logger'); 37 | const operationContext = require('./../../Common/sources/operationContext'); 38 | 39 | if (cluster.isMaster) { 40 | const fs = require('fs'); 41 | const co = require('co'); 42 | const os = require('os'); 43 | const config = require('config'); 44 | const license = require('./../../Common/sources/license'); 45 | 46 | const cfgLicenseFile = config.get('license.license_file'); 47 | const cfgMaxProcessCount = config.get('FileConverter.converter.maxprocesscount'); 48 | 49 | var workersCount = 0; 50 | const readLicense = async function () { 51 | const numCPUs = os.cpus().length; 52 | const availableParallelism = os.availableParallelism?.(); 53 | operationContext.global.logger.warn('num of CPUs: %d; availableParallelism: %s', numCPUs, availableParallelism); 54 | workersCount = Math.ceil((availableParallelism || numCPUs) * cfgMaxProcessCount); 55 | let [licenseInfo] = await license.readLicense(cfgLicenseFile); 56 | workersCount = Math.min(licenseInfo.count, workersCount); 57 | //todo send license to workers for multi-tenancy 58 | }; 59 | const updateWorkers = () => { 60 | var i; 61 | const arrKeyWorkers = Object.keys(cluster.workers); 62 | if (arrKeyWorkers.length < workersCount) { 63 | for (i = arrKeyWorkers.length; i < workersCount; ++i) { 64 | const newWorker = cluster.fork(); 65 | operationContext.global.logger.warn('worker %s started.', newWorker.process.pid); 66 | } 67 | } else { 68 | for (i = workersCount; i < arrKeyWorkers.length; ++i) { 69 | const killWorker = cluster.workers[arrKeyWorkers[i]]; 70 | if (killWorker) { 71 | killWorker.kill(); 72 | } 73 | } 74 | } 75 | }; 76 | const updateLicense = async () => { 77 | try { 78 | await readLicense(); 79 | operationContext.global.logger.warn('update cluster with %s workers', workersCount); 80 | updateWorkers(); 81 | } catch (err) { 82 | operationContext.global.logger.error('updateLicense error: %s', err.stack); 83 | } 84 | }; 85 | 86 | cluster.on('exit', (worker, code, signal) => { 87 | operationContext.global.logger.warn('worker %s died (code = %s; signal = %s).', worker.process.pid, code, signal); 88 | updateWorkers(); 89 | }); 90 | 91 | updateLicense(); 92 | 93 | fs.watchFile(cfgLicenseFile, updateLicense); 94 | setInterval(updateLicense, 86400000); 95 | } else { 96 | const converter = require('./converter'); 97 | converter.run(); 98 | } 99 | 100 | process.on('uncaughtException', (err) => { 101 | operationContext.global.logger.error((new Date).toUTCString() + ' uncaughtException:', err.message); 102 | operationContext.global.logger.error(err.stack); 103 | logger.shutdown(() => { 104 | process.exit(1); 105 | }); 106 | }); 107 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | const path = require('path'); 33 | const _ = require('lodash'); 34 | var packageFile = require('./package.json'); 35 | 36 | module.exports = function (grunt) { 37 | 38 | let addons = grunt.option('addon') || []; 39 | if (!Array.isArray(addons)) 40 | addons = [addons]; 41 | 42 | addons.forEach((element,index,self) => self[index] = path.join('..', element)); 43 | addons = addons.filter(element => grunt.file.isDir(element)); 44 | 45 | function _merge(target, ...sources) { 46 | if (!sources.length) return target; 47 | const source = sources.shift(); 48 | 49 | for (const key in source) { 50 | if (_.isObject(source[key])) { 51 | if (_.isArray(source[key])) { 52 | if (!_.isArray(target[key])){ 53 | target[key]=[]; 54 | } 55 | target[key].push(...source[key]) 56 | } 57 | else { 58 | if (!target[key]) { 59 | Object.assign(target, { [key]: {} }); 60 | } 61 | _merge(target[key], source[key]); 62 | } 63 | } 64 | else { 65 | Object.assign(target, { [key]: source[key] }); 66 | } 67 | } 68 | } 69 | addons.forEach(element => { 70 | let _path = path.join(element, 'package.json'); 71 | if (grunt.file.exists(_path)) { 72 | _merge(packageFile, require(_path)); 73 | grunt.log.ok('addon '.green + element + ' is merged successfully'.green); 74 | } 75 | }); 76 | 77 | //grunt.file.write("package-test.json", JSON.stringify(packageFile, null, 4)); 78 | 79 | var checkDependencies = {}; 80 | 81 | for(var i of packageFile.npm) { 82 | checkDependencies[i] = { 83 | options: { 84 | install: true, 85 | continueAfterInstall: true, 86 | packageDir: i 87 | } 88 | } 89 | } 90 | 91 | grunt.initConfig({ 92 | clean: packageFile.grunt.clean, 93 | mkdir: packageFile.grunt.mkdir, 94 | copy: packageFile.grunt.copy, 95 | comments: { 96 | js: { 97 | options: { 98 | singleline: true, 99 | multiline: true 100 | }, 101 | src: packageFile.postprocess.src 102 | } 103 | }, 104 | usebanner: { 105 | copyright: { 106 | options: { 107 | position: 'top', 108 | banner: '/*\n' + 109 | ' * Copyright (C) ' + process.env['PUBLISHER_NAME'] + ' 2012-<%= grunt.template.today("yyyy") %>. All rights reserved\n' + 110 | ' *\n' + 111 | ' * ' + process.env['PUBLISHER_URL'] + ' \n' + 112 | ' *\n' + 113 | ' * Version: ' + process.env['PRODUCT_VERSION'] + ' (build:' + process.env['BUILD_NUMBER'] + ')\n' + 114 | ' */\n', 115 | linebreak: false 116 | }, 117 | files: { 118 | src: packageFile.postprocess.src 119 | } 120 | } 121 | }, 122 | checkDependencies: checkDependencies 123 | }); 124 | 125 | grunt.registerTask('build-develop', 'Build develop scripts', function () { 126 | grunt.initConfig({ 127 | copy: packageFile.grunt["develop-copy"] 128 | }); 129 | }); 130 | 131 | grunt.loadNpmTasks('grunt-contrib-clean'); 132 | grunt.loadNpmTasks('grunt-contrib-copy'); 133 | grunt.loadNpmTasks('grunt-mkdir'); 134 | grunt.loadNpmTasks('grunt-stripcomments'); 135 | grunt.loadNpmTasks('grunt-banner'); 136 | grunt.loadNpmTasks('grunt-check-dependencies'); 137 | 138 | grunt.registerTask('default', ['clean', 'mkdir', 'copy', 'comments', 'usebanner', 'checkDependencies']); 139 | grunt.registerTask('develop', ['build-develop', 'copy']); 140 | }; 141 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GRUNT = grunt 2 | GRUNT_FLAGS = --no-color -v 3 | 4 | GRUNT_FILES = Gruntfile.js.out 5 | 6 | PRODUCT_VERSION ?= 0.0.0 7 | BUILD_NUMBER ?= 0 8 | 9 | PUBLISHER_NAME ?= Ascensio System SIA 10 | PUBLISHER_URL ?= https://www.onlyoffice.com/ 11 | 12 | GRUNT_ENV += PRODUCT_VERSION=$(PRODUCT_VERSION) 13 | GRUNT_ENV += BUILD_NUMBER=$(BUILD_NUMBER) 14 | GRUNT_ENV += PUBLISHER_NAME="$(PUBLISHER_NAME)" 15 | GRUNT_ENV += PUBLISHER_URL="$(PUBLISHER_URL)" 16 | 17 | BRANDING_DIR ?= ./branding 18 | 19 | DOCUMENT_ROOT ?= /var/www/onlyoffice/documentserver 20 | 21 | ifeq ($(OS),Windows_NT) 22 | PLATFORM := win 23 | EXEC_EXT := .exe 24 | SHARED_EXT := .dll 25 | ifeq ($(PROCESSOR_ARCHITECTURE),AMD64) 26 | ARCHITECTURE := 64 27 | endif 28 | ifeq ($(PROCESSOR_ARCHITECTURE),x86) 29 | ARCHITECTURE := 32 30 | endif 31 | else 32 | UNAME_S := $(shell uname -s) 33 | ifeq ($(UNAME_S),Linux) 34 | PLATFORM := linux 35 | SHARED_EXT := .so* 36 | LIB_PREFIX := lib 37 | endif 38 | UNAME_M := $(shell uname -m) 39 | ifeq ($(UNAME_M),x86_64) 40 | ARCHITECTURE := 64 41 | endif 42 | ifneq ($(filter %86,$(UNAME_M)),) 43 | ARCHITECTURE := 32 44 | endif 45 | endif 46 | 47 | TARGET := $(PLATFORM)_$(ARCHITECTURE) 48 | 49 | OUTPUT = ../build_tools/out/$(TARGET)/onlyoffice/documentserver/server 50 | 51 | SPELLCHECKER_DICTIONARIES := $(OUTPUT)/../dictionaries 52 | SPELLCHECKER_DICTIONARY_FILES += ../dictionaries/*_* 53 | 54 | SCHEMA_DIR = schema 55 | SCHEMA_FILES = $(SCHEMA_DIR)/** 56 | SCHEMA = $(OUTPUT)/$(SCHEMA_DIR)/ 57 | 58 | TOOLS_DIR = tools 59 | TOOLS_FILES += ../core/build/bin/$(TARGET)/allfontsgen$(EXEC_EXT) 60 | TOOLS_FILES += ../core/build/bin/$(TARGET)/allthemesgen$(EXEC_EXT) 61 | TOOLS = $(OUTPUT)/$(TOOLS_DIR) 62 | 63 | LICENSE_FILES = LICENSE.txt 3rd-Party.txt license/ 64 | LICENSE = $(addsuffix $(OUTPUT)/, LICENSE_FILES) 65 | 66 | LICENSE_JS := $(OUTPUT)/Common/sources/license.js 67 | COMMON_DEFINES_JS := $(OUTPUT)/Common/sources/commondefines.js 68 | 69 | WELCOME_DIR = welcome 70 | WELCOME_FILES = $(BRANDING_DIR)/$(WELCOME_DIR)/** 71 | WELCOME = $(OUTPUT)/$(WELCOME_DIR)/ 72 | 73 | INFO_DIR = info 74 | INFO_FILES = $(BRANDING_DIR)/$(INFO_DIR)/** 75 | INFO = $(OUTPUT)/$(INFO_DIR)/ 76 | 77 | CORE_FONTS_DIR = core-fonts 78 | CORE_FONTS_FILES = ../$(CORE_FONTS_DIR)/** 79 | CORE_FONTS = $(OUTPUT)/../$(CORE_FONTS_DIR)/ 80 | 81 | DOCUMENT_TEMPLATES_DIR = document-templates 82 | DOCUMENT_TEMPLATES_FILES = ../$(DOCUMENT_TEMPLATES_DIR)/** 83 | DOCUMENT_TEMPLATES = $(OUTPUT)/../$(DOCUMENT_TEMPLATES_DIR)/ 84 | 85 | DEBUG = $(BRANDING_DIR)/debug.js 86 | 87 | .PHONY: all clean install uninstall build-date 88 | 89 | .NOTPARALLEL: 90 | all: $(SPELLCHECKER_DICTIONARIES) $(TOOLS) $(SCHEMA) $(CORE_FONTS) $(DOCUMENT_TEMPLATES) $(LICENSE) $(WELCOME) $(INFO) build-date 91 | 92 | build-date: $(GRUNT_FILES) 93 | sed "s|\(const buildVersion = \).*|\1'${PRODUCT_VERSION}';|" -i $(COMMON_DEFINES_JS) 94 | sed "s|\(const buildNumber = \).*|\1${BUILD_NUMBER};|" -i $(COMMON_DEFINES_JS) 95 | sed "s|\(const buildDate = \).*|\1'$$(date +%F)';|" -i $(LICENSE_JS) 96 | test -e $(DEBUG) && \ 97 | cp $(DEBUG) $(OUTPUT)/Common/sources || true 98 | 99 | $(SPELLCHECKER_DICTIONARIES): $(GRUNT_FILES) 100 | mkdir -p $(SPELLCHECKER_DICTIONARIES) && \ 101 | cp -r -t $(SPELLCHECKER_DICTIONARIES) $(SPELLCHECKER_DICTIONARY_FILES) 102 | 103 | $(SCHEMA): 104 | mkdir -p $(SCHEMA) && \ 105 | cp -r -t $(SCHEMA) $(SCHEMA_FILES) 106 | 107 | $(TOOLS): 108 | mkdir -p $(TOOLS) && \ 109 | cp -r -t $(TOOLS) $(TOOLS_FILES) 110 | 111 | $(LICENSE): 112 | mkdir -p $(OUTPUT) && \ 113 | cp -r -t $(OUTPUT) $(LICENSE_FILES) 114 | 115 | $(GRUNT_FILES): 116 | cd $(@D) && \ 117 | npm install && \ 118 | $(GRUNT_ENV) $(GRUNT) $(GRUNT_FLAGS) 119 | mkdir -p $(OUTPUT) 120 | cp -r -t $(OUTPUT) ./build/server/* 121 | echo "Done" > $@ 122 | 123 | $(WELCOME): 124 | mkdir -p $(WELCOME) && \ 125 | cp -r -t $(WELCOME) $(WELCOME_FILES) 126 | 127 | $(INFO): 128 | mkdir -p $(INFO) && \ 129 | cp -r -t $(INFO) $(INFO_FILES) 130 | 131 | $(CORE_FONTS): 132 | mkdir -p $(CORE_FONTS) && \ 133 | cp -r -t $(CORE_FONTS) $(CORE_FONTS_FILES) 134 | 135 | $(DOCUMENT_TEMPLATES): 136 | mkdir -p $(DOCUMENT_TEMPLATES) && \ 137 | cp -r -t $(DOCUMENT_TEMPLATES) $(DOCUMENT_TEMPLATES_FILES) 138 | 139 | clean: 140 | rm -rf $(GRUNT_FILES) 141 | 142 | install: 143 | mkdir -pv ${DESTDIR}/var/www/onlyoffice 144 | if ! id -u onlyoffice > /dev/null 2>&1; then useradd -m -d /var/www/onlyoffice -r -U onlyoffice; fi 145 | 146 | mkdir -p ${DESTDIR}${DOCUMENT_ROOT}/fonts 147 | mkdir -p ${DESTDIR}/var/log/onlyoffice/documentserver 148 | mkdir -p ${DESTDIR}/var/lib/onlyoffice/documentserver/App_Data 149 | 150 | cp -fr -t ${DESTDIR}${DOCUMENT_ROOT} build/* ../web-apps/deploy/* 151 | mkdir -p ${DESTDIR}/etc/onlyoffice/documentserver 152 | mv ${DESTDIR}${DOCUMENT_ROOT}/server/Common/config/* ${DESTDIR}/etc/onlyoffice/documentserver 153 | 154 | chown onlyoffice:onlyoffice -R ${DESTDIR}/var/www/onlyoffice 155 | chown onlyoffice:onlyoffice -R ${DESTDIR}/var/log/onlyoffice 156 | chown onlyoffice:onlyoffice -R ${DESTDIR}/var/lib/onlyoffice 157 | 158 | # Make symlinks for shared libs 159 | find \ 160 | ${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin \ 161 | -maxdepth 1 \ 162 | -name *$(SHARED_EXT) \ 163 | -exec sh -c 'ln -sf {} ${DESTDIR}/lib/$$(basename {})' \; 164 | 165 | sudo -u onlyoffice "${DESTDIR}${DOCUMENT_ROOT}/server/tools/allfontsgen"\ 166 | --input="${DESTDIR}${DOCUMENT_ROOT}/core-fonts"\ 167 | --allfonts-web="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/common/AllFonts.js"\ 168 | --allfonts="${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin/AllFonts.js"\ 169 | --images="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/common/Images"\ 170 | --selection="${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin/font_selection.bin"\ 171 | --output-web="${DESTDIR}${DOCUMENT_ROOT}/fonts"\ 172 | --use-system="true" 173 | 174 | sudo -u onlyoffice "${DESTDIR}${DOCUMENT_ROOT}/server/tools/allthemesgen"\ 175 | --converter-dir="${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin"\ 176 | --src="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/slide/themes"\ 177 | --output="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/common/Images" 178 | 179 | uninstall: 180 | userdel onlyoffice 181 | 182 | # Unlink installed shared libs 183 | find /lib -type l | while IFS= read -r lnk; do if (readlink "$$lnk" | grep -q '^${DOCUMENT_ROOT}/server/FileConverter/bin/'); then rm "$$lnk"; fi; done 184 | 185 | rm -rf /var/www/onlyoffice/documentserver 186 | rm -rf /var/log/onlyoffice/documentserver 187 | rm -rf /var/lib/onlyoffice/documentserver 188 | rm -rf /etc/onlyoffice/documentserver 189 | -------------------------------------------------------------------------------- /Metrics/npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "metrics", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "commander": { 8 | "version": "1.3.1", 9 | "resolved": "https://registry.npmjs.org/commander/-/commander-1.3.1.tgz", 10 | "integrity": "sha1-AkQ+AtuW9LMrZ0IlRRq7bpUQAA4=", 11 | "optional": true, 12 | "requires": { 13 | "keypress": "0.1.x" 14 | } 15 | }, 16 | "connection-parse": { 17 | "version": "0.0.7", 18 | "resolved": "https://registry.npmjs.org/connection-parse/-/connection-parse-0.0.7.tgz", 19 | "integrity": "sha1-GOcxiqsGppkmc3KxDFIm0locmmk=", 20 | "optional": true 21 | }, 22 | "generic-pool": { 23 | "version": "2.2.0", 24 | "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-2.2.0.tgz", 25 | "integrity": "sha1-i0ZcGnWI6p3SuxM72gu2a/74pj4=" 26 | }, 27 | "hashring": { 28 | "version": "3.2.0", 29 | "resolved": "https://registry.npmjs.org/hashring/-/hashring-3.2.0.tgz", 30 | "integrity": "sha1-/aTv3oqiLNuX+x0qZeiEAeHBRM4=", 31 | "optional": true, 32 | "requires": { 33 | "connection-parse": "0.0.x", 34 | "simple-lru-cache": "0.0.x" 35 | } 36 | }, 37 | "keypress": { 38 | "version": "0.1.0", 39 | "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz", 40 | "integrity": "sha1-SjGI1CkbZrT2XtuZ+AaqmuKTWSo=", 41 | "optional": true 42 | }, 43 | "modern-syslog": { 44 | "version": "1.2.0", 45 | "resolved": "https://registry.npmjs.org/modern-syslog/-/modern-syslog-1.2.0.tgz", 46 | "integrity": "sha512-dmFE23qpyZJf8MOdzuNKliW4j1PCqxaRtSzyNnv6QDUWjf1z8T4ZoQ7Qf0t6It2ewNv9/XJZSJoUgwpq3D0X7A==", 47 | "optional": true, 48 | "requires": { 49 | "nan": "^2.13.2" 50 | } 51 | }, 52 | "nan": { 53 | "version": "2.14.0", 54 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", 55 | "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", 56 | "optional": true 57 | }, 58 | "sequence": { 59 | "version": "2.2.1", 60 | "resolved": "https://registry.npmjs.org/sequence/-/sequence-2.2.1.tgz", 61 | "integrity": "sha1-f1YXiV1ENRwKBH52RGdpBJChawM=", 62 | "optional": true 63 | }, 64 | "simple-lru-cache": { 65 | "version": "0.0.2", 66 | "resolved": "https://registry.npmjs.org/simple-lru-cache/-/simple-lru-cache-0.0.2.tgz", 67 | "integrity": "sha1-1ZzDoZPBpdAyD4Tucy9uRxPlEd0=", 68 | "optional": true 69 | }, 70 | "statsd": { 71 | "version": "0.8.4", 72 | "resolved": "https://registry.npmjs.org/statsd/-/statsd-0.8.4.tgz", 73 | "integrity": "sha512-GLxev8J5AtlQILyT2/ofRVgGIbMMu2dMBwcQaEg3BIPZwQQlIG48OYjVyjxo7yI/1AKur97LnJKvjELV6Elx+A==", 74 | "requires": { 75 | "generic-pool": "2.2.0", 76 | "hashring": "3.2.0", 77 | "modern-syslog": "1.2.0", 78 | "winser": "=0.1.6" 79 | } 80 | }, 81 | "winser": { 82 | "version": "0.1.6", 83 | "resolved": "https://registry.npmjs.org/winser/-/winser-0.1.6.tgz", 84 | "integrity": "sha1-CGY9wyh4oSu84WLYQNpQl7SEZsk=", 85 | "optional": true, 86 | "requires": { 87 | "commander": "1.3.1", 88 | "sequence": "2.2.1" 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Metrics/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "metrics", 3 | "version": "1.0.0", 4 | "homepage": "https://www.onlyoffice.com", 5 | "private": true, 6 | "bin": "node_modules/statsd/bin/statsd", 7 | "dependencies": { 8 | "statsd": "0.8.4" 9 | }, 10 | "pkg": { 11 | "scripts": [ 12 | "node_modules/statsd/backends/console.js", 13 | "node_modules/statsd/backends/graphite.js", 14 | "node_modules/statsd/backends/repeater.js", 15 | "node_modules/statsd/servers/tcp.js", 16 | "node_modules/statsd/servers/udp.js" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # Server 3 | 4 | [![License](https://img.shields.io/badge/License-GNU%20AGPL%20V3-green.svg?style=flat)](https://www.gnu.org/licenses/agpl-3.0.en.html) 5 | 6 | The backend server software layer which is the part of [ONLYOFFICE Document Server][2] and is the base for all other components. 7 | 8 | ## Document service set up 9 | 10 | This instruction describes document service deployment for Windows based platform. 11 | 12 | ### Installing necessary components 13 | 14 | For the document service to work correctly it is necessary to install the following components for your Windows system (if not specified additionally, the latest version for 32 or 64 bit Windows can be installed with default settings): 15 | 16 | 1. [Node.js](https://nodejs.org/en/download/) version 8.0.0 or later 17 | 18 | 2. [Java](https://java.com/en/download/). Necessary for the sdk build. 19 | 20 | 3. Database (MySQL or PostgreSQL). When installing use the `onlyoffice` password for the `root` user. 21 | * [MySQL Server](http://dev.mysql.com/downloads/windows/installer/) version 5.5 or later 22 | 23 | * [PostgreSQL Server](https://www.postgresql.org/download/) version 9.1 or later 24 | 25 | 4. [Erlang](https://www.erlang.org/download.html) 26 | 27 | 5. [RabbitMQ](https://www.rabbitmq.com/releases/rabbitmq-server/v3.5.4/rabbitmq-server-3.5.4.exe) 28 | 29 | 6. [Redis](https://github.com/microsoftarchive/redis/releases/latest) 30 | 31 | 7. [Python 2.7](https://www.python.org/downloads/release/python-2716/) 32 | 33 | 8. Microsoft Visual C++ Express 2010 (necessary for the spellchecker modules build) 34 | 35 | ### Setting up the system 36 | 37 | 1. Database setup: 38 | 39 | * Database setup for MySQL 40 | Run the `schema/mysql/createdb.sql` script for MySQL 41 | 42 | * Database setup for PostgreSQL 43 | 1. Enter in `psql` (PostgreSQL interactive terminal) with 44 | login and password introduced during installation, then enter commands: 45 | 46 | ```sql 47 | CREATE USER onlyoffice WITH PASSWORD 'onlyoffice'; 48 | CREATE DATABASE onlyoffice OWNER onlyoffice; 49 | \c onlyoffice 50 | \i 'schema/postgresql/createdb.sql'; 51 | ``` 52 | 53 | 2. Delete from `server\Common\config\development-windows.json` option `sql`. 54 | 55 | 2. Install the Web Monitor for RabbitMQ (see the details for the installation [here](https://www.rabbitmq.com/management.html)) 56 | 3. Open the command line `cmd` executable. 57 | 4. Switch to the installation directory using the `cd /d Installation-directory/sbin` command. 58 | 5. Run the following command: 59 | 60 | ```powershell 61 | rabbitmq-plugins.bat enable rabbitmq_management 62 | ``` 63 | 64 | 6. The Web Monitor is located at the [http://localhost:15672/](http://localhost:15672/) address. 65 | Use the `guest:guest` for the login:password combination. 66 | 67 | 7. If Redis does not start or crashes after the start for some reason, 68 | try to change the `maxheap` parameter in the config settings. 69 | For 64 bit version of Windows 7 the config file can be found here: 70 | `C:\Program Files\Redis\redis.windows-service.conf`. 71 | Find the `# maxheap ` line and change it to, e.g. 72 | 73 | ```config 74 | maxheap 128MB 75 | ``` 76 | 77 | and restart the service 78 | 79 | ### Running the service 80 | 81 | Run the `run.bat` script to start the service. 82 | 83 | Notes 84 | 85 | All config files for the server part can be found in the `Common\config` folder 86 | 87 | * `default.json` - common config files similar for all production versions. 88 | * `production-windows.json` - config files for the production version running on a Windows based platform. 89 | * `production-linux.json` - config files for the production version running on a Linux based platform. 90 | * `development-windows.json` - config files for the development version running on a Windows based platform (this configuration is used when running the 'run.bat' script). 91 | 92 | In case it is necessary to temporarily edit the config files, create the local.json file and reassign the values there. It will allow to prevent from uploading local changes and losing config files when updating the repository. See [Configuration Files](https://github.com/lorenwest/node-config/wiki/Configuration-Files) for more information about the configuration files. 93 | 94 | ## User Feedback and Support 95 | 96 | If you have any problems with or questions about [ONLYOFFICE Document Server][2], please visit our official forum to find answers to your questions: [forum.onlyoffice.com][1] or you can ask and answer ONLYOFFICE development questions on [Stack Overflow][3]. 97 | 98 | [1]: https://forum.onlyoffice.com 99 | [2]: https://github.com/ONLYOFFICE/DocumentServer 100 | [3]: https://stackoverflow.com/questions/tagged/onlyoffice 101 | 102 | ## License 103 | 104 | Server is released under an GNU AGPL v3.0 license. See the LICENSE file for more information. 105 | -------------------------------------------------------------------------------- /SpellChecker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spellchecker", 3 | "version": "1.0.1", 4 | "homepage": "https://www.onlyoffice.com", 5 | "private": true, 6 | "bin": "sources/server.js", 7 | "dependencies": { 8 | "co": "4.6.0", 9 | "config": "2.0.1", 10 | "express": "4.19.2", 11 | "nodehun": "git+https://git@github.com/ONLYOFFICE/nodehun.git#2411a56828c7d58214c61781b4a5c63d18adba99", 12 | "sockjs": "0.3.21" 13 | }, 14 | "pkg": { 15 | "assets": [ 16 | "dictionaries/**/*" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SpellChecker/sources/server.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | const cluster = require('cluster'); 36 | const config = require('config').get('SpellChecker'); 37 | 38 | //process.env.NODE_ENV = config.get('server.mode'); 39 | 40 | const logger = require('./../../Common/sources/logger'); 41 | 42 | const c_nCheckHealth = 60000, c_sCheckWord = 'color', c_sCheckLang = 1033; 43 | let idCheckInterval, canStartCheck = true; 44 | let statusCheckHealth = true; 45 | function checkHealth (worker) { 46 | logger.info('checkHealth'); 47 | if (!statusCheckHealth) { 48 | logger.error('error check health, restart!'); 49 | worker.kill(); 50 | return; 51 | } 52 | worker.send({type: 'spell'}); 53 | statusCheckHealth = false; 54 | } 55 | function endCheckHealth (msg) { 56 | logger.info('endCheckHealth'); 57 | statusCheckHealth = true; 58 | } 59 | 60 | const workersCount = 1; // ToDo So far, we will use only 1 process. But in the future it is worth considering a few. 61 | if (cluster.isMaster) { 62 | logger.warn('start cluster with %s workers', workersCount); 63 | cluster.on('listening', function(worker) { 64 | if (canStartCheck) { 65 | canStartCheck = false; 66 | idCheckInterval = setInterval(function(){checkHealth(worker);}, c_nCheckHealth); 67 | worker.on('message', function(msg){endCheckHealth(msg);}); 68 | } 69 | }); 70 | for (let nIndexWorker = 0; nIndexWorker < workersCount; ++nIndexWorker) { 71 | logger.warn('worker %s started.', cluster.fork().process.pid); 72 | } 73 | 74 | cluster.on('exit', (worker, code, signal) => { 75 | logger.warn('worker %s died (code = %s; signal = %s). restart...', worker.process.pid, code, signal); 76 | clearInterval(idCheckInterval); 77 | endCheckHealth(); 78 | canStartCheck = true; 79 | cluster.fork(); 80 | }); 81 | } else { 82 | const express = require('express'), 83 | http = require('http'), 84 | https = require('https'), 85 | fs = require("fs"), 86 | app = express(), 87 | spellCheck = require('./spellCheck'); 88 | let server = null; 89 | 90 | 91 | logger.warn('Express server starting...'); 92 | 93 | if (config.has('ssl')) { 94 | const privateKey = fs.readFileSync(config.get('ssl.key')).toString(); 95 | const certificateKey = fs.readFileSync(config.get('ssl.cert')).toString(); 96 | const trustedCertificate = fs.readFileSync(config.get('ssl.ca')).toString(); 97 | //See detailed options format here: http://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener 98 | const options = {key: privateKey, cert: certificateKey, ca: [trustedCertificate]}; 99 | 100 | server = https.createServer(options, app); 101 | } else { 102 | server = http.createServer(app); 103 | } 104 | 105 | // If you want to use 'development' and 'production', 106 | // then with app.settings.env (https://github.com/strongloop/express/issues/936) 107 | // If error handling is needed, now it's like this https://github.com/expressjs/errorhandler spellCheck.install(server, function(){ 108 | server.listen(config.get('server.port'), function(){ 109 | logger.warn("Express server listening on port %d in %s mode", config.get('server.port'), app.settings.env); 110 | }); 111 | 112 | app.get('/index.html', function(req, res) { 113 | res.send('Server is functioning normally'); 114 | }); 115 | }); 116 | 117 | process.on('message', function(msg) { 118 | if (!spellCheck) 119 | return; 120 | spellCheck.spellSuggest(msg.type, c_sCheckWord, c_sCheckLang, function(res) { 121 | process.send({type: msg.type, res: res}); 122 | }); 123 | }); 124 | 125 | process.on('uncaughtException', function(err) { 126 | logger.error((new Date).toUTCString() + ' uncaughtException:', err.message); 127 | logger.error(err.stack); 128 | logger.shutdown(function () { 129 | process.exit(1); 130 | }); 131 | }); 132 | } 133 | -------------------------------------------------------------------------------- /SpellChecker/sources/spellCheck.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | const sockjs = require('sockjs'); 36 | const nodehun = require('nodehun'); 37 | const logger = require('./../../Common/sources/logger'); 38 | const utils = require('./../../Common/sources/utils'); 39 | const fs = require('fs'); 40 | const co = require('co'); 41 | const cfgSockjs = require('config').get('services.CoAuthoring.sockjs'); 42 | const languages = require('./languages'); 43 | const allLanguages = languages.allLanguages; 44 | const path = require('path'); 45 | const arrExistDictionaries = {}; 46 | const pathDictionaries = require('config').get('SpellChecker.server.dictDir'); 47 | const arrDictionaries = {}; 48 | 49 | function spell(type, word, id) { 50 | return new Promise(function(resolve, reject) { 51 | let dict = null; 52 | if (arrDictionaries[id]) { 53 | dict = arrDictionaries[id]; 54 | } else { 55 | if (arrExistDictionaries[id]) { 56 | let pathTmp = path.join(pathDictionaries, allLanguages[id], allLanguages[id] + '.'); 57 | 58 | dict = arrDictionaries[id] = new nodehun(pathTmp + 'aff', pathTmp + 'dic'); 59 | } 60 | } 61 | 62 | if (dict) { 63 | if ("spell" === type) { 64 | // use setImmediate because https://github.com/nodejs/node/issues/5691 65 | dict.spell(word) 66 | .then(isCorrect => { 67 | return setImmediate(resolve, isCorrect); 68 | }); 69 | } else if ("suggest" === type) { 70 | dict.suggest(word) 71 | .then(suggestions => { 72 | return setImmediate(resolve, suggestions); 73 | }); 74 | } 75 | } else { 76 | return setImmediate(resolve, true); 77 | } 78 | }); 79 | } 80 | 81 | exports.install = function (server, callbackFunction) { 82 | 'use strict'; 83 | 84 | utils.listFolders(pathDictionaries, true).then((values) => { 85 | return co(function*() { 86 | let lang; 87 | for (let i = 0; i < values.length; ++i) { 88 | lang = languages.sToId(path.basename(values[i])); 89 | if (-1 !== lang) { 90 | arrExistDictionaries[lang] = 1; 91 | } 92 | } 93 | yield spell('spell', 'color', 0x0409); 94 | callbackFunction(); 95 | }); 96 | }); 97 | 98 | const sockjs_echo = sockjs.createServer(cfgSockjs); 99 | 100 | sockjs_echo.on('connection', function (conn) { 101 | if (!conn) { 102 | logger.error ("null == conn"); 103 | return; 104 | } 105 | conn.on('data', function (message) { 106 | try { 107 | let data = JSON.parse(message); 108 | switch (data.type) { 109 | case 'spellCheck': spellCheck(conn, data.spellCheckData);break; 110 | } 111 | } catch (e) { 112 | logger.error("error receiving response: %s", e); 113 | } 114 | }); 115 | conn.on('error', function () { 116 | logger.error("On error"); 117 | }); 118 | conn.on('close', function () { 119 | logger.info("Connection closed or timed out"); 120 | }); 121 | 122 | sendData(conn, {type: 'init', languages: Object.keys(arrExistDictionaries)}); 123 | }); 124 | 125 | function sendData(conn, data) { 126 | conn.write(JSON.stringify(data)); 127 | } 128 | 129 | function spellCheck(conn, data) { 130 | return co(function*() { 131 | let promises = []; 132 | for (let i = 0, length = data.usrWords.length; i < length; ++i) { 133 | promises.push(spell(data.type, data.usrWords[i], data.usrLang[i])); 134 | } 135 | yield Promise.all(promises).then(values => { 136 | data[('spell' === data.type ? 'usrCorrect' : 'usrSuggest')] = values; 137 | }); 138 | sendData(conn, {type: 'spellCheck', spellCheckData: data}); 139 | }); 140 | } 141 | 142 | sockjs_echo.installHandlers(server, {prefix:'/doc/[0-9-.a-zA-Z_=]*/c', log:function (severity, message) { 143 | //TODO: handle severity 144 | logger.info(message); 145 | }}); 146 | }; 147 | exports.spellSuggest = function (type, word, lang, callbackFunction) { 148 | return co(function*() { 149 | callbackFunction(yield spell(type, word, lang)); 150 | }); 151 | }; 152 | -------------------------------------------------------------------------------- /branding/info/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ONLYOFFICE/server/4933ff7a1aed0c999a621b8bee2e154a8a914930/branding/info/img/favicon.ico -------------------------------------------------------------------------------- /branding/info/img/icon-cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ONLYOFFICE/server/4933ff7a1aed0c999a621b8bee2e154a8a914930/branding/info/img/icon-cross.png -------------------------------------------------------------------------------- /branding/info/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ONLYOFFICE/server/4933ff7a1aed0c999a621b8bee2e154a8a914930/branding/info/img/logo.png -------------------------------------------------------------------------------- /branding/welcome/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ONLYOFFICE/server/4933ff7a1aed0c999a621b8bee2e154a8a914930/branding/welcome/img/favicon.ico -------------------------------------------------------------------------------- /branding/welcome/img/icon-cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ONLYOFFICE/server/4933ff7a1aed0c999a621b8bee2e154a8a914930/branding/welcome/img/icon-cross.png -------------------------------------------------------------------------------- /branding/welcome/img/icon-done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ONLYOFFICE/server/4933ff7a1aed0c999a621b8bee2e154a8a914930/branding/welcome/img/icon-done.png -------------------------------------------------------------------------------- /branding/welcome/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ONLYOFFICE™ 5 | 6 | 7 | 8 | 9 | 69 | 70 | 71 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /license/Backbone.license: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2013 Jeremy Ashkenas, DocumentCloud 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /license/Hunspell.license: -------------------------------------------------------------------------------- 1 | /* ***** BEGIN LICENSE BLOCK ***** 2 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 | * 4 | * The contents of this file are subject to the Mozilla Public License Version 5 | * 1.1 (the "License"); you may not use this file except in compliance with 6 | * the License. You may obtain a copy of the License at 7 | * http://www.mozilla.org/MPL/ 8 | * 9 | * Software distributed under the License is distributed on an "AS IS" basis, 10 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 | * for the specific language governing rights and limitations under the 12 | * License. 13 | * 14 | * The Original Code is Hunspell, based on MySpell. 15 | * 16 | * The Initial Developers of the Original Code are 17 | * Kevin Hendricks (MySpell) and Nemeth Laszlo (Hunspell). 18 | * Portions created by the Initial Developers are Copyright (C) 2002-2005 19 | * the Initial Developers. All Rights Reserved. 20 | * 21 | * Contributor(s): 22 | * David Einstein 23 | * Davide Prina 24 | * Giuseppe Modugno 25 | * Gianluca Turconi 26 | * Simon Brouwer 27 | * Noll Janos 28 | * Biro Arpad 29 | * Goldman Eleonora 30 | * Sarlos Tamas 31 | * Bencsath Boldizsar 32 | * Halacsy Peter 33 | * Dvornik Laszlo 34 | * Gefferth Andras 35 | * Nagy Viktor 36 | * Varga Daniel 37 | * Chris Halls 38 | * Rene Engelhard 39 | * Bram Moolenaar 40 | * Dafydd Jones 41 | * Harri Pitkanen 42 | * 43 | * Alternatively, the contents of this file may be used under the terms of 44 | * either the GNU General Public License Version 2 or later (the "GPL"), or 45 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 46 | * in which case the provisions of the GPL or the LGPL are applicable instead 47 | * of those above. If you wish to allow use of your version of this file only 48 | * under the terms of either the GPL or the LGPL, and not to allow others to 49 | * use your version of this file under the terms of the MPL, indicate your 50 | * decision by deleting the provisions above and replace them with the notice 51 | * and other provisions required by the GPL or the LGPL. If you do not delete 52 | * the provisions above, a recipient may use your version of this file under 53 | * the terms of any one of the MPL, the GPL or the LGPL. 54 | * 55 | * ***** END LICENSE BLOCK ***** */ 56 | -------------------------------------------------------------------------------- /license/Megapixel.license: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2012 Shinichi Tomita ; 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /license/NodeHun.license: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Nathan Sweet, DataSphere Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the 8 | Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 17 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 18 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /license/PerfectScrollbar.license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) Copyright (c) 2012, 2014 Hyeonje Alex Jun and other contributors. 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /license/RequireJS.license: -------------------------------------------------------------------------------- 1 | RequireJS is released under two licenses: new BSD, and MIT. You may pick the 2 | license that best suits your development needs. The text of both licenses are 3 | provided below. 4 | 5 | 6 | The "New" BSD License: 7 | ---------------------- 8 | 9 | Copyright (c) 2010-2013, The Dojo Foundation 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | * Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | * Neither the name of the Dojo Foundation nor the names of its contributors 21 | may be used to endorse or promote products derived from this software 22 | without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 25 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 28 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | 35 | 36 | 37 | MIT License 38 | ----------- 39 | 40 | Copyright (c) 2010-2013, The Dojo Foundation 41 | 42 | Permission is hereby granted, free of charge, to any person obtaining a copy 43 | of this software and associated documentation files (the "Software"), to deal 44 | in the Software without restriction, including without limitation the rights 45 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 46 | copies of the Software, and to permit persons to whom the Software is 47 | furnished to do so, subject to the following conditions: 48 | 49 | The above copyright notice and this permission notice shall be included in 50 | all copies or substantial portions of the Software. 51 | 52 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 53 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 54 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 55 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 56 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 57 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 58 | THE SOFTWARE. 59 | -------------------------------------------------------------------------------- /license/SocketIO.license: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2014-2018 Automattic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /license/Underscore.license: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative 2 | Reporters & Editors 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /license/XRegExp.license: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ONLYOFFICE/server/4933ff7a1aed0c999a621b8bee2e154a8a914930/license/XRegExp.license -------------------------------------------------------------------------------- /license/jQuery.browser.license: -------------------------------------------------------------------------------- 1 | Copyright 2013 jQuery Foundation and other contributors, http://jquery.com/ 2 | Modifications Copyright 2013 Gabriel Cebrian, https://www.github.com/gabceb 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /license/jQuery.license: -------------------------------------------------------------------------------- 1 | Copyright 2013 jQuery Foundation and other contributors 2 | http://jquery.com/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /license/requirejs-text.license: -------------------------------------------------------------------------------- 1 | Copyright jQuery Foundation and other contributors, https://jquery.org/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/requirejs/text 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | Copyright and related rights for sample code are waived via CC0. Sample 34 | code is defined as all source code displayed within the prose of the 35 | documentation. 36 | 37 | CC0: http://creativecommons.org/publicdomain/zero/1.0/ 38 | 39 | ==== 40 | 41 | Files located in the node_modules directory, and certain utilities used 42 | to build or test the software in the test and dist directories, are 43 | externally maintained libraries used by this software which have their own 44 | licenses; we recommend you read them, as their terms may differ from the 45 | terms above. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "builder", 3 | "version": "1.0.1", 4 | "homepage": "https://www.onlyoffice.com", 5 | "private": true, 6 | "grunt": { 7 | "copy": { 8 | "server": { 9 | "expand": true, 10 | "src": [ 11 | "./**/sources/*.js", 12 | "./Common/package.json", 13 | "./DocService/package.json", 14 | "./DocService/public/healthcheck.docx", 15 | "./FileConverter/package.json", 16 | "./FileConverter/bin/DoctRenderer.config", 17 | "./Metrics/package.json", 18 | "./Common/config/*.json", 19 | "./Common/config/log4js/*.json", 20 | "./Metrics/config/config.js" 21 | ], 22 | "dest": "./build/server" 23 | } 24 | }, 25 | "develop-copy": { 26 | "server": {} 27 | }, 28 | "clean": { 29 | "options": { 30 | "force": true 31 | }, 32 | "server": "./build/server" 33 | }, 34 | "mkdir": { 35 | "server": { 36 | "options": { 37 | "create": [ 38 | "./build/server" 39 | ] 40 | } 41 | } 42 | } 43 | }, 44 | "postprocess": { 45 | "src": [ 46 | "./build/server/**/sources/*.js" 47 | ], 48 | "dest": "./" 49 | }, 50 | "npm": [ 51 | "./build/server/Common", 52 | "./build/server/DocService", 53 | "./build/server/FileConverter", 54 | "./build/server/Metrics" 55 | ], 56 | "dependencies": { 57 | "grunt": "1.5.3", 58 | "grunt-banner": "0.6.0", 59 | "grunt-check-dependencies": "1.0.0", 60 | "grunt-contrib-clean": "2.0.0", 61 | "grunt-contrib-copy": "1.0.0", 62 | "grunt-mkdir": "1.1.0", 63 | "grunt-stripcomments": "0.7.2", 64 | "license-downloader": "1.0.8", 65 | "license-report": "6.5.0", 66 | "npm-run-all": "4.1.5" 67 | }, 68 | "devDependencies": { 69 | "@jest/globals": "29.5.0", 70 | "cross-env": "7.0.3", 71 | "jest": "29.5.0" 72 | }, 73 | "scripts": { 74 | "perf-expired": "cd ./DocService&& cross-env NODE_ENV=development-windows NODE_CONFIG_DIR=../Common/config node ../tests/perf/checkFileExpire.js", 75 | "perf-exif": "cd ./DocService&& cross-env NODE_ENV=development-windows NODE_CONFIG_DIR=../Common/config node ../tests/perf/fixImageExifRotation.js", 76 | "perf-png": "cd ./DocService&& cross-env NODE_ENV=development-windows NODE_CONFIG_DIR=../Common/config node ../tests/perf/convertImageToPng.js", 77 | "unit tests": "cd ./DocService && jest unit --inject-globals=false --config=../tests/jest.config.js", 78 | "integration tests with server instance": "cd ./DocService && jest integration/withServerInstance --inject-globals=false --config=../tests/jest.config.js", 79 | "integration database tests": "cd ./DocService && jest integration/databaseTests --inject-globals=false --config=../tests/jest.config.js", 80 | "tests": "cd ./DocService && jest --inject-globals=false --config=../tests/jest.config.js", 81 | "install:Common": "npm ci --prefix ./Common", 82 | "install:DocService": "npm ci --prefix ./DocService", 83 | "install:FileConverter": "npm ci --prefix ./FileConverter", 84 | "install:Metrics": "npm ci --prefix ./Metrics", 85 | "3d-party-lic-json:Common": "license-report --output=json --package=./Common/package.json --config ./3d-party-lic-report/license-report-config.json > ./3d-party-lic-report/license-report.json", 86 | "3d-party-lic-json:DocService": "license-report --output=json --package=./DocService/package.json --config ./3d-party-lic-report/license-report-config.json > ./3d-party-lic-report/license-report.json", 87 | "3d-party-lic-json:FileConverter": "license-report --output=json --package=./FileConverter/package.json --config ./3d-party-lic-report/license-report-config.json > ./3d-party-lic-report/license-report.json", 88 | "3d-party-lic-json:Metrics": "license-report --output=json --package=./Metrics/package.json --config ./3d-party-lic-report/license-report-config.json > ./3d-party-lic-report/license-report.json", 89 | "3d-party-lic-downloader": "license-downloader --source ./3d-party-lic-report/license-report.json", 90 | "3d-party-lic-md-header": "node ./3d-party-lic-report/json2md.js ./3DPARTY.md", 91 | "3d-party-lic-md": "node ./3d-party-lic-report/json2md.js ./3DPARTY.md ./3d-party-lic-report/license-report.ext.json", 92 | "3d-party-lic-report:Common": "run-s 3d-party-lic-json:Common 3d-party-lic-downloader 3d-party-lic-md", 93 | "3d-party-lic-report:DocService": "run-s 3d-party-lic-json:DocService 3d-party-lic-downloader 3d-party-lic-md", 94 | "3d-party-lic-report:FileConverter": "run-s 3d-party-lic-json:FileConverter 3d-party-lic-downloader 3d-party-lic-md", 95 | "3d-party-lic-report:Metrics": "run-s 3d-party-lic-json:Metrics 3d-party-lic-downloader 3d-party-lic-md", 96 | "3d-party-lic-report": "run-s 3d-party-lic-md-header 3d-party-lic-report:*", 97 | "build": "run-p install:*" 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /schema/dameng/createdb.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Create schema onlyoffice 3 | -- 4 | 5 | -- CREATE DATABASE onlyoffice ENCODING = 'UTF8' CONNECTION LIMIT = -1; 6 | 7 | -- ---------------------------- 8 | -- Table structure for doc_changes 9 | -- ---------------------------- 10 | CREATE TABLE doc_changes 11 | ( 12 | tenant varchar(255) NOT NULL, 13 | id varchar(255) NOT NULL, 14 | change_id int NOT NULL, 15 | user_id varchar(255) NOT NULL, 16 | user_id_original varchar(255) NOT NULL, 17 | user_name varchar(255) NOT NULL, 18 | change_data text NOT NULL, 19 | change_date TIMESTAMP(6) NOT NULL, 20 | PRIMARY KEY (tenant, id, change_id) 21 | ); 22 | 23 | -- ---------------------------- 24 | -- Table structure for task_result 25 | -- ---------------------------- 26 | CREATE TABLE task_result 27 | ( 28 | tenant varchar(255) NOT NULL, 29 | id varchar(255) NOT NULL, 30 | status int NOT NULL, 31 | status_info int NOT NULL, 32 | created_at TIMESTAMP(6) DEFAULT NOW(), 33 | last_open_date TIMESTAMP(6) NOT NULL, 34 | user_index int NOT NULL DEFAULT 1, 35 | change_id int NOT NULL DEFAULT 0, 36 | callback text NOT NULL, 37 | baseurl text NOT NULL, 38 | password text NULL, 39 | additional text NULL, 40 | PRIMARY KEY (tenant, id) 41 | ); 42 | -------------------------------------------------------------------------------- /schema/dameng/removetbl.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS "doc_changes"; 2 | DROP TABLE IF EXISTS "task_result"; -------------------------------------------------------------------------------- /schema/json-api/opening-file.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "$id": "https://example.com/example.json", 4 | "type": "object", 5 | "required": [ 6 | "document", 7 | "editorConfig" 8 | ], 9 | "properties": { 10 | "document": { 11 | "$id": "#/properties/document", 12 | "type": "object", 13 | "required": [ 14 | "key", 15 | "permissions", 16 | "url" 17 | ], 18 | "properties": { 19 | "key": { 20 | "$id": "#/properties/document/properties/key", 21 | "type": "string" 22 | }, 23 | "permissions": { 24 | "$id": "#/properties/document/properties/permissions", 25 | "type": "object", 26 | "required": [], 27 | "additionalProperties": true 28 | }, 29 | "url": { 30 | "$id": "#/properties/document/properties/url", 31 | "type": "string" 32 | } 33 | }, 34 | "additionalProperties": true 35 | }, 36 | "editorConfig": { 37 | "$id": "#/properties/editorConfig", 38 | "type": "object", 39 | "required": [ 40 | "callbackUrl", 41 | "mode" 42 | ], 43 | "properties": { 44 | "callbackUrl": { 45 | "$id": "#/properties/editorConfig/properties/callbackUrl", 46 | "type": "string" 47 | }, 48 | "mode": { 49 | "$id": "#/properties/editorConfig/properties/mode", 50 | "type": "string" 51 | }, 52 | "user": { 53 | "$id": "#/properties/editorConfig/properties/user", 54 | "type": "object", 55 | "required": [], 56 | "properties": { 57 | "group": { 58 | "$id": "#/properties/editorConfig/properties/user/properties/group", 59 | "type": "string" 60 | }, 61 | "id": { 62 | "$id": "#/properties/editorConfig/properties/user/properties/id", 63 | "anyOf": [ 64 | { 65 | "$id": "#/properties/editorConfig/properties/user/properties/id/anyOf/0", 66 | "type": "string" 67 | }, 68 | { 69 | "$id": "#/properties/editorConfig/properties/user/properties/id/anyOf/1", 70 | "type": "integer" 71 | } 72 | ] 73 | }, 74 | "name": { 75 | "$id": "#/properties/editorConfig/properties/user/properties/name", 76 | "type": "string" 77 | } 78 | }, 79 | "additionalProperties": true 80 | } 81 | }, 82 | "additionalProperties": true 83 | } 84 | }, 85 | "additionalProperties": true 86 | } -------------------------------------------------------------------------------- /schema/mssql/createdb.sql: -------------------------------------------------------------------------------- 1 | -- CREATE DATABASE onlyoffice; 2 | -- GO 3 | 4 | -- USE onlyoffice; 5 | 6 | CREATE TABLE doc_changes( 7 | tenant NVARCHAR(255) NOT NULL, 8 | id NVARCHAR(255) NOT NULL, 9 | change_id DECIMAL NOT NULL CONSTRAINT unsigned_doc_changes CHECK(change_id BETWEEN 0 AND 4294967295), 10 | user_id NVARCHAR(255) NOT NULL, 11 | user_id_original NVARCHAR(255) NOT NULL, 12 | user_name NVARCHAR(255) NOT NULL, 13 | change_data NVARCHAR(MAX) NOT NULL, 14 | change_date DATETIME NOT NULL, 15 | UNIQUE (tenant, id, change_id) 16 | ); 17 | 18 | CREATE TABLE task_result ( 19 | tenant NVARCHAR(255) NOT NULL, 20 | id NVARCHAR(255) NOT NULL, 21 | status SMALLINT NOT NULL, 22 | status_info INT NOT NULL, 23 | created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, 24 | last_open_date DATETIME NOT NULL, 25 | user_index DECIMAL DEFAULT 1 NOT NULL, 26 | change_id DECIMAL DEFAULT 0 NOT NULL, 27 | callback NVARCHAR(MAX) NOT NULL, 28 | baseurl NVARCHAR(MAX) NOT NULL, 29 | password NVARCHAR(MAX) NULL, 30 | additional NVARCHAR(MAX) NULL, 31 | UNIQUE (tenant, id), 32 | CONSTRAINT unsigned_task_result CHECK(change_id BETWEEN 0 AND 4294967295 AND user_index BETWEEN 0 AND 4294967295) 33 | ); 34 | 35 | GO 36 | -------------------------------------------------------------------------------- /schema/mssql/removetbl.sql: -------------------------------------------------------------------------------- 1 | -- USE onlyoffice; 2 | DROP TABLE IF EXISTS doc_changes, task_result; -------------------------------------------------------------------------------- /schema/mysql/createdb.sql: -------------------------------------------------------------------------------- 1 | -- MySQL Administrator dump 1.4 2 | -- 3 | -- ------------------------------------------------------ 4 | -- Server version 5.5.15 5 | 6 | 7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 10 | /*!40101 SET NAMES utf8 */; 11 | 12 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 13 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 14 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 15 | 16 | 17 | -- 18 | -- Create schema onlyoffice 19 | -- 20 | 21 | -- CREATE DATABASE IF NOT EXISTS onlyoffice DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; 22 | -- USE onlyoffice; 23 | 24 | -- 25 | -- Definition of table `doc_changes` 26 | -- 27 | 28 | CREATE TABLE IF NOT EXISTS `doc_changes` ( 29 | `tenant` varchar(255) NOT NULL, 30 | `id` varchar(255) NOT NULL, 31 | `change_id` int(10) unsigned NOT NULL, 32 | `user_id` varchar(255) NOT NULL, 33 | `user_id_original` varchar(255) NOT NULL, 34 | `user_name` varchar(255) NOT NULL, 35 | `change_data` longtext NOT NULL, 36 | `change_date` datetime NOT NULL, 37 | PRIMARY KEY (`tenant`, `id`,`change_id`) 38 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 39 | 40 | -- 41 | -- Dumping data for table `doc_changes` 42 | -- 43 | 44 | /*!40000 ALTER TABLE `doc_changes` DISABLE KEYS */; 45 | /*!40000 ALTER TABLE `doc_changes` ENABLE KEYS */; 46 | 47 | 48 | -- 49 | -- Definition of table `task_result` 50 | -- 51 | 52 | CREATE TABLE IF NOT EXISTS `task_result` ( 53 | `tenant` varchar(255) NOT NULL, 54 | `id` varchar(255) NOT NULL, 55 | `status` tinyint(3) NOT NULL, 56 | `status_info` int(10) NOT NULL, 57 | `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 58 | `last_open_date` datetime NOT NULL, 59 | `user_index` int(10) unsigned NOT NULL DEFAULT 1, 60 | `change_id` int(10) unsigned NOT NULL DEFAULT 0, 61 | `callback` longtext NOT NULL, 62 | `baseurl` text NOT NULL, 63 | `password` longtext NULL, 64 | `additional` longtext NULL, 65 | PRIMARY KEY (`tenant`, `id`) 66 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 67 | 68 | -- 69 | -- Dumping data for table `task_result` 70 | -- 71 | 72 | /*!40000 ALTER TABLE `task_result` DISABLE KEYS */; 73 | /*!40000 ALTER TABLE `task_result` ENABLE KEYS */; 74 | 75 | 76 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 77 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 78 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 79 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 80 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 81 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 82 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 83 | -------------------------------------------------------------------------------- /schema/mysql/removetbl.sql: -------------------------------------------------------------------------------- 1 | -- USE onlyoffice; 2 | -- 3 | -- Drop tables 4 | -- 5 | DROP TABLE IF EXISTS `doc_callbacks`; 6 | DROP TABLE IF EXISTS `doc_changes`; 7 | DROP TABLE IF EXISTS `task_result`; 8 | -------------------------------------------------------------------------------- /schema/mysql/upgrade/upgradev630.sql: -------------------------------------------------------------------------------- 1 | DELIMITER DLM00 2 | 3 | DROP PROCEDURE IF EXISTS upgrade630 DLM00 4 | 5 | CREATE PROCEDURE upgrade630() 6 | BEGIN 7 | 8 | IF (SELECT DATA_TYPE FROM information_schema.`COLUMNS` WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'task_result' AND COLUMN_NAME = 'callback') <> 'longtext' THEN 9 | ALTER TABLE `task_result` CHANGE COLUMN `callback` `callback` LONGTEXT NOT NULL ; 10 | END IF; 11 | 12 | IF NOT EXISTS(SELECT * FROM information_schema.`COLUMNS` WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'task_result' AND COLUMN_NAME = 'created_at') THEN 13 | ALTER TABLE `task_result` ADD COLUMN `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `status_info`; 14 | ALTER TABLE `task_result` ADD COLUMN `password` LONGTEXT NULL AFTER `baseurl`; 15 | END IF; 16 | 17 | END DLM00 18 | 19 | CALL upgrade630() DLM00 20 | 21 | DELIMITER ; 22 | -------------------------------------------------------------------------------- /schema/mysql/upgrade/upgradev710.sql: -------------------------------------------------------------------------------- 1 | DELIMITER DLM00 2 | 3 | DROP PROCEDURE IF EXISTS upgrade710 DLM00 4 | 5 | CREATE PROCEDURE upgrade710() 6 | BEGIN 7 | 8 | IF NOT EXISTS(SELECT * FROM information_schema.`COLUMNS` WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'task_result' AND COLUMN_NAME = 'additional') THEN 9 | ALTER TABLE `task_result` ADD COLUMN `additional` LONGTEXT NULL DEFAULT NULL AFTER `password`; 10 | END IF; 11 | 12 | END DLM00 13 | 14 | CALL upgrade710() DLM00 15 | 16 | DELIMITER ; 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /schema/mysql/upgrade/upgradev720.sql: -------------------------------------------------------------------------------- 1 | DELIMITER DLM00 2 | 3 | DROP PROCEDURE IF EXISTS upgrade720 DLM00 4 | 5 | CREATE PROCEDURE upgrade720() 6 | BEGIN 7 | 8 | IF NOT EXISTS(SELECT * FROM information_schema.`COLUMNS` WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'task_result' AND COLUMN_NAME = 'tenant') THEN 9 | SET SQL_SAFE_UPDATES=0; 10 | ALTER TABLE `task_result` ADD COLUMN `tenant` VARCHAR(255) NULL FIRST; 11 | UPDATE `task_result` SET `tenant`='localhost' WHERE `tenant` IS NULL; 12 | ALTER TABLE `task_result` CHANGE COLUMN `tenant` `tenant` VARCHAR(255) NOT NULL; 13 | ALTER TABLE `task_result` DROP PRIMARY KEY; 14 | ALTER TABLE `task_result` ADD PRIMARY KEY (`tenant`, `id`); 15 | SET SQL_SAFE_UPDATES=1; 16 | END IF; 17 | 18 | IF NOT EXISTS(SELECT * FROM information_schema.`COLUMNS` WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'doc_changes' AND COLUMN_NAME = 'tenant') THEN 19 | SET SQL_SAFE_UPDATES=0; 20 | ALTER TABLE `doc_changes` ADD COLUMN `tenant` VARCHAR(255) NULL FIRST; 21 | UPDATE `doc_changes` SET `tenant`='localhost' WHERE `tenant` IS NULL; 22 | ALTER TABLE `doc_changes` CHANGE COLUMN `tenant` `tenant` VARCHAR(255) NOT NULL; 23 | ALTER TABLE `doc_changes` DROP PRIMARY KEY; 24 | ALTER TABLE `doc_changes` ADD PRIMARY KEY (`tenant`, `id`,`change_id`); 25 | SET SQL_SAFE_UPDATES=1; 26 | END IF; 27 | 28 | END DLM00 29 | 30 | CALL upgrade720() DLM00 31 | 32 | DELIMITER ; 33 | -------------------------------------------------------------------------------- /schema/oracle/createdb.sql: -------------------------------------------------------------------------------- 1 | -- You must be logged in as SYS(sysdba) user. 2 | -- Here, "onlyoffice" is a PBD(service) name. 3 | alter session set container = xepdb1; 4 | 5 | -- Oracle uses users as namespaces for tables creation. In "onlyoffice.table_name" onlyoffice is a user name, so table_name exist only at this namespace. 6 | -- ---------------------------- 7 | -- Table structure for doc_changes 8 | -- ---------------------------- 9 | 10 | CREATE TABLE doc_changes ( 11 | tenant NVARCHAR2(255) NOT NULL, 12 | id NVARCHAR2(255) NOT NULL, 13 | change_id NUMBER NOT NULL, 14 | user_id NVARCHAR2(255) NOT NULL, 15 | user_id_original NVARCHAR2(255) NOT NULL, 16 | user_name NVARCHAR2(255) NOT NULL, 17 | change_data NCLOB NOT NULL, 18 | change_date TIMESTAMP NOT NULL, 19 | CONSTRAINT doc_changes_unique UNIQUE (tenant, id, change_id), 20 | CONSTRAINT doc_changes_unsigned_int CHECK (change_id between 0 and 4294967295) 21 | ); 22 | 23 | -- ---------------------------- 24 | -- Table structure for task_result 25 | -- ---------------------------- 26 | 27 | CREATE TABLE task_result ( 28 | tenant NVARCHAR2(255) NOT NULL, 29 | id NVARCHAR2(255) NOT NULL, 30 | status NUMBER NOT NULL, 31 | status_info NUMBER NOT NULL, 32 | created_at TIMESTAMP DEFAULT SYSDATE NOT NULL, 33 | last_open_date TIMESTAMP NOT NULL, 34 | user_index NUMBER DEFAULT 1 NOT NULL, 35 | change_id NUMBER DEFAULT 0 NOT NULL, 36 | callback NCLOB, -- codebase uses '' as default values here, but Oracle treat '' as NULL, so NULL permitted for this value. 37 | baseurl NCLOB, -- codebase uses '' as default values here, but Oracle treat '' as NULL, so NULL permitted for this value. 38 | password NCLOB NULL, 39 | additional NCLOB NULL, 40 | CONSTRAINT task_result_unique UNIQUE (tenant, id), 41 | CONSTRAINT task_result_unsigned_int CHECK (user_index BETWEEN 0 AND 4294967295 AND change_id BETWEEN 0 AND 4294967295) 42 | ); 43 | -------------------------------------------------------------------------------- /schema/oracle/removetbl.sql: -------------------------------------------------------------------------------- 1 | -- You must be logged in as SYS(sysdba) user. 2 | -- Here, "onlyoffice" is a PBD(service) name. 3 | alter session set container = xepdb1; 4 | 5 | DROP TABLE onlyoffice.doc_changes CASCADE CONSTRAINTS PURGE; 6 | DROP TABLE onlyoffice.task_result CASCADE CONSTRAINTS PURGE; -------------------------------------------------------------------------------- /schema/postgresql/createdb.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Create schema onlyoffice 3 | -- 4 | 5 | -- CREATE DATABASE onlyoffice ENCODING = 'UTF8' CONNECTION LIMIT = -1; 6 | 7 | -- ---------------------------- 8 | -- Table structure for doc_changes 9 | -- ---------------------------- 10 | CREATE TABLE IF NOT EXISTS "public"."doc_changes" ( 11 | "tenant" varchar(255) COLLATE "default" NOT NULL, 12 | "id" varchar(255) COLLATE "default" NOT NULL, 13 | "change_id" int4 NOT NULL, 14 | "user_id" varchar(255) COLLATE "default" NOT NULL, 15 | "user_id_original" varchar(255) COLLATE "default" NOT NULL, 16 | "user_name" varchar(255) COLLATE "default" NOT NULL, 17 | "change_data" text COLLATE "default" NOT NULL, 18 | "change_date" timestamp without time zone NOT NULL, 19 | PRIMARY KEY ("tenant", "id", "change_id") 20 | ) 21 | WITH (OIDS=FALSE); 22 | 23 | -- ---------------------------- 24 | -- Table structure for task_result 25 | -- ---------------------------- 26 | CREATE TABLE IF NOT EXISTS "public"."task_result" ( 27 | "tenant" varchar(255) COLLATE "default" NOT NULL, 28 | "id" varchar(255) COLLATE "default" NOT NULL, 29 | "status" int2 NOT NULL, 30 | "status_info" int4 NOT NULL, 31 | "created_at" timestamp without time zone DEFAULT NOW(), 32 | "last_open_date" timestamp without time zone NOT NULL, 33 | "user_index" int4 NOT NULL DEFAULT 1, 34 | "change_id" int4 NOT NULL DEFAULT 0, 35 | "callback" text COLLATE "default" NOT NULL, 36 | "baseurl" text COLLATE "default" NOT NULL, 37 | "password" text COLLATE "default" NULL, 38 | "additional" text COLLATE "default" NULL, 39 | PRIMARY KEY ("tenant", "id") 40 | ) 41 | WITH (OIDS=FALSE); 42 | 43 | CREATE OR REPLACE FUNCTION merge_db(_tenant varchar(255), _id varchar(255), _status int2, _status_info int4, _last_open_date timestamp without time zone, _user_index int4, _change_id int4, _callback text, _baseurl text, OUT isupdate char(5), OUT userindex int4) AS 44 | $$ 45 | DECLARE 46 | t_var "public"."task_result"."user_index"%TYPE; 47 | BEGIN 48 | LOOP 49 | -- first try to update the key 50 | -- note that "a" must be unique 51 | IF ((_callback <> '') IS TRUE) AND ((_baseurl <> '') IS TRUE) THEN 52 | UPDATE "public"."task_result" SET last_open_date=_last_open_date, user_index=user_index+1,callback=_callback,baseurl=_baseurl WHERE tenant = _tenant AND id = _id RETURNING user_index into userindex; 53 | ELSE 54 | UPDATE "public"."task_result" SET last_open_date=_last_open_date, user_index=user_index+1 WHERE tenant = _tenant AND id = _id RETURNING user_index into userindex; 55 | END IF; 56 | IF found THEN 57 | isupdate := 'true'; 58 | RETURN; 59 | END IF; 60 | -- not there, so try to insert the key 61 | -- if someone else inserts the same key concurrently, 62 | -- we could get a unique-key failure 63 | BEGIN 64 | INSERT INTO "public"."task_result"(tenant, id, status, status_info, last_open_date, user_index, change_id, callback, baseurl) VALUES(_tenant, _id, _status, _status_info, _last_open_date, _user_index, _change_id, _callback, _baseurl) RETURNING user_index into userindex; 65 | isupdate := 'false'; 66 | RETURN; 67 | EXCEPTION WHEN unique_violation THEN 68 | -- do nothing, and loop to try the UPDATE again 69 | END; 70 | END LOOP; 71 | END; 72 | $$ 73 | LANGUAGE plpgsql; 74 | -------------------------------------------------------------------------------- /schema/postgresql/removetbl.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Drop tables 3 | -- 4 | DROP TABLE IF EXISTS "public"."doc_callbacks"; 5 | DROP TABLE IF EXISTS "public"."doc_changes"; 6 | DROP TABLE IF EXISTS "public"."task_result"; 7 | 8 | --https://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE 9 | DROP FUNCTION IF EXISTS merge_db(_id varchar(255), _status int2, _status_info int8, _last_open_date timestamp without time zone, _title varchar(255), _user_index int8, _change_id int8, OUT isupdate char(5), OUT userindex int8) CASCADE; 10 | DROP FUNCTION IF EXISTS merge_db(_id varchar(255), _status int2, _status_info int4, _last_open_date timestamp without time zone, _title varchar(255), _user_index int4, _change_id int4, OUT isupdate char(5), OUT userindex int4) CASCADE; 11 | DROP FUNCTION IF EXISTS merge_db(_id varchar(255), _status int2, _status_info int4, _last_open_date timestamp without time zone, _user_index int4, _change_id int4, _callback text, _baseurl text, OUT isupdate char(5), OUT userindex int4) CASCADE; 12 | -------------------------------------------------------------------------------- /schema/postgresql/upgrade/upgradev630.sql: -------------------------------------------------------------------------------- 1 | DO $$ 2 | BEGIN 3 | BEGIN 4 | ALTER TABLE "task_result" ADD COLUMN "created_at" timestamp without time zone DEFAULT NOW(); 5 | EXCEPTION 6 | WHEN duplicate_column THEN RAISE NOTICE 'column created_at already exists.'; 7 | END; 8 | 9 | BEGIN 10 | ALTER TABLE "task_result" ADD COLUMN "password" text; 11 | EXCEPTION 12 | WHEN duplicate_column THEN RAISE NOTICE 'column password already exists.'; 13 | END; 14 | END; 15 | $$ -------------------------------------------------------------------------------- /schema/postgresql/upgrade/upgradev710.sql: -------------------------------------------------------------------------------- 1 | DO $$ 2 | BEGIN 3 | BEGIN 4 | ALTER TABLE "task_result" ADD COLUMN "additional" text; 5 | EXCEPTION 6 | WHEN duplicate_column THEN RAISE NOTICE 'column additional already exists.'; 7 | END; 8 | END; 9 | $$ -------------------------------------------------------------------------------- /schema/postgresql/upgrade/upgradev720.sql: -------------------------------------------------------------------------------- 1 | DO $$ 2 | BEGIN 3 | BEGIN 4 | ALTER TABLE "task_result" ADD COLUMN "tenant" varchar(255) COLLATE "default" NOT NULL DEFAULT 'localhost'; 5 | ALTER TABLE "task_result" ALTER COLUMN "tenant" DROP DEFAULT; 6 | ALTER TABLE "task_result" DROP CONSTRAINT IF EXISTS task_result_pkey; 7 | ALTER TABLE "task_result" ADD PRIMARY KEY ("tenant", "id"); 8 | EXCEPTION 9 | WHEN duplicate_column THEN RAISE NOTICE 'column `tenant` already exists.'; 10 | END; 11 | 12 | BEGIN 13 | ALTER TABLE "doc_changes" ADD COLUMN "tenant" varchar(255) COLLATE "default" NOT NULL DEFAULT 'localhost'; 14 | ALTER TABLE "doc_changes" ALTER COLUMN "tenant" DROP DEFAULT; 15 | ALTER TABLE "doc_changes" DROP CONSTRAINT IF EXISTS doc_changes_pkey; 16 | ALTER TABLE "doc_changes" ADD PRIMARY KEY ("tenant", "id", "change_id"); 17 | EXCEPTION 18 | WHEN duplicate_column THEN RAISE NOTICE 'column `tenant` already exists.'; 19 | END; 20 | END; 21 | $$ 22 | -------------------------------------------------------------------------------- /tests/env-setup.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | const platforms = { 34 | 'win32': 'windows', 35 | 'darwin': 'mac', 36 | 'linux': 'linux' 37 | }; 38 | const platform = platforms[process.platform]; 39 | 40 | process.env.NODE_ENV = `development-${platform}`; 41 | process.env.NODE_CONFIG_DIR = '../Common/config'; 42 | 43 | if (platform === 'mac') { 44 | process.env.DYLD_LIBRARY_PATH = '../FileConverter/bin/'; 45 | } else if (platform === 'linux') { 46 | process.env.LD_LIBRARY_PATH = '../FileConverter/bin/'; 47 | } 48 | -------------------------------------------------------------------------------- /tests/perf/checkFileExpire.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | const { 36 | createHistogram, 37 | performance, 38 | PerformanceObserver, 39 | } = require('node:perf_hooks'); 40 | 41 | const co = require('co'); 42 | const taskResult = require('./../../DocService/sources/taskresult'); 43 | const storage = require('./../../Common/sources/storage-base'); 44 | const storageFs = require('./../../Common/sources/storage-fs'); 45 | const operationContext = require('./../../Common/sources/operationContext'); 46 | const utils = require('./../../Common/sources/utils'); 47 | const docsCoServer = require("./../../DocService/sources/DocsCoServer"); 48 | const gc = require("./../../DocService/sources/gc"); 49 | 50 | let ctx = operationContext.global; 51 | 52 | let addRandomKeyTask; 53 | let histograms = {}; 54 | 55 | async function beforeStart() { 56 | let timerify = function (func, name) { 57 | //todo remove anonymous functions. use func.name 58 | Object.defineProperty(func, 'name', { 59 | value: name 60 | }); 61 | let histogram = createHistogram(); 62 | histograms[func.name] = histogram; 63 | return performance.timerify(func, {histogram: histogram}); 64 | } 65 | 66 | addRandomKeyTask = timerify(co.wrap(taskResult.addRandomKeyTask), "addRandomKeyTask"); 67 | taskResult.getExpired = timerify(taskResult.getExpired, "getExpired"); 68 | taskResult.remove = timerify(taskResult.remove, "remove"); 69 | storage.putObject = timerify(storage.putObject, "putObject"); 70 | storage.listObjects = timerify(storage.listObjects, "listObjects"); 71 | storageFs.deletePath = timerify(storageFs.deletePath, "deletePath"); 72 | storageFs.deleteObject = timerify(storageFs.deleteObject, "deleteObject"); 73 | docsCoServer.getEditorsCountPromise = timerify(docsCoServer.getEditorsCountPromise, "getEditorsCountPromise"); 74 | 75 | const obs = new PerformanceObserver((list) => { 76 | const entries = list.getEntries(); 77 | entries.forEach((entry) => { 78 | let duration = Math.round(entry.duration * 1000) / 1000; 79 | console.log(`${entry.name}:${duration}ms`); 80 | }); 81 | }); 82 | obs.observe({ entryTypes: ['function']}); 83 | 84 | await docsCoServer.editorData.connect(); 85 | } 86 | 87 | async function beforeEnd() { 88 | let logHistogram = function (histogram, name) { 89 | let mean = Math.round(histogram.mean / 1000) / 1000; 90 | let min = Math.round(histogram.min / 1000) / 1000; 91 | let max = Math.round(histogram.max / 1000) / 1000; 92 | let count = histogram.count; 93 | ctx.logger.info(`histogram ${name}: count=${count}, mean=${mean}ms, min=${min}ms, max=${max}ms`); 94 | } 95 | await utils.sleep(1000); 96 | for (let name in histograms) { 97 | logHistogram(histograms[name], name); 98 | } 99 | } 100 | 101 | async function addFileExpire(count, size, prefix, filesInFolder) { 102 | while (count > 0) { 103 | let task = await addRandomKeyTask(ctx, undefined, prefix, 8); 104 | let data = Buffer.alloc(size, 0); 105 | let rand = Math.floor(Math.random() * filesInFolder) + 1; 106 | for (let i = 0; i < rand && count > 0; i++) { 107 | await storage.putObject(ctx, `${task.key}/data${i}`, data, data.length); 108 | count--; 109 | } 110 | } 111 | } 112 | 113 | async function startTest() { 114 | let args = process.argv.slice(2); 115 | if (args.length < 4) { 116 | ctx.logger.error('missing arguments.USAGE: checkFileExpire.js [add-files-count] [file-size-bytes] [key-prefix] [seconds-to-expire]'); 117 | return; 118 | } 119 | ctx.logger.info("test started"); 120 | await beforeStart(); 121 | 122 | await addFileExpire(parseInt(args[0]), parseInt(args[1]), args[2], parseInt(args[4] || 1)); 123 | //delay to log observer events 124 | await utils.sleep(1000); 125 | await gc.checkFileExpire(args[3]); 126 | 127 | await beforeEnd(); 128 | ctx.logger.info("test finished"); 129 | } 130 | 131 | startTest().then(()=>{ 132 | //delay to log observer events 133 | return utils.sleep(1000); 134 | }).catch((err) => { 135 | ctx.logger.error(err.stack); 136 | }).finally(() => { 137 | process.exit(0); 138 | }); 139 | -------------------------------------------------------------------------------- /tests/perf/convertImageToPng.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2023 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | const { 36 | createHistogram, 37 | performance, 38 | PerformanceObserver, 39 | } = require('node:perf_hooks'); 40 | 41 | const { readdir, mkdir, readFile, writeFile } = require("node:fs/promises"); 42 | const path = require("path"); 43 | // const Jimp = require('Jimp'); 44 | const utils = require('./../../Common/sources/utils'); 45 | const operationContext = require('./../../Common/sources/operationContext'); 46 | const utilsDocService = require("./../../DocService/sources/utilsDocService"); 47 | 48 | let ctx = operationContext.global; 49 | 50 | let histograms = {}; 51 | 52 | async function beforeStart() { 53 | let timerify = function (func) { 54 | let histogram = createHistogram(); 55 | histograms[func.name] = histogram; 56 | return performance.timerify(func, {histogram: histogram}); 57 | } 58 | utilsDocService.convertImageToPng = timerify(utilsDocService.convertImageToPng); 59 | // Jimp.read = timerify(Jimp.read); 60 | 61 | const obs = new PerformanceObserver((list) => { 62 | const entries = list.getEntries(); 63 | entries.forEach((entry) => { 64 | let duration = Math.round(entry.duration * 1000) / 1000; 65 | console.log(`${entry.name}:${duration}ms`); 66 | }); 67 | }); 68 | obs.observe({ entryTypes: ['function']}); 69 | } 70 | 71 | async function beforeEnd() { 72 | let logHistogram = function (histogram, name) { 73 | let mean = Math.round(histogram.mean / 1000) / 1000; 74 | let min = Math.round(histogram.min / 1000) / 1000; 75 | let max = Math.round(histogram.max / 1000) / 1000; 76 | let count = histogram.count; 77 | ctx.logger.info(`histogram ${name}: count=${count}, mean=${mean}ms, min=${min}ms, max=${max}ms`); 78 | } 79 | await utils.sleep(1000); 80 | for (let name in histograms) { 81 | logHistogram(histograms[name], name); 82 | } 83 | } 84 | 85 | async function fixInDir(dirIn, dirOut) { 86 | ctx.logger.info("dirIn:%s", dirIn); 87 | ctx.logger.info("dirOut:%s", dirOut); 88 | let dirents = await readdir(dirIn, {withFileTypes : true, recursive: true}); 89 | for (let dirent of dirents) { 90 | if (dirent.isFile()) { 91 | let file = dirent.name; 92 | ctx.logger.info("fixInDir:%s", file); 93 | let buffer = await readFile(path.join(dirent.path, file)); 94 | let bufferNew = await utilsDocService.convertImageToPng(ctx, buffer); 95 | if (buffer !== bufferNew) { 96 | let outputPath = path.join(dirOut, dirent.path.substring(dirIn.length), path.basename(file, path.extname(file)) + '.png'); 97 | await mkdir(path.dirname(outputPath), {recursive: true}); 98 | await writeFile(outputPath, bufferNew); 99 | } 100 | } 101 | } 102 | } 103 | 104 | async function startTest() { 105 | let args = process.argv.slice(2); 106 | if (args.length < 2) { 107 | ctx.logger.error('missing arguments.USAGE: convertImageToPng.js "dirIn" "dirOut"'); 108 | return; 109 | } 110 | ctx.logger.info("test started"); 111 | await beforeStart(); 112 | 113 | 114 | await fixInDir(args[0], args[1]); 115 | 116 | await beforeEnd(); 117 | ctx.logger.info("test finished"); 118 | } 119 | 120 | startTest().then(()=>{ 121 | //delay to log observer events 122 | return utils.sleep(1000); 123 | }).catch((err) => { 124 | ctx.logger.error(err.stack); 125 | }).finally(() => { 126 | process.exit(0); 127 | }); 128 | -------------------------------------------------------------------------------- /tests/perf/fixImageExifRotation.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | 'use strict'; 34 | 35 | const { 36 | createHistogram, 37 | performance, 38 | PerformanceObserver, 39 | } = require('node:perf_hooks'); 40 | 41 | const { readdir, mkdir, readFile, writeFile } = require("node:fs/promises"); 42 | const path = require("path"); 43 | // const Jimp = require('Jimp'); 44 | const utils = require('./../../Common/sources/utils'); 45 | const operationContext = require('./../../Common/sources/operationContext'); 46 | const utilsDocService = require("./../../DocService/sources/utilsDocService"); 47 | 48 | let ctx = operationContext.global; 49 | 50 | let histograms = {}; 51 | 52 | async function beforeStart() { 53 | let timerify = function (func) { 54 | let histogram = createHistogram(); 55 | histograms[func.name] = histogram; 56 | return performance.timerify(func, {histogram: histogram}); 57 | } 58 | utilsDocService.fixImageExifRotation = timerify(utilsDocService.fixImageExifRotation); 59 | // Jimp.read = timerify(Jimp.read); 60 | 61 | const obs = new PerformanceObserver((list) => { 62 | const entries = list.getEntries(); 63 | entries.forEach((entry) => { 64 | let duration = Math.round(entry.duration * 1000) / 1000; 65 | console.log(`${entry.name}:${duration}ms`); 66 | }); 67 | }); 68 | obs.observe({ entryTypes: ['function']}); 69 | } 70 | 71 | async function beforeEnd() { 72 | let logHistogram = function (histogram, name) { 73 | let mean = Math.round(histogram.mean / 1000) / 1000; 74 | let min = Math.round(histogram.min / 1000) / 1000; 75 | let max = Math.round(histogram.max / 1000) / 1000; 76 | let count = histogram.count; 77 | ctx.logger.info(`histogram ${name}: count=${count}, mean=${mean}ms, min=${min}ms, max=${max}ms`); 78 | } 79 | await utils.sleep(1000); 80 | for (let name in histograms) { 81 | logHistogram(histograms[name], name); 82 | } 83 | } 84 | 85 | async function fixInDir(dirIn, dirOut) { 86 | ctx.logger.info("dirIn:%s", dirIn); 87 | ctx.logger.info("dirOut:%s", dirOut); 88 | let dirents = await readdir(dirIn, {withFileTypes : true, recursive: true}); 89 | for (let dirent of dirents) { 90 | if (dirent.isFile()) { 91 | let file = dirent.name; 92 | ctx.logger.info("fixInDir:%s", file); 93 | let buffer = await readFile(path.join(dirent.path, file)); 94 | let bufferNew = await utilsDocService.fixImageExifRotation(ctx, buffer); 95 | if (buffer !== bufferNew) { 96 | let outputPath = path.join(dirOut, dirent.path.substring(dirIn.length), file); 97 | await mkdir(path.dirname(outputPath), {recursive: true}); 98 | await writeFile(outputPath, bufferNew); 99 | } 100 | } 101 | } 102 | } 103 | 104 | async function startTest() { 105 | let args = process.argv.slice(2); 106 | if (args.length < 2) { 107 | ctx.logger.error('missing arguments.USAGE: fixImageExifRotation.js "dirIn" "dirOut"'); 108 | return; 109 | } 110 | ctx.logger.info("test started"); 111 | await beforeStart(); 112 | 113 | 114 | await fixInDir(args[0], args[1]); 115 | 116 | await beforeEnd(); 117 | ctx.logger.info("test finished"); 118 | } 119 | 120 | startTest().then(()=>{ 121 | //delay to log observer events 122 | return utils.sleep(1000); 123 | }).catch((err) => { 124 | ctx.logger.error(err.stack); 125 | }).finally(() => { 126 | process.exit(0); 127 | }); 128 | -------------------------------------------------------------------------------- /tests/unit/mailService.tests.js: -------------------------------------------------------------------------------- 1 | const { describe, test, expect, afterAll } = require('@jest/globals'); 2 | const nodemailer = require('../../Common/node_modules/nodemailer'); 3 | 4 | const operationContext = require('../../Common/sources/operationContext'); 5 | const mailService = require('../../Common/sources/mailService'); 6 | 7 | const ctx = new operationContext.Context(); 8 | const defaultTestSMTPServer = { 9 | host: 'smtp.ethereal.email', 10 | port: 587 11 | }; 12 | const testTimeout = 1000 * 10; 13 | 14 | afterAll(function () { 15 | mailService.transportersRelease(); 16 | }) 17 | 18 | describe('Mail service', function () { 19 | describe('SMTP', function () { 20 | const { host, port } = defaultTestSMTPServer; 21 | 22 | test('Transporters life cycle', async function () { 23 | // Accounts created at https://ethereal.email/, all messages in tests goes here: https://ethereal.email/messages 24 | // Ethereial is a special SMTP sever for mailing tests in collaboration with Nodemailer. 25 | const accounts = await Promise.all([nodemailer.createTestAccount(), nodemailer.createTestAccount(), nodemailer.createTestAccount()]); 26 | const auth = accounts.map(account => { return { user: account.user, pass: account.pass }}); 27 | auth.forEach(credential => mailService.createTransporter(ctx, host, port, credential, { from: 'some.mail@ethereal.com' })); 28 | 29 | for (let i = 0; i < auth.length; i++) { 30 | const credentials = auth[i]; 31 | const mail = await mailService.send( 32 | host, 33 | credentials.user, 34 | { to: `some.recipient@server${i + 1}.com`, text: 'simple test text', subject: 'Mail service test' } 35 | ); 36 | 37 | expect(mail.envelope).toEqual({ from: 'some.mail@ethereal.com', to: [`some.recipient@server${i + 1}.com`] }); 38 | } 39 | 40 | const accountToBeDeleted = auth[1]; 41 | mailService.deleteTransporter(ctx, host, accountToBeDeleted.user); 42 | 43 | const errorPromise = mailService.send( 44 | host, 45 | accountToBeDeleted.user, 46 | { to: 'no.recipient@server.com', text: 'simple test text', subject: 'Mail service test' } 47 | ); 48 | 49 | await expect(errorPromise).rejects.toThrow(); 50 | }, testTimeout); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /tests/unit/sample.tests.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | const { describe, test, expect } = require('@jest/globals'); 34 | 35 | describe('Successful and failure tests', function () { 36 | test('Successful test', function () { 37 | expect(true).toBeTruthy(); 38 | }); 39 | 40 | test.skip('Failure test', function () { 41 | expect(true).toBeFalsy(); 42 | }); 43 | }); -------------------------------------------------------------------------------- /tests/unit/utils.tests.js: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Copyright Ascensio System SIA 2010-2024 3 | * 4 | * This program is a free software product. You can redistribute it and/or 5 | * modify it under the terms of the GNU Affero General Public License (AGPL) 6 | * version 3 as published by the Free Software Foundation. In accordance with 7 | * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect 8 | * that Ascensio System SIA expressly excludes the warranty of non-infringement 9 | * of any third-party rights. 10 | * 11 | * This program is distributed WITHOUT ANY WARRANTY; without even the implied 12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For 13 | * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html 14 | * 15 | * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish 16 | * street, Riga, Latvia, EU, LV-1050. 17 | * 18 | * The interactive user interfaces in modified source and object code versions 19 | * of the Program must display Appropriate Legal Notices, as required under 20 | * Section 5 of the GNU AGPL version 3. 21 | * 22 | * Pursuant to Section 7(b) of the License you must retain the original Product 23 | * logo when distributing the program. Pursuant to Section 7(e) we decline to 24 | * grant you any rights under trademark law for use of our trademarks. 25 | * 26 | * All the Product's GUI elements, including illustrations and icon sets, as 27 | * well as technical writing content are licensed under the terms of the 28 | * Creative Commons Attribution-ShareAlike 4.0 International. See the License 29 | * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode 30 | * 31 | */ 32 | 33 | const { describe, test, expect } = require('@jest/globals'); 34 | const config = require('../../Common/node_modules/config'); 35 | 36 | const operationContext = require('../../Common/sources/operationContext'); 37 | const utils = require('../../Common/sources/utils'); 38 | 39 | const ctx = new operationContext.Context(); 40 | const minimumIterationsByteLength = 4; 41 | 42 | 43 | describe('AES encryption & decryption', function () { 44 | test('Iterations range', async function () { 45 | const configuration = config.get('aesEncrypt.config'); 46 | const encrypted = await utils.encryptPassword(ctx, 'secretstring'); 47 | const { iterationsByteLength = 5 } = configuration; 48 | 49 | const [iterationsHex] = encrypted.split(':'); 50 | const iterations = parseInt(iterationsHex, 16); 51 | 52 | const iterationsLength = iterationsByteLength < minimumIterationsByteLength ? minimumIterationsByteLength : iterationsByteLength; 53 | expect(iterations).toBeGreaterThanOrEqual(Math.pow(10, iterationsLength - 1)); 54 | expect(iterations).toBeLessThanOrEqual(Math.pow(10, iterationsLength) - 1); 55 | }); 56 | 57 | test('Correct workflow', async function () { 58 | const encrypted = await utils.encryptPassword(ctx, 'secretstring'); 59 | const decrypted = await utils.decryptPassword(ctx, encrypted); 60 | expect(decrypted).toEqual('secretstring'); 61 | }); 62 | }); 63 | --------------------------------------------------------------------------------