[prettier] auto-fix

This commit is contained in:
PauI Ostrovckij
2025-08-27 10:50:22 +03:00
parent 79de4b3eaa
commit fb20086ef1
82 changed files with 11568 additions and 10222 deletions

View File

@ -1,4 +1,4 @@
name: "CodeQL"
name: 'CodeQL'
on:
push:
@ -27,23 +27,22 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'javascript-typescript' ]
language: ['javascript-typescript']
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: '/language:${{matrix.language}}'

View File

@ -39,7 +39,7 @@ jobs:
run: |
echo '{"services": {"CoAuthoring": {"sql": {"type": "mysql", "dbHost": "127.0.0.1", "dbPort": "8080", "dbUser": "root", "dbPass": "onlyoffice"}}}}' >> Common/config/local.json
- name : Creating schema
- name: Creating schema
run: |
docker cp ./schema/mysql/createdb.sql mysql:/
docker exec mysql mysql -h 127.0.0.1 -u root --password=onlyoffice -D onlyoffice -e 'source /createdb.sql'

View File

@ -7,4 +7,4 @@ script:
- make
matrix:
allow_failures:
- node_js: '6'
- node_js: '6'

View File

@ -1,4 +1,3 @@
## Third-party
- @aws-sdk/client-s3 3.637.0 ([Apache-2.0](https://raw.githubusercontent.com/aws/aws-sdk-js-v3/main/LICENSE))

View File

@ -31,7 +31,7 @@
*/
'use strict';
const { readFile, writeFile } = require("node:fs/promises");
const {readFile, writeFile} = require('node:fs/promises');
async function startTest() {
const args = process.argv.slice(2);
@ -39,7 +39,7 @@ async function startTest() {
console.error('missing arguments.USAGE: json2md.js [output.md] [input.json]');
return;
}
console.info("3d license report start");
console.info('3d license report start');
let outputMd = '';
let outputFlag = 'a';
const outputPath = args[0];
@ -48,14 +48,14 @@ async function startTest() {
if (inputPath) {
const licensesText = await readFile(inputPath, 'utf-8');
const licensesJson = JSON.parse(licensesText);
console.info("3d license report license count: %d", licensesJson.length);
console.info('3d license report license count: %d', licensesJson.length);
for (const element of licensesJson) {
const name = element['name'];
const installedVersion = element['installedVersion'];
const licenseType = element['licenseType'];
const licenseFileLink = element['licenseFileLink'];
outputMd += `- ${name} ${installedVersion} ([${licenseType}](${licenseFileLink}))\n`
outputMd += `- ${name} ${installedVersion} ([${licenseType}](${licenseFileLink}))\n`;
}
} else {
outputMd = '\n## Third-party\n\n';
@ -63,11 +63,13 @@ async function startTest() {
}
await writeFile(outputPath, outputMd, {flag: outputFlag}, 'utf-8');
console.info("3d license report end");
console.info('3d license report end');
}
startTest().catch((err) => {
console.error(err.stack);
}).finally(() => {
process.exit(0);
});
startTest()
.catch(err => {
console.error(err.stack);
})
.finally(() => {
process.exit(0);
});

View File

@ -1,8 +1,3 @@
{
"fields": [
"name",
"licenseType",
"link",
"installedVersion"
]
"fields": ["name", "licenseType", "link", "installedVersion"]
}

View File

@ -1,10 +1,15 @@
# Change log
## develop
### Back-end
*
-
## 5.1.1
### Back-end
* Add reconnection.attempts, reconnection.delay options to config - applicable for editor-server connection
* Add sockjs config section for testing purposes
* Fix inconsistent database status after files assemble in case of rapid open/close connection
- Add reconnection.attempts, reconnection.delay options to config - applicable for editor-server connection
- Add sockjs config section for testing purposes
- Fix inconsistent database status after files assemble in case of rapid open/close connection

View File

@ -43,31 +43,31 @@ function connetPromise(closeCallback) {
return new Promise((resolve, _reject) => {
//todo use built-in reconnect logic
function startConnect() {
let onDisconnected = function() {
let onDisconnected = function () {
if (isConnected) {
closeCallback();
} else {
setTimeout(startConnect, RECONNECT_TIMEOUT);
}
}
};
const conn = container.create_container().connect(cfgRabbitSocketOptions);
let isConnected = false;
conn.on('connection_open', (_context) => {
conn.on('connection_open', _context => {
operationContext.global.logger.debug('[AMQP] connected');
isConnected = true;
resolve(conn);
});
conn.on('connection_error', (context) => {
conn.on('connection_error', context => {
operationContext.global.logger.debug('[AMQP] connection_error %s', context.error && context.error);
});
conn.on('connection_close', (_context) => {
conn.on('connection_close', _context => {
operationContext.global.logger.debug('[AMQP] conn close');
if (onDisconnected) {
onDisconnected();
onDisconnected = null;
}
});
conn.on('disconnected', (context) => {
conn.on('disconnected', context => {
operationContext.global.logger.error('[AMQP] disconnected %s', context.error && context.error.stack);
if (onDisconnected) {
onDisconnected();

View File

@ -37,8 +37,8 @@ const constants = require('./constants');
function InputCommand(data, copyExplicit) {
//must be set explicitly to prevent vulnerability(downloadAs(with url) creates request to integrator with authorization)
this['withAuthorization'] = undefined;//bool
this['externalChangeInfo'] = undefined;//zero DB changes case: set password, undo all changes
this['withAuthorization'] = undefined; //bool
this['externalChangeInfo'] = undefined; //zero DB changes case: set password, undo all changes
this['wopiParams'] = undefined;
this['builderParams'] = undefined;
this['userconnectiondocid'] = undefined;
@ -118,45 +118,45 @@ function InputCommand(data, copyExplicit) {
this['originformat'] = data['originformat'];
}
} else {
this['c'] = undefined;//string command
this['id'] = undefined;//string document id
this['userid'] = undefined;//string
this['c'] = undefined; //string command
this['id'] = undefined; //string document id
this['userid'] = undefined; //string
this['userindex'] = undefined;
this['username'] = undefined;
this['tokenSession'] = undefined;//string validate
this['tokenDownload'] = undefined;//string validate
this['data'] = undefined;//string
this['tokenSession'] = undefined; //string validate
this['tokenDownload'] = undefined; //string validate
this['data'] = undefined; //string
//to open
this['editorid'] = undefined;//int
this['format'] = undefined;//string extention
this['url'] = undefined;//string
this['title'] = undefined;//string filename
this['editorid'] = undefined; //int
this['format'] = undefined; //string extention
this['url'] = undefined; //string
this['title'] = undefined; //string filename
// to save
this['outputformat'] = undefined;//int
this['outputpath'] = undefined;//int internal
this['savetype'] = undefined;//int part type
this['saveindex'] = undefined;//int part index
this['outputformat'] = undefined; //int
this['outputpath'] = undefined; //int internal
this['savetype'] = undefined; //int part type
this['saveindex'] = undefined; //int part index
//nullable
this['codepage'] = undefined;
this['delimiter'] = undefined;
this['delimiterChar'] = undefined;
this['embeddedfonts'] = undefined;//bool
this['embeddedfonts'] = undefined; //bool
this['mailmergesend'] = undefined;
this['thumbnail'] = undefined;
//private
this['status'] = undefined;//int
this['status_info'] = undefined;//int
this['savekey'] = undefined;//int document id to save
this['userconnectionid'] = undefined;//string internal
this['status'] = undefined; //int
this['status_info'] = undefined; //int
this['savekey'] = undefined; //int document id to save
this['userconnectionid'] = undefined; //string internal
this['responsekey'] = undefined;
this['jsonparams'] = undefined;//string
this['jsonparams'] = undefined; //string
this['lcid'] = undefined;
this['useractionid'] = undefined;
this['useractionindex'] = undefined;
this['forcesave'] = undefined;
this['userdata'] = undefined;
this['formdata'] = undefined;
this['inline'] = undefined;//content disposition
this['inline'] = undefined; //content disposition
this['password'] = undefined;
this['savepassword'] = undefined;
this['withoutPassword'] = undefined;
@ -355,7 +355,7 @@ InputCommand.prototype = {
getJsonParams() {
return this['jsonparams'];
},
appendJsonParams (data) {
appendJsonParams(data) {
if (this['jsonparams']) {
config.util.extendDeep(this['jsonparams'], data);
} else {
@ -529,34 +529,34 @@ function CForceSaveData(obj) {
this['authoruserindex'] = null;
}
}
CForceSaveData.prototype.getType = function() {
return this['type']
CForceSaveData.prototype.getType = function () {
return this['type'];
};
CForceSaveData.prototype.setType = function(v) {
CForceSaveData.prototype.setType = function (v) {
this['type'] = v;
};
CForceSaveData.prototype.getTime = function() {
return this['time']
CForceSaveData.prototype.getTime = function () {
return this['time'];
};
CForceSaveData.prototype.setTime = function(v) {
CForceSaveData.prototype.setTime = function (v) {
this['time'] = v;
};
CForceSaveData.prototype.getIndex = function() {
return this['index']
CForceSaveData.prototype.getIndex = function () {
return this['index'];
};
CForceSaveData.prototype.setIndex = function(v) {
CForceSaveData.prototype.setIndex = function (v) {
this['index'] = v;
};
CForceSaveData.prototype.getAuthorUserId = function() {
CForceSaveData.prototype.getAuthorUserId = function () {
return this['authoruserid'];
};
CForceSaveData.prototype.setAuthorUserId = function(v) {
CForceSaveData.prototype.setAuthorUserId = function (v) {
this['authoruserid'] = v;
};
CForceSaveData.prototype.getAuthorUserIndex = function() {
CForceSaveData.prototype.getAuthorUserIndex = function () {
return this['authoruserindex'];
};
CForceSaveData.prototype.setAuthorUserIndex = function(v) {
CForceSaveData.prototype.setAuthorUserIndex = function (v) {
this['authoruserindex'] = v;
};
@ -575,34 +575,34 @@ function CThumbnailData(obj) {
this['height'] = null;
}
}
CThumbnailData.prototype.getFormat = function() {
return this['format']
CThumbnailData.prototype.getFormat = function () {
return this['format'];
};
CThumbnailData.prototype.setFormat = function(v) {
CThumbnailData.prototype.setFormat = function (v) {
this['format'] = v;
};
CThumbnailData.prototype.getAspect = function() {
return this['aspect']
CThumbnailData.prototype.getAspect = function () {
return this['aspect'];
};
CThumbnailData.prototype.setAspect = function(v) {
CThumbnailData.prototype.setAspect = function (v) {
this['aspect'] = v;
};
CThumbnailData.prototype.getFirst = function() {
return this['first']
CThumbnailData.prototype.getFirst = function () {
return this['first'];
};
CThumbnailData.prototype.setFirst = function(v) {
CThumbnailData.prototype.setFirst = function (v) {
this['first'] = v;
};
CThumbnailData.prototype.getWidth = function() {
return this['width']
CThumbnailData.prototype.getWidth = function () {
return this['width'];
};
CThumbnailData.prototype.setWidth = function(v) {
CThumbnailData.prototype.setWidth = function (v) {
this['width'] = v;
};
CThumbnailData.prototype.getHeight = function() {
return this['height']
CThumbnailData.prototype.getHeight = function () {
return this['height'];
};
CThumbnailData.prototype.setHeight = function(v) {
CThumbnailData.prototype.setHeight = function (v) {
this['height'] = v;
};
function CTextParams(obj) {
@ -612,10 +612,10 @@ function CTextParams(obj) {
this['association'] = null;
}
}
CTextParams.prototype.getAssociation = function() {
return this['association']
CTextParams.prototype.getAssociation = function () {
return this['association'];
};
CTextParams.prototype.setAssociation = function(v) {
CTextParams.prototype.setAssociation = function (v) {
this['association'] = v;
};
@ -635,7 +635,7 @@ function CMailMergeSendData(obj) {
this['url'] = obj['url'];
this['baseUrl'] = obj['baseUrl'];
this['jsonkey'] = obj['jsonkey'];
this['isJson'] = obj['isJson'];
this['isJson'] = obj['isJson'];
} else {
this['from'] = null;
this['to'] = null;
@ -651,97 +651,97 @@ function CMailMergeSendData(obj) {
this['url'] = null;
this['baseUrl'] = null;
this['jsonkey'] = null;
this['isJson'] = null;
this['isJson'] = null;
}
}
CMailMergeSendData.prototype.getFrom = function() {
return this['from']
CMailMergeSendData.prototype.getFrom = function () {
return this['from'];
};
CMailMergeSendData.prototype.setFrom = function(v) {
CMailMergeSendData.prototype.setFrom = function (v) {
this['from'] = v;
};
CMailMergeSendData.prototype.getTo = function() {
return this['to']
CMailMergeSendData.prototype.getTo = function () {
return this['to'];
};
CMailMergeSendData.prototype.setTo = function(v) {
CMailMergeSendData.prototype.setTo = function (v) {
this['to'] = v;
};
CMailMergeSendData.prototype.getSubject = function() {
return this['subject']
CMailMergeSendData.prototype.getSubject = function () {
return this['subject'];
};
CMailMergeSendData.prototype.setSubject = function(v) {
CMailMergeSendData.prototype.setSubject = function (v) {
this['subject'] = v;
};
CMailMergeSendData.prototype.getMailFormat = function() {
return this['mailFormat']
CMailMergeSendData.prototype.getMailFormat = function () {
return this['mailFormat'];
};
CMailMergeSendData.prototype.setMailFormat = function(v) {
CMailMergeSendData.prototype.setMailFormat = function (v) {
this['mailFormat'] = v;
};
CMailMergeSendData.prototype.getFileName = function() {
return this['fileName']
CMailMergeSendData.prototype.getFileName = function () {
return this['fileName'];
};
CMailMergeSendData.prototype.setFileName = function(v) {
CMailMergeSendData.prototype.setFileName = function (v) {
this['fileName'] = v;
};
CMailMergeSendData.prototype.getMessage = function() {
return this['message']
CMailMergeSendData.prototype.getMessage = function () {
return this['message'];
};
CMailMergeSendData.prototype.setMessage = function(v) {
CMailMergeSendData.prototype.setMessage = function (v) {
this['message'] = v;
};
CMailMergeSendData.prototype.getRecordFrom = function() {
return this['recordFrom']
CMailMergeSendData.prototype.getRecordFrom = function () {
return this['recordFrom'];
};
CMailMergeSendData.prototype.setRecordFrom = function(v) {
CMailMergeSendData.prototype.setRecordFrom = function (v) {
this['recordFrom'] = v;
};
CMailMergeSendData.prototype.getRecordTo = function() {
return this['recordTo']
CMailMergeSendData.prototype.getRecordTo = function () {
return this['recordTo'];
};
CMailMergeSendData.prototype.setRecordTo = function(v) {
CMailMergeSendData.prototype.setRecordTo = function (v) {
this['recordTo'] = v;
};
CMailMergeSendData.prototype.getRecordCount = function() {
return this['recordCount']
CMailMergeSendData.prototype.getRecordCount = function () {
return this['recordCount'];
};
CMailMergeSendData.prototype.setRecordCount = function(v) {
CMailMergeSendData.prototype.setRecordCount = function (v) {
this['recordCount'] = v;
};
CMailMergeSendData.prototype.getRecordErrorCount = function() {
return this['recordErrorCount']
CMailMergeSendData.prototype.getRecordErrorCount = function () {
return this['recordErrorCount'];
};
CMailMergeSendData.prototype.setRecordErrorCount = function(v) {
CMailMergeSendData.prototype.setRecordErrorCount = function (v) {
this['recordErrorCount'] = v;
};
CMailMergeSendData.prototype.getUserId = function() {
return this['userId']
CMailMergeSendData.prototype.getUserId = function () {
return this['userId'];
};
CMailMergeSendData.prototype.setUserId = function(v) {
CMailMergeSendData.prototype.setUserId = function (v) {
this['userId'] = v;
};
CMailMergeSendData.prototype.getUrl = function() {
return this['url']
CMailMergeSendData.prototype.getUrl = function () {
return this['url'];
};
CMailMergeSendData.prototype.setUrl = function(v) {
CMailMergeSendData.prototype.setUrl = function (v) {
this['url'] = v;
};
CMailMergeSendData.prototype.getBaseUrl = function() {
return this['baseUrl']
CMailMergeSendData.prototype.getBaseUrl = function () {
return this['baseUrl'];
};
CMailMergeSendData.prototype.setBaseUrl = function(v) {
CMailMergeSendData.prototype.setBaseUrl = function (v) {
this['baseUrl'] = v;
};
CMailMergeSendData.prototype.getJsonKey = function() {
return this['jsonkey']
CMailMergeSendData.prototype.getJsonKey = function () {
return this['jsonkey'];
};
CMailMergeSendData.prototype.setJsonKey = function(v) {
CMailMergeSendData.prototype.setJsonKey = function (v) {
this['jsonkey'] = v;
};
CMailMergeSendData.prototype.getIsJsonKey = function() {
return this['isJson']
CMailMergeSendData.prototype.getIsJsonKey = function () {
return this['isJson'];
};
CMailMergeSendData.prototype.setIsJsonKey = function(v) {
CMailMergeSendData.prototype.setIsJsonKey = function (v) {
this['isJson'] = v;
};
function TaskQueueData(data) {
@ -774,55 +774,55 @@ TaskQueueData.prototype = {
return this['ctx'];
},
setCtx(data) {
return this['ctx'] = data;
return (this['ctx'] = data);
},
getCmd() {
return this['cmd'];
},
setCmd(data) {
return this['cmd'] = data;
return (this['cmd'] = data);
},
getToFile() {
return this['toFile'];
},
setToFile(data) {
return this['toFile'] = data;
return (this['toFile'] = data);
},
getFromOrigin() {
return this['fromOrigin'];
},
setFromOrigin(data) {
return this['fromOrigin'] = data;
return (this['fromOrigin'] = data);
},
getFromSettings() {
return this['fromSettings'];
},
setFromSettings(data) {
return this['fromSettings'] = data;
return (this['fromSettings'] = data);
},
getFromChanges() {
return this['fromChanges'];
},
setFromChanges(data) {
return this['fromChanges'] = data;
return (this['fromChanges'] = data);
},
getPaid() {
return this['paid'];
},
setPaid(data) {
return this['paid'] = data;
return (this['paid'] = data);
},
getDataKey() {
return this['dataKey'];
},
setDataKey(data) {
return this['dataKey'] = data;
return (this['dataKey'] = data);
},
getVisibilityTimeout() {
return this['visibilityTimeout'];
},
setVisibilityTimeout(data) {
return this['visibilityTimeout'] = data;
return (this['visibilityTimeout'] = data);
}
};
@ -844,100 +844,100 @@ function OutputSfcData(key) {
this['token'] = undefined;
}
OutputSfcData.prototype.getKey = function() {
OutputSfcData.prototype.getKey = function () {
return this['key'];
};
OutputSfcData.prototype.setKey = function(data) {
return this['key'] = data;
OutputSfcData.prototype.setKey = function (data) {
return (this['key'] = data);
};
OutputSfcData.prototype.getStatus = function() {
OutputSfcData.prototype.getStatus = function () {
return this['status'];
};
OutputSfcData.prototype.setStatus = function(data) {
return this['status'] = data;
OutputSfcData.prototype.setStatus = function (data) {
return (this['status'] = data);
};
OutputSfcData.prototype.getUrl = function() {
OutputSfcData.prototype.getUrl = function () {
return this['url'];
};
OutputSfcData.prototype.setUrl = function(data) {
return this['url'] = data;
OutputSfcData.prototype.setUrl = function (data) {
return (this['url'] = data);
};
OutputSfcData.prototype.getExtName = function() {
OutputSfcData.prototype.getExtName = function () {
return this['filetype'];
};
OutputSfcData.prototype.setExtName = function(data) {
return this['filetype'] = data.substring(1);
OutputSfcData.prototype.setExtName = function (data) {
return (this['filetype'] = data.substring(1));
};
OutputSfcData.prototype.getChangeUrl = function() {
OutputSfcData.prototype.getChangeUrl = function () {
return this['changesurl'];
};
OutputSfcData.prototype.setChangeUrl = function(data) {
return this['changesurl'] = data;
OutputSfcData.prototype.setChangeUrl = function (data) {
return (this['changesurl'] = data);
};
OutputSfcData.prototype.getChangeHistory = function() {
OutputSfcData.prototype.getChangeHistory = function () {
return this['history'];
};
OutputSfcData.prototype.setChangeHistory = function(data) {
return this['history'] = data;
OutputSfcData.prototype.setChangeHistory = function (data) {
return (this['history'] = data);
};
OutputSfcData.prototype.getUsers = function() {
OutputSfcData.prototype.getUsers = function () {
return this['users'];
};
OutputSfcData.prototype.setUsers = function(data) {
return this['users'] = data;
OutputSfcData.prototype.setUsers = function (data) {
return (this['users'] = data);
};
OutputSfcData.prototype.getMailMerge = function() {
OutputSfcData.prototype.getMailMerge = function () {
return this['mailMerge'];
};
OutputSfcData.prototype.setMailMerge = function(data) {
return this['mailMerge'] = data;
OutputSfcData.prototype.setMailMerge = function (data) {
return (this['mailMerge'] = data);
};
OutputSfcData.prototype.getActions = function() {
OutputSfcData.prototype.getActions = function () {
return this['actions'];
};
OutputSfcData.prototype.setActions = function(data) {
return this['actions'] = data;
OutputSfcData.prototype.setActions = function (data) {
return (this['actions'] = data);
};
OutputSfcData.prototype.getUserData= function() {
OutputSfcData.prototype.getUserData = function () {
return this['userdata'];
};
OutputSfcData.prototype.setUserData = function(data) {
return this['userdata'] = data;
OutputSfcData.prototype.setUserData = function (data) {
return (this['userdata'] = data);
};
OutputSfcData.prototype.getFormsDataUrl= function() {
OutputSfcData.prototype.getFormsDataUrl = function () {
return this['formsdataurl'];
};
OutputSfcData.prototype.setFormsDataUrl = function(data) {
return this['formsdataurl'] = data;
OutputSfcData.prototype.setFormsDataUrl = function (data) {
return (this['formsdataurl'] = data);
};
OutputSfcData.prototype.getLastSave = function() {
return this['lastsave']
OutputSfcData.prototype.getLastSave = function () {
return this['lastsave'];
};
OutputSfcData.prototype.setLastSave = function(v) {
OutputSfcData.prototype.setLastSave = function (v) {
this['lastsave'] = v;
};
OutputSfcData.prototype.getNotModified = function() {
return this['notmodified']
OutputSfcData.prototype.getNotModified = function () {
return this['notmodified'];
};
OutputSfcData.prototype.setNotModified = function(v) {
OutputSfcData.prototype.setNotModified = function (v) {
this['notmodified'] = v;
};
OutputSfcData.prototype.getForceSaveType = function() {
return this['forcesavetype']
OutputSfcData.prototype.getForceSaveType = function () {
return this['forcesavetype'];
};
OutputSfcData.prototype.setForceSaveType = function(v) {
OutputSfcData.prototype.setForceSaveType = function (v) {
this['forcesavetype'] = v;
};
OutputSfcData.prototype.getEncrypted = function() {
return this['encrypted']
OutputSfcData.prototype.getEncrypted = function () {
return this['encrypted'];
};
OutputSfcData.prototype.setEncrypted = function(v) {
OutputSfcData.prototype.setEncrypted = function (v) {
this['encrypted'] = v;
};
OutputSfcData.prototype.getToken = function() {
return this['token']
OutputSfcData.prototype.getToken = function () {
return this['token'];
};
OutputSfcData.prototype.setToken = function(v) {
OutputSfcData.prototype.setToken = function (v) {
this['token'] = v;
};
@ -949,16 +949,16 @@ function OutputMailMerge(mailMergeSendData) {
this['title'] = mailMergeSendData.getFileName();
const mailFormat = mailMergeSendData.getMailFormat();
switch (mailFormat) {
case constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_HTML :
case constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_HTML:
this['type'] = 0;
break;
case constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX :
case constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX:
this['type'] = 1;
break;
case constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF :
case constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF:
this['type'] = 2;
break;
default :
default:
this['type'] = 0;
break;
}
@ -978,23 +978,23 @@ function OutputMailMerge(mailMergeSendData) {
this['recordErrorCount'] = null;
}
}
OutputMailMerge.prototype.getRecordIndex = function() {
OutputMailMerge.prototype.getRecordIndex = function () {
return this['recordIndex'];
};
OutputMailMerge.prototype.setRecordIndex = function(data) {
return this['recordIndex'] = data;
OutputMailMerge.prototype.setRecordIndex = function (data) {
return (this['recordIndex'] = data);
};
OutputMailMerge.prototype.getRecordErrorCount = function() {
OutputMailMerge.prototype.getRecordErrorCount = function () {
return this['recordErrorCount'];
};
OutputMailMerge.prototype.setRecordErrorCount = function(data) {
return this['recordErrorCount'] = data;
OutputMailMerge.prototype.setRecordErrorCount = function (data) {
return (this['recordErrorCount'] = data);
};
OutputMailMerge.prototype.getTo = function() {
OutputMailMerge.prototype.getTo = function () {
return this['to'];
};
OutputMailMerge.prototype.setTo = function(data) {
return this['to'] = data;
OutputMailMerge.prototype.setTo = function (data) {
return (this['to'] = data);
};
function OutputAction(type, userid) {
this['type'] = type;
@ -1007,22 +1007,22 @@ function ConvertStatus(err, url, filetype) {
this.filetype = filetype;
this.end = !!url;
}
ConvertStatus.prototype.setExtName = function(extname) {
ConvertStatus.prototype.setExtName = function (extname) {
this.filetype = extname.substring(1);
};
ConvertStatus.prototype.setUrl = function(url) {
ConvertStatus.prototype.setUrl = function (url) {
this.url = url;
this.end = true;
};
const c_oPublishType = {
drop : 0,
releaseLock : 1,
participantsState : 2,
message : 3,
getLock : 4,
changes : 5,
auth : 6,
receiveTask : 7,
drop: 0,
releaseLock: 1,
participantsState: 2,
message: 3,
getLock: 4,
changes: 5,
auth: 6,
receiveTask: 7,
warning: 8,
cursor: 9,
shutdown: 10,
@ -1043,79 +1043,132 @@ const c_oAscCsvDelimiter = {
Space: 5
};
const c_oAscEncodings = [
[ 0, 28596, "ISO-8859-6", "Arabic (ISO 8859-6)" ],
[ 1, 720, "DOS-720", "Arabic (OEM 720)" ],
[ 2, 1256, "windows-1256", "Arabic (Windows)" ],
[0, 28596, 'ISO-8859-6', 'Arabic (ISO 8859-6)'],
[1, 720, 'DOS-720', 'Arabic (OEM 720)'],
[2, 1256, 'windows-1256', 'Arabic (Windows)'],
[ 3, 28594, "ISO-8859-4", "Baltic (ISO 8859-4)" ],
[ 4, 28603, "ISO-8859-13", "Baltic (ISO 8859-13)" ],
[ 5, 775, "IBM775", "Baltic (OEM 775)" ],
[ 6, 1257, "windows-1257", "Baltic (Windows)" ],
[3, 28594, 'ISO-8859-4', 'Baltic (ISO 8859-4)'],
[4, 28603, 'ISO-8859-13', 'Baltic (ISO 8859-13)'],
[5, 775, 'IBM775', 'Baltic (OEM 775)'],
[6, 1257, 'windows-1257', 'Baltic (Windows)'],
[ 7, 28604, "ISO-8859-14", "Celtic (ISO 8859-14)" ],
[7, 28604, 'ISO-8859-14', 'Celtic (ISO 8859-14)'],
[ 8, 28595, "ISO-8859-5", "Cyrillic (ISO 8859-5)" ],
[ 9, 20866, "KOI8-R", "Cyrillic (KOI8-R)" ],
[ 10, 21866, "KOI8-U", "Cyrillic (KOI8-U)" ],
[ 11, 10007, "x-mac-cyrillic", "Cyrillic (Mac)" ],
[ 12, 855, "IBM855", "Cyrillic (OEM 855)" ],
[ 13, 866, "cp866", "Cyrillic (OEM 866)" ],
[ 14, 1251, "windows-1251", "Cyrillic (Windows)" ],
[8, 28595, 'ISO-8859-5', 'Cyrillic (ISO 8859-5)'],
[9, 20866, 'KOI8-R', 'Cyrillic (KOI8-R)'],
[10, 21866, 'KOI8-U', 'Cyrillic (KOI8-U)'],
[11, 10007, 'x-mac-cyrillic', 'Cyrillic (Mac)'],
[12, 855, 'IBM855', 'Cyrillic (OEM 855)'],
[13, 866, 'cp866', 'Cyrillic (OEM 866)'],
[14, 1251, 'windows-1251', 'Cyrillic (Windows)'],
[ 15, 852, "IBM852", "Central European (OEM 852)" ],
[ 16, 1250, "windows-1250", "Central European (Windows)" ],
[15, 852, 'IBM852', 'Central European (OEM 852)'],
[16, 1250, 'windows-1250', 'Central European (Windows)'],
[ 17, 950, "Big5", "Chinese (Big5 Traditional)" ],
[ 18, 936, "GB2312", "Central (GB2312 Simplified)" ],
[17, 950, 'Big5', 'Chinese (Big5 Traditional)'],
[18, 936, 'GB2312', 'Central (GB2312 Simplified)'],
[ 19, 28592, "ISO-8859-2", "Eastern European (ISO 8859-2)" ],
[19, 28592, 'ISO-8859-2', 'Eastern European (ISO 8859-2)'],
[ 20, 28597, "ISO-8859-7", "Greek (ISO 8859-7)" ],
[ 21, 737, "IBM737", "Greek (OEM 737)" ],
[ 22, 869, "IBM869", "Greek (OEM 869)" ],
[ 23, 1253, "windows-1253", "Greek (Windows)" ],
[20, 28597, 'ISO-8859-7', 'Greek (ISO 8859-7)'],
[21, 737, 'IBM737', 'Greek (OEM 737)'],
[22, 869, 'IBM869', 'Greek (OEM 869)'],
[23, 1253, 'windows-1253', 'Greek (Windows)'],
[ 24, 28598, "ISO-8859-8", "Hebrew (ISO 8859-8)" ],
[ 25, 862, "DOS-862", "Hebrew (OEM 862)" ],
[ 26, 1255, "windows-1255", "Hebrew (Windows)" ],
[24, 28598, 'ISO-8859-8', 'Hebrew (ISO 8859-8)'],
[25, 862, 'DOS-862', 'Hebrew (OEM 862)'],
[26, 1255, 'windows-1255', 'Hebrew (Windows)'],
[ 27, 932, "Shift_JIS", "Japanese (Shift-JIS)" ],
[27, 932, 'Shift_JIS', 'Japanese (Shift-JIS)'],
[ 28, 949, "KS_C_5601-1987", "Korean (Windows)" ],
[ 29, 51949, "EUC-KR", "Korean (EUC)" ],
[28, 949, 'KS_C_5601-1987', 'Korean (Windows)'],
[29, 51949, 'EUC-KR', 'Korean (EUC)'],
[ 30, 861, "IBM861", "North European (Icelandic OEM 861)" ],
[ 31, 865, "IBM865", "North European (Nordic OEM 865)" ],
[30, 861, 'IBM861', 'North European (Icelandic OEM 861)'],
[31, 865, 'IBM865', 'North European (Nordic OEM 865)'],
[ 32, 874, "windows-874", "Thai (TIS-620)" ],
[32, 874, 'windows-874', 'Thai (TIS-620)'],
[ 33, 28593, "ISO-8859-3", "Turkish (ISO 8859-3)" ],
[ 34, 28599, "ISO-8859-9", "Turkish (ISO 8859-9)" ],
[ 35, 857, "IBM857", "Turkish (OEM 857)" ],
[ 36, 1254, "windows-1254", "Turkish (Windows)" ],
[33, 28593, 'ISO-8859-3', 'Turkish (ISO 8859-3)'],
[34, 28599, 'ISO-8859-9', 'Turkish (ISO 8859-9)'],
[35, 857, 'IBM857', 'Turkish (OEM 857)'],
[36, 1254, 'windows-1254', 'Turkish (Windows)'],
[ 37, 28591, "ISO-8859-1", "Western European (ISO-8859-1)" ],
[ 38, 28605, "ISO-8859-15", "Western European (ISO-8859-15)" ],
[ 39, 850, "IBM850", "Western European (OEM 850)" ],
[ 40, 858, "IBM858", "Western European (OEM 858)" ],
[ 41, 860, "IBM860", "Western European (OEM 860 : Portuguese)" ],
[ 42, 863, "IBM863", "Western European (OEM 863 : French)" ],
[ 43, 437, "IBM437", "Western European (OEM-US)" ],
[ 44, 1252, "windows-1252", "Western European (Windows)" ],
[37, 28591, 'ISO-8859-1', 'Western European (ISO-8859-1)'],
[38, 28605, 'ISO-8859-15', 'Western European (ISO-8859-15)'],
[39, 850, 'IBM850', 'Western European (OEM 850)'],
[40, 858, 'IBM858', 'Western European (OEM 858)'],
[41, 860, 'IBM860', 'Western European (OEM 860 : Portuguese)'],
[42, 863, 'IBM863', 'Western European (OEM 863 : French)'],
[43, 437, 'IBM437', 'Western European (OEM-US)'],
[44, 1252, 'windows-1252', 'Western European (Windows)'],
[ 45, 1258, "windows-1258", "Vietnamese (Windows)" ],
[45, 1258, 'windows-1258', 'Vietnamese (Windows)'],
[ 46, 65001, "UTF-8", "Unicode (UTF-8)" ],
[ 47, 65000, "UTF-7", "Unicode (UTF-7)" ],
[46, 65001, 'UTF-8', 'Unicode (UTF-8)'],
[47, 65000, 'UTF-7', 'Unicode (UTF-7)'],
[ 48, 1200, "UTF-16", "Unicode (UTF-16)" ],
[ 49, 1201, "UTF-16BE", "Unicode (UTF-16 Big Endian)" ],
[48, 1200, 'UTF-16', 'Unicode (UTF-16)'],
[49, 1201, 'UTF-16BE', 'Unicode (UTF-16 Big Endian)'],
[ 50, 12000, "UTF-32", "Unicode (UTF-32)" ],
[ 51, 12001, "UTF-32BE", "Unicode (UTF-32 Big Endian)" ]
[50, 12000, 'UTF-32', 'Unicode (UTF-32)'],
[51, 12001, 'UTF-32BE', 'Unicode (UTF-32 Big Endian)']
];
const c_oAscEncodingsMap = {"437": 43, "720": 1, "737": 21, "775": 5, "850": 39, "852": 15, "855": 12, "857": 35, "858": 40, "860": 41, "861": 30, "862": 25, "863": 42, "865": 31, "866": 13, "869": 22, "874": 32, "932": 27, "936": 18, "949": 28, "950": 17, "1200": 48, "1201": 49, "1250": 16, "1251": 14, "1252": 44, "1253": 23, "1254": 36, "1255": 26, "1256": 2, "1257": 6, "1258": 45, "10007": 11, "12000": 50, "12001": 51, "20866": 9, "21866": 10, "28591": 37, "28592": 19, "28593": 33, "28594": 3, "28595": 8, "28596": 0, "28597": 20, "28598": 24, "28599": 34, "28603": 4, "28604": 7, "28605": 38, "51949": 29, "65000": 47, "65001": 46}
const c_oAscCodePageUtf8 = 46;//65001
const c_oAscEncodingsMap = {
437: 43,
720: 1,
737: 21,
775: 5,
850: 39,
852: 15,
855: 12,
857: 35,
858: 40,
860: 41,
861: 30,
862: 25,
863: 42,
865: 31,
866: 13,
869: 22,
874: 32,
932: 27,
936: 18,
949: 28,
950: 17,
1200: 48,
1201: 49,
1250: 16,
1251: 14,
1252: 44,
1253: 23,
1254: 36,
1255: 26,
1256: 2,
1257: 6,
1258: 45,
10007: 11,
12000: 50,
12001: 51,
20866: 9,
21866: 10,
28591: 37,
28592: 19,
28593: 33,
28594: 3,
28595: 8,
28596: 0,
28597: 20,
28598: 24,
28599: 34,
28603: 4,
28604: 7,
28605: 38,
51949: 29,
65000: 47,
65001: 46
};
const c_oAscCodePageUtf8 = 46; //65001
const c_oAscUserAction = {
Out: 0,
In: 1,

View File

@ -33,13 +33,13 @@
'use strict';
exports.DOC_ID_PATTERN = '0-9-.a-zA-Z_=';
exports.DOC_ID_REGEX = new RegExp("^[" + exports.DOC_ID_PATTERN + "]*$", 'i');
exports.DOC_ID_REPLACE_REGEX = new RegExp("[^" + exports.DOC_ID_PATTERN + "]", 'g');
exports.DOC_ID_SOCKET_PATTERN = new RegExp("^/doc/([" + exports.DOC_ID_PATTERN + "]*)/c.+", 'i');
exports.DOC_ID_REGEX = new RegExp('^[' + exports.DOC_ID_PATTERN + ']*$', 'i');
exports.DOC_ID_REPLACE_REGEX = new RegExp('[^' + exports.DOC_ID_PATTERN + ']', 'g');
exports.DOC_ID_SOCKET_PATTERN = new RegExp('^/doc/([' + exports.DOC_ID_PATTERN + ']*)/c.+', 'i');
exports.DOC_ID_MAX_LENGTH = 240;
exports.USER_ID_MAX_LENGTH = 240;//255-240=15 symbols to make user id unique
exports.USER_ID_MAX_LENGTH = 240; //255-240=15 symbols to make user id unique
exports.USER_NAME_MAX_LENGTH = 255;
exports.PASSWORD_MAX_LENGTH = 255;//set password limit for DoS protection with long password
exports.PASSWORD_MAX_LENGTH = 255; //set password limit for DoS protection with long password
exports.EXTENTION_REGEX = /^[a-zA-Z0-9]*$/;
exports.CHAR_DELIMITER = String.fromCharCode(5);
exports.OUTPUT_NAME = 'output';
@ -54,11 +54,11 @@ exports.SHARD_KEY_WOPI_NAME = 'WOPISrc';
exports.SHARD_KEY_API_NAME = 'shardkey';
exports.RIGHTS = {
None : 0,
Edit : 1,
Review : 2,
Comment : 3,
View : 4
None: 0,
Edit: 1,
Review: 2,
Comment: 3,
View: 4
};
exports.LICENSE_MODE = {
@ -69,16 +69,16 @@ exports.LICENSE_MODE = {
};
exports.LICENSE_RESULT = {
Error : 1,
Expired : 2,
Success : 3,
UnknownUser : 4,
Connections : 5,
ExpiredTrial : 6,
SuccessLimit : 7,
UsersCount : 8,
ConnectionsOS : 9,
UsersCountOS : 10,
Error: 1,
Expired: 2,
Success: 3,
UnknownUser: 4,
Connections: 5,
ExpiredTrial: 6,
SuccessLimit: 7,
UsersCount: 8,
ConnectionsOS: 9,
UsersCountOS: 10,
ExpiredLimited: 11,
ConnectionsLiveOS: 12,
ConnectionsLive: 13,
@ -91,7 +91,7 @@ exports.LICENSE_CONNECTIONS = 20;
exports.LICENSE_USERS = 3;
exports.LICENSE_EXPIRE_USERS_ONE_DAY = 24 * 60 * 60; // day in seconds
exports.AVS_OFFICESTUDIO_FILE_UNKNOWN = 0x0000;
exports.AVS_OFFICESTUDIO_FILE_UNKNOWN = 0x0000;
exports.AVS_OFFICESTUDIO_FILE_DOCUMENT = 0x0040;
exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0001;
exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOC = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0002;
@ -128,7 +128,7 @@ exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_POTM = exports.AVS_OFFICESTUDIO_FILE_
exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_ODP_FLAT = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0009;
exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_OTP = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x000a;
exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTX_PACKAGE = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x000b;
exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_ODG = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x000c;
exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_ODG = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x000c;
exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET = 0x0100;
exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSX = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0001;
@ -195,7 +195,7 @@ exports.AVS_OFFICESTUDIO_FILE_CANVAS_SPREADSHEET = exports.AVS_OFFICESTUDIO_FILE
exports.AVS_OFFICESTUDIO_FILE_CANVAS_PRESENTATION = exports.AVS_OFFICESTUDIO_FILE_CANVAS + 0x0003;
exports.AVS_OFFICESTUDIO_FILE_CANVAS_PDF = exports.AVS_OFFICESTUDIO_FILE_CANVAS + 0x0004;
exports.AVS_OFFICESTUDIO_FILE_DRAW = 0x4000;
exports.AVS_OFFICESTUDIO_FILE_DRAW = 0x4000;
exports.AVS_OFFICESTUDIO_FILE_DRAW_VSDX = exports.AVS_OFFICESTUDIO_FILE_DRAW + 0x0001;
exports.AVS_OFFICESTUDIO_FILE_DRAW_VSSX = exports.AVS_OFFICESTUDIO_FILE_DRAW + 0x0002;
exports.AVS_OFFICESTUDIO_FILE_DRAW_VSTX = exports.AVS_OFFICESTUDIO_FILE_DRAW + 0x0003;
@ -291,16 +291,16 @@ exports.NO_CACHE_CODE = 4009;
exports.NO_CACHE = 'no cache';
exports.RESTORE_CODE = 4010;
exports.RESTORE = 'restore';
exports.QUIET_CODE = 4011;//browser only
exports.QUIET_CODE = 4011; //browser only
exports.QUIET = 'quiet';
exports.RECONNECT_FAILED_CODE = 4012;//browser only
exports.RECONNECT_FAILED_CODE = 4012; //browser only
exports.RECONNECT_FAILED = 'reconnect failed';
//update connection error codes
exports.CONTENT_DISPOSITION_INLINE = 'inline';
exports.CONTENT_DISPOSITION_ATTACHMENT = 'attachment';
exports.CONN_CLOSED = "closed";
exports.CONN_CLOSED = 'closed';
exports.FILE_STATUS_OK = 'ok';
exports.FILE_STATUS_UPDATE_VERSION = 'updateversion';
@ -310,9 +310,9 @@ exports.ACTIVEMQ_TOPIC_PREFIX = 'topic://';
exports.TEMPLATES_DEFAULT_LOCALE = 'en-US';
exports.TEMPLATES_FOLDER_LOCALE_COLLISON_MAP = {
'en': 'en-US',
'pt': 'pt-BR',
'zh': 'zh-CH',
en: 'en-US',
pt: 'pt-BR',
zh: 'zh-CH',
'pt-PT': 'pt-PT',
'zh-TW': 'zh-TW'
};
@ -330,13 +330,4 @@ exports.TABLE_RESULT_SCHEMA = [
'password',
'additional'
];
exports.TABLE_CHANGES_SCHEMA = [
'tenant',
'id',
'change_id',
'user_id',
'user_id_original',
'user_name',
'change_data',
'change_date',
];
exports.TABLE_CHANGES_SCHEMA = ['tenant', 'id', 'change_id', 'user_id', 'user_id_original', 'user_name', 'change_data', 'change_date'];

View File

@ -33,7 +33,7 @@
'use strict';
var constants = require('./constants');
const {open} = require("node:fs/promises");
const {open} = require('node:fs/promises');
function getImageFormatBySignature(buffer) {
var length = buffer.length;
@ -42,7 +42,7 @@ function getImageFormatBySignature(buffer) {
//jpeg
// Hex: FF D8 FF
if ((3 <= length) && (0xFF == buffer[0]) && (0xD8 == buffer[1]) && (0xFF == buffer[2])) {
if (3 <= length && 0xff == buffer[0] && 0xd8 == buffer[1] && 0xff == buffer[2]) {
return constants.AVS_OFFICESTUDIO_FILE_IMAGE_JPG;
}
@ -55,12 +55,27 @@ function getImageFormatBySignature(buffer) {
//Hex (position 29): 00
//Hex (position 30): 00 || 01 || 02 || 03 || 04 || 05
//Hex (position 31): 00 00 00
if ((34 <= length) && (0x42 == buffer[0]) && (0x4D == buffer[1]) && (0x00 == buffer[6]) && (0x00 == buffer[7]) &&
(0x01 == buffer[26]) && (0x00 == buffer[27]) && ((0x00 == buffer[28]) || (0x01 == buffer[28]) ||
(0x04 == buffer[28]) || (0x08 == buffer[28]) || (0x10 == buffer[28]) || (0x18 == buffer[28]) ||
(0x20 == buffer[28])) && (0x00 == buffer[29]) && ((0x00 == buffer[30]) || (0x01 == buffer[30]) ||
(0x02 == buffer[30]) || (0x03 == buffer[30]) || (0x04 == buffer[30]) || (0x05 == buffer[30])) &&
(0x00 == buffer[31]) && (0x00 == buffer[32]) && (0x00 == buffer[33])) {
if (
34 <= length &&
0x42 == buffer[0] &&
0x4d == buffer[1] &&
0x00 == buffer[6] &&
0x00 == buffer[7] &&
0x01 == buffer[26] &&
0x00 == buffer[27] &&
(0x00 == buffer[28] ||
0x01 == buffer[28] ||
0x04 == buffer[28] ||
0x08 == buffer[28] ||
0x10 == buffer[28] ||
0x18 == buffer[28] ||
0x20 == buffer[28]) &&
0x00 == buffer[29] &&
(0x00 == buffer[30] || 0x01 == buffer[30] || 0x02 == buffer[30] || 0x03 == buffer[30] || 0x04 == buffer[30] || 0x05 == buffer[30]) &&
0x00 == buffer[31] &&
0x00 == buffer[32] &&
0x00 == buffer[33]
) {
return constants.AVS_OFFICESTUDIO_FILE_IMAGE_BMP;
}
@ -83,19 +98,44 @@ function getImageFormatBySignature(buffer) {
//png
//Hex: 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52
//ASCII: .PNG........IHDR
if ((16 <= length) && (0x89 == buffer[0]) && (0x50 == buffer[1]) && (0x4E == buffer[2]) && (0x47 == buffer[3]) &&
(0x0D == buffer[4]) && (0x0A == buffer[5]) && (0x1A == buffer[6]) && (0x0A == buffer[7]) &&
(0x00 == buffer[8]) && (0x00 == buffer[9]) && (0x00 == buffer[10]) && (0x0D == buffer[11]) &&
(0x49 == buffer[12]) && (0x48 == buffer[13]) && (0x44 == buffer[14]) && (0x52 == buffer[15])) {
if (
16 <= length &&
0x89 == buffer[0] &&
0x50 == buffer[1] &&
0x4e == buffer[2] &&
0x47 == buffer[3] &&
0x0d == buffer[4] &&
0x0a == buffer[5] &&
0x1a == buffer[6] &&
0x0a == buffer[7] &&
0x00 == buffer[8] &&
0x00 == buffer[9] &&
0x00 == buffer[10] &&
0x0d == buffer[11] &&
0x49 == buffer[12] &&
0x48 == buffer[13] &&
0x44 == buffer[14] &&
0x52 == buffer[15]
) {
return constants.AVS_OFFICESTUDIO_FILE_IMAGE_PNG;
}
//CR2
//Hex: 49 49 2A 00 10 00 00 00 43 52
//ASCII: II*.....CR
if ((10 <= length) && (0x49 == buffer[0]) && (0x49 == buffer[1]) && (0x2A == buffer[2]) &&
(0x00 == buffer[3]) && (0x10 == buffer[4]) && (0x00 == buffer[5]) && (0x00 == buffer[6]) &&
(0x00 == buffer[7]) && (0x43 == buffer[8]) && (0x52 == buffer[9])) {
if (
10 <= length &&
0x49 == buffer[0] &&
0x49 == buffer[1] &&
0x2a == buffer[2] &&
0x00 == buffer[3] &&
0x10 == buffer[4] &&
0x00 == buffer[5] &&
0x00 == buffer[6] &&
0x00 == buffer[7] &&
0x43 == buffer[8] &&
0x52 == buffer[9]
) {
return constants.AVS_OFFICESTUDIO_FILE_IMAGE_CR2;
}
@ -109,9 +149,11 @@ function getImageFormatBySignature(buffer) {
//Hex: 49 49 2A 00
//ASCII: II*
if (4 <= length) {
if (((0x49 == buffer[0]) && (0x49 == buffer[1]) && (0x2A == buffer[2]) && (0x00 == buffer[3])) ||
((0x4D == buffer[0]) && (0x4D == buffer[1]) && (0x00 == buffer[2]) && (0x2A == buffer[3])) ||
((0x49 == buffer[0]) && (0x49 == buffer[1]) && (0x2A == buffer[2]) && (0x00 == buffer[3]))) {
if (
(0x49 == buffer[0] && 0x49 == buffer[1] && 0x2a == buffer[2] && 0x00 == buffer[3]) ||
(0x4d == buffer[0] && 0x4d == buffer[1] && 0x00 == buffer[2] && 0x2a == buffer[3]) ||
(0x49 == buffer[0] && 0x49 == buffer[1] && 0x2a == buffer[2] && 0x00 == buffer[3])
) {
return constants.AVS_OFFICESTUDIO_FILE_IMAGE_TIFF;
}
}
@ -121,9 +163,10 @@ function getImageFormatBySignature(buffer) {
//or for Windows 3.x
//Hex: 01 00 09 00 00 03
if (6 <= length) {
if (((0xD7 == buffer[0]) && (0xCD == buffer[1]) && (0xC6 == buffer[2]) && (0x9A == buffer[3]) &&
(0x00 == buffer[4]) && (0x00 == buffer[5])) || ((0x01 == buffer[0]) && (0x00 == buffer[1]) &&
(0x09 == buffer[2]) && (0x00 == buffer[3]) && (0x00 == buffer[4]) && (0x03 == buffer[5]))) {
if (
(0xd7 == buffer[0] && 0xcd == buffer[1] && 0xc6 == buffer[2] && 0x9a == buffer[3] && 0x00 == buffer[4] && 0x00 == buffer[5]) ||
(0x01 == buffer[0] && 0x00 == buffer[1] && 0x09 == buffer[2] && 0x00 == buffer[3] && 0x00 == buffer[4] && 0x03 == buffer[5])
) {
return constants.AVS_OFFICESTUDIO_FILE_IMAGE_WMF;
}
}
@ -131,8 +174,17 @@ function getImageFormatBySignature(buffer) {
//emf ( http://wvware.sourceforge.net/caolan/ora-wmf.html )
//Hex: 01 00 00 00
//Hex (position 40): 20 45 4D 46
if ((44 <= length) && (0x01 == buffer[0]) && (0x00 == buffer[1]) && (0x00 == buffer[2]) && (0x00 == buffer[3]) &&
(0x20 == buffer[40]) && (0x45 == buffer[41]) && (0x4D == buffer[42]) && (0x46 == buffer[43])) {
if (
44 <= length &&
0x01 == buffer[0] &&
0x00 == buffer[1] &&
0x00 == buffer[2] &&
0x00 == buffer[3] &&
0x20 == buffer[40] &&
0x45 == buffer[41] &&
0x4d == buffer[42] &&
0x46 == buffer[43]
) {
return constants.AVS_OFFICESTUDIO_FILE_IMAGE_EMF;
}
@ -140,9 +192,12 @@ function getImageFormatBySignature(buffer) {
//Hex (position 0): 0A
//Hex (position 1): 00 || 01 || 02 || 03 || 04 || 05
//Hex (position 3): 01 || 02 || 04 || 08 ( Bytes per pixel )
if ((4 <= length) && (0x0A == buffer[0]) && (0x00 == buffer[1] || 0x01 == buffer[1] ||
0x02 == buffer[1] || 0x03 == buffer[1] || 0x04 == buffer[1] || 0x05 == buffer[1]) &&
(0x01 == buffer[3] || 0x02 == buffer[3] || 0x04 == buffer[3] || 0x08 == buffer[3])) {
if (
4 <= length &&
0x0a == buffer[0] &&
(0x00 == buffer[1] || 0x01 == buffer[1] || 0x02 == buffer[1] || 0x03 == buffer[1] || 0x04 == buffer[1] || 0x05 == buffer[1]) &&
(0x01 == buffer[3] || 0x02 == buffer[3] || 0x04 == buffer[3] || 0x08 == buffer[3])
) {
return constants.AVS_OFFICESTUDIO_FILE_IMAGE_PCX;
}
@ -154,17 +209,23 @@ function getImageFormatBySignature(buffer) {
//DATA TYPE 10-RUN-LENGTH ENCODED(RLE),TRUE-COLOR IMAGES : Hex (position 1) : 00 0A
//DATA TYPE 11-RUN-LENGTH ENCODED(RLE),BLACK AND WHITE IMAGES : Hex (position 1) : 00 0B
// + Bytes per pixel : Hex (position 16): 0x08 || 0x10 || 0x18 || 0x20
if ((17 <= length) && ((0x01 == buffer[1] && 0x01 == buffer[2]) || (0x00 == buffer[1] && 0x02 == buffer[2]) ||
(0x00 == buffer[1] && 0x03 == buffer[2]) || (0x01 == buffer[1] && 0x09 == buffer[2]) ||
(0x00 == buffer[1] && 0x0A == buffer[2]) || (0x00 == buffer[1] && 0x0B == buffer[2])) &&
(0x08 == buffer[16] || 0x10 == buffer[16] || 0x18 == buffer[16] || 0x20 == buffer[16])) {
if (
17 <= length &&
((0x01 == buffer[1] && 0x01 == buffer[2]) ||
(0x00 == buffer[1] && 0x02 == buffer[2]) ||
(0x00 == buffer[1] && 0x03 == buffer[2]) ||
(0x01 == buffer[1] && 0x09 == buffer[2]) ||
(0x00 == buffer[1] && 0x0a == buffer[2]) ||
(0x00 == buffer[1] && 0x0b == buffer[2])) &&
(0x08 == buffer[16] || 0x10 == buffer[16] || 0x18 == buffer[16] || 0x20 == buffer[16])
) {
return constants.AVS_OFFICESTUDIO_FILE_IMAGE_TGA;
}
//ras
//Hex: 59 A6 6A 95
//ASCII: Y
if ((4 <= length) && (0x59 == buffer[0]) && (0xA6 == buffer[1]) && (0x6A == buffer[2]) && (0x95 == buffer[3])) {
if (4 <= length && 0x59 == buffer[0] && 0xa6 == buffer[1] && 0x6a == buffer[2] && 0x95 == buffer[3]) {
return constants.AVS_OFFICESTUDIO_FILE_IMAGE_RAS;
}
@ -174,10 +235,22 @@ function getImageFormatBySignature(buffer) {
//psd
//Hex: 38 42 50 53 00 01 00 00 00 00 00 00 00
//ASCII: 8BPS
if ((13 <= length) && (0x38 == buffer[0]) && (0x42 == buffer[1]) && (0x50 == buffer[2]) &&
(0x53 == buffer[3]) && (0x00 == buffer[4]) && (0x01 == buffer[5]) && (0x00 == buffer[6]) &&
(0x00 == buffer[7]) && (0x00 == buffer[8]) && (0x00 == buffer[9]) && (0x00 == buffer[10]) &&
(0x00 == buffer[11]) && (0x00 == buffer[12])) {
if (
13 <= length &&
0x38 == buffer[0] &&
0x42 == buffer[1] &&
0x50 == buffer[2] &&
0x53 == buffer[3] &&
0x00 == buffer[4] &&
0x01 == buffer[5] &&
0x00 == buffer[6] &&
0x00 == buffer[7] &&
0x00 == buffer[8] &&
0x00 == buffer[9] &&
0x00 == buffer[10] &&
0x00 == buffer[11] &&
0x00 == buffer[12]
) {
return constants.AVS_OFFICESTUDIO_FILE_IMAGE_PSD;
}
@ -195,7 +268,7 @@ function getImageFormatBySignature(buffer) {
return constants.AVS_OFFICESTUDIO_FILE_UNKNOWN;
}
exports.getFormatFromString = function(ext) {
exports.getFormatFromString = function (ext) {
if (!ext) {
return constants.AVS_OFFICESTUDIO_FILE_UNKNOWN;
}
@ -356,7 +429,7 @@ exports.getFormatFromString = function(ext) {
return constants.AVS_OFFICESTUDIO_FILE_UNKNOWN;
}
};
exports.getStringFromFormat = function(format) {
exports.getStringFromFormat = function (format) {
switch (format) {
case constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX:
return 'docx';
@ -535,62 +608,71 @@ exports.getStringFromFormat = function(format) {
return '';
}
};
exports.getImageFormat = function(ctx, buffer) {
exports.getImageFormat = function (ctx, buffer) {
var format = constants.AVS_OFFICESTUDIO_FILE_UNKNOWN;
try {
//signature
format = getImageFormatBySignature(buffer);
}
catch (e) {
} catch (e) {
ctx.logger.error('error getImageFormat: %s', e.stack);
}
return format;
};
exports.isDocumentFormat = function(format) {
return 0 !== (format & constants.AVS_OFFICESTUDIO_FILE_DOCUMENT) ||
exports.isDocumentFormat = function (format) {
return (
0 !== (format & constants.AVS_OFFICESTUDIO_FILE_DOCUMENT) ||
format === constants.AVS_OFFICESTUDIO_FILE_CANVAS_WORD ||
format === constants.AVS_OFFICESTUDIO_FILE_TEAMLAB_DOCY;
format === constants.AVS_OFFICESTUDIO_FILE_TEAMLAB_DOCY
);
};
exports.isSpreadsheetFormat = function(format) {
return 0 !== (format & constants.AVS_OFFICESTUDIO_FILE_SPREADSHEET) ||
exports.isSpreadsheetFormat = function (format) {
return (
0 !== (format & constants.AVS_OFFICESTUDIO_FILE_SPREADSHEET) ||
format === constants.AVS_OFFICESTUDIO_FILE_CANVAS_SPREADSHEET ||
format === constants.AVS_OFFICESTUDIO_FILE_TEAMLAB_XLSY;
format === constants.AVS_OFFICESTUDIO_FILE_TEAMLAB_XLSY
);
};
exports.isPresentationFormat = function(format) {
return 0 !== (format & constants.AVS_OFFICESTUDIO_FILE_PRESENTATION) ||
exports.isPresentationFormat = function (format) {
return (
0 !== (format & constants.AVS_OFFICESTUDIO_FILE_PRESENTATION) ||
format === constants.AVS_OFFICESTUDIO_FILE_CANVAS_PRESENTATION ||
format === constants.AVS_OFFICESTUDIO_FILE_TEAMLAB_PPTY;
format === constants.AVS_OFFICESTUDIO_FILE_TEAMLAB_PPTY
);
};
exports.isOOXFormat = function(format) {
return constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX === format
|| constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCM === format
|| constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOTX === format
|| constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOTM === format
|| constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_OFORM === format
|| constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCXF === format
|| constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_OFORM_PDF === format
|| constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTX === format
|| constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPSX === format
|| constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTM === format
|| constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPSM === format
|| constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_POTX === format
|| constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_POTM === format
|| constants.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSX === format
|| constants.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSM === format
|| constants.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLTX === format
|| constants.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLTM === format;
exports.isOOXFormat = function (format) {
return (
constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX === format ||
constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCM === format ||
constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOTX === format ||
constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOTM === format ||
constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_OFORM === format ||
constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCXF === format ||
constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_OFORM_PDF === format ||
constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTX === format ||
constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPSX === format ||
constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTM === format ||
constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPSM === format ||
constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_POTX === format ||
constants.AVS_OFFICESTUDIO_FILE_PRESENTATION_POTM === format ||
constants.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSX === format ||
constants.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSM === format ||
constants.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLTX === format ||
constants.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLTM === format
);
};
exports.isBrowserEditorFormat = function(format) {
return constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF === format ||
exports.isBrowserEditorFormat = function (format) {
return (
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF === format ||
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA === format ||
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_DJVU === format ||
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_XPS === format;
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_XPS === format
);
};
function getDocumentFormatBySignature(buffer) {
if (!buffer) {
return constants.AVS_OFFICESTUDIO_FILE_UNKNOWN;
}
const text = buffer.toString("latin1");
const text = buffer.toString('latin1');
// Check for binary DOCT format.
if (4 <= text.length && text[0] === 'D' && text[1] === 'O' && text[2] === 'C' && text[3] === 'Y') {
return constants.AVS_OFFICESTUDIO_FILE_CANVAS_WORD;
@ -608,14 +690,14 @@ function getDocumentFormatBySignature(buffer) {
// Unknown format
return constants.AVS_OFFICESTUDIO_FILE_UNKNOWN;
};
}
async function getDocumentFormatByFile(file) {
const firstBytesLen = 100;
let buffer;
let fd;
try {
fd = await open(file, 'r');
const stream = fd.createReadStream({ start: 0, end: firstBytesLen });
const stream = fd.createReadStream({start: 0, end: firstBytesLen});
const chunks = [];
for await (const chunk of stream) {
chunks.push(Buffer.from(chunk));
@ -625,6 +707,6 @@ async function getDocumentFormatByFile(file) {
await fd?.close();
}
return getDocumentFormatBySignature(buffer);
};
}
exports.getDocumentFormatBySignature = getDocumentFormatBySignature;
exports.getDocumentFormatByFile = getDocumentFormatByFile
exports.getDocumentFormatByFile = getDocumentFormatByFile;

View File

@ -38,30 +38,33 @@ const buildDate = '6/29/2016';
const oBuildDate = new Date(buildDate);
exports.readLicense = async function () {
const c_LR = constants.LICENSE_RESULT;
var now = new Date();
var startDate = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));//first day of current month
return [{
count: 1,
type: c_LR.Success,
packageType: constants.PACKAGE_TYPE_OS,
mode: constants.LICENSE_MODE.None,
branding: false,
connections: constants.LICENSE_CONNECTIONS,
connectionsView: constants.LICENSE_CONNECTIONS,
customization: false,
advancedApi: false,
usersCount: 0,
usersViewCount: 0,
usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY,
hasLicense: false,
buildDate: oBuildDate,
startDate,
endDate: null,
customerId: "",
alias: "",
multitenancy: false
}, null];
const c_LR = constants.LICENSE_RESULT;
var now = new Date();
var startDate = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1)); //first day of current month
return [
{
count: 1,
type: c_LR.Success,
packageType: constants.PACKAGE_TYPE_OS,
mode: constants.LICENSE_MODE.None,
branding: false,
connections: constants.LICENSE_CONNECTIONS,
connectionsView: constants.LICENSE_CONNECTIONS,
customization: false,
advancedApi: false,
usersCount: 0,
usersViewCount: 0,
usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY,
hasLicense: false,
buildDate: oBuildDate,
startDate,
endDate: null,
customerId: '',
alias: '',
multitenancy: false
},
null
];
};
exports.packageType = constants.PACKAGE_TYPE_OS;

View File

@ -41,25 +41,23 @@ var log4js = require('log4js');
var dateToJSONWithTZ = function (d) {
var timezoneOffsetInHours = -(d.getTimezoneOffset() / 60); //UTC minus local time
var sign = timezoneOffsetInHours >= 0 ? '+' : '-';
var leadingZero = (Math.abs(timezoneOffsetInHours) < 10) ? '0' : '';
var leadingZero = Math.abs(timezoneOffsetInHours) < 10 ? '0' : '';
//It's a bit unfortunate that we need to construct a new Date instance
//(we don't want _d_ Date instance to be modified)
var correctedDate = new Date(d.getFullYear(), d.getMonth(),
d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(),
d.getMilliseconds());
var correctedDate = new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
correctedDate.setHours(d.getHours() + timezoneOffsetInHours);
var iso = correctedDate.toISOString().replace('Z', '');
return iso + sign + leadingZero + Math.abs(timezoneOffsetInHours).toString() + ':00';
};
log4js.addLayout('json', (_config) => {
return function(logEvent) {
logEvent['startTime'] = dateToJSONWithTZ(logEvent['startTime']);
logEvent['message'] = util.format(...logEvent['data']);
delete logEvent['data'];
return JSON.stringify(logEvent);
}
log4js.addLayout('json', _config => {
return function (logEvent) {
logEvent['startTime'] = dateToJSONWithTZ(logEvent['startTime']);
logEvent['message'] = util.format(...logEvent['data']);
delete logEvent['data'];
return JSON.stringify(logEvent);
};
});
log4js.configure(config.get('log.filePath'));
@ -67,33 +65,33 @@ log4js.configure(config.get('log.filePath'));
var logger = log4js.getLogger('nodeJS');
if (config.get('log.options.replaceConsole')) {
console.log = logger.info.bind(logger);
console.info = logger.info.bind(logger);
console.warn = logger.warn.bind(logger);
console.error = logger.error.bind(logger);
console.debug = logger.debug.bind(logger);
console.log = logger.info.bind(logger);
console.info = logger.info.bind(logger);
console.warn = logger.warn.bind(logger);
console.error = logger.error.bind(logger);
console.debug = logger.debug.bind(logger);
}
exports.getLogger = function (){
return log4js.getLogger.apply(log4js, Array.prototype.slice.call(arguments));
exports.getLogger = function () {
return log4js.getLogger.apply(log4js, Array.prototype.slice.call(arguments));
};
exports.trace = function (){
return logger.trace.apply(logger, Array.prototype.slice.call(arguments));
exports.trace = function () {
return logger.trace.apply(logger, Array.prototype.slice.call(arguments));
};
exports.debug = function (){
return logger.debug.apply(logger, Array.prototype.slice.call(arguments));
exports.debug = function () {
return logger.debug.apply(logger, Array.prototype.slice.call(arguments));
};
exports.info = function (){
return logger.info.apply(logger, Array.prototype.slice.call(arguments));
exports.info = function () {
return logger.info.apply(logger, Array.prototype.slice.call(arguments));
};
exports.warn = function (){
return logger.warn.apply(logger, Array.prototype.slice.call(arguments));
exports.warn = function () {
return logger.warn.apply(logger, Array.prototype.slice.call(arguments));
};
exports.error = function (){
return logger.error.apply(logger, Array.prototype.slice.call(arguments));
exports.error = function () {
return logger.error.apply(logger, Array.prototype.slice.call(arguments));
};
exports.fatal = function (){
return logger.fatal.apply(logger, Array.prototype.slice.call(arguments));
exports.fatal = function () {
return logger.fatal.apply(logger, Array.prototype.slice.call(arguments));
};
exports.shutdown = function (callback) {
return log4js.shutdown(callback);
return log4js.shutdown(callback);
};

View File

@ -64,7 +64,13 @@ function createTransporter(ctx, host, port, auth, messageCommonParameters = {})
const transporter = nodemailer.createTransport(transport, messageCommonParameters);
smtpTransporters.set(`${host}:${auth.user}`, transporter);
} catch (error) {
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);
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
);
}
}
@ -99,4 +105,3 @@ module.exports = {
deleteTransporter,
transportersRelease
};

View File

@ -98,7 +98,7 @@ class Transport {
break;
case 'telegram':
this.transport = new TelegramTransport(ctx);
break
break;
default:
ctx.logger.warn(`Notification service: error: transport method "${transportName}" not implemented`);
}
@ -108,7 +108,7 @@ class Transport {
async function notify(ctx, notificationType, title, message, opt_cacheKey = undefined) {
const tenRule = ctx.getCfg(`notification.rules.${notificationType}`, config.get(`notification.rules.${notificationType}`));
if (tenRule?.enable) {
ctx.logger.debug('Notification service: notify "%s"', notificationType);
ctx.logger.debug('Notification service: notify "%s"', notificationType);
const checkRes = await checkRulePolicies(ctx, notificationType, tenRule, opt_cacheKey);
if (checkRes) {
await notifyRule(ctx, tenRule, title, message);
@ -117,9 +117,9 @@ async function notify(ctx, notificationType, title, message, opt_cacheKey = unde
}
async function checkRulePolicies(ctx, notificationType, tenRule, opt_cacheKey) {
const { repeatInterval } = tenRule.policies;
const {repeatInterval} = tenRule.policies;
//decrease repeatInterval by 1% to avoid race condition if timeout=repeatInterval
const ttl = Math.floor(ms(repeatInterval) * 0.99 / 1000);
const ttl = Math.floor((ms(repeatInterval) * 0.99) / 1000);
let isLock = false;
//todo for compatibility remove if after 8.2
if (editorStat?.lockNotification) {

View File

@ -39,11 +39,11 @@ const constants = require('./constants');
const tenantManager = require('./tenantManager');
const runtimeConfigManager = require('./runtimeConfigManager');
function Context(){
function Context() {
this.logger = logger.getLogger('nodeJS');
this.initDefault();
}
Context.prototype.init = function(tenant, docId, userId, opt_shardKey, opt_WopiSrc) {
Context.prototype.init = function (tenant, docId, userId, opt_shardKey, opt_WopiSrc) {
this.setTenant(tenant);
this.setDocId(docId);
this.setUserId(userId);
@ -56,10 +56,10 @@ Context.prototype.init = function(tenant, docId, userId, opt_shardKey, opt_WopiS
//cache
this.taskResultCache = null;
};
Context.prototype.initDefault = function() {
Context.prototype.initDefault = function () {
this.init(tenantManager.getDefautTenant(), constants.DEFAULT_DOC_ID, constants.DEFAULT_USER_ID, undefined);
};
Context.prototype.initFromConnection = function(conn) {
Context.prototype.initFromConnection = function (conn) {
const tenant = tenantManager.getTenantByConnection(this, conn);
let docId = conn.docid;
if (!docId) {
@ -74,21 +74,21 @@ Context.prototype.initFromConnection = function(conn) {
const wopiSrc = utils.getWopiSrcByConnection(this, conn);
this.init(tenant, docId || this.docId, userId || this.userId, shardKey, wopiSrc);
};
Context.prototype.initFromRequest = function(req) {
Context.prototype.initFromRequest = function (req) {
const tenant = tenantManager.getTenantByRequest(this, req);
const shardKey = utils.getShardKeyByRequest(this, req);
const wopiSrc = utils.getWopiSrcByRequest(this, req);
this.init(tenant, this.docId, this.userId, shardKey, wopiSrc);
};
Context.prototype.initFromTaskQueueData = function(task) {
Context.prototype.initFromTaskQueueData = function (task) {
const ctx = task.getCtx();
this.init(ctx.tenant, ctx.docId, ctx.userId, ctx.shardKey, ctx.wopiSrc);
};
Context.prototype.initFromPubSub = function(data) {
Context.prototype.initFromPubSub = function (data) {
const ctx = data.ctx;
this.init(ctx.tenant, ctx.docId, ctx.userId, ctx.shardKey, ctx.wopiSrc);
};
Context.prototype.initTenantCache = async function() {
Context.prototype.initTenantCache = async function () {
const runtimeConfig = await runtimeConfigManager.getConfig(this);
const tenantConfig = await tenantManager.getTenantConfig(this);
this.config = utils.deepMergeObjects({}, runtimeConfig, tenantConfig);
@ -96,35 +96,35 @@ Context.prototype.initTenantCache = async function() {
//todo license and secret
};
Context.prototype.setTenant = function(tenant) {
Context.prototype.setTenant = function (tenant) {
this.tenant = tenant;
this.logger.addContext('TENANT', tenant);
};
Context.prototype.setDocId = function(docId) {
Context.prototype.setDocId = function (docId) {
this.docId = docId;
this.logger.addContext('DOCID', docId);
};
Context.prototype.setUserId = function(userId) {
Context.prototype.setUserId = function (userId) {
this.userId = userId;
this.logger.addContext('USERID', userId);
};
Context.prototype.setShardKey = function(shardKey) {
Context.prototype.setShardKey = function (shardKey) {
this.shardKey = shardKey;
};
Context.prototype.setWopiSrc = function(wopiSrc) {
Context.prototype.setWopiSrc = function (wopiSrc) {
this.wopiSrc = wopiSrc;
};
Context.prototype.toJSON = function() {
Context.prototype.toJSON = function () {
return {
tenant: this.tenant,
docId: this.docId,
userId: this.userId,
shardKey: this.shardKey,
wopiSrc: this.wopiSrc
}
};
};
Context.prototype.getCfg = function(property, defaultValue) {
if (this.config){
Context.prototype.getCfg = function (property, defaultValue) {
if (this.config) {
return getImpl(this.config, property) ?? defaultValue;
}
return defaultValue;
@ -133,7 +133,7 @@ Context.prototype.getCfg = function(property, defaultValue) {
* Get the full configuration by combining system config with context config
* @returns {object} The merged configuration object
*/
Context.prototype.getFullCfg = function() {
Context.prototype.getFullCfg = function () {
return utils.deepMergeObjects(config.util.toObject(), this.config);
};
@ -159,7 +159,7 @@ function getImpl(object, property) {
return undefined;
}
return getImpl(value, elems.slice(1));
};
}
exports.Context = Context;
exports.global = new Context();

View File

@ -48,10 +48,10 @@ function connetPromise(closeCallback) {
operationContext.global.logger.error('[AMQP] %s', err.stack);
setTimeout(startConnect, RECONNECT_TIMEOUT);
} else {
conn.on('error', (err) => {
conn.on('error', err => {
operationContext.global.logger.error('[AMQP] conn error', err.stack);
});
var closeEventCallback = function() {
var closeEventCallback = function () {
//in some case receive multiple close events
conn.removeListener('close', closeEventCallback);
operationContext.global.logger.debug('[AMQP] conn close');
@ -123,7 +123,7 @@ function consumePromise(channel, queue, messageCallback, options) {
}
function closePromise(conn) {
return new Promise((resolve, reject) => {
conn.close((err) => {
conn.close(err => {
if (err) {
reject(err);
} else {

View File

@ -35,7 +35,7 @@
const fs = require('fs/promises');
const path = require('path');
const config = require('config');
const NodeCache = require("node-cache");
const NodeCache = require('node-cache');
const operationContext = require('./operationContext');
const utils = require('./utils');
@ -89,7 +89,7 @@ async function saveConfig(ctx, config) {
if (!configFilePath) {
throw new Error('runtimeConfig.filePath is not specified');
}
await fs.mkdir(path.dirname(configFilePath), { recursive: true });
await fs.mkdir(path.dirname(configFilePath), {recursive: true});
let newConfig = await getConfig(ctx);
newConfig = utils.deepMergeObjects(newConfig || {}, config);
await fs.writeFile(configFilePath, JSON.stringify(newConfig, null, 2), 'utf8');

View File

@ -41,10 +41,10 @@ var cfgStatsDPort = configStatsD.get('port');
var cfgStatsDPrefix = configStatsD.get('prefix');
var clientStatsD = null;
if(cfgStatsDUseMetrics) {
clientStatsD = new statsD({host: cfgStatsDHost, port:cfgStatsDPort, prefix: cfgStatsDPrefix});
if (cfgStatsDUseMetrics) {
clientStatsD = new statsD({host: cfgStatsDHost, port: cfgStatsDPort, prefix: cfgStatsDPrefix});
}
exports.getClient = function() {
exports.getClient = function () {
return clientStatsD;
};

View File

@ -1,7 +1,7 @@
'use strict';
const fs = require('fs');
const path = require('path');
const { BlobServiceClient, StorageSharedKeyCredential, generateBlobSASQueryParameters, BlobSASPermissions } = require('@azure/storage-blob');
const {BlobServiceClient, StorageSharedKeyCredential, generateBlobSASQueryParameters, BlobSASPermissions} = require('@azure/storage-blob');
const mime = require('mime');
const config = require('config');
const utils = require('../utils');
@ -22,17 +22,12 @@ const blobServiceClients = {};
function getBlobServiceClient(storageCfg) {
const configKey = `${storageCfg.accessKeyId}_${storageCfg.bucketName}`;
if (!blobServiceClients[configKey]) {
const credential = new StorageSharedKeyCredential(
storageCfg.accessKeyId,
storageCfg.secretAccessKey
);
const credential = new StorageSharedKeyCredential(storageCfg.accessKeyId, storageCfg.secretAccessKey);
if (storageCfg.endpoint.includes(storageCfg.accessKeyId)) {
blobServiceClients[configKey] = new BlobServiceClient(storageCfg.endpoint, credential);
} else {
const endpointUrl = new URL(storageCfg.endpoint.replace(/\/+$/, ''));
blobServiceClients[configKey] = new BlobServiceClient(
`${endpointUrl.protocol}//${storageCfg.accessKeyId}.${endpointUrl.host}`,
credential);
blobServiceClients[configKey] = new BlobServiceClient(`${endpointUrl.protocol}//${storageCfg.accessKeyId}.${endpointUrl.host}`, credential);
}
}
return blobServiceClients[configKey];
@ -79,8 +74,7 @@ async function listObjectsExec(storageCfg, prefix, output = []) {
const prefixWithFolder = storageFolderName ? `${storageFolderName}/${prefix}` : prefix;
for await (const blob of containerClient.listBlobsFlat({prefix: prefixWithFolder})) {
const relativePath = storageFolderName ?
blob.name.substring(storageFolderName.length + 1) : blob.name;
const relativePath = storageFolderName ? blob.name.substring(storageFolderName.length + 1) : blob.name;
output.push(relativePath);
}
return output;
@ -88,9 +82,7 @@ async function listObjectsExec(storageCfg, prefix, output = []) {
async function deleteObjectsHelp(storageCfg, aKeys) {
const containerClient = getContainerClient(storageCfg);
await Promise.all(
aKeys.map(key => containerClient.deleteBlob(key.Key))
);
await Promise.all(aKeys.map(key => containerClient.deleteBlob(key.Key)));
}
async function headObject(storageCfg, strPath) {
@ -138,29 +130,27 @@ async function uploadObject(storageCfg, strPath, filePath) {
const blockBlobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath));
const uploadStream = fs.createReadStream(filePath);
await blockBlobClient.uploadStream(
uploadStream,
undefined,
undefined,
{
blobHTTPHeaders: {
contentType: mime.getType(strPath),
contentDisposition: utils.getContentDisposition(path.basename(strPath))
}
await blockBlobClient.uploadStream(uploadStream, undefined, undefined, {
blobHTTPHeaders: {
contentType: mime.getType(strPath),
contentDisposition: utils.getContentDisposition(path.basename(strPath))
}
);
});
}
async function copyObject(storageCfgSrc, storageCfgDst, sourceKey, destinationKey) {
const sourceBlobClient = getBlobClient(storageCfgSrc, getFilePath(storageCfgSrc, sourceKey));
const destBlobClient = getBlobClient(storageCfgDst, getFilePath(storageCfgDst, destinationKey));
const sasToken = generateBlobSASQueryParameters({
containerName: storageCfgSrc.bucketName,
blobName: getFilePath(storageCfgSrc, sourceKey),
permissions: BlobSASPermissions.parse("r"),
startsOn: new Date(),
expiresOn: new Date(Date.now() + 3600 * 1000)
}, new StorageSharedKeyCredential(storageCfgSrc.accessKeyId, storageCfgSrc.secretAccessKey)).toString();
const sasToken = generateBlobSASQueryParameters(
{
containerName: storageCfgSrc.bucketName,
blobName: getFilePath(storageCfgSrc, sourceKey),
permissions: BlobSASPermissions.parse('r'),
startsOn: new Date(),
expiresOn: new Date(Date.now() + 3600 * 1000)
},
new StorageSharedKeyCredential(storageCfgSrc.accessKeyId, storageCfgSrc.secretAccessKey)
).toString();
await destBlobClient.syncCopyFromURL(`${sourceBlobClient.url}?${sasToken}`);
}
@ -191,13 +181,13 @@ async function getDirectSignedUrl(ctx, storageCfg, baseUrl, strPath, urlType, op
let expires = (commonDefines.c_oAscUrlTypes.Session === urlType ? cfgExpSessionAbsolute / 1000 : storageUrlExpires) || 31536000;
expires = Math.min(expires, 604800);
const userFriendlyName = optFilename ? optFilename.replace(/\//g, "%2f") : path.basename(strPath);
const userFriendlyName = optFilename ? optFilename.replace(/\//g, '%2f') : path.basename(strPath);
const contentDisposition = utils.getContentDisposition(userFriendlyName, null, null);
const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath));
const sasOptions = {
permissions: BlobSASPermissions.parse("r"),
permissions: BlobSASPermissions.parse('r'),
expiresOn: new Date(Date.now() + expires * 1000),
contentDisposition,
contentType: mime.getType(strPath)

View File

@ -59,10 +59,10 @@ function getStoragePath(ctx, strPath, opt_specialDir) {
return opt_specialDir + '/' + tenantManager.getTenantPathPrefix(ctx) + strPath.replace(/\\/g, '/');
}
function getStorage(opt_specialDir) {
return (opt_specialDir && opt_specialDir !== cfgCacheStorage.cacheFolderName) ? persistentStorage : cacheStorage;
return opt_specialDir && opt_specialDir !== cfgCacheStorage.cacheFolderName ? persistentStorage : cacheStorage;
}
function getStorageCfg(ctx, opt_specialDir) {
return (opt_specialDir && opt_specialDir !== cfgCacheStorage.cacheFolderName) ? cfgPersistentStorage : cfgCacheStorage;
return opt_specialDir && opt_specialDir !== cfgCacheStorage.cacheFolderName ? cfgPersistentStorage : cfgCacheStorage;
}
function canCopyBetweenStorage(storageCfgSrc, storageCfgDst) {
return storageCfgSrc.name === storageCfgDst.name && storageCfgSrc.endpoint === storageCfgDst.endpoint;
@ -102,7 +102,7 @@ async function copyObject(ctx, sourceKey, destinationKey, opt_specialDirSrc, opt
const storagePathDst = getStoragePath(ctx, destinationKey, opt_specialDirDst);
const storageCfgSrc = getStorageCfg(ctx, opt_specialDirSrc);
const storageCfgDst = getStorageCfg(ctx, opt_specialDirDst);
if (canCopyBetweenStorage(storageCfgSrc, storageCfgDst)){
if (canCopyBetweenStorage(storageCfgSrc, storageCfgDst)) {
return await storageSrc.copyObject(storageCfgSrc, storageCfgDst, storagePathSrc, storagePathDst);
} else {
const storageDst = getStorage(opt_specialDirDst);
@ -113,17 +113,19 @@ async function copyObject(ctx, sourceKey, destinationKey, opt_specialDirSrc, opt
}
async function copyPath(ctx, sourcePath, destinationPath, opt_specialDirSrc, opt_specialDirDst) {
const list = await listObjects(ctx, sourcePath, opt_specialDirSrc);
await Promise.all(list.map((curValue) => {
return copyObject(ctx, curValue, destinationPath + '/' + getRelativePath(sourcePath, curValue), opt_specialDirSrc, opt_specialDirDst);
}));
await Promise.all(
list.map(curValue => {
return copyObject(ctx, curValue, destinationPath + '/' + getRelativePath(sourcePath, curValue), opt_specialDirSrc, opt_specialDirDst);
})
);
}
async function listObjects(ctx, strPath, opt_specialDir) {
const storage = getStorage(opt_specialDir);
const storageCfg = getStorageCfg(ctx, opt_specialDir);
const prefix = getStoragePath(ctx, "", opt_specialDir);
const prefix = getStoragePath(ctx, '', opt_specialDir);
try {
const list = await storage.listObjects(storageCfg, getStoragePath(ctx, strPath, opt_specialDir));
return list.map((currentValue) => {
return list.map(currentValue => {
return currentValue.substring(prefix.length);
});
} catch (e) {
@ -156,21 +158,24 @@ async function getSignedUrl(ctx, baseUrl, strPath, urlType, optFilename, opt_cre
const bucketName = storageCfg.name === 'storage-fs' ? 'cache' : 'storage-cache';
const storageFolderName = storageCfg.storageFolderName;
//replace '/' with %2f before encodeURIComponent becase nginx determine %2f as '/' and get wrong system path
const userFriendlyName = optFilename ? encodeURIComponent(optFilename.replace(/\//g, "%2f")) : path.basename(strPath);
const userFriendlyName = optFilename ? encodeURIComponent(optFilename.replace(/\//g, '%2f')) : path.basename(strPath);
var uri = '/' + bucketName + '/' + storageFolderName + '/' + storagePath + '/' + userFriendlyName;
//RFC 1123 does not allow underscores https://stackoverflow.com/questions/2180465/can-domain-name-subdomains-have-an-underscore-in-it
var url = utils.checkBaseUrl(ctx, baseUrl, storageCfg).replace(/_/g, "%5f");
var url = utils.checkBaseUrl(ctx, baseUrl, storageCfg).replace(/_/g, '%5f');
url += uri;
var date = Date.now();
const creationDate = opt_creationDate || date;
const expiredAfter = (commonDefines.c_oAscUrlTypes.Session === urlType ? (cfgExpSessionAbsolute / 1000) : storageUrlExpires) || 31536000;
const expiredAfter = (commonDefines.c_oAscUrlTypes.Session === urlType ? cfgExpSessionAbsolute / 1000 : storageUrlExpires) || 31536000;
//todo creationDate can be greater because mysql CURRENT_TIMESTAMP uses local time, not UTC
var expires = creationDate + Math.ceil(Math.abs(date - creationDate) / expiredAfter) * expiredAfter;
expires = Math.ceil(expires / 1000);
expires += expiredAfter;
var md5 = crypto.createHash('md5').update(expires + decodeURIComponent(uri) + storageSecretString).digest("base64");
md5 = md5.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
var md5 = crypto
.createHash('md5')
.update(expires + decodeURIComponent(uri) + storageSecretString)
.digest('base64');
md5 = md5.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
url += '?md5=' + encodeURIComponent(md5);
url += '&expires=' + encodeURIComponent(expires);
@ -203,9 +208,11 @@ async function getSignedUrls(ctx, baseUrl, strPath, urlType, opt_creationDate, o
return outputMap;
}
async function getSignedUrlsArrayByArray(ctx, baseUrl, list, urlType, opt_specialDir) {
return await Promise.all(list.map((curValue) => {
return getSignedUrl(ctx, baseUrl, curValue, urlType, undefined, undefined, opt_specialDir);
}));
return await Promise.all(
list.map(curValue => {
return getSignedUrl(ctx, baseUrl, curValue, urlType, undefined, undefined, opt_specialDir);
})
);
}
async function getSignedUrlsByArray(ctx, baseUrl, list, optPath, urlType, opt_specialDir) {
const urls = await getSignedUrlsArrayByArray(ctx, baseUrl, list, urlType, opt_specialDir);

View File

@ -32,11 +32,10 @@
'use strict';
const { cp, rm, mkdir } = require('fs/promises');
const { stat, readFile, writeFile } = require('fs/promises');
const {cp, rm, mkdir} = require('fs/promises');
const {stat, readFile, writeFile} = require('fs/promises');
var path = require('path');
var utils = require("../utils");
var utils = require('../utils');
function getFilePath(storageCfg, strPath) {
const storageFolderPath = storageCfg.fs.folderPath;
@ -95,7 +94,7 @@ async function listObjects(storageCfg, strPath) {
const storageFolderPath = storageCfg.fs.folderPath;
const fsPath = getFilePath(storageCfg, strPath);
const values = await utils.listObjects(fsPath);
return values.map((curvalue) => {
return values.map(curvalue => {
return getOutputPath(curvalue.substring(storageFolderPath.length + 1));
});
}

View File

@ -32,14 +32,14 @@
'use strict';
const fs = require('fs');
const { Agent: HttpsAgent } = require('https');
const { Agent: HttpAgent } = require('http');
const {Agent: HttpsAgent} = require('https');
const {Agent: HttpAgent} = require('http');
const path = require('path');
const { S3Client, ListObjectsCommand, HeadObjectCommand} = require("@aws-sdk/client-s3");
const { GetObjectCommand, PutObjectCommand, CopyObjectCommand} = require("@aws-sdk/client-s3");
const { DeleteObjectsCommand, DeleteObjectCommand } = require("@aws-sdk/client-s3");
const { getSignedUrl } = require("@aws-sdk/s3-request-presigner");
const { NodeHttpHandler } = require("@smithy/node-http-handler");
const {S3Client, ListObjectsCommand, HeadObjectCommand} = require('@aws-sdk/client-s3');
const {GetObjectCommand, PutObjectCommand, CopyObjectCommand} = require('@aws-sdk/client-s3');
const {DeleteObjectsCommand, DeleteObjectCommand} = require('@aws-sdk/client-s3');
const {getSignedUrl} = require('@aws-sdk/s3-request-presigner');
const {NodeHttpHandler} = require('@smithy/node-http-handler');
const mime = require('mime');
const config = require('config');
const utils = require('../utils');
@ -60,7 +60,9 @@ const clients = {};
* @param {string} commandType - putObject, copyObject, etc.
*/
function applyCommandOptions(input, storageCfg, commandType) {
if (!storageCfg.commandOptions) {return;}
if (!storageCfg.commandOptions) {
return;
}
if (storageCfg.commandOptions.s3 && storageCfg.commandOptions.s3[commandType]) {
Object.assign(input, storageCfg.commandOptions.s3[commandType]);
@ -83,7 +85,7 @@ function getS3Client(storageCfg) {
configS3.credentials = {
accessKeyId: storageCfg.accessKeyId,
secretAccessKey: storageCfg.secretAccessKey
}
};
}
if (configS3.endpoint) {
@ -133,14 +135,14 @@ async function listObjectsExec(storageCfg, output, params) {
}
}
async function deleteObjectsHelp(storageCfg, aKeys) {
//By default, the operation uses verbose mode in which the response includes the result of deletion of each key in your request.
//In quiet mode the response includes only keys where the delete operation encountered an error.
//By default, the operation uses verbose mode in which the response includes the result of deletion of each key in your request.
//In quiet mode the response includes only keys where the delete operation encountered an error.
const input = {
Bucket: storageCfg.bucketName,
Delete: {
Objects: aKeys,
Quiet: true
}
}
};
applyCommandOptions(input, storageCfg, 'deleteObject');
@ -184,7 +186,7 @@ async function createReadStream(storageCfg, strPath) {
};
}
async function putObject(storageCfg, strPath, buffer, contentLength) {
//todo consider Expires
//todo consider Expires
const input = {
Bucket: storageCfg.bucketName,
Key: getFilePath(storageCfg, strPath),
@ -241,9 +243,9 @@ async function deleteObject(storageCfg, strPath) {
const command = new DeleteObjectCommand(input);
await getS3Client(storageCfg).send(command);
};
}
async function deleteObjects(storageCfg, strPaths) {
const aKeys = strPaths.map((currentValue) => {
const aKeys = strPaths.map(currentValue => {
return {Key: getFilePath(storageCfg, currentValue)};
});
for (let i = 0; i < aKeys.length; i += MAX_DELETE_OBJECTS) {
@ -261,7 +263,7 @@ async function getDirectSignedUrl(ctx, storageCfg, baseUrl, strPath, urlType, op
// Signature version 4 presigned URLs must have an expiration date less than one week in the future
expires = Math.min(expires, 604800);
const userFriendlyName = optFilename ? optFilename.replace(/\//g, "%2f") : path.basename(strPath);
const userFriendlyName = optFilename ? optFilename.replace(/\//g, '%2f') : path.basename(strPath);
const contentDisposition = utils.getContentDisposition(userFriendlyName, null, null);
const input = {
@ -272,7 +274,7 @@ async function getDirectSignedUrl(ctx, storageCfg, baseUrl, strPath, urlType, op
applyCommandOptions(input, storageCfg, 'getObject');
const command = new GetObjectCommand(input);
//default Expires 900 seconds
//default Expires 900 seconds
const options = {
expiresIn: expires
};

View File

@ -77,15 +77,17 @@ function initRabbit(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAdd
const optionsTaskQueue = {...optionsTaskQueueDefault, ...cfgRabbitQueueConvertTask.options};
if (isAddTask) {
taskqueue.channelConvertTask = yield rabbitMQCore.createConfirmChannelPromise(conn);
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertTask, cfgRabbitQueueConvertTask.name,
optionsTaskQueue);
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertTask, cfgRabbitQueueConvertTask.name, optionsTaskQueue);
bAssertTaskQueue = true;
}
var bAssertResponseQueue = false;
if (isAddResponse) {
taskqueue.channelConvertResponse = yield rabbitMQCore.createConfirmChannelPromise(conn);
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertResponse, cfgRabbitQueueConvertResponse.name,
cfgRabbitQueueConvertResponse.options);
yield rabbitMQCore.assertQueuePromise(
taskqueue.channelConvertResponse,
cfgRabbitQueueConvertResponse.name,
cfgRabbitQueueConvertResponse.options
);
bAssertResponseQueue = true;
}
var optionsReceive = {noAck: false};
@ -93,13 +95,14 @@ function initRabbit(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAdd
taskqueue.channelConvertTaskReceive = yield rabbitMQCore.createChannelPromise(conn);
taskqueue.channelConvertTaskReceive.prefetch(1);
if (!bAssertTaskQueue) {
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertTaskReceive, cfgRabbitQueueConvertTask.name,
optionsTaskQueue);
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertTaskReceive, cfgRabbitQueueConvertTask.name, optionsTaskQueue);
}
yield rabbitMQCore.consumePromise(taskqueue.channelConvertTaskReceive, cfgRabbitQueueConvertTask.name,
(message) => {
yield rabbitMQCore.consumePromise(
taskqueue.channelConvertTaskReceive,
cfgRabbitQueueConvertTask.name,
message => {
co(function* () {
const ack = function() {
const ack = function () {
taskqueue.channelConvertTaskReceive && taskqueue.channelConvertTaskReceive.ack(message);
};
const redelivered = yield* pushBackRedeliveredRabbit(taskqueue, message, ack);
@ -109,22 +112,31 @@ function initRabbit(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAdd
}
}
});
}, optionsReceive);
},
optionsReceive
);
}
if (isAddResponseReceive) {
taskqueue.channelConvertResponseReceive = yield rabbitMQCore.createChannelPromise(conn);
if (!bAssertResponseQueue) {
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertResponseReceive, cfgRabbitQueueConvertResponse.name,
cfgRabbitQueueConvertResponse.options);
yield rabbitMQCore.assertQueuePromise(
taskqueue.channelConvertResponseReceive,
cfgRabbitQueueConvertResponse.name,
cfgRabbitQueueConvertResponse.options
);
}
yield rabbitMQCore.consumePromise(taskqueue.channelConvertResponseReceive, cfgRabbitQueueConvertResponse.name,
(message) => {
yield rabbitMQCore.consumePromise(
taskqueue.channelConvertResponseReceive,
cfgRabbitQueueConvertResponse.name,
message => {
if (message) {
taskqueue.emit('response', message.content.toString(), () => {
taskqueue.channelConvertResponseReceive && taskqueue.channelConvertResponseReceive.ack(message);
});
}
}, optionsReceive);
},
optionsReceive
);
}
if (isAddDelayed) {
const optionsDelayedQueueDefault = {
@ -136,20 +148,33 @@ function initRabbit(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAdd
}
if (isEmitDead) {
taskqueue.channelConvertDead = yield rabbitMQCore.createChannelPromise(conn);
yield rabbitMQCore.assertExchangePromise(taskqueue.channelConvertDead, cfgRabbitExchangeConvertDead.name, 'fanout',
cfgRabbitExchangeConvertDead.options);
var queue = yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertDead, cfgRabbitQueueConvertDead.name, cfgRabbitQueueConvertDead.options);
yield rabbitMQCore.assertExchangePromise(
taskqueue.channelConvertDead,
cfgRabbitExchangeConvertDead.name,
'fanout',
cfgRabbitExchangeConvertDead.options
);
var queue = yield rabbitMQCore.assertQueuePromise(
taskqueue.channelConvertDead,
cfgRabbitQueueConvertDead.name,
cfgRabbitQueueConvertDead.options
);
taskqueue.channelConvertDead.bindQueue(queue, cfgRabbitExchangeConvertDead.name, '');
yield rabbitMQCore.consumePromise(taskqueue.channelConvertDead, queue, (message) => {
if (null != taskqueue.channelConvertDead) {
if (message) {
taskqueue.emit('dead', message.content.toString(), () => {
taskqueue.channelConvertDead.ack(message);
});
yield rabbitMQCore.consumePromise(
taskqueue.channelConvertDead,
queue,
message => {
if (null != taskqueue.channelConvertDead) {
if (message) {
taskqueue.emit('dead', message.content.toString(), () => {
taskqueue.channelConvertDead.ack(message);
});
}
}
}
}, {noAck: false});
},
{noAck: false}
);
}
//process messages received while reconnection time
@ -163,7 +188,7 @@ function initRabbit(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAdd
});
}
function initActive(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAddResponseReceive, isEmitDead, isAddDelayed, callback) {
return co(function*() {
return co(function* () {
var e = null;
try {
var conn = yield activeMQCore.connetPromise(() => {
@ -208,9 +233,9 @@ function initActive(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAdd
const receiver = yield activeMQCore.openReceiverPromise(conn, optionsConvertTask);
//todo ?consumer.dispatchAsync=false&consumer.prefetchSize=1
receiver.add_credit(1);
receiver.on("message", (context) => {
co(function*() {
const ack = function() {
receiver.on('message', context => {
co(function* () {
const ack = function () {
context.delivery.accept();
receiver.add_credit(1);
};
@ -236,7 +261,7 @@ function initActive(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAdd
const receiver = yield activeMQCore.openReceiverPromise(conn, optionsConvertResponse);
//todo ?consumer.dispatchAsync=false&consumer.prefetchSize=1
receiver.add_credit(1);
receiver.on("message", (context) => {
receiver.on('message', context => {
if (context) {
taskqueue.emit('response', context.message.body, () => {
context.delivery.accept();
@ -268,9 +293,9 @@ function initActive(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAdd
const receiver = yield activeMQCore.openReceiverPromise(conn, optionsConvertDead);
//todo ?consumer.dispatchAsync=false&consumer.prefetchSize=1
receiver.add_credit(1);
receiver.on("message", (context) => {
receiver.on('message', context => {
if (context) {
taskqueue.emit('dead', context.message.body, () =>{
taskqueue.emit('dead', context.message.body, () => {
context.delivery.accept();
receiver.add_credit(1);
});
@ -316,7 +341,7 @@ function* pushBackRedeliveredRabbit(taskqueue, message, ack) {
}
} catch (err) {
operationContext.global.logger.error('checkRedelivered error: %s', err.stack);
} finally{
} finally {
ack();
}
return true;
@ -381,13 +406,20 @@ function addTaskString(taskqueue, task, priority, opt_expiration, opt_headers) {
return new Promise((resolve, reject) => {
var content = Buffer.from(task);
if (null != taskqueue.channelConvertTask) {
addTask(taskqueue, content, priority, (err, _ok) => {
if (null != err) {
reject(err);
} else {
resolve();
}
}, opt_expiration, opt_headers);
addTask(
taskqueue,
content,
priority,
(err, _ok) => {
if (null != err) {
reject(err);
} else {
resolve();
}
},
opt_expiration,
opt_headers
);
} else {
taskqueue.addTaskStore.push({task: content, priority, expiration: opt_expiration, headers: opt_headers});
resolve();
@ -428,8 +460,12 @@ function healthCheckRabbit(taskqueue) {
if (!taskqueue.channelConvertDead) {
return false;
}
const exchange = yield rabbitMQCore.assertExchangePromise(taskqueue.channelConvertDead, cfgRabbitExchangeConvertDead.name,
'fanout', cfgRabbitExchangeConvertDead.options);
const exchange = yield rabbitMQCore.assertExchangePromise(
taskqueue.channelConvertDead,
cfgRabbitExchangeConvertDead.name,
'fanout',
cfgRabbitExchangeConvertDead.options
);
return !!exchange;
});
}
@ -451,25 +487,25 @@ function initSenderActive(sender, senderData) {
delete senderData[id];
callback(res);
}
}
};
sender.on('accepted', (context) => {
sender.on('accepted', context => {
processEvent(context, null);
});
sender.on('rejected ', (context) => {
sender.on('rejected ', context => {
const error = context.delivery?.remote_state?.error;
processEvent(context, new Error("[AMQP] message is rejected (error=" + error + ")"));
processEvent(context, new Error('[AMQP] message is rejected (error=' + error + ')'));
});
sender.on('released', (context) => {
sender.on('released', context => {
const delivery_failed = context.delivery?.remote_state?.delivery_failed;
const undeliverable_here = context.delivery?.remote_state?.undeliverable_here;
const err = new Error("[AMQP] message is released (delivery_failed=" + delivery_failed + ", undeliverable_here=" + undeliverable_here + ")");
const err = new Error('[AMQP] message is released (delivery_failed=' + delivery_failed + ', undeliverable_here=' + undeliverable_here + ')');
processEvent(context, err);
});
sender.on('modified ', (context) => {
sender.on('modified ', context => {
const delivery_failed = context.delivery?.remote_state?.delivery_failed;
const undeliverable_here = context.delivery?.remote_state?.undeliverable_here;
const err = new Error("[AMQP] message is modified (delivery_failed=" + delivery_failed + ", undeliverable_here=" + undeliverable_here + ")");
const err = new Error('[AMQP] message is modified (delivery_failed=' + delivery_failed + ', undeliverable_here=' + undeliverable_here + ')');
processEvent(context, err);
});
}
@ -516,10 +552,10 @@ util.inherits(TaskQueueRabbitMQ, events.EventEmitter);
TaskQueueRabbitMQ.prototype.init = function (isAddTask, isAddResponse, isAddTaskReceive, isAddResponseReceive, isEmitDead, isAddDelayed, callback) {
init(this, isAddTask, isAddResponse, isAddTaskReceive, isAddResponseReceive, isEmitDead, isAddDelayed, callback);
};
TaskQueueRabbitMQ.prototype.initPromise = function(isAddTask, isAddResponse, isAddTaskReceive, isAddResponseReceive, isEmitDead, isAddDelayed) {
TaskQueueRabbitMQ.prototype.initPromise = function (isAddTask, isAddResponse, isAddTaskReceive, isAddResponseReceive, isEmitDead, isAddDelayed) {
var t = this;
return new Promise((resolve, reject) => {
init(t, isAddTask, isAddResponse, isAddTaskReceive, isAddResponseReceive, isEmitDead, isAddDelayed, (err) => {
init(t, isAddTask, isAddResponse, isAddTaskReceive, isAddResponseReceive, isEmitDead, isAddDelayed, err => {
if (err) {
reject(err);
} else {
@ -592,7 +628,7 @@ TaskQueueRabbitMQ.prototype.close = function () {
yield close(t.connection);
});
};
TaskQueueRabbitMQ.prototype.closeOrWait = function() {
TaskQueueRabbitMQ.prototype.closeOrWait = function () {
if (commonDefines.c_oAscQueueType.rabbitmq === cfgQueueType) {
return this.close();
} else {
@ -603,7 +639,7 @@ TaskQueueRabbitMQ.prototype.closeOrWait = function() {
});
}
};
TaskQueueRabbitMQ.prototype.healthCheck = function() {
TaskQueueRabbitMQ.prototype.healthCheck = function () {
return healthCheck(this);
};

View File

@ -34,11 +34,11 @@
const config = require('config');
const co = require('co');
const NodeCache = require( "node-cache" );
const NodeCache = require('node-cache');
const constants = require('./../../Common/sources/constants');
const commonDefines = require('./../../Common/sources/commondefines');
const utils = require('./../../Common/sources/utils');
const { readFile, readdir, writeFile } = require('fs/promises');
const {readFile, readdir, writeFile} = require('fs/promises');
const path = require('path');
const cfgTenantsBaseDomain = config.get('tenants.baseDomain');
@ -54,7 +54,7 @@ const cfgSecretSession = config.get('services.CoAuthoring.secret.session');
let licenseInfo;
let licenseOriginal;
let licenseTuple;//to avoid array creating in getTenantLicense
let licenseTuple; //to avoid array creating in getTenantLicense
const c_LM = constants.LICENSE_MODE;
@ -71,7 +71,7 @@ function getTenant(ctx, domain) {
if (cfgTenantsBaseDomain && domain.endsWith('.' + cfgTenantsBaseDomain)) {
tenant = domain.substring(0, domain.length - cfgTenantsBaseDomain.length - 1);
} else if(cfgTenantsBaseDomain === domain) {
} else if (cfgTenantsBaseDomain === domain) {
tenant = getDefautTenant();
} else {
tenant = domain;
@ -83,7 +83,7 @@ async function getAllTenants(ctx) {
let dirList = [];
try {
if (isMultitenantMode(ctx)) {
const entitiesList = await readdir(cfgTenantsBaseDir, { withFileTypes: true });
const entitiesList = await readdir(cfgTenantsBaseDir, {withFileTypes: true});
dirList = entitiesList.filter(direntObj => direntObj.isDirectory()).map(directory => directory.name);
}
} catch (error) {
@ -141,7 +141,7 @@ async function setTenantConfig(ctx, config) {
}
function getTenantSecret(ctx, type) {
return co(function*() {
return co(function* () {
let cfgTenant;
//check config
switch (type) {
@ -224,7 +224,7 @@ function fixTenantLicense(ctx, licenseInfo, licenseInfoTenant) {
}
//can not turn on
const flags = ['branding', 'customization'];
flags.forEach((flag) => {
flags.forEach(flag => {
if (!licenseInfo[flag] && licenseInfoTenant[flag]) {
licenseInfoTenant[flag] = licenseInfo[flag];
errors.push(flag);
@ -295,7 +295,7 @@ function isMultitenantMode(_ctx) {
}
function setMultitenantMode(val) {
//for tests only!!
return hasBaseDir = val;
return (hasBaseDir = val);
}
function isDefaultTenant(ctx) {
return ctx.tenant === cfgTenantsDefaultTenant;
@ -325,7 +325,7 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) {
}
if (oLicense['customer_id']) {
res.customerId = oLicense['customer_id']
res.customerId = oLicense['customer_id'];
}
if (oLicense['alias']) {
@ -340,13 +340,13 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) {
res.mode |= c_LM.Limited;
}
if (oLicense.hasOwnProperty('trial')) {
res.mode |= ((true === oLicense['trial'] || 'true' === oLicense['trial'] || 'True' === oLicense['trial']) ? c_LM.Trial : c_LM.None); // Someone who likes to put json string instead of bool
res.mode |= true === oLicense['trial'] || 'true' === oLicense['trial'] || 'True' === oLicense['trial'] ? c_LM.Trial : c_LM.None; // Someone who likes to put json string instead of bool
}
if (true === oLicense['developer']) {
res.mode |= c_LM.Developer;
}
if (oLicense.hasOwnProperty('branding')) {
res.branding = (true === oLicense['branding'] || 'true' === oLicense['branding'] || 'True' === oLicense['branding']); // Someone who likes to put json string instead of bool
res.branding = true === oLicense['branding'] || 'true' === oLicense['branding'] || 'True' === oLicense['branding']; // Someone who likes to put json string instead of bool
}
if (oLicense.hasOwnProperty('customization')) {
res.customization = !!oLicense['customization'];
@ -367,8 +367,7 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) {
res.usersViewCount = oLicense['users_view_count'] >> 0;
}
if (oLicense.hasOwnProperty('users_expire')) {
res.usersExpire = Math.max(constants.LICENSE_EXPIRE_USERS_ONE_DAY, (oLicense['users_expire'] >> 0) *
constants.LICENSE_EXPIRE_USERS_ONE_DAY);
res.usersExpire = Math.max(constants.LICENSE_EXPIRE_USERS_ONE_DAY, (oLicense['users_expire'] >> 0) * constants.LICENSE_EXPIRE_USERS_ONE_DAY);
}
// Read grace_days setting from license file if available
@ -378,7 +377,7 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) {
const timeLimited = 0 !== (res.mode & c_LM.Limited);
const checkDate = ((res.mode & c_LM.Trial) || timeLimited) ? new Date() : licenseInfo.buildDate;
const checkDate = res.mode & c_LM.Trial || timeLimited ? new Date() : licenseInfo.buildDate;
//Calendar check of start_date allows to issue a license for old versions
const checkStartDate = new Date();
if (startDate <= checkStartDate && checkDate <= res.endDate) {
@ -395,9 +394,11 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) {
res.usersCount = Math.min(res.usersCount, constants.LICENSE_USERS);
res.usersViewCount = Math.min(res.usersViewCount, constants.LICENSE_USERS);
const errStr = res.usersCount ? `${res.usersCount} unique users` : `${res.connections} concurrent connections`;
ctx.logger.error(`License: License needs to be renewed.\nYour users have only ${errStr} ` +
`available for document editing for the next ${res.graceDays} days.\nPlease renew the ` +
'license to restore the full access');
ctx.logger.error(
`License: License needs to be renewed.\nYour users have only ${errStr} ` +
`available for document editing for the next ${res.graceDays} days.\nPlease renew the ` +
'license to restore the full access'
);
} else {
res.type = c_LR.ExpiredLimited;
}
@ -420,14 +421,14 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) {
let errorMessage;
if (res.type === c_LR.Expired) {
errorMessage = 'Your access to updates and support has expired.\n' +
errorMessage =
'Your access to updates and support has expired.\n' +
'Your license key can not be applied to new versions.\n' +
'Please extend the license to get updates and support.';
} else if (res.type === c_LR.ExpiredLimited) {
errorMessage = 'License expired.\nYour users can not edit or view document anymore.\n' +
'Please renew the license.';
errorMessage = 'License expired.\nYour users can not edit or view document anymore.\n' + 'Please renew the license.';
} else {
errorMessage ='License Expired!!!';
errorMessage = 'License Expired!!!';
}
ctx.logger.warn('License: ' + errorMessage);
}

View File

@ -33,11 +33,11 @@
'use strict';
//Fix EPROTO error in node 8.x at some web sites(https://github.com/nodejs/node/issues/21513)
require("tls").DEFAULT_ECDH_CURVE = "auto";
require('tls').DEFAULT_ECDH_CURVE = 'auto';
const { pipeline } = require('node:stream/promises');
const { buffer } = require('node:stream/consumers');
const { Transform } = require('stream');
const {pipeline} = require('node:stream/promises');
const {buffer} = require('node:stream/consumers');
const {Transform} = require('stream');
var config = require('config');
var fs = require('fs');
const fsPromises = require('node:fs/promises');
@ -46,24 +46,24 @@ const crypto = require('crypto');
var url = require('url');
var axios = require('../node_modules/axios/dist/node/axios.cjs');
var co = require('co');
var URI = require("uri-js-replace");
var URI = require('uri-js-replace');
const escapeStringRegexp = require('escape-string-regexp');
const ipaddr = require('ipaddr.js');
const getDnsCache = require('dnscache');
const jwt = require('jsonwebtoken');
const NodeCache = require( "node-cache" );
const NodeCache = require('node-cache');
const ms = require('ms');
const constants = require('./constants');
const commonDefines = require('./commondefines');
const forwarded = require('forwarded');
const { RequestFilteringHttpAgent, RequestFilteringHttpsAgent } = require("request-filtering-agent");
const {RequestFilteringHttpAgent, RequestFilteringHttpsAgent} = require('request-filtering-agent');
const https = require('https');
const http = require('http');
const ca = require('win-ca/api');
const util = require('util');
const contentDisposition = require('content-disposition');
const operationContext = require("./operationContext");
const operationContext = require('./operationContext');
//Clone sealed config objects before passing to external libraries using config.util.cloneDeep
const cfgDnsCache = config.util.cloneDeep(config.get('dnscache'));
@ -94,9 +94,10 @@ ca(cfgWinCa);
const minimumIterationsByteLength = 4;
const dnscache = getDnsCache(cfgDnsCache);
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#use_within_json
BigInt.prototype.toJSON = function() { return this.toString() };
BigInt.prototype.toJSON = function () {
return this.toString();
};
var g_oIpFilterRules = new Map();
function getIpFilterRule(address) {
@ -108,9 +109,14 @@ function getIpFilterRule(address) {
}
return exp;
}
const pemfileCache = new NodeCache({stdTTL: ms(cfgExpPemStdTtl) / 1000, checkperiod: ms(cfgExpPemCheckPeriod) / 1000, errorOnMissing: false, useClones: true});
const pemfileCache = new NodeCache({
stdTTL: ms(cfgExpPemStdTtl) / 1000,
checkperiod: ms(cfgExpPemCheckPeriod) / 1000,
errorOnMissing: false,
useClones: true
});
exports.getConvertionTimeout = function(opt_ctx) {
exports.getConvertionTimeout = function (opt_ctx) {
if (opt_ctx) {
const tenVisibilityTimeout = opt_ctx.getCfg('queue.visibilityTimeout', cfgVisibilityTimeout);
const tenQueueRetentionPeriod = opt_ctx.getCfg('queue.retentionPeriod', cfgQueueRetentionPeriod);
@ -118,28 +124,37 @@ exports.getConvertionTimeout = function(opt_ctx) {
} else {
return 1.5 * (cfgVisibilityTimeout + cfgQueueRetentionPeriod) * 1000;
}
}
};
exports.addSeconds = function(date, sec) {
exports.addSeconds = function (date, sec) {
date.setSeconds(date.getSeconds() + sec);
};
exports.getMillisecondsOfHour = function(date) {
return (date.getUTCMinutes() * 60 + date.getUTCSeconds()) * 1000 + date.getUTCMilliseconds();
exports.getMillisecondsOfHour = function (date) {
return (date.getUTCMinutes() * 60 + date.getUTCSeconds()) * 1000 + date.getUTCMilliseconds();
};
exports.encodeXml = function(value) {
return value.replace(/[<>&'"\r\n\t\xA0]/g, (c) => {
switch (c) {
case '<': return '&lt;';
case '>': return '&gt;';
case '&': return '&amp;';
case '\'': return '&apos;';
case '"': return '&quot;';
case '\r': return '&#xD;';
case '\n': return '&#xA;';
case '\t': return '&#x9;';
case '\xA0': return '&#xA0;';
}
});
exports.encodeXml = function (value) {
return value.replace(/[<>&'"\r\n\t\xA0]/g, c => {
switch (c) {
case '<':
return '&lt;';
case '>':
return '&gt;';
case '&':
return '&amp;';
case "'":
return '&apos;';
case '"':
return '&quot;';
case '\r':
return '&#xD;';
case '\n':
return '&#xA;';
case '\t':
return '&#x9;';
case '\xA0':
return '&#xA0;';
}
});
};
function fsStat(fsPath) {
return new Promise((resolve, reject) => {
@ -189,7 +204,7 @@ function* walkDir(fsPath, results, optNoSubDir, optOnlyFolders) {
}
}
}
exports.listFolders = function(fsPath, optNoSubDir) {
exports.listFolders = function (fsPath, optNoSubDir) {
return co(function* () {
let stats;
const list = [];
@ -200,12 +215,12 @@ exports.listFolders = function(fsPath, optNoSubDir) {
stats = null;
}
if (stats && stats.isDirectory()) {
yield* walkDir(fsPath, list, optNoSubDir, true);
yield* walkDir(fsPath, list, optNoSubDir, true);
}
return list;
});
};
exports.listObjects = function(fsPath, optNoSubDir) {
exports.listObjects = function (fsPath, optNoSubDir) {
return co(function* () {
let stats;
const list = [];
@ -225,12 +240,12 @@ exports.listObjects = function(fsPath, optNoSubDir) {
return list;
});
};
exports.sleep = function(ms) {
return new Promise((resolve) => {
exports.sleep = function (ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
};
exports.readFile = function(file) {
exports.readFile = function (file) {
return new Promise((resolve, reject) => {
fs.readFile(file, (err, data) => {
if (err) {
@ -241,7 +256,7 @@ exports.readFile = function(file) {
});
});
};
function getContentDisposition (opt_filename, opt_useragent, opt_type) {
function getContentDisposition(opt_filename, opt_useragent, opt_type) {
const type = opt_type || constants.CONTENT_DISPOSITION_ATTACHMENT;
return contentDisposition(opt_filename, {type});
}
@ -252,14 +267,14 @@ function isAllowDirectRequest(ctx, uri, isInJwtToken) {
const tenExternalRequestDirectIfIn = ctx.getCfg('externalRequest.directIfIn', cfgExternalRequestDirectIfIn);
const allowList = tenExternalRequestDirectIfIn.allowList;
if (allowList.length > 0) {
const allowIndex = allowList.findIndex((allowPrefix) => {
const allowIndex = allowList.findIndex(allowPrefix => {
return uri.startsWith(allowPrefix);
}, uri);
res = -1 !== allowIndex;
ctx.logger.debug("isAllowDirectRequest check allow list res=%s", res);
ctx.logger.debug('isAllowDirectRequest check allow list res=%s', res);
} else if (tenExternalRequestDirectIfIn.jwtToken) {
res = isInJwtToken;
ctx.logger.debug("isAllowDirectRequest url in jwt token res=%s", res);
ctx.logger.debug('isAllowDirectRequest url in jwt token res=%s', res);
}
return res;
}
@ -314,7 +329,7 @@ function changeOptionsForCompatibilityWithRequest(options, httpAgentOptions, htt
options.maxRedirects = 0;
}
if (false === options.gzip) {
options.headers = { ...options.headers, 'Accept-Encoding': 'identity' };
options.headers = {...options.headers, 'Accept-Encoding': 'identity'};
delete options.gzip;
}
if (options.forever !== undefined) {
@ -343,8 +358,8 @@ async function downloadUrlPromise(ctx, uri, optTimeout, optLimit, opt_Authorizat
const options = config.util.cloneDeep(tenTenantRequestDefaults);
//baseRequest creates new agent(win-ca injects in globalAgent)
const httpsAgentOptions = { ...https.globalAgent.options, ...options};
const httpAgentOptions = { ...http.globalAgent.options, ...options};
const httpsAgentOptions = {...https.globalAgent.options, ...options};
const httpAgentOptions = {...http.globalAgent.options, ...options};
changeOptionsForCompatibilityWithRequest(options, httpAgentOptions, httpsAgentOptions);
if (!addExternalRequestOptions(ctx, uri, opt_filterPrivate, options, httpAgentOptions, httpsAgentOptions)) {
@ -356,7 +371,7 @@ async function downloadUrlPromise(ctx, uri, optTimeout, optLimit, opt_Authorizat
options.httpAgent = new http.Agent(httpAgentOptions);
}
const headers = { ...options.headers };
const headers = {...options.headers};
if (opt_Authorization) {
headers[tenTokenOutboxHeader] = tenTokenOutboxPrefix + opt_Authorization;
}
@ -371,11 +386,11 @@ async function downloadUrlPromise(ctx, uri, optTimeout, optLimit, opt_Authorizat
responseType: 'stream',
headers,
signal: optTimeout?.wholeCycle && AbortSignal.timeout ? AbortSignal.timeout(ms(optTimeout.wholeCycle)) : undefined,
timeout: optTimeout?.connectionAndInactivity ? ms(optTimeout.connectionAndInactivity) : undefined,
timeout: optTimeout?.connectionAndInactivity ? ms(optTimeout.connectionAndInactivity) : undefined
};
try {
const response = await axios(axiosConfig);
const { status, headers } = response;
const {status, headers} = response;
if (![200, 206].includes(status)) {
const error = new Error(`Error response: statusCode:${status}; headers:${JSON.stringify(headers)};`);
error.statusCode = status;
@ -395,19 +410,19 @@ async function downloadUrlPromise(ctx, uri, optTimeout, optLimit, opt_Authorizat
if (opt_returnStream) {
// When returning a stream, we'll return the response for the caller to handle streaming
// The content-length check is already done above
return { response, sha256: null, body: null, stream: response.data.pipe(limitedStream) };
return {response, sha256: null, body: null, stream: response.data.pipe(limitedStream)};
}
const body = await pipeline(response.data, limitedStream, buffer);
const sha256 = crypto.createHash('sha256').update(body).digest('hex');
return { response, sha256, body, stream: null };
return {response, sha256, body, stream: null};
} catch (err) {
if('ERR_CANCELED' === err.code) {
if ('ERR_CANCELED' === err.code) {
err.code = 'ETIMEDOUT';
} else if(['ECONNABORTED', 'ECONNRESET'].includes(err.code)) {
} else if (['ECONNABORTED', 'ECONNRESET'].includes(err.code)) {
err.code = 'ESOCKETTIMEDOUT';
}
if (err.status){
if (err.status) {
err.statusCode = err.status;
}
throw err;
@ -421,8 +436,8 @@ async function postRequestPromise(ctx, uri, postData, postDataStream, postDataSi
uri = URI.serialize(URI.parse(uri));
const options = config.util.cloneDeep(tenTenantRequestDefaults);
const httpsAgentOptions = { ...https.globalAgent.options, ...options};
const httpAgentOptions = { ...http.globalAgent.options, ...options};
const httpsAgentOptions = {...https.globalAgent.options, ...options};
const httpAgentOptions = {...http.globalAgent.options, ...options};
changeOptionsForCompatibilityWithRequest(options, httpAgentOptions, httpsAgentOptions);
if (!addExternalRequestOptions(ctx, uri, opt_isInJwtToken, options, httpAgentOptions, httpsAgentOptions)) {
@ -434,7 +449,7 @@ async function postRequestPromise(ctx, uri, postData, postDataStream, postDataSi
options.httpAgent = new http.Agent(httpAgentOptions);
}
const headers = { ...options.headers };
const headers = {...options.headers};
if (opt_Authorization) {
headers[tenTokenOutboxHeader] = tenTokenOutboxPrefix + opt_Authorization;
}
@ -456,7 +471,7 @@ async function postRequestPromise(ctx, uri, postData, postDataStream, postDataSi
method: 'POST',
headers,
signal: optTimeout?.wholeCycle && AbortSignal.timeout ? AbortSignal.timeout(ms(optTimeout.wholeCycle)) : undefined,
timeout: optTimeout?.connectionAndInactivity ? ms(optTimeout.connectionAndInactivity) : undefined,
timeout: optTimeout?.connectionAndInactivity ? ms(optTimeout.connectionAndInactivity) : undefined
};
if (postData) {
@ -467,7 +482,7 @@ async function postRequestPromise(ctx, uri, postData, postDataStream, postDataSi
try {
const response = await axios(axiosConfig);
const { status, headers, data } = response;
const {status, headers, data} = response;
if (status === 200 || status === 204) {
return {
@ -513,8 +528,8 @@ async function httpRequest(ctx, method, uri, opt_headers, opt_body, opt_timeout,
uri = URI.serialize(URI.parse(uri));
const options = config.util.cloneDeep(tenTenantRequestDefaults);
const httpsAgentOptions = { ...https.globalAgent.options, ...options};
const httpAgentOptions = { ...http.globalAgent.options, ...options};
const httpsAgentOptions = {...https.globalAgent.options, ...options};
const httpAgentOptions = {...http.globalAgent.options, ...options};
changeOptionsForCompatibilityWithRequest(options, httpAgentOptions, httpsAgentOptions);
if (!addExternalRequestOptions(ctx, uri, opt_filterPrivate, options, httpAgentOptions, httpsAgentOptions)) {
@ -526,7 +541,7 @@ async function httpRequest(ctx, method, uri, opt_headers, opt_body, opt_timeout,
options.httpAgent = new http.Agent(httpAgentOptions);
}
const requestHeaders = { ...options.headers };
const requestHeaders = {...options.headers};
if (opt_headers) {
Object.assign(requestHeaders, opt_headers);
}
@ -538,7 +553,7 @@ async function httpRequest(ctx, method, uri, opt_headers, opt_body, opt_timeout,
headers: requestHeaders,
responseType: 'stream',
signal: opt_timeout?.wholeCycle && AbortSignal.timeout ? AbortSignal.timeout(ms(opt_timeout.wholeCycle)) : undefined,
timeout: opt_timeout?.connectionAndInactivity ? ms(opt_timeout.connectionAndInactivity) : undefined,
timeout: opt_timeout?.connectionAndInactivity ? ms(opt_timeout.connectionAndInactivity) : undefined
};
if (opt_body) {
@ -547,7 +562,7 @@ async function httpRequest(ctx, method, uri, opt_headers, opt_body, opt_timeout,
try {
const response = await axios(axiosConfig);
const { headers } = response;
const {headers} = response;
const contentLength = headers['content-length'];
if (opt_limit && contentLength && parseInt(contentLength) > opt_limit) {
@ -580,63 +595,63 @@ async function httpRequest(ctx, method, uri, opt_headers, opt_body, opt_timeout,
exports.httpRequest = httpRequest;
exports.postRequestPromise = postRequestPromise;
exports.downloadUrlPromise = downloadUrlPromise;
exports.mapAscServerErrorToOldError = function(error) {
exports.mapAscServerErrorToOldError = function (error) {
var res = -1;
switch (error) {
case constants.NO_ERROR :
case constants.CONVERT_CELLLIMITS :
case constants.NO_ERROR:
case constants.CONVERT_CELLLIMITS:
res = 0;
break;
case constants.TASK_QUEUE :
case constants.TASK_RESULT :
case constants.TASK_QUEUE:
case constants.TASK_RESULT:
res = -6;
break;
case constants.CONVERT_PASSWORD :
case constants.CONVERT_DRM :
case constants.CONVERT_DRM_UNSUPPORTED :
case constants.CONVERT_PASSWORD:
case constants.CONVERT_DRM:
case constants.CONVERT_DRM_UNSUPPORTED:
res = -5;
break;
case constants.CONVERT_DOWNLOAD :
case constants.CONVERT_DOWNLOAD:
res = -4;
break;
case constants.CONVERT_TIMEOUT :
case constants.CONVERT_DEAD_LETTER :
case constants.CONVERT_TIMEOUT:
case constants.CONVERT_DEAD_LETTER:
res = -2;
break;
case constants.CONVERT_PARAMS :
case constants.CONVERT_PARAMS:
res = -7;
break;
case constants.CONVERT_LIMITS :
case constants.CONVERT_LIMITS:
res = -10;
break;
case constants.CONVERT_NEED_PARAMS :
case constants.CONVERT_LIBREOFFICE :
case constants.CONVERT_CORRUPTED :
case constants.CONVERT_UNKNOWN_FORMAT :
case constants.CONVERT_READ_FILE :
case constants.CONVERT_TEMPORARY :
case constants.CONVERT :
case constants.CONVERT_NEED_PARAMS:
case constants.CONVERT_LIBREOFFICE:
case constants.CONVERT_CORRUPTED:
case constants.CONVERT_UNKNOWN_FORMAT:
case constants.CONVERT_READ_FILE:
case constants.CONVERT_TEMPORARY:
case constants.CONVERT:
res = -3;
break;
case constants.CONVERT_DETECT :
case constants.CONVERT_DETECT:
res = -9;
break;
case constants.VKEY :
case constants.VKEY_ENCRYPT :
case constants.VKEY_KEY_EXPIRE :
case constants.VKEY_USER_COUNT_EXCEED :
case constants.VKEY:
case constants.VKEY_ENCRYPT:
case constants.VKEY_KEY_EXPIRE:
case constants.VKEY_USER_COUNT_EXCEED:
res = -8;
break;
case constants.STORAGE :
case constants.STORAGE_FILE_NO_FOUND :
case constants.STORAGE_READ :
case constants.STORAGE_WRITE :
case constants.STORAGE_REMOVE_DIR :
case constants.STORAGE_CREATE_DIR :
case constants.STORAGE_GET_INFO :
case constants.UPLOAD :
case constants.READ_REQUEST_STREAM :
case constants.UNKNOWN :
case constants.STORAGE:
case constants.STORAGE_FILE_NO_FOUND:
case constants.STORAGE_READ:
case constants.STORAGE_WRITE:
case constants.STORAGE_REMOVE_DIR:
case constants.STORAGE_CREATE_DIR:
case constants.STORAGE_GET_INFO:
case constants.UPLOAD:
case constants.READ_REQUEST_STREAM:
case constants.UNKNOWN:
res = -1;
break;
}
@ -688,7 +703,7 @@ function fillResponse(req, res, convertStatus, isJSON) {
if (constants.NO_ERROR != convertStatus.err) {
output = {error: exports.mapAscServerErrorToOldError(convertStatus.err)};
} else {
output = {fileUrl: convertStatus.url, fileType: convertStatus.filetype, percent: (convertStatus.end ? 100 : 0), endConvert: convertStatus.end};
output = {fileUrl: convertStatus.url, fileType: convertStatus.filetype, percent: convertStatus.end ? 100 : 0, endConvert: convertStatus.end};
}
const accepts = isJSON ? ['json', 'xml'] : ['xml', 'json'];
switch (req.accepts(accepts)) {
@ -720,7 +735,7 @@ exports.fillResponseBuilder = fillResponseBuilder;
function promiseCreateWriteStream(strPath, optOptions) {
return new Promise((resolve, reject) => {
var file = fs.createWriteStream(strPath, optOptions);
var errorCallback = function(e) {
var errorCallback = function (e) {
reject(e);
};
file.on('error', errorCallback);
@ -729,7 +744,7 @@ function promiseCreateWriteStream(strPath, optOptions) {
resolve(file);
});
});
};
}
exports.promiseCreateWriteStream = promiseCreateWriteStream;
function promiseWaitDrain(stream) {
@ -749,7 +764,7 @@ exports.promiseWaitClose = promiseWaitClose;
function promiseCreateReadStream(strPath) {
return new Promise((resolve, reject) => {
var file = fs.createReadStream(strPath);
var errorCallback = function(e) {
var errorCallback = function (e) {
reject(e);
};
file.on('error', errorCallback);
@ -758,9 +773,9 @@ function promiseCreateReadStream(strPath) {
resolve(file);
});
});
};
}
exports.promiseCreateReadStream = promiseCreateReadStream;
exports.compareStringByLength = function(x, y) {
exports.compareStringByLength = function (x, y) {
if (x && y) {
if (x.length == y.length) {
return x.localeCompare(y);
@ -776,7 +791,7 @@ exports.compareStringByLength = function(x, y) {
}
return 0;
};
exports.promiseRedis = function(client, func) {
exports.promiseRedis = function (client, func) {
var newArguments = Array.prototype.slice.call(arguments, 2);
return new Promise((resolve, reject) => {
newArguments.push((err, data) => {
@ -789,11 +804,11 @@ exports.promiseRedis = function(client, func) {
func.apply(client, newArguments);
});
};
exports.containsAllAscii = function(str) {
exports.containsAllAscii = function (str) {
return /^[\000-\177]*$/.test(str);
};
function containsAllAsciiNP(str) {
return /^[\040-\176]*$/.test(str);//non-printing characters
return /^[\040-\176]*$/.test(str); //non-printing characters
}
exports.containsAllAsciiNP = containsAllAsciiNP;
/**
@ -812,7 +827,7 @@ function getDomain(hostHeader, forwardedHostHeader) {
return hostHeader.split(',')[0].trim();
}
return 'localhost';
};
}
function getBaseUrl(protocol, hostHeader, forwardedProtoHeader, forwardedHostHeader, forwardedPrefixHeader) {
var url = '';
if (forwardedProtoHeader && constants.ALLOWED_PROTO.test(forwardedProtoHeader)) {
@ -838,8 +853,14 @@ function getBaseUrlByConnection(ctx, conn) {
const forwardedPrefix = conn.headers['x-forwarded-prefix'];
const host = conn.headers['host'];
const proto = cloudfrontForwardedProto || forwardedProto;
ctx.logger.debug(`getBaseUrlByConnection host=%s x-forwarded-host=%s x-forwarded-proto=%s x-forwarded-prefix=%s cloudfront-forwarded-proto=%s `,
host, forwardedHost, forwardedProto, forwardedPrefix, cloudfrontForwardedProto);
ctx.logger.debug(
`getBaseUrlByConnection host=%s x-forwarded-host=%s x-forwarded-proto=%s x-forwarded-prefix=%s cloudfront-forwarded-proto=%s `,
host,
forwardedHost,
forwardedProto,
forwardedPrefix,
cloudfrontForwardedProto
);
return getBaseUrl('', host, proto, forwardedHost, forwardedPrefix);
}
function getBaseUrlByRequest(ctx, req) {
@ -851,8 +872,15 @@ function getBaseUrlByRequest(ctx, req) {
const host = req.get('host');
const protocol = req.protocol;
const proto = cloudfrontForwardedProto || forwardedProto;
ctx.logger.debug(`getBaseUrlByRequest protocol=%s host=%s x-forwarded-host=%s x-forwarded-proto=%s x-forwarded-prefix=%s cloudfront-forwarded-proto=%s `,
protocol, host, forwardedHost, forwardedProto, forwardedPrefix, cloudfrontForwardedProto);
ctx.logger.debug(
`getBaseUrlByRequest protocol=%s host=%s x-forwarded-host=%s x-forwarded-proto=%s x-forwarded-prefix=%s cloudfront-forwarded-proto=%s `,
protocol,
host,
forwardedHost,
forwardedProto,
forwardedPrefix,
cloudfrontForwardedProto
);
return getBaseUrl(protocol, host, proto, forwardedHost, forwardedPrefix);
}
exports.getBaseUrlByConnection = getBaseUrlByConnection;
@ -873,10 +901,10 @@ function getDomainByRequest(ctx, req) {
exports.getDomainByConnection = getDomainByConnection;
exports.getDomainByRequest = getDomainByRequest;
function getShardKeyByConnection(ctx, conn) {
return conn?.handshake?.query?.[constants.SHARD_KEY_API_NAME];
return conn?.handshake?.query?.[constants.SHARD_KEY_API_NAME];
}
function getWopiSrcByConnection(ctx, conn) {
return conn?.handshake?.query?.[constants.SHARD_KEY_WOPI_NAME];
return conn?.handshake?.query?.[constants.SHARD_KEY_WOPI_NAME];
}
function getShardKeyByRequest(ctx, req) {
return req.query?.[constants.SHARD_KEY_API_NAME];
@ -894,7 +922,7 @@ function stream2Buffer(stream) {
resolve(Buffer.alloc(0));
}
var bufs = [];
stream.on('data', (data) => {
stream.on('data', data => {
bufs.push(data);
});
function onEnd(err) {
@ -925,7 +953,7 @@ function pipeStreams(from, to, isEnd) {
from.on('end', () => {
resolve();
});
from.on('error', (e) => {
from.on('error', e => {
reject(e);
});
});
@ -990,17 +1018,17 @@ function checkClientIp(req, res, next) {
const ctx = new operationContext.Context();
ctx.initFromRequest(req);
const tenIpFilterUseForRequest = ctx.getCfg('services.CoAuthoring.ipfilter.useforrequest', cfgIpFilterUseForRequest);
let status = 0;
if (tenIpFilterUseForRequest) {
const addresses = forwarded(req);
const ipString = addresses[addresses.length - 1];
status = checkIpFilter(ctx, ipString);
}
if (status > 0) {
res.sendStatus(status);
} else {
next();
}
let status = 0;
if (tenIpFilterUseForRequest) {
const addresses = forwarded(req);
const ipString = addresses[addresses.length - 1];
status = checkIpFilter(ctx, ipString);
}
if (status > 0) {
res.sendStatus(status);
} else {
next();
}
}
exports.checkClientIp = checkClientIp;
function lowercaseQueryString(req, res, next) {
@ -1015,7 +1043,7 @@ function lowercaseQueryString(req, res, next) {
exports.lowercaseQueryString = lowercaseQueryString;
function dnsLookup(hostname, options) {
return new Promise((resolve, reject) => {
dnscache.lookup(hostname, options, (err, addresses) =>{
dnscache.lookup(hostname, options, (err, addresses) => {
if (err) {
reject(err);
} else {
@ -1063,10 +1091,10 @@ function fillJwtForRequest(ctx, payload, secret, opt_inBody) {
}
exports.fillJwtForRequest = fillJwtForRequest;
exports.forwarded = forwarded;
exports.getIndexFromUserId = function(userId, userIdOriginal){
exports.getIndexFromUserId = function (userId, userIdOriginal) {
return parseInt(userId.substring(userIdOriginal.length));
};
exports.checkPathTraversal = function(ctx, docId, rootDirectory, filename) {
exports.checkPathTraversal = function (ctx, docId, rootDirectory, filename) {
if (filename.indexOf('\0') !== -1) {
ctx.logger.warn('checkPathTraversal Poison Null Bytes filename=%s', filename);
return false;
@ -1077,28 +1105,28 @@ exports.checkPathTraversal = function(ctx, docId, rootDirectory, filename) {
}
return true;
};
exports.getConnectionInfo = function(conn){
var user = conn.user;
var data = {
id: user.id,
idOriginal: user.idOriginal,
username: user.username,
indexUser: user.indexUser,
view: user.view,
connectionId: conn.id,
isCloseCoAuthoring: conn.isCloseCoAuthoring,
isLiveViewer: exports.isLiveViewer(conn),
encrypted: conn.encrypted
};
return data;
exports.getConnectionInfo = function (conn) {
var user = conn.user;
var data = {
id: user.id,
idOriginal: user.idOriginal,
username: user.username,
indexUser: user.indexUser,
view: user.view,
connectionId: conn.id,
isCloseCoAuthoring: conn.isCloseCoAuthoring,
isLiveViewer: exports.isLiveViewer(conn),
encrypted: conn.encrypted
};
return data;
};
exports.getConnectionInfoStr = function(conn){
exports.getConnectionInfoStr = function (conn) {
return JSON.stringify(exports.getConnectionInfo(conn));
};
exports.isLiveViewer = function(conn){
return conn.user?.view && "fast" === conn.coEditingMode;
exports.isLiveViewer = function (conn) {
return conn.user?.view && 'fast' === conn.coEditingMode;
};
exports.isLiveViewerSupport = function(licenseInfo){
exports.isLiveViewerSupport = function (licenseInfo) {
return licenseInfo.connectionsView > 0 || licenseInfo.usersViewCount > 0;
};
exports.canIncludeOutboxAuthorization = function (ctx, url) {
@ -1122,12 +1150,7 @@ exports.encryptPassword = async function (ctx, password) {
const pbkdf2Promise = util.promisify(crypto.pbkdf2);
const tenSecret = ctx.getCfg('aesEncrypt.secret', cfgSecret);
const tenAESConfig = ctx.getCfg('aesEncrypt.config', cfgAESConfig) ?? {};
const {
keyByteLength = 32,
saltByteLength = 64,
initializationVectorByteLength = 16,
iterationsByteLength = 5
} = tenAESConfig;
const {keyByteLength = 32, saltByteLength = 64, initializationVectorByteLength = 16, iterationsByteLength = 5} = tenAESConfig;
const salt = crypto.randomBytes(saltByteLength);
const initializationVector = crypto.randomBytes(initializationVectorByteLength);
@ -1140,7 +1163,7 @@ exports.encryptPassword = async function (ctx, password) {
const encryptionKey = await pbkdf2Promise(tenSecret, salt, iterations, keyByteLength, 'sha512');
//todo chacha20-poly1305 (clean db)
const cipher = crypto.createCipheriv('aes-256-gcm', encryptionKey, initializationVector, {authTagLength:16});
const cipher = crypto.createCipheriv('aes-256-gcm', encryptionKey, initializationVector, {authTagLength: 16});
const encryptedData = Buffer.concat([cipher.update(password, 'utf8'), cipher.final()]);
const authTag = cipher.getAuthTag();
const predicate = iterations.toString(16);
@ -1152,11 +1175,7 @@ exports.decryptPassword = async function (ctx, password) {
const pbkdf2Promise = util.promisify(crypto.pbkdf2);
const tenSecret = ctx.getCfg('aesEncrypt.secret', cfgSecret);
const tenAESConfig = ctx.getCfg('aesEncrypt.config', cfgAESConfig) ?? {};
const {
keyByteLength = 32,
saltByteLength = 64,
initializationVectorByteLength = 16,
} = tenAESConfig;
const {keyByteLength = 32, saltByteLength = 64, initializationVectorByteLength = 16} = tenAESConfig;
const [iterations, dataHex] = password.split(':');
const data = Buffer.from(dataHex, 'hex');
@ -1174,23 +1193,18 @@ exports.decryptPassword = async function (ctx, password) {
}
}
const [
salt,
initializationVector,
authTag,
encryptedData
] = pointerArray;
const [salt, initializationVector, authTag, encryptedData] = pointerArray;
const decryptionKey = await pbkdf2Promise(tenSecret, salt, parseInt(iterations, 16), keyByteLength, 'sha512');
const decipher = crypto.createDecipheriv('aes-256-gcm', decryptionKey, initializationVector, {authTagLength:16});
const decipher = crypto.createDecipheriv('aes-256-gcm', decryptionKey, initializationVector, {authTagLength: 16});
decipher.setAuthTag(authTag);
return Buffer.concat([decipher.update(encryptedData, 'binary'), decipher.final()]).toString();
};
exports.getDateTimeTicks = function(date) {
exports.getDateTimeTicks = function (date) {
return BigInt(date.getTime() * 10000) + 621355968000000000n;
};
exports.convertLicenseInfoToFileParams = function(licenseInfo) {
exports.convertLicenseInfoToFileParams = function (licenseInfo) {
// todo
// {
// user_quota = 0;
@ -1219,7 +1233,7 @@ exports.convertLicenseInfoToFileParams = function(licenseInfo) {
license.grace_days = licenseInfo.graceDays;
return license;
};
exports.convertLicenseInfoToServerParams = function(licenseInfo) {
exports.convertLicenseInfoToServerParams = function (licenseInfo) {
const license = {};
license.workersCount = licenseInfo.count;
license.resultType = licenseInfo.type;
@ -1229,20 +1243,20 @@ exports.convertLicenseInfoToServerParams = function(licenseInfo) {
license.buildNumber = commonDefines.buildNumber;
return license;
};
exports.checkBaseUrl = function(ctx, baseUrl, opt_storageCfg) {
const storageExternalHost = opt_storageCfg ? opt_storageCfg.externalHost : cfgStorageExternalHost
exports.checkBaseUrl = function (ctx, baseUrl, opt_storageCfg) {
const storageExternalHost = opt_storageCfg ? opt_storageCfg.externalHost : cfgStorageExternalHost;
const tenStorageExternalHost = ctx.getCfg('storage.externalHost', storageExternalHost);
return tenStorageExternalHost ? tenStorageExternalHost : baseUrl;
};
exports.resolvePath = function(object, path, defaultValue) {
return path.split('.').reduce((o, p) => o ? o[p] : defaultValue, object);
exports.resolvePath = function (object, path, defaultValue) {
return path.split('.').reduce((o, p) => (o ? o[p] : defaultValue), object);
};
Date.isLeapYear = function (year) {
return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
};
Date.getDaysInMonth = function (year, month) {
return [31, (Date.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
return [31, Date.isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
};
Date.prototype.isLeapYear = function () {
@ -1309,34 +1323,35 @@ class SizeLimitStream extends Transform {
callback(null, chunk);
}
}
exports.getLicensePeriod = function(startDate, now) {
startDate = new Date(startDate.getTime());//clone
exports.getLicensePeriod = function (startDate, now) {
startDate = new Date(startDate.getTime()); //clone
startDate.addMonths(getMonthDiff(startDate, now));
if (startDate > now) {
startDate.addMonths(-1);
}
startDate.setUTCHours(0,0,0,0);
startDate.setUTCHours(0, 0, 0, 0);
return startDate.getTime();
};
exports.removeIllegalCharacters = function(filename) {
exports.removeIllegalCharacters = function (filename) {
return filename?.replace(/[/\\?%*:|"<>]/g, '-') || filename;
}
exports.getFunctionArguments = function(func) {
return func.toString().
replace(/[\r\n\s]+/g, ' ').
match(/(?:function\s*\w*)?\s*(?:\((.*?)\)|([^\s]+))/).
slice(1, 3).
join('').
split(/\s*,\s*/);
};
exports.isUselesSfc = function(row, cmd) {
exports.getFunctionArguments = function (func) {
return func
.toString()
.replace(/[\r\n\s]+/g, ' ')
.match(/(?:function\s*\w*)?\s*(?:\((.*?)\)|([^\s]+))/)
.slice(1, 3)
.join('')
.split(/\s*,\s*/);
};
exports.isUselesSfc = function (row, cmd) {
return !(row && commonDefines.FileStatus.SaveVersion === row.status && cmd.getStatusInfoIn() === row.status_info);
};
exports.getChangesFileHeader = function() {
exports.getChangesFileHeader = function () {
return `CHANGES\t${commonDefines.buildVersion}\n`;
};
exports.checksumFile = function(hashName, path) {
exports.checksumFile = function (hashName, path) {
//https://stackoverflow.com/a/44643479
return new Promise((resolve, reject) => {
const hash = crypto.createHash(hashName);
@ -1348,7 +1363,7 @@ exports.checksumFile = function(hashName, path) {
};
function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
return item && typeof item === 'object' && !Array.isArray(item);
}
function deepMergeObjects(target, ...sources) {
@ -1361,12 +1376,12 @@ function deepMergeObjects(target, ...sources) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) {
Object.assign(target, { [key]: {} });
Object.assign(target, {[key]: {}});
}
deepMergeObjects(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
Object.assign(target, {[key]: source[key]});
}
}
}
@ -1375,19 +1390,19 @@ function deepMergeObjects(target, ...sources) {
}
exports.isObject = isObject;
exports.deepMergeObjects = deepMergeObjects;
exports.NodeCache = NodeCache;//todo via require
exports.NodeCache = NodeCache; //todo via require
//like suggestion in https://github.com/paulmillr/chokidar/issues/242#issuecomment-76205459
const UNSAFE_MAGIC = new Set([
0x6969, // NFS
0xFF534D42, // CIFS/SMB1
0xFE534D42, // SMB2+
0x517B, // legacy SMB
0x65735546, // FUSE
0x794C7630, // overlayfs
0x00C36400, // CephFS
0x73757245, // Coda
0x6B414653 // AFS
0x6969, // NFS
0xff534d42, // CIFS/SMB1
0xfe534d42, // SMB2+
0x517b, // legacy SMB
0x65735546, // FUSE
0x794c7630, // overlayfs
0x00c36400, // CephFS
0x73757245, // Coda
0x6b414653 // AFS
]);
/**
@ -1408,7 +1423,6 @@ async function getFsType(ctx, path) {
}
}
/**
* File watcher with native events fallback to polling
* @param {operationContext} ctx - Operation context
@ -1428,7 +1442,7 @@ exports.watchWithFallback = async function watchWithFallback(ctx, dirPath, fileP
//Try native watch
try {
const watcher = fs.watch(dirPath, opts, listener);
watcher.on('error', (err) => {
watcher.on('error', err => {
watcher.close();
ctx.logger.info(`watchWithFallback error ${dirPath} fallback to watchFile ${filePath}: ${err.message}`);
fs.watchFile(filePath, opts, listener);
@ -1439,4 +1453,4 @@ exports.watchWithFallback = async function watchWithFallback(ctx, dirPath, fileP
ctx.logger.info(`watchWithFallback error ${dirPath} fallback to watchFile ${filePath}: ${err.message}`);
return fs.watchFile(filePath, opts, listener);
}
}
};

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,7 @@
'use strict';
const { buffer } = require('node:stream/consumers');
const {buffer} = require('node:stream/consumers');
const config = require('config');
const utils = require('../../../Common/sources/utils');
const operationContext = require('../../../Common/sources/operationContext');
@ -48,7 +48,7 @@ const engineScriptsDir = path.join(cfgAiPluginDir, 'scripts/engine');
function setCtx(ctx) {
sandbox.ctx = ctx;
console.log = ctx.logger.debug.bind(ctx.logger);//todo make default in logger
console.log = ctx.logger.debug.bind(ctx.logger); //todo make default in logger
console.error = ctx.logger.error.bind(ctx.logger);
}
@ -60,14 +60,26 @@ const sandbox = {
TmpProviderForModels: null,
Providers: {},
InternalProviders: [],
_getHeaders() {return {};},
_getEndpointUrl() {return "";},
serializeProviders() {return [];},
ActionsGetSorted() {return [];},
getModels() {return [];},
_getHeaders() {
return {};
},
_getEndpointUrl() {
return '';
},
serializeProviders() {
return [];
},
ActionsGetSorted() {
return [];
},
getModels() {
return [];
},
onLoadInternalProviders() {},
Storage: {
serializeModels() {return [];}
serializeModels() {
return [];
}
},
CapabilitiesUI: {}
}
@ -97,31 +109,32 @@ const sandbox = {
connectionAndInactivity: cfgAiApiTimeout,
wholeCycle: cfgAiApiTimeout
};
ctx.logger.debug("engineWrapper fetch", url, options);
return utils.httpRequest(
sandbox.ctx,
method,
url,
options.headers || {},
options.body || null,
timeoutOptions,
null,
true //true because request limited by local network
)
.then(async (result) => {
const responseBuffer = await buffer(result.stream);
const text = responseBuffer.toString('utf8');
ctx.logger.debug('engineWrapper fetch', url, options);
return utils
.httpRequest(
sandbox.ctx,
method,
url,
options.headers || {},
options.body || null,
timeoutOptions,
null,
true //true because request limited by local network
)
.then(async result => {
const responseBuffer = await buffer(result.stream);
const text = responseBuffer.toString('utf8');
return {
status: result.response.status,
statusText: result.response.statusText,
ok: result.response.status >= 200 && result.response.status < 300,
headers: result.response.headers,
text: () => Promise.resolve(text),
json: () => Promise.resolve(JSON.parse(text)),
arrayBuffer: () => Promise.resolve(responseBuffer.buffer)
};
});
return {
status: result.response.status,
statusText: result.response.statusText,
ok: result.response.status >= 200 && result.response.status < 300,
headers: result.response.headers,
text: () => Promise.resolve(text),
json: () => Promise.resolve(JSON.parse(text)),
arrayBuffer: () => Promise.resolve(responseBuffer.buffer)
};
});
}
};
@ -155,7 +168,7 @@ function loadInternalProviders() {
try {
//sandbox.ctx.logger.debug(`Loading provider ${file}:`);
const content = "(function(){\n" + providerCode + "\nreturn new Provider();})();";
const content = '(function(){\n' + providerCode + '\nreturn new Provider();})();';
// Execute provider code in sandbox
const provider = vm.runInNewContext(content, sandbox, {
filename: file,
@ -197,39 +210,38 @@ if (engineCode) {
}
//start from engine/register.js
(function() {
(function () {
const AI = sandbox.AI;
const Asc = sandbox.Asc;
AI.ActionType = {
Chat : "Chat",
Summarization : "Summarization",
Translation : "Translation",
TextAnalyze : "TextAnalyze",
ImageGeneration : "ImageGeneration",
OCR : "OCR",
Vision : "Vision"
Chat: 'Chat',
Summarization: 'Summarization',
Translation: 'Translation',
TextAnalyze: 'TextAnalyze',
ImageGeneration: 'ImageGeneration',
OCR: 'OCR',
Vision: 'Vision'
};
AI.Actions = {};
function ActionUI(name, icon, modelId, capabilities) {
this.name = name || "";
this.icon = icon || "";
this.model = modelId || "";
this.capabilities = (capabilities === undefined) ? AI.CapabilitiesUI.Chat : capabilities;
this.name = name || '';
this.icon = icon || '';
this.model = modelId || '';
this.capabilities = capabilities === undefined ? AI.CapabilitiesUI.Chat : capabilities;
}
AI.Actions[AI.ActionType.Chat] = new ActionUI("Chatbot", "ask-ai");
AI.Actions[AI.ActionType.Summarization] = new ActionUI("Summarization", "summarization");
AI.Actions[AI.ActionType.Translation] = new ActionUI("Translation", "translation");
AI.Actions[AI.ActionType.TextAnalyze] = new ActionUI("Text analysis", "text-analysis-ai");
AI.Actions[AI.ActionType.ImageGeneration] = new ActionUI("Image generation", "image-ai", "", AI.CapabilitiesUI.Image);
AI.Actions[AI.ActionType.OCR] = new ActionUI("OCR", "text-analysis-ai", "", AI.CapabilitiesUI.Vision);
AI.Actions[AI.ActionType.Vision] = new ActionUI("Vision", "vision-ai", "", AI.CapabilitiesUI.Vision);
AI.Actions[AI.ActionType.Chat] = new ActionUI('Chatbot', 'ask-ai');
AI.Actions[AI.ActionType.Summarization] = new ActionUI('Summarization', 'summarization');
AI.Actions[AI.ActionType.Translation] = new ActionUI('Translation', 'translation');
AI.Actions[AI.ActionType.TextAnalyze] = new ActionUI('Text analysis', 'text-analysis-ai');
AI.Actions[AI.ActionType.ImageGeneration] = new ActionUI('Image generation', 'image-ai', '', AI.CapabilitiesUI.Image);
AI.Actions[AI.ActionType.OCR] = new ActionUI('OCR', 'text-analysis-ai', '', AI.CapabilitiesUI.Vision);
AI.Actions[AI.ActionType.Vision] = new ActionUI('Vision', 'vision-ai', '', AI.CapabilitiesUI.Vision);
AI.ActionsGetKeys = function()
{
AI.ActionsGetKeys = function () {
return [
AI.ActionType.Chat,
AI.ActionType.Summarization,
@ -241,21 +253,19 @@ if (engineCode) {
];
};
AI.ActionsGetSorted = function()
{
AI.ActionsGetSorted = function () {
const keys = AI.ActionsGetKeys();
const count = keys.length;
const actions = new Array(count);
for (let i = 0; i < count; i++)
{
for (let i = 0; i < count; i++) {
const src = AI.Actions[keys[i]];
actions[i] = {
id : keys[i],
name : Asc.plugin.tr(src.name),
icon : src.icon,
model : src.model,
capabilities : src.capabilities
}
id: keys[i],
name: Asc.plugin.tr(src.name),
icon: src.icon,
model: src.model,
capabilities: src.capabilities
};
}
return actions;
};

View File

@ -32,8 +32,8 @@
'use strict';
const { pipeline } = require('stream/promises');
const { URL } = require('url');
const {pipeline} = require('stream/promises');
const {URL} = require('url');
const config = require('config');
const utils = require('./../../../Common/sources/utils');
const operationContext = require('./../../../Common/sources/operationContext');
@ -115,34 +115,34 @@ function handleCorsHeaders(req, res, ctx, handleOptions = true) {
* @returns {string} The updated URI with API key as a query parameter, if applicable.
*/
function appendApiKeyToQuery(ctx, provider, uri) {
const urlWithKey = AI._getEndpointUrl(provider, AI.Endpoints.Types.v1.Models);
const urlWithKey = AI._getEndpointUrl(provider, AI.Endpoints.Types.v1.Models);
// To check if the key is part of the query, we get the URL without the key.
const originalKey = provider.key;
provider.key = undefined;
const urlWithoutKey = AI._getEndpointUrl(provider, AI.Endpoints.Types.v1.Models);
provider.key = originalKey; // Restore the key on the provider object.
// To check if the key is part of the query, we get the URL without the key.
const originalKey = provider.key;
provider.key = undefined;
const urlWithoutKey = AI._getEndpointUrl(provider, AI.Endpoints.Types.v1.Models);
provider.key = originalKey; // Restore the key on the provider object.
if (urlWithKey !== urlWithoutKey) {
try {
const parsedUrlWithKey = new URL(urlWithKey);
if (parsedUrlWithKey.search) {
const parsedUri = new URL(uri);
for (const [key, value] of parsedUrlWithKey.searchParams) {
if (originalKey === value) {
parsedUri.searchParams.set(key, value);
break;
}
}
ctx.logger.debug(`appendApiKeyToQuery: Appended API key to URI for provider ${provider.name}`);
return parsedUri.toString();
}
} catch (error) {
ctx.logger.error(`appendApiKeyToQuery: Failed to parse provider URL for ${provider.name}: ${urlWithKey}`, error);
if (urlWithKey !== urlWithoutKey) {
try {
const parsedUrlWithKey = new URL(urlWithKey);
if (parsedUrlWithKey.search) {
const parsedUri = new URL(uri);
for (const [key, value] of parsedUrlWithKey.searchParams) {
if (originalKey === value) {
parsedUri.searchParams.set(key, value);
break;
}
}
ctx.logger.debug(`appendApiKeyToQuery: Appended API key to URI for provider ${provider.name}`);
return parsedUri.toString();
}
} catch (error) {
ctx.logger.error(`appendApiKeyToQuery: Failed to parse provider URL for ${provider.name}: ${urlWithKey}`, error);
}
}
return uri;
return uri;
}
/**
@ -179,9 +179,9 @@ async function proxyRequest(req, res) {
if (!checkJwtRes || checkJwtRes.err) {
ctx.logger.error('proxyRequest: checkJwtHeader error: %s', checkJwtRes?.err);
res.status(403).json({
"error": {
"message": "proxyRequest: checkJwtHeader error",
"code": "403"
error: {
message: 'proxyRequest: checkJwtHeader error',
code: '403'
}
});
return;
@ -196,9 +196,9 @@ async function proxyRequest(req, res) {
if (!tenAiApi?.providers) {
ctx.logger.error('proxyRequest: No providers configured');
res.status(403).json({
"error": {
"message": "proxyRequest: No providers configured",
"code": "403"
error: {
message: 'proxyRequest: No providers configured',
code: '403'
}
});
return;
@ -229,17 +229,16 @@ async function proxyRequest(req, res) {
if (!providerHeaders) {
ctx.logger.warn(`proxyRequest: target '${uri}' does not match any configured AI provider. Denying access.`);
res.status(403).json({
"error": {
"message": "proxyRequest: target does not match any configured AI provider",
"code": "403"
error: {
message: 'proxyRequest: target does not match any configured AI provider',
code: '403'
}
});
return;
}
// Merge key in headers
const headers = { ...body.headers, ...providerHeaders };
const headers = {...body.headers, ...providerHeaders};
// use proxy instead of direct request
if (tenAiApiProxy) {
@ -253,7 +252,7 @@ async function proxyRequest(req, res) {
key: docId,
user: userId,
customer_id: licenseInfo.customerId
}
};
const secret = await tenantManager.getTenantSecret(ctx, commonDefines.c_oAscSecretType.Outbox);
const auth = utils.fillJwtForRequest(ctx, dataObject, secret, false);
@ -290,13 +289,13 @@ async function proxyRequest(req, res) {
// Use utils.httpRequest to make the request
const result = await utils.httpRequest(
ctx, // Operation context
requestParams.method, // HTTP method
requestParams.uri, // Target URL
ctx, // Operation context
requestParams.method, // HTTP method
requestParams.uri, // Target URL
requestParams.headers, // Request headers
requestParams.body, // Request body
requestParams.body, // Request body
requestParams.timeout, // Timeout configuration
requestParams.limit, // Size limit
requestParams.limit, // Size limit
requestParams.isInJwtToken // Filter private requests
);
@ -306,10 +305,9 @@ async function proxyRequest(req, res) {
// Use pipeline to pipe the response data to the client
await pipeline(result.stream, res);
success = true;
} catch (error) {
ctx.logger.error(`proxyRequest: AI API request error: %s`, error);
if (error.response){
if (error.response) {
// Set the response headers to match the target response
res.set(error.response.headers);
@ -317,19 +315,19 @@ async function proxyRequest(req, res) {
await pipeline(error.response.data, res);
} else {
res.status(500).json({
"error": {
"message": "proxyRequest: AI API request error",
"code": "500"
error: {
message: 'proxyRequest: AI API request error',
code: '500'
}
});
}
} finally {
// Record the time taken for the proxyRequest in StatsD (skip cors requests and errors)
if (clientStatsD && success) {
clientStatsD.timing('coauth.aiProxy', new Date() - startDate);
}
ctx.logger.info('End proxyRequest');
} finally {
// Record the time taken for the proxyRequest in StatsD (skip cors requests and errors)
if (clientStatsD && success) {
clientStatsD.timing('coauth.aiProxy', new Date() - startDate);
}
ctx.logger.info('End proxyRequest');
}
}
/**
@ -366,7 +364,7 @@ async function processProvider(ctx, provider) {
return {
name: provider.name,
url: provider.url,
key: "",
key: '',
models: engineModels,
modelsUI: engineModelsUI
};
@ -393,7 +391,7 @@ async function getPluginSettings(ctx) {
const tenProviders = ctx.getCfg('aiSettings.providers', cfgAiSettings.providers);
// Process providers and their models if configuration exists
if (tenProviders && Object.keys(tenProviders).length > 0) {
result.providers = tenProviders
result.providers = tenProviders;
} else {
const providers = AI.serializeProviders();
for (let i = 0; i < providers.length; i++) {
@ -440,8 +438,7 @@ async function getPluginSettings(ctx) {
result.version = tenVersion;
} catch (error) {
logger.error('Error retrieving AI models from config:', error);
}
finally {
} finally {
logger.info('Completed getPluginSettings');
}
return result;
@ -464,7 +461,7 @@ async function getPluginSettingsForInterface(ctx) {
//remove keys from providers
if (pluginSettings && pluginSettings.providers) {
for (const key in pluginSettings.providers) {
pluginSettings.providers[key].key = "";
pluginSettings.providers[key].key = '';
}
}
return pluginSettings;
@ -472,11 +469,11 @@ async function getPluginSettingsForInterface(ctx) {
async function requestSettings(req, res) {
const ctx = new operationContext.Context();
ctx.initFromRequest(req);
ctx.initFromRequest(req);
try {
await ctx.initTenantCache();
const result = await getPluginSettings(ctx);
res.json(result);
const result = await getPluginSettings(ctx);
res.json(result);
} catch (error) {
ctx.logger.error('getSettings error: %s', error.stack);
res.sendStatus(400);
@ -485,7 +482,7 @@ async function requestSettings(req, res) {
async function requestModels(req, res) {
const ctx = new operationContext.Context();
ctx.initFromRequest(req);
ctx.initFromRequest(req);
try {
await ctx.initTenantCache();
const body = JSON.parse(req.body);

View File

@ -34,7 +34,7 @@
const crypto = require('crypto');
var pathModule = require('path');
var urlModule = require('url');
const { pipeline } = require('node:stream/promises');
const {pipeline} = require('node:stream/promises');
var co = require('co');
const ms = require('ms');
const retry = require('retry');
@ -79,8 +79,8 @@ var SAVE_TYPE_COMPLETE_ALL = 3;
var clientStatsD = statsDClient.getClient();
var redisKeyShutdown = cfgRedisPrefix + constants.REDIS_KEY_SHUTDOWN;
let hasPasswordCol = false;//stub on upgradev630.sql update failure
exports.hasAdditionalCol = false;//stub on upgradev710.sql update failure
let hasPasswordCol = false; //stub on upgradev630.sql update failure
exports.hasAdditionalCol = false; //stub on upgradev710.sql update failure
function OutputDataWrap(type, data) {
this['type'] = type;
@ -156,7 +156,6 @@ function getOpenedAt(row) {
if (row) {
return sqlBase.DocumentAdditional.prototype.getOpenedAt(row.additional);
}
}
function getOpenedAtJSONParams(row) {
const documentLayout = row && sqlBase.DocumentAdditional.prototype.getDocumentLayout(row.additional);
@ -187,17 +186,18 @@ async function getOutputData(ctx, cmd, outputData, key, optConn, optAdditionalOu
case commonDefines.FileStatus.SaveVersion:
case commonDefines.FileStatus.UpdateVersion:
case commonDefines.FileStatus.Ok:
if(commonDefines.FileStatus.Ok === status) {
if (commonDefines.FileStatus.Ok === status) {
outputData.setStatus('ok');
} else if (optConn && optConn.isCloseCoAuthoring) {
outputData.setStatus(constants.FILE_STATUS_UPDATE_VERSION);
} else if (optConn && optConn.user.view) {
outputData.setStatus('ok');
} else if (commonDefines.FileStatus.SaveVersion === status ||
(!opt_bIsRestore && commonDefines.FileStatus.UpdateVersion === status &&
Date.now() - statusInfo * 60000 > tenExpUpdateVersionStatus)) {
} else if (
commonDefines.FileStatus.SaveVersion === status ||
(!opt_bIsRestore && commonDefines.FileStatus.UpdateVersion === status && Date.now() - statusInfo * 60000 > tenExpUpdateVersionStatus)
) {
if (commonDefines.FileStatus.UpdateVersion === status) {
ctx.logger.warn("UpdateVersion expired");
ctx.logger.warn('UpdateVersion expired');
}
var updateMask = new taskResult.TaskResultData();
updateMask.tenant = ctx.tenant;
@ -221,11 +221,10 @@ async function getOutputData(ctx, cmd, outputData, key, optConn, optAdditionalOu
var strPath = key + '/' + cmd.getOutputPath();
if (optConn) {
let url;
if(cmd.getInline()) {
if (cmd.getInline()) {
url = await getPrintFileUrl(ctx, key, optConn.baseUrl, cmd.getTitle());
} else {
url = await storage.getSignedUrl(ctx, optConn.baseUrl, strPath, commonDefines.c_oAscUrlTypes.Temporary,
cmd.getTitle());
url = await storage.getSignedUrl(ctx, optConn.baseUrl, strPath, commonDefines.c_oAscUrlTypes.Temporary, cmd.getTitle());
}
outputData.setData(url);
outputData.setExtName(pathModule.extname(strPath));
@ -252,7 +251,7 @@ async function getOutputData(ctx, cmd, outputData, key, optConn, optAdditionalOu
isNeedPassword = 0 !== formEditor.length;
}
if (isNeedPassword) {
ctx.logger.debug("getOutputData password mismatch");
ctx.logger.debug('getOutputData password mismatch');
if (encryptedUserPassword) {
outputData.setStatus('needpassword');
outputData.setData(constants.CONVERT_PASSWORD);
@ -357,7 +356,7 @@ function* saveParts(ctx, cmd, filename) {
var saveType = cmd.getSaveType();
if (SAVE_TYPE_COMPLETE_ALL !== saveType) {
const ext = pathModule.extname(filename);
const saveIndex = parseInt(cmd.getSaveIndex()) || 1;//prevent path traversal
const saveIndex = parseInt(cmd.getSaveIndex()) || 1; //prevent path traversal
filename = pathModule.basename(filename, ext) + saveIndex + ext;
}
if ((SAVE_TYPE_PART_START === saveType || SAVE_TYPE_COMPLETE_ALL === saveType) && !cmd.getSaveKey()) {
@ -370,7 +369,7 @@ function* saveParts(ctx, cmd, filename) {
yield storage.putObject(ctx, cmd.getDocId() + cmd.getSaveKey() + '/' + filename, buffer, buffer.length);
//delete data to prevent serialize into json
cmd.data = null;
result = (SAVE_TYPE_COMPLETE_ALL === saveType || SAVE_TYPE_COMPLETE === saveType);
result = SAVE_TYPE_COMPLETE_ALL === saveType || SAVE_TYPE_COMPLETE === saveType;
} else {
result = true;
}
@ -409,7 +408,7 @@ async function getUpdateResponse(ctx, cmd) {
const selectRes = await taskResult.select(ctx, updateTask.key);
hasPasswordCol = selectRes.length > 0 && undefined !== selectRes[0].password;
}
if(hasPasswordCol) {
if (hasPasswordCol) {
updateTask.password = password;
}
}
@ -445,7 +444,7 @@ var cleanupCache = co.wrap(function* (ctx, docId) {
yield storage.deletePath(ctx, docId);
res = true;
}
ctx.logger.debug("cleanupCache docId=%s db.affectedRows=%d", docId, removeRes.affectedRows);
ctx.logger.debug('cleanupCache docId=%s db.affectedRows=%d', docId, removeRes.affectedRows);
return res;
});
var cleanupCacheIf = co.wrap(function* (ctx, mask) {
@ -457,7 +456,7 @@ var cleanupCacheIf = co.wrap(function* (ctx, mask) {
yield storage.deletePath(ctx, mask.key);
res = true;
}
ctx.logger.debug("cleanupCacheIf db.affectedRows=%d", removeRes.affectedRows);
ctx.logger.debug('cleanupCacheIf db.affectedRows=%d', removeRes.affectedRows);
return res;
});
async function cleanupErrToReload(ctx, key) {
@ -500,7 +499,7 @@ function* commandOpen(ctx, conn, cmd, outputData, opt_upsertRes, opt_bIsRestore)
needAddTask = yield* commandOpenFillOutput(ctx, conn, cmd, outputData, opt_bIsRestore);
}
if (conn.encrypted) {
ctx.logger.debug("commandOpen encrypted %j", outputData);
ctx.logger.debug('commandOpen encrypted %j', outputData);
if (constants.FILE_STATUS_UPDATE_VERSION !== outputData.getStatus()) {
//don't send output data
outputData.setStatus(undefined);
@ -516,30 +515,30 @@ function* commandOpen(ctx, conn, cmd, outputData, opt_upsertRes, opt_bIsRestore)
task.statusInfo = constants.NO_ERROR;
const updateIfRes = yield taskResult.updateIf(ctx, task, updateMask);
if (updateIfRes.affectedRows > 0) {
const forgotten = yield storage.listObjects(ctx, cmd.getDocId(), tenForgottenFiles);
//replace url with forgotten file because it absorbed all lost changes
if (forgotten.length > 0) {
ctx.logger.debug("commandOpen from forgotten");
cmd.setUrl(undefined);
cmd.setForgotten(cmd.getDocId());
}
//add task
if (!cmd.getOutputFormat()) {
//todo remove getOpenFormatByEditor after 8.2.1
cmd.setOutputFormat(docsCoServer.getOpenFormatByEditor(conn.editorType));
}
cmd.setEmbeddedFonts(false);
var dataQueue = new commonDefines.TaskQueueData();
dataQueue.setCtx(ctx);
dataQueue.setCmd(cmd);
dataQueue.setToFile('Editor.bin');
yield* docsCoServer.addTask(dataQueue, constants.QUEUE_PRIORITY_HIGH);
} else {
yield* commandOpenFillOutput(ctx, conn, cmd, outputData, opt_bIsRestore);
if (updateIfRes.affectedRows > 0) {
const forgotten = yield storage.listObjects(ctx, cmd.getDocId(), tenForgottenFiles);
//replace url with forgotten file because it absorbed all lost changes
if (forgotten.length > 0) {
ctx.logger.debug('commandOpen from forgotten');
cmd.setUrl(undefined);
cmd.setForgotten(cmd.getDocId());
}
//add task
if (!cmd.getOutputFormat()) {
//todo remove getOpenFormatByEditor after 8.2.1
cmd.setOutputFormat(docsCoServer.getOpenFormatByEditor(conn.editorType));
}
cmd.setEmbeddedFonts(false);
var dataQueue = new commonDefines.TaskQueueData();
dataQueue.setCtx(ctx);
dataQueue.setCmd(cmd);
dataQueue.setToFile('Editor.bin');
yield* docsCoServer.addTask(dataQueue, constants.QUEUE_PRIORITY_HIGH);
} else {
yield* commandOpenFillOutput(ctx, conn, cmd, outputData, opt_bIsRestore);
}
}
}
function* commandOpenFillOutput(ctx, conn, cmd, outputData, opt_bIsRestore) {
const status = yield getOutputData(ctx, cmd, outputData, cmd.getDocId(), conn, undefined, opt_bIsRestore);
return commonDefines.FileStatus.None === status;
@ -574,7 +573,7 @@ function* commandReopen(ctx, conn, cmd, outputData) {
var upsertRes = yield taskResult.updateIf(ctx, task, updateMask);
if (upsertRes.affectedRows > 0) {
//add task
cmd.setUrl(null);//url may expire
cmd.setUrl(null); //url may expire
if (!cmd.getOutputFormat()) {
//todo remove getOpenFormatByEditor after 8.2.1
cmd.setOutputFormat(docsCoServer.getOpenFormatByEditor(conn.editorType));
@ -600,7 +599,7 @@ function* commandReopen(ctx, conn, cmd, outputData) {
}
function* commandSave(ctx, cmd, outputData) {
const format = cmd.getFormat() || 'bin';
var completeParts = yield* saveParts(ctx, cmd, "Editor." + format);
var completeParts = yield* saveParts(ctx, cmd, 'Editor.' + format);
if (completeParts) {
var queueData = getSaveTask(ctx, cmd);
yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW);
@ -611,7 +610,7 @@ function* commandSave(ctx, cmd, outputData) {
function* commandSendMailMerge(ctx, cmd, outputData) {
const mailMergeSend = cmd.getMailMergeSend();
const isJson = mailMergeSend.getIsJsonKey();
var completeParts = yield* saveParts(ctx, cmd, isJson ? "Editor.json" : "Editor.bin");
var completeParts = yield* saveParts(ctx, cmd, isJson ? 'Editor.json' : 'Editor.bin');
var isErr = false;
if (completeParts && !isJson) {
isErr = true;
@ -638,7 +637,7 @@ function* commandSendMailMerge(ctx, cmd, outputData) {
outputData.setData(cmd.getSaveKey());
}
}
const commandSfctByCmd = co.wrap(function*(ctx, cmd, opt_priority, opt_expiration, opt_queue, opt_initShardKey) {
const commandSfctByCmd = co.wrap(function* (ctx, cmd, opt_priority, opt_expiration, opt_queue, opt_initShardKey) {
var selectRes = yield taskResult.selectWithCache(ctx, cmd.getDocId());
var row = selectRes.length > 0 ? selectRes[0] : null;
if (!row) {
@ -672,8 +671,9 @@ function isDisplayedImage(strName) {
var displayN = parseInt(strName[index + findStr.length]);
if (!isNaN(displayN)) {
var imageIndex = index + findStr.length + 1;
if (imageIndex == strName.indexOf("image", imageIndex))
{res = displayN;}
if (imageIndex == strName.indexOf('image', imageIndex)) {
res = displayN;
}
}
}
}
@ -696,7 +696,7 @@ function* commandImgurls(ctx, conn, cmd, outputData) {
if (checkJwtRes.decoded) {
//todo multiple url case
if (checkJwtRes.decoded.images) {
urls = checkJwtRes.decoded.images.map((curValue) => {
urls = checkJwtRes.decoded.images.map(curValue => {
return curValue.url;
});
} else {
@ -718,7 +718,7 @@ function* commandImgurls(ctx, conn, cmd, outputData) {
var outputUrls = [];
if (constants.NO_ERROR === errorCode && !conn.user.view && !conn.isCloseCoAuthoring) {
//todo Promise.all()
const displayedImageMap = {};//to make one prefix for ole object urls
const displayedImageMap = {}; //to make one prefix for ole object urls
for (var i = 0; i < urls.length; ++i) {
var urlSource = urls[i];
var urlParsed;
@ -794,7 +794,7 @@ function* commandImgurls(ctx, conn, cmd, outputData) {
format = constants.AVS_OFFICESTUDIO_FILE_IMAGE_PNG;
formatStr = formatChecker.getStringFromFormat(format);
}
let strLocalPath = 'media/' + crypto.randomBytes(16).toString("hex") + '_';
let strLocalPath = 'media/' + crypto.randomBytes(16).toString('hex') + '_';
if (urlParsed) {
var urlBasename = pathModule.basename(urlParsed.pathname);
var displayN = isDisplayedImage(urlBasename);
@ -820,7 +820,7 @@ function* commandImgurls(ctx, conn, cmd, outputData) {
}
outputUrls.push(outputUrl);
}
} else if(constants.NO_ERROR === errorCode) {
} else if (constants.NO_ERROR === errorCode) {
ctx.logger.warn('error commandImgurls: access deny');
errorCode = constants.UPLOAD;
}
@ -833,7 +833,7 @@ function* commandImgurls(ctx, conn, cmd, outputData) {
}
}
function* commandPathUrls(ctx, conn, data, outputData) {
const listImages = data.map((currentValue) => {
const listImages = data.map(currentValue => {
return conn.docId + '/' + currentValue;
});
const urls = yield storage.getSignedUrlsArrayByArray(ctx, conn.baseUrl, listImages, commonDefines.c_oAscUrlTypes.Session);
@ -854,7 +854,7 @@ function* commandPathUrl(ctx, conn, cmd, outputData) {
}
}
function* commandSaveFromOrigin(ctx, cmd, outputData, password) {
var completeParts = yield* saveParts(ctx, cmd, "changes0.json");
var completeParts = yield* saveParts(ctx, cmd, 'changes0.json');
if (completeParts) {
const docPassword = sqlBase.DocumentPassword.prototype.getDocPassword(ctx, password);
//Use current password for pdf because password is entered in the browser when opening and is set via setPassword
@ -896,7 +896,13 @@ function* commandSetPassword(ctx, conn, cmd, outputData) {
//https://github.com/ONLYOFFICE/web-apps/blob/4a7879b4f88f315fe94d9f7d97c0ed8aa9f82221/apps/documenteditor/main/app/controller/Main.js#L1652
//this.appOptions.isPasswordSupport = this.appOptions.isEdit && this.api.asc_isProtectionSupport() && (this.permissions.protect!==false);
const isPasswordSupport = tenOpenProtectedFile && !conn.user?.view && false !== conn.permissions?.protect;
ctx.logger.debug('commandSetPassword isEnterCorrectPassword=%s, hasDocumentPassword=%s, hasPasswordCol=%s, isPasswordSupport=%s', conn.isEnterCorrectPassword, hasDocumentPassword, hasPasswordCol, isPasswordSupport);
ctx.logger.debug(
'commandSetPassword isEnterCorrectPassword=%s, hasDocumentPassword=%s, hasPasswordCol=%s, isPasswordSupport=%s',
conn.isEnterCorrectPassword,
hasDocumentPassword,
hasPasswordCol,
isPasswordSupport
);
if (isPasswordSupport && hasPasswordCol && hasDocumentPassword && !isDocumentPasswordModified) {
outputData.setStatus('ok');
} else if (isPasswordSupport && (conn.isEnterCorrectPassword || !hasDocumentPassword) && hasPasswordCol) {
@ -906,10 +912,10 @@ function* commandSetPassword(ctx, conn, cmd, outputData) {
updateMask.status = commonDefines.FileStatus.Ok;
const newChangesLastDate = new Date();
newChangesLastDate.setMilliseconds(0);//remove milliseconds avoid issues with MySQL datetime rounding
newChangesLastDate.setMilliseconds(0); //remove milliseconds avoid issues with MySQL datetime rounding
var task = new taskResult.TaskResultData();
task.password = cmd.getPassword() || "";
task.password = cmd.getPassword() || '';
let changeInfo = null;
if (conn.user && (hasDocumentPassword || !formatChecker.isBrowserEditorFormat(originFormat))) {
changeInfo = task.innerPasswordChange = docsCoServer.getExternalChangeInfo(conn.user, newChangesLastDate.getTime(), conn.lang);
@ -924,7 +930,14 @@ function* commandSetPassword(ctx, conn, cmd, outputData) {
if (changeInfo) {
const forceSave = yield docsCoServer.editorData.getForceSave(ctx, cmd.getDocId());
const index = forceSave?.index || 0;
yield docsCoServer.resetForceSaveAfterChanges(ctx, cmd.getDocId(), newChangesLastDate.getTime(), index, utils.getBaseUrlByConnection(ctx, conn), changeInfo);
yield docsCoServer.resetForceSaveAfterChanges(
ctx,
cmd.getDocId(),
newChangesLastDate.getTime(),
index,
utils.getBaseUrlByConnection(ctx, conn),
changeInfo
);
}
} else {
ctx.logger.debug('commandSetPassword sql update error');
@ -938,14 +951,14 @@ function* commandSetPassword(ctx, conn, cmd, outputData) {
}
function* commandChangeDocInfo(ctx, conn, cmd, outputData) {
const res = yield docsCoServer.changeConnectionInfo(ctx, conn, cmd);
if(res) {
if (res) {
outputData.setStatus('ok');
} else {
outputData.setStatus('err');
outputData.setData(constants.CHANGE_DOC_INFO);
}
}
function checkAndFixAuthorizationLength(authorization, data){
function checkAndFixAuthorizationLength(authorization, data) {
//todo it is stub (remove in future versions)
//8kb(https://stackoverflow.com/questions/686217/maximum-on-http-header-values) - 1kb(for other headers)
const res = authorization.length < 7168;
@ -955,7 +968,7 @@ function checkAndFixAuthorizationLength(authorization, data){
}
return res;
}
const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
const commandSfcCallback = co.wrap(function* (ctx, cmd, isSfcm, isEncrypted) {
const tenForgottenFiles = ctx.getCfg('services.CoAuthoring.server.forgottenfiles', cfgForgottenFiles);
const tenForgottenFilesName = ctx.getCfg('services.CoAuthoring.server.forgottenfilesname', cfgForgottenFilesName);
const tenCallbackBackoffOptions = ctx.getCfg('services.CoAuthoring.callbackBackoffOptions', cfgCallbackBackoffOptions);
@ -983,7 +996,7 @@ const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
var forceSaveType = forceSave ? forceSave.getType() : commonDefines.c_oAscForceSaveTypes.Command;
const forceSaveUserId = forceSave ? forceSave.getAuthorUserId() : undefined;
const forceSaveUserIndex = forceSave ? forceSave.getAuthorUserIndex() : undefined;
const callbackUserIndex = (forceSaveUserIndex || 0 === forceSaveUserIndex) ? forceSaveUserIndex : userLastChangeIndex;
const callbackUserIndex = forceSaveUserIndex || 0 === forceSaveUserIndex ? forceSaveUserIndex : userLastChangeIndex;
let uri, baseUrl, wopiParams, lastOpenDate;
const selectRes = yield taskResult.select(ctx, docId);
const row = selectRes.length > 0 ? selectRes[0] : null;
@ -1012,7 +1025,7 @@ const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
recoverTask.statusInfo = constants.NO_ERROR;
let updateIfTask = new taskResult.TaskResultData();
updateIfTask.status = commonDefines.FileStatus.UpdateVersion;
updateIfTask.statusInfo = Math.floor(Date.now() / 60000);//minutes
updateIfTask.statusInfo = Math.floor(Date.now() / 60000); //minutes
let updateIfRes;
const updateMask = new taskResult.TaskResultData();
@ -1022,8 +1035,10 @@ const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
if (isEncrypted) {
recoverTask.status = updateMask.status = row.status;
recoverTask.statusInfo = updateMask.statusInfo = row.status_info;
} else if ((commonDefines.FileStatus.SaveVersion === row.status && cmd.getStatusInfoIn() === row.status_info) ||
commonDefines.FileStatus.UpdateVersion === row.status) {
} else if (
(commonDefines.FileStatus.SaveVersion === row.status && cmd.getStatusInfoIn() === row.status_info) ||
commonDefines.FileStatus.UpdateVersion === row.status
) {
if (commonDefines.FileStatus.UpdateVersion === row.status) {
updateIfRes = {affectedRows: 1};
}
@ -1056,7 +1071,7 @@ const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
actions.push(new commonDefines.OutputAction(commonDefines.c_oAscUserAction.Out, userActionId));
}
outputSfc.setActions(actions);
} else if(forceSaveUserId) {
} else if (forceSaveUserId) {
outputSfc.setActions([new commonDefines.OutputAction(commonDefines.c_oAscUserAction.ForceSaveButton, forceSaveUserId)]);
}
outputSfc.setUserData(cmd.getUserData());
@ -1084,8 +1099,7 @@ const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
//don't send history info because changes isn't from file in storage
var data = yield storage.getObject(ctx, savePathHistory);
outputSfc.setChangeHistory(JSON.parse(data.toString('utf-8')));
const changeUrl = yield storage.getSignedUrl(ctx, baseUrl, savePathChanges,
commonDefines.c_oAscUrlTypes.Temporary);
const changeUrl = yield storage.getSignedUrl(ctx, baseUrl, savePathChanges, commonDefines.c_oAscUrlTypes.Temporary);
outputSfc.setChangeUrl(changeUrl);
} else {
//for backward compatibility. remove this when Community is ready
@ -1112,7 +1126,7 @@ const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
//send only if FileStatus.Ok to prevent forcesave after final save
if (row && row.status == commonDefines.FileStatus.Ok) {
if (forceSave) {
const forceSaveDate = forceSave.getTime() ? new Date(forceSave.getTime()): new Date();
const forceSaveDate = forceSave.getTime() ? new Date(forceSave.getTime()) : new Date();
outputSfc.setForceSaveType(forceSaveType);
outputSfc.setLastSave(forceSaveDate.toISOString());
}
@ -1127,11 +1141,12 @@ const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
yield processWopiSaveAs(ctx, cmd);
replyStr = JSON.stringify({error: 0});
} else {
const isAutoSave = forceSaveType !== commonDefines.c_oAscForceSaveTypes.Button && forceSaveType !== commonDefines.c_oAscForceSaveTypes.Form;
const isAutoSave =
forceSaveType !== commonDefines.c_oAscForceSaveTypes.Button && forceSaveType !== commonDefines.c_oAscForceSaveTypes.Form;
replyStr = yield processWopiPutFile(ctx, docId, wopiParams, savePathDoc, userLastChangeId, true, isAutoSave, false);
}
} else {
replyStr = JSON.stringify({error: 1, descr: "wopi: no file"});
replyStr = JSON.stringify({error: 1, descr: 'wopi: no file'});
}
} else {
replyStr = yield docsCoServer.sendServerRequest(ctx, uri, outputSfc, checkAndFixAuthorizationLength);
@ -1156,7 +1171,7 @@ const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
}
if (updateIfRes.affectedRows > 0) {
const actualForceSave = yield docsCoServer.editorData.getForceSave(ctx, docId);
const forceSaveDate = (actualForceSave && actualForceSave.time) ? new Date(actualForceSave.time) : new Date();
const forceSaveDate = actualForceSave && actualForceSave.time ? new Date(actualForceSave.time) : new Date();
const notModified = actualForceSave && true === actualForceSave.ended;
outputSfc.setLastSave(forceSaveDate.toISOString());
outputSfc.setNotModified(notModified);
@ -1168,7 +1183,7 @@ const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
if (outputSfc.getUrl()) {
replyStr = yield processWopiPutFile(ctx, docId, wopiParams, savePathDoc, userLastChangeId, !notModified, false, true);
} else {
replyStr = JSON.stringify({error: 1, descr: "wopi: no file"});
replyStr = JSON.stringify({error: 1, descr: 'wopi: no file'});
}
} else {
replyStr = yield docsCoServer.sendServerRequest(ctx, uri, outputSfc, checkAndFixAuthorizationLength);
@ -1190,7 +1205,7 @@ const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
if (replyData && commonDefines.c_oAscServerCommandErrors.NoError == replyData.error) {
//in the case of a community server, a request will come to the Command Service, check the result
var savedVal = yield docsCoServer.editorData.getdelSaved(ctx, docId);
requestRes = (null == savedVal || '1' === savedVal);
requestRes = null == savedVal || '1' === savedVal;
}
if (replyData && commonDefines.c_oAscServerCommandErrors.NoError != replyData.error) {
ctx.logger.warn('sendServerRequest returned an error: data = %s', replyStr);
@ -1240,7 +1255,7 @@ const commandSfcCallback = co.wrap(function*(ctx, cmd, isSfcm, isEncrypted) {
}
if (storeForgotten && !needRetry && !isEncrypted && (!isError || isErrorCorrupted)) {
try {
ctx.logger.warn("storeForgotten");
ctx.logger.warn('storeForgotten');
const forgottenName = tenForgottenFilesName + pathModule.extname(cmd.getOutputPath());
yield storage.copyObject(ctx, savePathDoc, docId + '/' + forgottenName, undefined, tenForgottenFiles);
} catch (err) {
@ -1290,7 +1305,17 @@ function* processWopiPutFile(ctx, docId, wopiParams, savePathDoc, userLastChange
let res = '{"error": 1}';
const metadata = yield storage.headObject(ctx, savePathDoc);
const streamObj = yield storage.createReadStream(ctx, savePathDoc);
const postRes = yield wopiClient.putFile(ctx, wopiParams, null, streamObj.readStream, metadata.ContentLength, userLastChangeId, isModifiedByUser, isAutosave, isExitSave);
const postRes = yield wopiClient.putFile(
ctx,
wopiParams,
null,
streamObj.readStream,
metadata.ContentLength,
userLastChangeId,
isModifiedByUser,
isAutosave,
isExitSave
);
if (postRes) {
res = '{"error": 0}';
const body = wopiClient.parsePutFileResponse(ctx, postRes);
@ -1320,7 +1345,7 @@ function* commandSendMMCallback(ctx, cmd) {
var data = yield storage.getObject(ctx, saveKey + '/' + cmd.getOutputPath());
var xml = data.toString('utf8');
var files = xml.match(/[< ]file.*?\/>/g);
var recordRemain = (mailMergeSendData.getRecordTo() - mailMergeSendData.getRecordFrom() + 1);
var recordRemain = mailMergeSendData.getRecordTo() - mailMergeSendData.getRecordFrom() + 1;
var recordIndexStart = mailMergeSendData.getRecordCount() - recordRemain;
for (var i = 0; i < files.length; ++i) {
var file = files[i];
@ -1328,8 +1353,12 @@ function* commandSendMMCallback(ctx, cmd) {
outputMailMerge.setTo(fieldRes[1]);
outputMailMerge.setRecordIndex(recordIndexStart + i);
var pathRes = /path=["'](.*?)["']/.exec(file);
var signedUrl = yield storage.getSignedUrl(ctx, mailMergeSendData.getBaseUrl(), saveKey + '/' + pathRes[1],
commonDefines.c_oAscUrlTypes.Temporary);
var signedUrl = yield storage.getSignedUrl(
ctx,
mailMergeSendData.getBaseUrl(),
saveKey + '/' + pathRes[1],
commonDefines.c_oAscUrlTypes.Temporary
);
outputSfc.setUrl(signedUrl);
outputSfc.setExtName(pathModule.extname(pathRes[1]));
var uri = mailMergeSendData.getUrl();
@ -1363,12 +1392,12 @@ function* commandSendMMCallback(ctx, cmd) {
ctx.logger.debug('End commandSendMMCallback');
}
exports.openDocument = function(ctx, conn, cmd, opt_upsertRes, opt_bIsRestore) {
exports.openDocument = function (ctx, conn, cmd, opt_upsertRes, opt_bIsRestore) {
return co(function* () {
var outputData;
try {
var startDate = null;
if(clientStatsD) {
if (clientStatsD) {
startDate = new Date();
}
ctx.logger.debug('Start command: %s', JSON.stringify(cmd));
@ -1400,23 +1429,21 @@ exports.openDocument = function(ctx, conn, cmd, opt_upsertRes, opt_bIsRestore) {
res = false;
break;
}
if(!res){
outputData.setStatus('err');
outputData.setData(constants.UNKNOWN);
if (!res) {
outputData.setStatus('err');
outputData.setData(constants.UNKNOWN);
}
if(clientStatsD) {
if (clientStatsD) {
clientStatsD.timing('coauth.openDocument.' + cmd.getCommand(), new Date() - startDate);
}
}
catch (e) {
} catch (e) {
ctx.logger.error('Error openDocument: %s', e.stack);
if (!outputData) {
outputData = new OutputData();
}
outputData.setStatus('err');
outputData.setData(constants.UNKNOWN);
}
finally {
} finally {
if (outputData?.getStatus()) {
ctx.logger.debug('Response command: %s', JSON.stringify(outputData));
docsCoServer.sendData(ctx, conn, new OutputDataWrap('documentOpen', outputData));
@ -1425,13 +1452,13 @@ exports.openDocument = function(ctx, conn, cmd, opt_upsertRes, opt_bIsRestore) {
}
});
};
exports.downloadAs = function(req, res) {
exports.downloadAs = function (req, res) {
return co(function* () {
var docId = 'null';
const ctx = new operationContext.Context();
try {
var startDate = null;
if(clientStatsD) {
if (clientStatsD) {
startDate = new Date();
}
ctx.initFromRequest(req);
@ -1460,7 +1487,7 @@ exports.downloadAs = function(req, res) {
if (checkJwtRes.decoded) {
const decoded = checkJwtRes.decoded;
var doc = checkJwtRes.decoded.document;
if (!doc.permissions || (false !== doc.permissions.download || false !== doc.permissions.print)) {
if (!doc.permissions || false !== doc.permissions.download || false !== doc.permissions.print) {
isValidJwt = true;
docId = doc.key;
cmd.setDocId(doc.key);
@ -1505,18 +1532,17 @@ exports.downloadAs = function(req, res) {
res.setHeader('Content-Type', 'application/json');
res.send(strRes);
ctx.logger.debug('End downloadAs: %s', strRes);
if(clientStatsD) {
if (clientStatsD) {
clientStatsD.timing('coauth.downloadAs.' + cmd.getCommand(), new Date() - startDate);
}
}
catch (e) {
} catch (e) {
ctx.logger.error('Error downloadAs: %s', e.stack);
res.sendStatus(400);
}
});
};
exports.saveFile = function(req, res) {
return co(function*() {
exports.saveFile = function (req, res) {
return co(function* () {
let docId = 'null';
const ctx = new operationContext.Context();
try {
@ -1569,15 +1595,14 @@ exports.saveFile = function(req, res) {
if (clientStatsD) {
clientStatsD.timing('coauth.saveFile', new Date() - startDate);
}
}
catch (e) {
} catch (e) {
ctx.logger.error('Error saveFile: %s', e.stack);
res.sendStatus(400);
}
});
};
function getPrintFileUrl(ctx, docId, baseUrl, filename) {
return co(function*() {
return co(function* () {
const tenTokenEnableBrowser = ctx.getCfg('services.CoAuthoring.token.enable.browser', cfgTokenEnableBrowser);
const tenTokenSessionAlgorithm = ctx.getCfg('services.CoAuthoring.token.session.algorithm', cfgTokenSessionAlgorithm);
const tenTokenSessionExpires = ms(ctx.getCfg('services.CoAuthoring.token.session.expires', cfgTokenSessionExpires));
@ -1586,11 +1611,17 @@ function getPrintFileUrl(ctx, docId, baseUrl, filename) {
let token = '';
if (tenTokenEnableBrowser) {
const payload = {document: {key: docId}};
token = yield docsCoServer.signToken(ctx, payload, tenTokenSessionAlgorithm, tenTokenSessionExpires / 1000, commonDefines.c_oAscSecretType.Session);
token = yield docsCoServer.signToken(
ctx,
payload,
tenTokenSessionAlgorithm,
tenTokenSessionExpires / 1000,
commonDefines.c_oAscSecretType.Session
);
}
//while save printed file Chrome's extension seems to rely on the resource name set in the URI https://stackoverflow.com/a/53593453
//replace '/' with %2f before encodeURIComponent becase nginx determine %2f as '/' and get wrong system path
const userFriendlyName = encodeURIComponent(filename.replace(/\//g, "%2f"));
const userFriendlyName = encodeURIComponent(filename.replace(/\//g, '%2f'));
let res = `${baseUrl}/printfile/${encodeURIComponent(docId)}/${userFriendlyName}?token=${encodeURIComponent(token)}`;
if (ctx.shardKey) {
res += `&${constants.SHARD_KEY_API_NAME}=${encodeURIComponent(ctx.shardKey)}`;
@ -1603,8 +1634,8 @@ function getPrintFileUrl(ctx, docId, baseUrl, filename) {
});
}
exports.getPrintFileUrl = getPrintFileUrl;
exports.printFile = function(req, res) {
return co(function*() {
exports.printFile = function (req, res) {
return co(function* () {
let docId = 'null';
const ctx = new operationContext.Context();
try {
@ -1646,12 +1677,10 @@ exports.printFile = function(req, res) {
if (clientStatsD) {
clientStatsD.timing('coauth.printFile', new Date() - startDate);
}
}
catch (e) {
} catch (e) {
ctx.logger.error('Error printFile: %s', e.stack);
res.sendStatus(400);
}
finally {
} finally {
ctx.logger.info('End printFile');
}
});
@ -1662,8 +1691,8 @@ exports.printFile = function(req, res) {
* @param {object} res - The HTTP response object
* @returns {Promise}
*/
exports.downloadFile = function(req, res) {
return co(function*() {
exports.downloadFile = function (req, res) {
return co(function* () {
const ctx = new operationContext.Context();
let stream = null;
try {
@ -1767,7 +1796,16 @@ exports.downloadFile = function(req, res) {
headers['Range'] = req.get('Range');
}
const downloadResult = yield utils.downloadUrlPromise(ctx, url, tenDownloadTimeout, tenDownloadMaxBytes, authorization, isInJwtToken, headers, true);
const downloadResult = yield utils.downloadUrlPromise(
ctx,
url,
tenDownloadTimeout,
tenDownloadMaxBytes,
authorization,
isInJwtToken,
headers,
true
);
const response = downloadResult.response;
stream = downloadResult.stream;
//Set-Cookie resets browser session
@ -1782,9 +1820,8 @@ exports.downloadFile = function(req, res) {
if (clientStatsD) {
clientStatsD.timing('coauth.downloadFile', new Date() - startDate);
}
}
catch (err) {
if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
} catch (err) {
if (err.code === 'ERR_STREAM_PREMATURE_CLOSE') {
ctx.logger.debug('Error downloadFile: %s', err.stack);
if (!res.headersSent) {
res.sendStatus(499);
@ -1808,8 +1845,7 @@ exports.downloadFile = function(req, res) {
}
}
}
}
finally {
} finally {
// Ensure stream is properly destroyed
if (stream && typeof stream.destroy === 'function') {
try {
@ -1822,11 +1858,11 @@ exports.downloadFile = function(req, res) {
}
});
};
exports.saveFromChanges = function(ctx, docId, statusInfo, optFormat, opt_userId, opt_userIndex, opt_userLcid, opt_queue, opt_initShardKey) {
exports.saveFromChanges = function (ctx, docId, statusInfo, optFormat, opt_userId, opt_userIndex, opt_userLcid, opt_queue, opt_initShardKey) {
return co(function* () {
try {
var startDate = null;
if(clientStatsD) {
if (clientStatsD) {
startDate = new Date();
}
ctx.logger.debug('Start saveFromChanges');
@ -1863,7 +1899,7 @@ exports.saveFromChanges = function(ctx, docId, statusInfo, optFormat, opt_userId
yield docsCoServer.editorStat.addShutdown(redisKeyShutdown, docId);
}
ctx.logger.debug('AddTask saveFromChanges');
} else if(row && !row.callback) {
} else if (row && !row.callback) {
ctx.logger.debug('saveFromChanges empty callback: %s', docId);
yield docsCoServer.cleanDocumentOnExitNoChangesPromise(ctx, docId, opt_userId, opt_userIndex, false, true);
//todo restore status
@ -1875,8 +1911,7 @@ exports.saveFromChanges = function(ctx, docId, statusInfo, optFormat, opt_userId
if (clientStatsD) {
clientStatsD.timing('coauth.saveFromChanges', new Date() - startDate);
}
}
catch (e) {
} catch (e) {
ctx.logger.error('Error saveFromChanges: %s', e.stack);
}
});
@ -1891,12 +1926,22 @@ async function processWopiSaveAs(ctx, cmd) {
const suggestedTarget = cmd.getSaveAsPath();
const storageFilePath = `${cmd.getDocId()}${cmd.getSaveKey()}/${cmd.getOutputPath()}`;
const stream = await storage.createReadStream(ctx, storageFilePath);
const { wopiSrc, access_token } = info.wopiParams.userAuth;
res = await wopiClient.putRelativeFile(ctx, wopiSrc, access_token, null, stream.readStream, stream.contentLength, suggestedExt, suggestedTarget, false);
const {wopiSrc, access_token} = info.wopiParams.userAuth;
res = await wopiClient.putRelativeFile(
ctx,
wopiSrc,
access_token,
null,
stream.readStream,
stream.contentLength,
suggestedExt,
suggestedTarget,
false
);
}
return {res, wopiParams: info?.wopiParams};
}
exports.receiveTask = function(data, ack) {
exports.receiveTask = function (data, ack) {
return co(function* () {
const ctx = new operationContext.Context();
try {
@ -1911,8 +1956,15 @@ exports.receiveTask = function(data, ack) {
if (updateRes.affectedRows > 0) {
var outputData = new OutputData(cmd.getCommand());
var command = cmd.getCommand();
var additionalOutput = {needUrlKey: null, needUrlMethod: null, needUrlType: null,
needUrlIsCorrectPassword: undefined, creationDate: undefined, openedAt: undefined, row: undefined};
var additionalOutput = {
needUrlKey: null,
needUrlMethod: null,
needUrlType: null,
needUrlIsCorrectPassword: undefined,
creationDate: undefined,
openedAt: undefined,
row: undefined
};
if ('open' === command || 'reopen' === command) {
yield getOutputData(ctx, cmd, outputData, cmd.getDocId(), null, additionalOutput);
//wopi from TemplateSource
@ -1924,11 +1976,25 @@ exports.receiveTask = function(data, ack) {
ctx.logger.debug('receiveTask: save document opened from TemplateSource');
//todo
//no need to wait to open file faster
void docsCoServer.startForceSave(ctx, cmd.getDocId(), commonDefines.c_oAscForceSaveTypes.Timeout,
undefined, undefined, undefined, undefined,
undefined, undefined, undefined, row.baseurl,
undefined,undefined,undefined,undefined,
undefined,cmd.getExternalChangeInfo());
void docsCoServer.startForceSave(
ctx,
cmd.getDocId(),
commonDefines.c_oAscForceSaveTypes.Timeout,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
row.baseurl,
undefined,
undefined,
undefined,
undefined,
undefined,
cmd.getExternalChangeInfo()
);
}
}
} else if ('save' === command || 'savefromorigin' === command) {
@ -1955,14 +2021,17 @@ exports.receiveTask = function(data, ack) {
ctx.logger.debug('receiveTask publish: %s', JSON.stringify(outputData));
var output = new OutputDataWrap('documentOpen', outputData);
yield docsCoServer.publish(ctx, {
type: commonDefines.c_oPublishType.receiveTask, ctx, cmd, output,
needUrlKey: additionalOutput.needUrlKey,
needUrlMethod: additionalOutput.needUrlMethod,
needUrlType: additionalOutput.needUrlType,
needUrlIsCorrectPassword: additionalOutput.needUrlIsCorrectPassword,
creationDate: additionalOutput.creationDate,
openedAt: additionalOutput.openedAt
});
type: commonDefines.c_oPublishType.receiveTask,
ctx,
cmd,
output,
needUrlKey: additionalOutput.needUrlKey,
needUrlMethod: additionalOutput.needUrlMethod,
needUrlType: additionalOutput.needUrlType,
needUrlIsCorrectPassword: additionalOutput.needUrlIsCorrectPassword,
creationDate: additionalOutput.creationDate,
openedAt: additionalOutput.openedAt
});
}
}
}

View File

@ -68,18 +68,25 @@ function updateDoc(ctx, docId, status, callback) {
const p3 = addSqlParam(ctx.tenant, values);
const p4 = addSqlParam(docId, values);
const sqlCommand = `UPDATE ${cfgTableResult} SET status=${p1},callback=${p2} WHERE tenant=${p3} AND id=${p4};`;
sqlBase.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}, undefined, undefined, values);
sqlBase.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
},
undefined,
undefined,
values
);
});
}
function shutdown() {
return co(function*() {
return co(function* () {
var res = true;
const ctx = new operationContext.Context();
try {
@ -112,7 +119,7 @@ function shutdown() {
const selectRes = yield taskResult.select(ctx, docId);
if (selectRes.length > 0) {
const row = selectRes[0];
if (commonDefines.FileStatus.SaveVersion !== row.status && commonDefines.FileStatus.UpdateVersion !== row.status){
if (commonDefines.FileStatus.SaveVersion !== row.status && commonDefines.FileStatus.UpdateVersion !== row.status) {
docsWithOutOfDateForgotten.push([tenant, docId]);
}
}
@ -131,7 +138,7 @@ function shutdown() {
ctx.setTenant(tenant);
yield ctx.initTenantCache();
yield updateDoc(ctx, docId, commonDefines.FileStatus.Ok, "");
yield updateDoc(ctx, docId, commonDefines.FileStatus.Ok, '');
yield editorStat.addShutdown(redisKeyShutdown, docId);
ctx.logger.debug('shutdown createSaveTimerPromise %s', docId);
yield docsCoServer.createSaveTimer(ctx, docId, null, null, null, queue, true);
@ -146,7 +153,7 @@ function shutdown() {
ctx.logger.debug('shutdown remaining files:%d', remainingFiles);
const curTime = new Date().getTime() - startTime;
if (curTime >= EXEC_TIMEOUT || remainingFiles <= 0) {
if(curTime >= EXEC_TIMEOUT) {
if (curTime >= EXEC_TIMEOUT) {
ctx.logger.debug('shutdown timeout');
}
break;
@ -183,6 +190,6 @@ function shutdown() {
process.exit(0);
return res;
});
};
}
exports.shutdown = shutdown;
shutdown();

View File

@ -49,7 +49,7 @@ var statsDClient = require('./../../Common/sources/statsdclient');
var storageBase = require('./../../Common/sources/storage/storage-base');
var operationContext = require('./../../Common/sources/operationContext');
const sqlBase = require('./databaseConnectors/baseConnector');
const utilsDocService = require("./utilsDocService");
const utilsDocService = require('./utilsDocService');
const cfgTokenEnableBrowser = config.get('services.CoAuthoring.token.enable.browser');
@ -72,10 +72,10 @@ function* getConvertStatus(ctx, docId, encryptedUserPassword, selectRes, opt_che
isCorrectPassword = decryptedPassword === userPassword;
}
if (isCorrectPassword) {
ctx.logger.debug("getConvertStatus password match");
ctx.logger.debug('getConvertStatus password match');
status.end = true;
} else {
ctx.logger.debug("getConvertStatus password mismatch");
ctx.logger.debug('getConvertStatus password mismatch');
status.err = constants.CONVERT_PASSWORD;
}
} else {
@ -146,9 +146,9 @@ function* convertByCmd(ctx, cmd, async, opt_fileTo, opt_taskExist, opt_priority,
var status;
if (!bCreate) {
selectRes = yield taskResult.select(ctx, docId);
status = yield* getConvertStatus(ctx, cmd.getDocId() ,cmd.getPassword(), selectRes, opt_checkPassword);
status = yield* getConvertStatus(ctx, cmd.getDocId(), cmd.getPassword(), selectRes, opt_checkPassword);
}
if (bCreate || (commonDefines.FileStatus.None === selectRes?.[0]?.status)) {
if (bCreate || commonDefines.FileStatus.None === selectRes?.[0]?.status) {
var queueData = new commonDefines.TaskQueueData();
queueData.setCtx(ctx);
queueData.setCmd(cmd);
@ -169,7 +169,7 @@ function* convertByCmd(ctx, cmd, async, opt_fileTo, opt_taskExist, opt_priority,
}
yield utils.sleep(CONVERT_ASYNC_DELAY);
selectRes = yield taskResult.select(ctx, docId);
status = yield* getConvertStatus(ctx, cmd.getDocId() ,cmd.getPassword(), selectRes, opt_checkPassword);
status = yield* getConvertStatus(ctx, cmd.getDocId(), cmd.getPassword(), selectRes, opt_checkPassword);
waitTime += CONVERT_ASYNC_DELAY;
if (waitTime > utils.getConvertionTimeout(ctx)) {
status.err = constants.CONVERT_TIMEOUT;
@ -183,9 +183,24 @@ function* convertByCmd(ctx, cmd, async, opt_fileTo, opt_taskExist, opt_priority,
return status;
}
async function convertFromChanges(ctx, docId, baseUrl, forceSave, externalChangeInfo, opt_userdata, opt_formdata,
opt_userConnectionId, opt_userConnectionDocId, opt_responseKey, opt_priority,
opt_expiration, opt_queue, opt_redisKey, opt_initShardKey, opt_jsonParams) {
async function convertFromChanges(
ctx,
docId,
baseUrl,
forceSave,
externalChangeInfo,
opt_userdata,
opt_formdata,
opt_userConnectionId,
opt_userConnectionDocId,
opt_responseKey,
opt_priority,
opt_expiration,
opt_queue,
opt_redisKey,
opt_initShardKey,
opt_jsonParams
) {
var cmd = new commonDefines.InputCommand();
cmd.setCommand('sfcm');
cmd.setDocId(docId);
@ -239,8 +254,8 @@ async function convertFromChanges(ctx, docId, baseUrl, forceSave, externalChange
}
return status;
}
function parseIntParam(val){
return (typeof val === 'string') ? parseInt(val) : val;
function parseIntParam(val) {
return typeof val === 'string' ? parseInt(val) : val;
}
function convertRequest(req, res, isJson) {
@ -252,7 +267,7 @@ function convertRequest(req, res, isJson) {
ctx.logger.info('convertRequest start');
let params;
const authRes = yield docsCoServer.getRequestParams(ctx, req);
if(authRes.code === constants.NO_ERROR){
if (authRes.code === constants.NO_ERROR) {
params = authRes.params;
} else {
ctx.logger.warn('convertRequest auth failed %j', authRes);
@ -286,8 +301,10 @@ function convertRequest(req, res, isJson) {
} else if (false === params.pdf.pdfa && constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA === outputFormat) {
outputFormat = constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF;
}
if (params.pdf.form && (constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF === outputFormat ||
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA === outputFormat)) {
if (
params.pdf.form &&
(constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF === outputFormat || constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA === outputFormat)
) {
outputFormat = constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_OFORM_PDF;
} else if (false === params.pdf.form) {
oformAsPdf = true;
@ -298,7 +315,7 @@ function convertRequest(req, res, isJson) {
var cmd = new commonDefines.InputCommand();
cmd.setCommand('conv');
cmd.setUrl(params.url);
cmd.setEmbeddedFonts(false);//params.embeddedfonts'];
cmd.setEmbeddedFonts(false); //params.embeddedfonts'];
cmd.setFormat(filetype);
cmd.setDocId(docId);
cmd.setOutputFormat(outputFormat);
@ -307,8 +324,9 @@ function convertRequest(req, res, isJson) {
cmd.setCodepage(commonDefines.c_oAscEncodingsMap[params.codePage] || commonDefines.c_oAscCodePageUtf8);
cmd.setDelimiter(parseIntParam(params.delimiter) || commonDefines.c_oAscCsvDelimiter.Comma);
if(undefined != params.delimiterChar)
{cmd.setDelimiterChar(params.delimiterChar);}
if (undefined != params.delimiterChar) {
cmd.setDelimiterChar(params.delimiterChar);
}
if (params.region) {
cmd.setLCID(utilsDocService.localeToLCID(params.region));
}
@ -389,9 +407,12 @@ function convertRequest(req, res, isJson) {
if (params.title) {
cmd.setTitle(path.basename(params.title, path.extname(params.title)) + '.' + outputExt);
}
var async = (typeof params.async === 'string') ? 'true' == params.async : params.async;
var async = typeof params.async === 'string' ? 'true' == params.async : params.async;
if (async && !req.query[constants.SHARD_KEY_API_NAME] && !req.query[constants.SHARD_KEY_WOPI_NAME] && process.env.DEFAULT_SHARD_KEY) {
ctx.logger.warn('convertRequest set async=false. Pass query string parameter "%s" to correctly process request in sharded cluster', constants.SHARD_KEY_API_NAME);
ctx.logger.warn(
'convertRequest set async=false. Pass query string parameter "%s" to correctly process request in sharded cluster',
constants.SHARD_KEY_API_NAME
);
async = false;
}
if (constants.AVS_OFFICESTUDIO_FILE_UNKNOWN !== cmd.getOutputFormat()) {
@ -466,25 +487,26 @@ function builderRequest(req, res) {
queueData.setCmd(cmd);
yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW);
}
let async = (typeof params.async === 'string') ? 'true' === params.async : params.async;
let async = typeof params.async === 'string' ? 'true' === params.async : params.async;
if (async && !req.query[constants.SHARD_KEY_API_NAME] && !req.query[constants.SHARD_KEY_WOPI_NAME] && process.env.DEFAULT_SHARD_KEY) {
ctx.logger.warn('builderRequest set async=false. Pass query string parameter "%s" to correctly process request in sharded cluster', constants.SHARD_KEY_API_NAME);
ctx.logger.warn(
'builderRequest set async=false. Pass query string parameter "%s" to correctly process request in sharded cluster',
constants.SHARD_KEY_API_NAME
);
async = false;
}
const status = yield* convertByCmd(ctx, cmd, async, undefined, undefined, constants.QUEUE_PRIORITY_LOW);
end = status.end;
error = status.err;
if (end) {
urls = yield storageBase.getSignedUrls(ctx, utils.getBaseUrlByRequest(ctx, req), docId + '/output',
commonDefines.c_oAscUrlTypes.Temporary);
urls = yield storageBase.getSignedUrls(ctx, utils.getBaseUrlByRequest(ctx, req), docId + '/output', commonDefines.c_oAscUrlTypes.Temporary);
}
} else if (error === constants.NO_ERROR) {
error = constants.UNKNOWN;
}
ctx.logger.debug('End builderRequest request: urls = %j end = %s error = %s', urls, end, error);
utils.fillResponseBuilder(res, docId, urls, end, error);
}
catch (e) {
} catch (e) {
ctx.logger.error('Error builderRequest: %s', e.stack);
utils.fillResponseBuilder(res, undefined, undefined, undefined, constants.UNKNOWN);
} finally {
@ -493,7 +515,7 @@ function builderRequest(req, res) {
});
}
function convertTo(req, res) {
return co(function*() {
return co(function* () {
const ctx = new operationContext.Context();
try {
ctx.initFromRequest(req);
@ -522,7 +544,7 @@ function convertTo(req, res) {
}
}
const pdfVer = req.body['PDFVer'];
if (pdfVer && pdfVer.startsWith("PDF/A") && 'pdf' === format) {
if (pdfVer && pdfVer.startsWith('PDF/A') && 'pdf' === format) {
format = 'pdfa';
}
const fullSheetPreview = req.body['FullSheetPreview'];
@ -563,18 +585,22 @@ function convertTo(req, res) {
cmd.setLCID(utilsDocService.localeToLCID(lang));
}
if (fullSheetPreview) {
cmd.appendJsonParams({'spreadsheetLayout': {
"ignorePrintArea": true,
"fitToWidth": 1,
"fitToHeight": 1
}});
cmd.appendJsonParams({
spreadsheetLayout: {
ignorePrintArea: true,
fitToWidth: 1,
fitToHeight: 1
}
});
} else {
cmd.appendJsonParams({'spreadsheetLayout': {
"ignorePrintArea": true,
"fitToWidth": 0,
"fitToHeight": 0,
"scale": 100
}});
cmd.appendJsonParams({
spreadsheetLayout: {
ignorePrintArea: true,
fitToWidth: 0,
fitToHeight: 0,
scale: 100
}
});
}
if (password) {
const encryptedPassword = yield utils.encryptPassword(ctx, password);
@ -621,7 +647,7 @@ function convertTo(req, res) {
});
}
function convertAndEdit(ctx, wopiParams, filetypeFrom, filetypeTo) {
return co(function*() {
return co(function* () {
try {
ctx.logger.info('convert-and-edit start');
@ -664,7 +690,7 @@ function convertAndEdit(ctx, wopiParams, filetypeFrom, filetypeTo) {
});
}
function getConverterHtmlHandler(req, res) {
return co(function*() {
return co(function* () {
const isJson = true;
const ctx = new operationContext.Context();
try {
@ -678,9 +704,17 @@ function getConverterHtmlHandler(req, res) {
const targetext = req.query['targetext'];
let docId = req.query['docid'];
ctx.setDocId(docId);
if (!(wopiSrc && access_token && access_token && targetext && docId) ||
constants.AVS_OFFICESTUDIO_FILE_UNKNOWN === formatChecker.getFormatFromString(targetext)) {
ctx.logger.debug('convert-and-edit-handler invalid params: WOPISrc=%s; access_token=%s; targetext=%s; docId=%s', wopiSrc, access_token, targetext, docId);
if (
!(wopiSrc && access_token && access_token && targetext && docId) ||
constants.AVS_OFFICESTUDIO_FILE_UNKNOWN === formatChecker.getFormatFromString(targetext)
) {
ctx.logger.debug(
'convert-and-edit-handler invalid params: WOPISrc=%s; access_token=%s; targetext=%s; docId=%s',
wopiSrc,
access_token,
targetext,
docId
);
utils.fillResponse(req, res, new commonDefines.ConvertStatus(constants.CONVERT_PARAMS), isJson);
return;
}
@ -704,7 +738,17 @@ function getConverterHtmlHandler(req, res) {
const metadata = yield storage.headObject(ctx, fileTo);
const streamObj = yield storage.createReadStream(ctx, fileTo);
const putRelativeRes = yield wopiClient.putRelativeFile(ctx, wopiSrc, access_token, null, streamObj.readStream, metadata.ContentLength, `.${targetext}`, undefined, true);
const putRelativeRes = yield wopiClient.putRelativeFile(
ctx,
wopiSrc,
access_token,
null,
streamObj.readStream,
metadata.ContentLength,
`.${targetext}`,
undefined,
true
);
if (putRelativeRes) {
status.setUrl(putRelativeRes.HostEditUrl);
status.setExtName('.' + targetext);

View File

@ -38,90 +38,96 @@ var _errorConnection = true;
var logger = require('./../../Common/sources/logger');
function CreateDbClient(){
return new mongoDB.Db(config['mongodb']['database'], new mongoDB.Server(config['mongodb']['host'], config['mongodb']['port'], {auto_reconnect: true}), {safe:false});
function CreateDbClient() {
return new mongoDB.Db(
config['mongodb']['database'],
new mongoDB.Server(config['mongodb']['host'], config['mongodb']['port'], {auto_reconnect: true}),
{safe: false}
);
}
exports.insert = function (_collectionName, _newElement) {
var _db = CreateDbClient();
if (!_db) {
logger.error ("Error _db");
return;
}
var _db = CreateDbClient();
if (!_db) {
logger.error('Error _db');
return;
}
_db.open ((err, db) => {
if (!err) {
// open collection. If it doesn't exist, it will be created
db.collection(_collectionName, (err, collection) => {
if (!err) {
collection.insert (_newElement);
} else {
logger.error ("Error collection");
return;
}
_db.open((err, db) => {
if (!err) {
// open collection. If it doesn't exist, it will be created
db.collection(_collectionName, (err, collection) => {
if (!err) {
collection.insert(_newElement);
} else {
logger.error('Error collection');
return;
}
db.close();
});
} else {
logger.error ("Error open database");
}
});
db.close();
});
} else {
logger.error('Error open database');
}
});
};
exports.remove = function (_collectionName, _removeElements) {
var _db = CreateDbClient();
if (!_db) {
logger.error ("Error _db");
return;
}
var _db = CreateDbClient();
if (!_db) {
logger.error('Error _db');
return;
}
// Opening the database
_db.open ((err, db) => {
if (!err) {
// open collection. If it doesn't exist, it will be created
db.collection(_collectionName, (err, collection) => {
if (!err) {
collection.remove (_removeElements, (_err, _collection) => {
logger.info ("All elements remove");
});
} else {
logger.error ("Error collection");
return;
}
// Opening the database
_db.open((err, db) => {
if (!err) {
// open collection. If it doesn't exist, it will be created
db.collection(_collectionName, (err, collection) => {
if (!err) {
collection.remove(_removeElements, (_err, _collection) => {
logger.info('All elements remove');
});
} else {
logger.error('Error collection');
return;
}
db.close();
});
} else {
logger.error ("Error open database");
}
});
db.close();
});
} else {
logger.error('Error open database');
}
});
};
exports.load = function (_collectionName, callbackFunction) {
var _db = CreateDbClient();
if (!_db) {
logger.error ("Error _db");
return callbackFunction (null);
}
var _db = CreateDbClient();
if (!_db) {
logger.error('Error _db');
return callbackFunction(null);
}
var result = [];
var result = [];
// opening database
_db.open ((err, db) => {
// open collection. If it doesn't exist, it will be created
db.collection(_collectionName, (err, collection) => {
// Get all elements of a collection with find()
collection.find((err, cursor) => {
cursor.each((err, item) => {
// Null denotes the last element
if (item != null) {
if (!result.hasOwnProperty (item.docid))
{result[item.docid] = [item];}
else
{result[item.docid].push(item);}
} else
{callbackFunction (result);}
});
// opening database
_db.open((err, db) => {
// open collection. If it doesn't exist, it will be created
db.collection(_collectionName, (err, collection) => {
// Get all elements of a collection with find()
collection.find((err, cursor) => {
cursor.each((err, item) => {
// Null denotes the last element
if (item != null) {
if (!result.hasOwnProperty(item.docid)) {
result[item.docid] = [item];
} else {
result[item.docid].push(item);
}
} else {
callbackFunction(result);
}
});
db.close();
});
});
});
db.close();
});
});
});
};

View File

@ -33,12 +33,12 @@
'use strict';
const sqlDataBaseType = {
mySql : 'mysql',
mariaDB : 'mariadb',
msSql : 'mssql',
postgreSql : 'postgres',
dameng : 'dameng',
oracle : 'oracle'
mySql: 'mysql',
mariaDB: 'mariadb',
msSql: 'mssql',
postgreSql: 'postgres',
dameng: 'dameng',
oracle: 'oracle'
};
const connectorUtilities = require('./connectorUtilities');
@ -127,23 +127,39 @@ function _getDateTime2(oDate) {
function _insertChangesCallback(ctx, startIndex, objChanges, docId, index, user, callback) {
var sqlCommand = `INSERT INTO ${cfgTableChanges} VALUES`;
var i = startIndex, l = objChanges.length, lengthUtf8Current = sqlCommand.length, lengthUtf8Row = 0, values = [];
if (i === l)
{return;}
var i = startIndex,
l = objChanges.length,
lengthUtf8Current = sqlCommand.length,
lengthUtf8Row = 0,
values = [];
if (i === l) {
return;
}
const indexBytes = 4;
const timeBytes = 8;
for (; i < l; ++i, ++index) {
//49 - length of "($1001,... $1008),"
//4 is max utf8 bytes per symbol
lengthUtf8Row = 49 + 4 * (ctx.tenant.length + docId.length + user.id.length + user.idOriginal.length + user.username.length + objChanges[i].change.length) + indexBytes + timeBytes;
lengthUtf8Row =
49 +
4 * (ctx.tenant.length + docId.length + user.id.length + user.idOriginal.length + user.username.length + objChanges[i].change.length) +
indexBytes +
timeBytes;
if (lengthUtf8Row + lengthUtf8Current >= maxPacketSize && i > startIndex) {
sqlCommand += ';';
(function(tmpStart, tmpIndex) {
dbInstance.sqlQuery(ctx, sqlCommand, () => {
// do not remove lock, but we continue to add
_insertChangesCallback(ctx, tmpStart, objChanges, docId, tmpIndex, user, callback);
}, undefined, undefined, values);
(function (tmpStart, tmpIndex) {
dbInstance.sqlQuery(
ctx,
sqlCommand,
() => {
// do not remove lock, but we continue to add
_insertChangesCallback(ctx, tmpStart, objChanges, docId, tmpIndex, user, callback);
},
undefined,
undefined,
values
);
})(i, index);
return;
}
@ -193,11 +209,15 @@ function deleteChangesPromise(ctx, docId, deleteIndex) {
}
function deleteChanges(ctx, docId, deleteIndex) {
lockCriticalSection(docId, () => {_deleteChanges(ctx, docId, deleteIndex);});
lockCriticalSection(docId, () => {
_deleteChanges(ctx, docId, deleteIndex);
});
}
function _deleteChanges (ctx, docId, deleteIndex) {
deleteChangesCallback(ctx, docId, deleteIndex, () => {unLockCriticalSection(docId);});
function _deleteChanges(ctx, docId, deleteIndex) {
deleteChangesCallback(ctx, docId, deleteIndex, () => {
unLockCriticalSection(docId);
});
}
function getChangesIndex(ctx, docId, callback) {
@ -247,21 +267,28 @@ function getChangesPromise(ctx, docId, optStartIndex, optEndIndex, opt_time) {
sqlWhere += ' ORDER BY change_id ASC';
var sqlCommand = `SELECT * FROM ${cfgTableChanges} WHERE ${sqlWhere};`;
dbInstance.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
if (reservoirMaximum > 0) {
const size = Math.min(getChangesSize(result), reservoirMaximum);
limiter.incrementReservoir(-size).then((cur) => {
ctx.logger.debug("getChangesPromise bottleneck reservoir cur=%s", cur);
resolve(result);
});
dbInstance.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
if (reservoirMaximum > 0) {
const size = Math.min(getChangesSize(result), reservoirMaximum);
limiter.incrementReservoir(-size).then(cur => {
ctx.logger.debug('getChangesPromise bottleneck reservoir cur=%s', cur);
resolve(result);
});
} else {
resolve(result);
}
}
}
}, undefined, undefined, values);
},
undefined,
undefined,
values
);
});
});
}
@ -269,17 +296,22 @@ function getChangesPromise(ctx, docId, optStartIndex, optEndIndex, opt_time) {
function getDocumentsWithChanges(ctx) {
return new Promise((resolve, reject) => {
const sqlCommand = `SELECT * FROM ${cfgTableResult} WHERE EXISTS(SELECT id FROM ${cfgTableChanges} WHERE tenant=${cfgTableResult}.tenant AND id = ${cfgTableResult}.id LIMIT 1);`;
dbInstance.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}, false, false);
dbInstance.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
},
false,
false
);
});
}
function getExpired(ctx, maxCount, expireSeconds) {
return new Promise((resolve, reject) => {
const values = [];
@ -287,15 +319,23 @@ function getExpired(ctx, maxCount, expireSeconds) {
utils.addSeconds(expireDate, -expireSeconds);
const date = addSqlParameter(expireDate, values);
const count = addSqlParameter(maxCount, values);
const sqlCommand = `SELECT * FROM ${cfgTableResult} WHERE last_open_date <= ${date}` +
const sqlCommand =
`SELECT * FROM ${cfgTableResult} WHERE last_open_date <= ${date}` +
` AND NOT EXISTS(SELECT tenant, id FROM ${cfgTableChanges} WHERE ${cfgTableChanges}.tenant = ${cfgTableResult}.tenant AND ${cfgTableChanges}.id = ${cfgTableResult}.id LIMIT 1) LIMIT ${count};`;
dbInstance.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}, false, false, values);
dbInstance.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
},
false,
false,
values
);
});
}
function getCountWithStatus(ctx, status, expireMs) {
@ -305,41 +345,49 @@ function getCountWithStatus(ctx, status, expireMs) {
const sqlStatus = addSqlParameter(status, values);
const sqlDate = addSqlParameter(expireDate, values);
const sqlCommand = `SELECT COUNT(id) AS count FROM ${cfgTableResult} WHERE status=${sqlStatus} AND last_open_date>${sqlDate};`;
dbInstance.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
const res = Number(result[0].count)
resolve(!isNaN(res) ? res : 0);
}
}, false, false, values);
dbInstance.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
const res = Number(result[0].count);
resolve(!isNaN(res) ? res : 0);
}
},
false,
false,
values
);
});
}
function isLockCriticalSection(id) {
return !!(g_oCriticalSection[id]);
return !!g_oCriticalSection[id];
}
// critical section
function lockCriticalSection(id, callback) {
if (g_oCriticalSection[id]) {
// wait
g_oCriticalSection[id].push(callback);
return;
}
// lock
g_oCriticalSection[id] = [];
g_oCriticalSection[id].push(callback);
callback();
if (g_oCriticalSection[id]) {
// wait
g_oCriticalSection[id].push(callback);
return;
}
// lock
g_oCriticalSection[id] = [];
g_oCriticalSection[id].push(callback);
callback();
}
function unLockCriticalSection(id) {
var arrCallbacks = g_oCriticalSection[id];
arrCallbacks.shift();
if (0 < arrCallbacks.length)
{arrCallbacks[0]();}
else
{delete g_oCriticalSection[id];}
var arrCallbacks = g_oCriticalSection[id];
arrCallbacks.shift();
if (0 < arrCallbacks.length) {
arrCallbacks[0]();
} else {
delete g_oCriticalSection[id];
}
}
function healthCheck(ctx) {
@ -374,13 +422,20 @@ function getTableColumns(ctx, tableName) {
const values = [];
const sqlParam = addSqlParameter(tableName, values);
const sqlCommand = `SELECT column_name as "column_name" FROM information_schema.COLUMNS WHERE TABLE_NAME = ${sqlParam};`;
dbInstance.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}, undefined, undefined, values);
dbInstance.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
},
undefined,
undefined,
values
);
});
}

View File

@ -36,20 +36,20 @@ function UserCallback() {
this.userIndex = undefined;
this.callback = undefined;
}
UserCallback.prototype.fromValues = function(userIndex, callback){
if(null !== userIndex){
UserCallback.prototype.fromValues = function (userIndex, callback) {
if (null !== userIndex) {
this.userIndex = userIndex;
}
if(null !== callback){
if (null !== callback) {
this.callback = callback;
}
};
UserCallback.prototype.delimiter = constants.CHAR_DELIMITER;
UserCallback.prototype.toSQLInsert = function(){
UserCallback.prototype.toSQLInsert = function () {
return this.delimiter + JSON.stringify(this);
};
UserCallback.prototype.getCallbackByUserIndex = function(ctx, callbacksStr, opt_userIndex) {
ctx.logger.debug("getCallbackByUserIndex: userIndex = %s callbacks = %s", opt_userIndex, callbacksStr);
UserCallback.prototype.getCallbackByUserIndex = function (ctx, callbacksStr, opt_userIndex) {
ctx.logger.debug('getCallbackByUserIndex: userIndex = %s callbacks = %s', opt_userIndex, callbacksStr);
if (!callbacksStr || !callbacksStr.startsWith(UserCallback.prototype.delimiter)) {
const index = callbacksStr.indexOf(UserCallback.prototype.delimiter);
if (-1 === index) {
@ -61,7 +61,7 @@ UserCallback.prototype.getCallbackByUserIndex = function(ctx, callbacksStr, opt_
}
}
const callbacks = callbacksStr.split(UserCallback.prototype.delimiter);
let callbackUrl = "";
let callbackUrl = '';
for (let i = 1; i < callbacks.length; ++i) {
const callback = JSON.parse(callbacks[i]);
callbackUrl = callback.callback;
@ -71,8 +71,8 @@ UserCallback.prototype.getCallbackByUserIndex = function(ctx, callbacksStr, opt_
}
return callbackUrl;
};
UserCallback.prototype.getCallbacks = function(ctx, callbacksStr) {
ctx.logger.debug("getCallbacks: callbacks = %s", callbacksStr);
UserCallback.prototype.getCallbacks = function (ctx, callbacksStr) {
ctx.logger.debug('getCallbacks: callbacks = %s', callbacksStr);
if (!callbacksStr || !callbacksStr.startsWith(UserCallback.prototype.delimiter)) {
const index = callbacksStr.indexOf(UserCallback.prototype.delimiter);
if (-1 === index) {
@ -96,29 +96,29 @@ function DocumentPassword() {
this.password = undefined;
this.change = undefined;
}
DocumentPassword.prototype.fromString = function(passwordStr){
DocumentPassword.prototype.fromString = function (passwordStr) {
var parsed = JSON.parse(passwordStr);
this.fromValues(parsed.password, parsed.change);
};
DocumentPassword.prototype.fromValues = function(password, change){
if(null !== password){
DocumentPassword.prototype.fromValues = function (password, change) {
if (null !== password) {
this.password = password;
}
if(null !== change) {
if (null !== change) {
this.change = change;
}
};
DocumentPassword.prototype.delimiter = constants.CHAR_DELIMITER;
DocumentPassword.prototype.toSQLInsert = function(){
DocumentPassword.prototype.toSQLInsert = function () {
return this.delimiter + JSON.stringify(this);
};
DocumentPassword.prototype.isInitial = function(){
DocumentPassword.prototype.isInitial = function () {
return !this.change;
};
DocumentPassword.prototype.getDocPassword = function(ctx, docPasswordStr) {
DocumentPassword.prototype.getDocPassword = function (ctx, docPasswordStr) {
const res = {initial: undefined, current: undefined, change: undefined};
if (docPasswordStr) {
ctx.logger.debug("getDocPassword: passwords = %s", docPasswordStr);
ctx.logger.debug('getDocPassword: passwords = %s', docPasswordStr);
const passwords = docPasswordStr.split(UserCallback.prototype.delimiter);
for (let i = 1; i < passwords.length; ++i) {
@ -134,11 +134,11 @@ DocumentPassword.prototype.getDocPassword = function(ctx, docPasswordStr) {
}
return res;
};
DocumentPassword.prototype.getCurPassword = function(ctx, docPasswordStr) {
DocumentPassword.prototype.getCurPassword = function (ctx, docPasswordStr) {
const docPassword = this.getDocPassword(ctx, docPasswordStr);
return docPassword.current;
};
DocumentPassword.prototype.hasPasswordChanges = function(ctx, docPasswordStr) {
DocumentPassword.prototype.hasPasswordChanges = function (ctx, docPasswordStr) {
const docPassword = this.getDocPassword(ctx, docPasswordStr);
return docPassword.initial !== docPassword.current;
};
@ -147,9 +147,9 @@ function DocumentAdditional() {
this.data = [];
}
DocumentAdditional.prototype.delimiter = constants.CHAR_DELIMITER;
DocumentAdditional.prototype.toSQLInsert = function() {
DocumentAdditional.prototype.toSQLInsert = function () {
if (this.data.length) {
const vals = this.data.map((currentValue) => {
const vals = this.data.map(currentValue => {
return JSON.stringify(currentValue);
});
return this.delimiter + vals.join(this.delimiter);
@ -157,53 +157,53 @@ DocumentAdditional.prototype.toSQLInsert = function() {
return null;
}
};
DocumentAdditional.prototype.fromString = function(str) {
DocumentAdditional.prototype.fromString = function (str) {
if (!str) {
return;
}
const vals = str.split(this.delimiter).slice(1);
this.data = vals.map((currentValue) => {
this.data = vals.map(currentValue => {
return JSON.parse(currentValue);
});
};
DocumentAdditional.prototype.setOpenedAt = function(time, timezoneOffset, headingsColor) {
DocumentAdditional.prototype.setOpenedAt = function (time, timezoneOffset, headingsColor) {
const additional = new DocumentAdditional();
additional.data.push({time, timezoneOffset, headingsColor});
return additional.toSQLInsert();
};
DocumentAdditional.prototype.getOpenedAt = function(str) {
DocumentAdditional.prototype.getOpenedAt = function (str) {
let res;
const val = new DocumentAdditional();
val.fromString(str);
val.data.forEach((elem) => {
val.data.forEach(elem => {
if (undefined !== elem.timezoneOffset) {
res = elem.time - (elem.timezoneOffset * 60 * 1000);
res = elem.time - elem.timezoneOffset * 60 * 1000;
}
});
return res;
};
DocumentAdditional.prototype.getDocumentLayout = function(str) {
DocumentAdditional.prototype.getDocumentLayout = function (str) {
let res;
const val = new DocumentAdditional();
val.fromString(str);
val.data.forEach((elem) => {
val.data.forEach(elem => {
if (undefined !== elem.timezoneOffset) {
res = {openedAt: elem.time - (elem.timezoneOffset * 60 * 1000), headingsColor: elem.headingsColor};
res = {openedAt: elem.time - elem.timezoneOffset * 60 * 1000, headingsColor: elem.headingsColor};
}
});
return res;
}
};
DocumentAdditional.prototype.setShardKey = function(shardKey) {
DocumentAdditional.prototype.setShardKey = function (shardKey) {
const additional = new DocumentAdditional();
additional.data.push({shardKey});
return additional.toSQLInsert();
};
DocumentAdditional.prototype.getShardKey = function(str) {
DocumentAdditional.prototype.getShardKey = function (str) {
let res;
const val = new DocumentAdditional();
val.fromString(str);
val.data.forEach((elem) => {
val.data.forEach(elem => {
if (elem.shardKey) {
res = elem.shardKey;
}
@ -211,16 +211,16 @@ DocumentAdditional.prototype.getShardKey = function(str) {
return res;
};
DocumentAdditional.prototype.setWopiSrc = function(wopiSrc) {
DocumentAdditional.prototype.setWopiSrc = function (wopiSrc) {
const additional = new DocumentAdditional();
additional.data.push({wopiSrc});
return additional.toSQLInsert();
};
DocumentAdditional.prototype.getWopiSrc = function(str) {
DocumentAdditional.prototype.getWopiSrc = function (str) {
let res;
const val = new DocumentAdditional();
val.fromString(str);
val.data.forEach((elem) => {
val.data.forEach(elem => {
if (elem.wopiSrc) {
res = elem.wopiSrc;
}
@ -232,4 +232,4 @@ module.exports = {
UserCallback,
DocumentPassword,
DocumentAdditional
}
};

View File

@ -49,7 +49,9 @@ const forceClosingCountdownMs = 2000;
// dmdb driver separates PoolAttributes and ConnectionAttributes.
// For some reason if you use pool you must define connection attributes in connectString, they are not included in config object, and pool.getConnection() can't configure it.
const poolHostInfo = `dm://${cfgDbUser}:${cfgDbPass}@${cfgDbHost}:${cfgDbPort}`;
const connectionOptions = Object.entries(cfgDamengExtraOptions).map(option => option.join('=')).join('&');
const connectionOptions = Object.entries(cfgDamengExtraOptions)
.map(option => option.join('='))
.join('&');
let pool = null;
const poolConfig = {
@ -64,12 +66,12 @@ function readLob(lob) {
let blobData = Buffer.alloc(0);
let totalLength = 0;
lob.on('data', (chunk) => {
lob.on('data', chunk => {
totalLength += chunk.length;
blobData = Buffer.concat([blobData, chunk], totalLength);
});
lob.on('error', (err) => {
lob.on('error', err => {
reject(err);
});
@ -117,16 +119,16 @@ async function executeQuery(ctx, sqlCommand, values = [], noModifyRes = false, n
}
connection = await pool.getConnection();
const result = await connection.execute(sqlCommand, values, { resultSet: false });
const result = await connection.execute(sqlCommand, values, {resultSet: false});
let output = result;
if (!noModifyRes) {
if (result?.rows) {
output = await formatResult(result);
} else if (result?.rowsAffected) {
output = { affectedRows: result.rowsAffected };
output = {affectedRows: result.rowsAffected};
} else {
output = { rows: [], affectedRows: 0 };
output = {rows: [], affectedRows: 0};
}
}
@ -147,7 +149,7 @@ function closePool() {
}
function addSqlParameter(val, values) {
values.push({ val });
values.push({val});
return `:${values.length}`;
}
@ -159,7 +161,9 @@ async function getTableColumns(ctx, tableName) {
const values = [];
const sqlParam = addSqlParameter(tableName.toUpperCase(), values);
const result = await executeQuery(ctx, `SELECT column_name FROM DBA_TAB_COLUMNS WHERE table_name = ${sqlParam};`, values);
return result.map(row => { return { column_name: row.column_name.toLowerCase() }});
return result.map(row => {
return {column_name: row.column_name.toLowerCase()};
});
}
async function upsert(ctx, task) {

View File

@ -106,11 +106,11 @@ function convertPlaceholdersValues(values) {
function registerPlaceholderValues(values, statement) {
if (values._typesMetadata !== undefined) {
for (const placeholderName of Object.keys(values._typesMetadata)) {
statement.input(placeholderName, values._typesMetadata[placeholderName]);
}
for (const placeholderName of Object.keys(values._typesMetadata)) {
statement.input(placeholderName, values._typesMetadata[placeholderName]);
}
delete values._typesMetadata;
delete values._typesMetadata;
} else {
for (const key of Object.keys(values)) {
statement.input(key, dataType(values[key]));
@ -138,7 +138,7 @@ async function executeQuery(ctx, sqlCommand, values = {}, noModifyRes = false, n
await statement.unprepare();
if (!result.recordset && !result.rowsAffected?.length) {
return { rows: [], affectedRows: 0 };
return {rows: [], affectedRows: 0};
}
let output = result;
@ -146,7 +146,7 @@ async function executeQuery(ctx, sqlCommand, values = {}, noModifyRes = false, n
if (result.recordset) {
output = result.recordset;
} else {
output = { affectedRows: result.rowsAffected.pop() };
output = {affectedRows: result.rowsAffected.pop()};
}
}
@ -165,7 +165,7 @@ async function executeBulk(ctx, table) {
await sql.connect(configuration);
const result = await new sql.Request().bulk(table);
return { affectedRows: result?.rowsAffected ?? 0 };
return {affectedRows: result?.rowsAffected ?? 0};
} catch (error) {
errorHandle(`sqlQuery() error while executing bulk for table ${table.name}`, error, ctx);
@ -219,10 +219,10 @@ function getExpired(ctx, maxCount, expireSeconds) {
const values = {};
const date = addSqlParameterObjectBased(expireDate, 'expireDate', sql.TYPES.DateTime(), values);
const count = addSqlParameterObjectBased(maxCount, 'maxCount', sql.TYPES.Int(), values);
const notExistingTenantAndId = `SELECT TOP(1) tenant, id FROM ${cfgTableChanges} WHERE ${cfgTableChanges}.tenant = ${cfgTableResult}.tenant AND ${cfgTableChanges}.id = ${cfgTableResult}.id`
const notExistingTenantAndId = `SELECT TOP(1) tenant, id FROM ${cfgTableChanges} WHERE ${cfgTableChanges}.tenant = ${cfgTableResult}.tenant AND ${cfgTableChanges}.id = ${cfgTableResult}.id`;
const sqlCommand = `SELECT TOP(${count}) * FROM ${cfgTableResult} WHERE last_open_date <= ${date} AND NOT EXISTS(${notExistingTenantAndId});`;
return executeQuery(ctx, sqlCommand, values);
return executeQuery(ctx, sqlCommand, values);
}
async function upsert(ctx, task) {
@ -247,7 +247,7 @@ async function upsert(ctx, task) {
addSqlParameterObjectBased(task.userIndex, 'userIndex', sql.TYPES.Decimal(18, 0), values),
addSqlParameterObjectBased(task.changeId, 'changeId', sql.TYPES.Decimal(18, 0), values),
addSqlParameterObjectBased(cbInsert, 'cbInsert', sql.TYPES.NVarChar(sql.MAX), values),
addSqlParameterObjectBased(task.baseurl, 'baseurl', sql.TYPES.NVarChar(sql.MAX), values),
addSqlParameterObjectBased(task.baseurl, 'baseurl', sql.TYPES.NVarChar(sql.MAX), values)
];
const tenant = insertValuesPlaceholder[0];
@ -265,7 +265,12 @@ async function upsert(ctx, task) {
if (task.callback) {
const parameter = addSqlParameterObjectBased(JSON.stringify(task.callback), 'callback', sql.TYPES.NVarChar(sql.MAX), values);
const concatenatedColumns = concatParams(
'target.callback', `'${connectorUtilities.UserCallback.prototype.delimiter}{"userIndex":'`, '(target.user_index + 1)', `',"callback":'`, parameter, `'}'`
'target.callback',
`'${connectorUtilities.UserCallback.prototype.delimiter}{"userIndex":'`,
'(target.user_index + 1)',
`',"callback":'`,
parameter,
`'}'`
);
updateColumns += `, target.callback = ${concatenatedColumns}`;
@ -277,18 +282,19 @@ async function upsert(ctx, task) {
updateColumns += ', target.user_index = target.user_index + 1';
const sqlMerge = `MERGE INTO ${cfgTableResult} AS target `
+ `USING(VALUES(${insertValues})) AS source(${sourceColumns}) `
+ `ON(${condition}) `
+ `WHEN MATCHED THEN UPDATE SET ${updateColumns} `
+ `WHEN NOT MATCHED THEN INSERT(${sourceColumns}) VALUES(${sourceValues}) `
+ `OUTPUT $ACTION as action, INSERTED.user_index as insertId;`;
const sqlMerge =
`MERGE INTO ${cfgTableResult} AS target ` +
`USING(VALUES(${insertValues})) AS source(${sourceColumns}) ` +
`ON(${condition}) ` +
`WHEN MATCHED THEN UPDATE SET ${updateColumns} ` +
`WHEN NOT MATCHED THEN INSERT(${sourceColumns}) VALUES(${sourceValues}) ` +
`OUTPUT $ACTION as action, INSERTED.user_index as insertId;`;
const result = await executeQuery(ctx, sqlMerge, values, true);
const insertId = result.recordset[0].insertId;
const isInsert = result.recordset[0].action === 'INSERT';
return { isInsert, insertId };
return {isInsert, insertId};
}
function insertChanges(ctx, tableChanges, startIndex, objChanges, docId, index, user, callback) {
@ -300,26 +306,29 @@ function insertChanges(ctx, tableChanges, startIndex, objChanges, docId, index,
async function insertChangesAsync(ctx, tableChanges, startIndex, objChanges, docId, index, user) {
if (startIndex === objChanges.length) {
return { affectedRows: 0 };
return {affectedRows: 0};
}
const table = new sql.Table(tableChanges);
table.columns.add('tenant', sql.TYPES.NVarChar(sql.MAX), { nullable: false, length: 'max' });
table.columns.add('id', sql.TYPES.NVarChar(sql.MAX), { nullable: false, length: 'max' });
table.columns.add('change_id', sql.TYPES.Int, { nullable: false });
table.columns.add('user_id', sql.TYPES.NVarChar(sql.MAX), { nullable: false , length: 'max' });
table.columns.add('user_id_original', sql.TYPES.NVarChar(sql.MAX), { nullable: false, length: 'max' });
table.columns.add('user_name', sql.TYPES.NVarChar(sql.MAX), { nullable: false, length: 'max' });
table.columns.add('change_data', sql.TYPES.NVarChar(sql.MAX), { nullable: false, length: 'max' });
table.columns.add('change_date', sql.TYPES.DateTime, { nullable: false });
table.columns.add('tenant', sql.TYPES.NVarChar(sql.MAX), {nullable: false, length: 'max'});
table.columns.add('id', sql.TYPES.NVarChar(sql.MAX), {nullable: false, length: 'max'});
table.columns.add('change_id', sql.TYPES.Int, {nullable: false});
table.columns.add('user_id', sql.TYPES.NVarChar(sql.MAX), {nullable: false, length: 'max'});
table.columns.add('user_id_original', sql.TYPES.NVarChar(sql.MAX), {nullable: false, length: 'max'});
table.columns.add('user_name', sql.TYPES.NVarChar(sql.MAX), {nullable: false, length: 'max'});
table.columns.add('change_data', sql.TYPES.NVarChar(sql.MAX), {nullable: false, length: 'max'});
table.columns.add('change_date', sql.TYPES.DateTime, {nullable: false});
const indexBytes = 4;
const timeBytes = 8;
let bytes = 0;
let currentIndex = startIndex;
for (; currentIndex < objChanges.length && bytes <= cfgMaxPacketSize; ++currentIndex, ++index) {
bytes += indexBytes + timeBytes
+ 4 * (ctx.tenant.length + docId.length + user.id.length + user.idOriginal.length + user.username.length + objChanges[currentIndex].change.length);
bytes +=
indexBytes +
timeBytes +
4 *
(ctx.tenant.length + docId.length + user.id.length + user.idOriginal.length + user.username.length + objChanges[currentIndex].change.length);
table.rows.add(ctx.tenant, docId, index, user.id, user.idOriginal, user.username, objChanges[currentIndex].change, objChanges[currentIndex].time);
}

View File

@ -41,15 +41,15 @@ const configSql = config.get('services.CoAuthoring.sql');
const cfgTableResult = configSql.get('tableResult');
const connectionConfiguration = {
host : configSql.get('dbHost'),
port : parseInt(configSql.get('dbPort')),
user : configSql.get('dbUser'),
password : configSql.get('dbPass'),
database : configSql.get('dbName'),
charset : configSql.get('charset'),
connectionLimit : configSql.get('connectionlimit'),
timezone : 'Z',
flags : '-FOUND_ROWS'
host: configSql.get('dbHost'),
port: parseInt(configSql.get('dbPort')),
user: configSql.get('dbUser'),
password: configSql.get('dbPass'),
database: configSql.get('dbName'),
charset: configSql.get('charset'),
connectionLimit: configSql.get('connectionlimit'),
timezone: 'Z',
flags: '-FOUND_ROWS'
};
const additionalOptions = config.util.cloneDeep(configSql.get('mysqlExtraOptions'));
@ -63,17 +63,18 @@ let autoCommit = false;
if (configuration.autoCommit !== undefined) {
//delete to fix issue with invalid configuration option
autoCommit = configuration.autoCommit;
delete configuration.autoCommit
delete configuration.autoCommit;
}
const pool = mysql.createPool(configuration);
// Set autocommit once per connection
if (autoCommit === true) {
pool.on('connection', async (conn) => {
conn.promise().query('SET autocommit=1').catch(err =>
operationContext.global.logger.error('Failed to set autocommit=1:', err.message)
);
pool.on('connection', async conn => {
conn
.promise()
.query('SET autocommit=1')
.catch(err => operationContext.global.logger.error('Failed to set autocommit=1:', err.message));
});
}
@ -89,16 +90,16 @@ async function executeQuery(ctx, sqlCommand, values = [], noModifyRes = false, n
try {
connection = await pool.getConnection();
const result = await connection.query({ sql: sqlCommand, timeout: queryTimeout, values });
const result = await connection.query({sql: sqlCommand, timeout: queryTimeout, values});
let output;
if (!noModifyRes) {
output = result[0]?.affectedRows ? { affectedRows: result[0].affectedRows } : result[0];
output = result[0]?.affectedRows ? {affectedRows: result[0].affectedRows} : result[0];
} else {
output = result[0];
}
return output ?? { rows: [], affectedRows: 0 };
return output ?? {rows: [], affectedRows: 0};
} catch (error) {
if (!noLog) {
ctx.logger.error(`sqlQuery() error while executing query: ${sqlCommand}\n${error.stack}`);
@ -169,7 +170,8 @@ async function upsert(ctx, task) {
updateStatement += ', user_index = LAST_INSERT_ID(user_index + 1);';
const sqlCommand = `INSERT INTO ${cfgTableResult} (tenant, id, status, status_info, last_open_date, user_index, change_id, callback, baseurl) `+
const sqlCommand =
`INSERT INTO ${cfgTableResult} (tenant, id, status, status_info, last_open_date, user_index, change_id, callback, baseurl) ` +
`VALUES (${valuesPlaceholder.join(', ')}) ` +
`ON DUPLICATE KEY UPDATE ${updateStatement}`;
@ -179,7 +181,7 @@ async function upsert(ctx, task) {
//http://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
const isInsert = result.affectedRows === 1;
return { isInsert, insertId };
return {isInsert, insertId};
}
module.exports.sqlQuery = sqlQuery;

View File

@ -54,7 +54,7 @@ const configuration = Object.assign({}, connectionConfiguration, additionalOptio
const forceClosingCountdownMs = 2000;
let pool = null;
oracledb.fetchAsString = [ oracledb.NCLOB, oracledb.CLOB ];
oracledb.fetchAsString = [oracledb.NCLOB, oracledb.CLOB];
oracledb.autoCommit = true;
function columnsToLowercase(rows) {
@ -93,13 +93,13 @@ async function executeQuery(ctx, sqlCommand, values = [], noModifyRes = false, n
connection = await pool.getConnection();
const bondedValues = values ?? [];
const outputFormat = { outFormat: !noModifyRes ? oracledb.OUT_FORMAT_OBJECT : oracledb.OUT_FORMAT_ARRAY };
const outputFormat = {outFormat: !noModifyRes ? oracledb.OUT_FORMAT_OBJECT : oracledb.OUT_FORMAT_ARRAY};
const result = await connection.execute(correctedSql, bondedValues, outputFormat);
let output = { rows: [], affectedRows: 0 };
let output = {rows: [], affectedRows: 0};
if (!noModifyRes) {
if (result?.rowsAffected) {
output = { affectedRows: result.rowsAffected };
output = {affectedRows: result.rowsAffected};
}
if (result?.rows) {
@ -141,7 +141,7 @@ async function executeBunch(ctx, sqlCommand, values = [], noLog = false) {
const result = await connection.executeMany(sqlCommand, values);
return { affectedRows: result?.rowsAffected ?? 0 };
return {affectedRows: result?.rowsAffected ?? 0};
} catch (error) {
if (!noLog) {
ctx.logger.error(`sqlQuery() error while executing query: ${sqlCommand}\n${error.stack}`);
@ -196,7 +196,7 @@ function getExpired(ctx, maxCount, expireSeconds) {
const values = [];
const date = addSqlParameter(expireDate, values);
const count = addSqlParameter(maxCount, values);
const notExistingTenantAndId = `SELECT tenant, id FROM ${cfgTableChanges} WHERE ${cfgTableChanges}.tenant = ${cfgTableResult}.tenant AND ${cfgTableChanges}.id = ${cfgTableResult}.id AND ROWNUM <= 1`
const notExistingTenantAndId = `SELECT tenant, id FROM ${cfgTableChanges} WHERE ${cfgTableChanges}.tenant = ${cfgTableResult}.tenant AND ${cfgTableChanges}.id = ${cfgTableResult}.id AND ROWNUM <= 1`;
const sqlCommand = `SELECT * FROM ${cfgTableResult} WHERE last_open_date <= ${date} AND NOT EXISTS(${notExistingTenantAndId}) AND ROWNUM <= ${count}`;
return executeQuery(ctx, sqlCommand, values);
@ -224,7 +224,7 @@ function makeUpdateSql(dateNow, task, values) {
const id = addSqlParameter(task.key, values);
const condition = `tenant = ${tenant} AND id = ${id}`;
const returning = addSqlParameter({ type: oracledb.NUMBER, dir: oracledb.BIND_OUT }, values);
const returning = addSqlParameter({type: oracledb.NUMBER, dir: oracledb.BIND_OUT}, values);
return `UPDATE ${cfgTableResult} SET ${updateQuery} WHERE ${condition} RETURNING user_index INTO ${returning}`;
}
@ -258,15 +258,16 @@ async function upsert(ctx, task) {
addSqlParameter(task.baseurl, insertValues)
];
const returned = addSqlParameter({ type: oracledb.NUMBER, dir: oracledb.BIND_OUT }, insertValues);
const sqlInsertTry = `INSERT INTO ${cfgTableResult} (tenant, id, status, status_info, last_open_date, user_index, change_id, callback, baseurl) `
+ `VALUES(${insertValuesPlaceholder.join(', ')}) RETURNING user_index INTO ${returned}`;
const returned = addSqlParameter({type: oracledb.NUMBER, dir: oracledb.BIND_OUT}, insertValues);
const sqlInsertTry =
`INSERT INTO ${cfgTableResult} (tenant, id, status, status_info, last_open_date, user_index, change_id, callback, baseurl) ` +
`VALUES(${insertValuesPlaceholder.join(', ')}) RETURNING user_index INTO ${returned}`;
try {
const insertResult = await executeQuery(ctx, sqlInsertTry, insertValues, true, true);
const insertId = getReturnedValue(insertResult);
return { isInsert: true, insertId };
return {isInsert: true, insertId};
} catch (insertError) {
if (insertError.code !== 'ORA-00001') {
throw insertError;
@ -276,7 +277,7 @@ async function upsert(ctx, task) {
const updateResult = await executeQuery(ctx, makeUpdateSql(dateNow, task, values), values, true);
const insertId = getReturnedValue(updateResult);
return { isInsert: false, insertId };
return {isInsert: false, insertId};
}
}
@ -289,13 +290,14 @@ function insertChanges(ctx, tableChanges, startIndex, objChanges, docId, index,
async function insertChangesAsync(ctx, tableChanges, startIndex, objChanges, docId, index, user) {
if (startIndex === objChanges.length) {
return { affectedRows: 0 };
return {affectedRows: 0};
}
const parametersCount = 8;
const maxPlaceholderLength = ':99'.length;
// (parametersCount - 1) - separator symbols length.
const maxInsertStatementLength = `INSERT /*+ APPEND_VALUES*/INTO ${tableChanges} VALUES()`.length + maxPlaceholderLength * parametersCount + (parametersCount - 1);
const maxInsertStatementLength =
`INSERT /*+ APPEND_VALUES*/INTO ${tableChanges} VALUES()`.length + maxPlaceholderLength * parametersCount + (parametersCount - 1);
let packetCapacityReached = false;
const values = [];
@ -305,8 +307,12 @@ async function insertChangesAsync(ctx, tableChanges, startIndex, objChanges, doc
let currentIndex = startIndex;
for (; currentIndex < objChanges.length; ++currentIndex, ++index) {
// 4 bytes is maximum for utf8 symbol.
const lengthUtf8Row = maxInsertStatementLength + indexBytes + timeBytes
+ 4 * (ctx.tenant.length + docId.length + user.id.length + user.idOriginal.length + user.username.length + objChanges[currentIndex].change.length);
const lengthUtf8Row =
maxInsertStatementLength +
indexBytes +
timeBytes +
4 *
(ctx.tenant.length + docId.length + user.id.length + user.idOriginal.length + user.username.length + objChanges[currentIndex].change.length);
if (lengthUtf8Row + lengthUtf8Current >= cfgMaxPacketSize && currentIndex > startIndex) {
packetCapacityReached = true;
@ -324,7 +330,7 @@ async function insertChangesAsync(ctx, tableChanges, startIndex, objChanges, doc
objChanges[currentIndex].time
];
const rowValues = { ...parameters };
const rowValues = {...parameters};
values.push(rowValues);
lengthUtf8Current += lengthUtf8Row;
@ -358,4 +364,4 @@ module.exports = {
getExpired,
upsert,
insertChanges
}
};

View File

@ -59,21 +59,21 @@ config.util.extendDeep(connectionConfig, pgPoolExtraOptions);
var pool = new pg.Pool(connectionConfig);
//listen "error" event otherwise - unhandled exception(https://github.com/brianc/node-postgres/issues/2764#issuecomment-1163475426)
pool.on('error', (err, _client) => {
operationContext.global.logger.error(`postgresql pool error %s`, err.stack)
})
operationContext.global.logger.error(`postgresql pool error %s`, err.stack);
});
//todo datetime timezone
pg.defaults.parseInputDatesAsUTC = true;
types.setTypeParser(1114, (stringValue) => {
types.setTypeParser(1114, stringValue => {
return new Date(stringValue + '+0000');
});
types.setTypeParser(1184, (stringValue) => {
types.setTypeParser(1184, stringValue => {
return new Date(stringValue + '+0000');
});
var maxPacketSize = configSql.get('max_allowed_packet');
function sqlQuery(ctx, sqlCommand, callbackFunction, opt_noModifyRes, opt_noLog, opt_values) {
co(function *() {
co(function* () {
var result = null;
var error = null;
try {
@ -158,26 +158,33 @@ function upsert(ctx, task) {
return new Promise((resolve, reject) => {
const values = [];
var sqlCommand = getUpsertString(task, values);
sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
if (isSupportOnConflict && '42601' === error.code) {
//SYNTAX ERROR
isSupportOnConflict = false;
ctx.logger.warn('checkIsSupportOnConflict false');
resolve(upsert(ctx, task));
sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
if (isSupportOnConflict && '42601' === error.code) {
//SYNTAX ERROR
isSupportOnConflict = false;
ctx.logger.warn('checkIsSupportOnConflict false');
resolve(upsert(ctx, task));
} else {
reject(error);
}
} else {
reject(error);
if (result && result.rows.length > 0) {
var first = result.rows[0];
result = {};
result.isInsert = task.userIndex === first.userindex;
result.insertId = first.userindex;
}
resolve(result);
}
} else {
if (result && result.rows.length > 0) {
var first = result.rows[0];
result = {};
result.isInsert = task.userIndex === first.userindex;
result.insertId = first.userindex;
}
resolve(result);
}
}, true, undefined, values);
},
true,
undefined,
values
);
});
}
@ -205,17 +212,24 @@ function insertChanges(ctx, tableChanges, startIndex, objChanges, docId, index,
//4 is max utf8 bytes per symbol
curLength += 4 * (docId.length + user.id.length + user.idOriginal.length + user.username.length + objChanges[i].change.length) + 4 + 8;
if (curLength >= maxPacketSize && i > startIndex) {
sqlQuery(ctx, sqlCommand, (error, output) => {
if (error && '42883' == error.code) {
isSupported = false;
ctx.logger.warn('postgresql does not support UNNEST');
}
if (error) {
callback(error, output, isSupported);
} else {
insertChanges(ctx, tableChanges, i, objChanges, docId, index, user, callback);
}
}, undefined, undefined, values);
sqlQuery(
ctx,
sqlCommand,
(error, output) => {
if (error && '42883' == error.code) {
isSupported = false;
ctx.logger.warn('postgresql does not support UNNEST');
}
if (error) {
callback(error, output, isSupported);
} else {
insertChanges(ctx, tableChanges, i, objChanges, docId, index, user, callback);
}
},
undefined,
undefined,
values
);
return;
}
tenant.push(ctx.tenant);
@ -227,13 +241,20 @@ function insertChanges(ctx, tableChanges, startIndex, objChanges, docId, index,
change.push(objChanges[i].change);
time.push(objChanges[i].time);
}
sqlQuery(ctx, sqlCommand, (error, output) => {
if (error && '42883' == error.code) {
isSupported = false;
ctx.logger.warn('postgresql does not support UNNEST');
}
callback(error, output, isSupported);
}, undefined, undefined, values);
sqlQuery(
ctx,
sqlCommand,
(error, output) => {
if (error && '42883' == error.code) {
isSupported = false;
ctx.logger.warn('postgresql does not support UNNEST');
}
callback(error, output, isSupported);
},
undefined,
undefined,
values
);
}
module.exports = {

View File

@ -43,19 +43,21 @@ function EditorCommon() {
this.data = {};
}
EditorCommon.prototype.connect = async function () {};
EditorCommon.prototype.isConnected = function() {
EditorCommon.prototype.isConnected = function () {
return true;
};
EditorCommon.prototype.ping = async function() {return "PONG"};
EditorCommon.prototype.close = async function() {};
EditorCommon.prototype.healthCheck = async function() {
EditorCommon.prototype.ping = async function () {
return 'PONG';
};
EditorCommon.prototype.close = async function () {};
EditorCommon.prototype.healthCheck = async function () {
if (this.isConnected()) {
await this.ping();
return true;
}
return false;
};
EditorCommon.prototype._getDocumentData = function(ctx, docId) {
EditorCommon.prototype._getDocumentData = function (ctx, docId) {
let tenantData = this.data[ctx.tenant];
if (!tenantData) {
this.data[ctx.tenant] = tenantData = {};
@ -66,7 +68,7 @@ EditorCommon.prototype._getDocumentData = function(ctx, docId) {
}
return options;
};
EditorCommon.prototype._checkAndLock = function(ctx, name, docId, fencingToken, ttl) {
EditorCommon.prototype._checkAndLock = function (ctx, name, docId, fencingToken, ttl) {
const data = this._getDocumentData(ctx, docId);
const now = Date.now();
let res = true;
@ -78,7 +80,7 @@ EditorCommon.prototype._checkAndLock = function(ctx, name, docId, fencingToken,
}
return res;
};
EditorCommon.prototype._checkAndUnlock = function(ctx, name, docId, fencingToken) {
EditorCommon.prototype._checkAndUnlock = function (ctx, name, docId, fencingToken) {
const data = this._getDocumentData(ctx, docId);
const now = Date.now();
let res;
@ -103,10 +105,10 @@ function EditorData() {
EditorData.prototype = Object.create(EditorCommon.prototype);
EditorData.prototype.constructor = EditorData;
EditorData.prototype.addPresence = async function(_ctx, _docId, _userId, _userInfo) {};
EditorData.prototype.updatePresence = async function(_ctx, _docId, _userId) {};
EditorData.prototype.removePresence = async function(_ctx, _docId, _userId) {};
EditorData.prototype.getPresence = async function(ctx, docId, connections) {
EditorData.prototype.addPresence = async function (_ctx, _docId, _userId, _userInfo) {};
EditorData.prototype.updatePresence = async function (_ctx, _docId, _userId) {};
EditorData.prototype.removePresence = async function (_ctx, _docId, _userId) {};
EditorData.prototype.getPresence = async function (ctx, docId, connections) {
const hvals = [];
if (connections) {
for (let i = 0; i < connections.length; ++i) {
@ -119,32 +121,32 @@ EditorData.prototype.getPresence = async function(ctx, docId, connections) {
return hvals;
};
EditorData.prototype.lockSave = async function(ctx, docId, userId, ttl) {
EditorData.prototype.lockSave = async function (ctx, docId, userId, ttl) {
return this._checkAndLock(ctx, 'lockSave', docId, userId, ttl);
};
EditorData.prototype.unlockSave = async function(ctx, docId, userId) {
EditorData.prototype.unlockSave = async function (ctx, docId, userId) {
return this._checkAndUnlock(ctx, 'lockSave', docId, userId);
};
EditorData.prototype.lockAuth = async function(ctx, docId, userId, ttl) {
EditorData.prototype.lockAuth = async function (ctx, docId, userId, ttl) {
return this._checkAndLock(ctx, 'lockAuth', docId, userId, ttl);
};
EditorData.prototype.unlockAuth = async function(ctx, docId, userId) {
EditorData.prototype.unlockAuth = async function (ctx, docId, userId) {
return this._checkAndUnlock(ctx, 'lockAuth', docId, userId);
};
EditorData.prototype.getDocumentPresenceExpired = async function(_now) {
EditorData.prototype.getDocumentPresenceExpired = async function (_now) {
return [];
};
EditorData.prototype.removePresenceDocument = async function(_ctx, _docId) {};
EditorData.prototype.removePresenceDocument = async function (_ctx, _docId) {};
EditorData.prototype.addLocks = async function(ctx, docId, locks) {
EditorData.prototype.addLocks = async function (ctx, docId, locks) {
const data = this._getDocumentData(ctx, docId);
if (!data.locks) {
data.locks = {};
}
Object.assign(data.locks, locks);
};
EditorData.prototype.addLocksNX = async function(ctx, docId, locks) {
EditorData.prototype.addLocksNX = async function (ctx, docId, locks) {
const data = this._getDocumentData(ctx, docId);
if (!data.locks) {
data.locks = {};
@ -159,7 +161,7 @@ EditorData.prototype.addLocksNX = async function(ctx, docId, locks) {
}
return {lockConflict, allLocks: data.locks};
};
EditorData.prototype.removeLocks = async function(ctx, docId, locks) {
EditorData.prototype.removeLocks = async function (ctx, docId, locks) {
const data = this._getDocumentData(ctx, docId);
if (data.locks) {
for (const lockId in locks) {
@ -167,50 +169,50 @@ EditorData.prototype.removeLocks = async function(ctx, docId, locks) {
}
}
};
EditorData.prototype.removeAllLocks = async function(ctx, docId) {
EditorData.prototype.removeAllLocks = async function (ctx, docId) {
const data = this._getDocumentData(ctx, docId);
data.locks = undefined;
};
EditorData.prototype.getLocks = async function(ctx, docId) {
EditorData.prototype.getLocks = async function (ctx, docId) {
const data = this._getDocumentData(ctx, docId);
return data.locks || {};
};
EditorData.prototype.addMessage = async function(ctx, docId, msg) {
EditorData.prototype.addMessage = async function (ctx, docId, msg) {
const data = this._getDocumentData(ctx, docId);
if (!data.messages) {
data.messages = [];
}
data.messages.push(msg);
};
EditorData.prototype.removeMessages = async function(ctx, docId) {
EditorData.prototype.removeMessages = async function (ctx, docId) {
const data = this._getDocumentData(ctx, docId);
data.messages = undefined;
};
EditorData.prototype.getMessages = async function(ctx, docId) {
EditorData.prototype.getMessages = async function (ctx, docId) {
const data = this._getDocumentData(ctx, docId);
return data.messages || [];
};
EditorData.prototype.setSaved = async function(ctx, docId, status) {
EditorData.prototype.setSaved = async function (ctx, docId, status) {
const data = this._getDocumentData(ctx, docId);
data.saved = status;
};
EditorData.prototype.getdelSaved = async function(ctx, docId) {
EditorData.prototype.getdelSaved = async function (ctx, docId) {
const data = this._getDocumentData(ctx, docId);
const res = data.saved;
data.saved = null;
return res;
};
EditorData.prototype.setForceSave = async function(ctx, docId, time, index, baseUrl, changeInfo, convertInfo) {
EditorData.prototype.setForceSave = async function (ctx, docId, time, index, baseUrl, changeInfo, convertInfo) {
const data = this._getDocumentData(ctx, docId);
data.forceSave = {time, index, baseUrl, changeInfo, started: false, ended: false, convertInfo};
};
EditorData.prototype.getForceSave = async function(ctx, docId) {
EditorData.prototype.getForceSave = async function (ctx, docId) {
const data = this._getDocumentData(ctx, docId);
return data.forceSave || null;
};
EditorData.prototype.checkAndStartForceSave = async function(ctx, docId) {
EditorData.prototype.checkAndStartForceSave = async function (ctx, docId) {
const data = this._getDocumentData(ctx, docId);
let res;
if (data.forceSave && !data.forceSave.started) {
@ -220,7 +222,7 @@ EditorData.prototype.checkAndStartForceSave = async function(ctx, docId) {
}
return res;
};
EditorData.prototype.checkAndSetForceSave = async function(ctx, docId, time, index, started, ended, convertInfo) {
EditorData.prototype.checkAndSetForceSave = async function (ctx, docId, time, index, started, ended, convertInfo) {
const data = this._getDocumentData(ctx, docId);
let res;
if (data.forceSave && time === data.forceSave.time && index === data.forceSave.index) {
@ -231,12 +233,12 @@ EditorData.prototype.checkAndSetForceSave = async function(ctx, docId, time, ind
}
return res;
};
EditorData.prototype.removeForceSave = async function(ctx, docId) {
EditorData.prototype.removeForceSave = async function (ctx, docId) {
const data = this._getDocumentData(ctx, docId);
data.forceSave = undefined;
};
EditorData.prototype.cleanDocumentOnExit = async function(ctx, docId) {
EditorData.prototype.cleanDocumentOnExit = async function (ctx, docId) {
const tenantData = this.data[ctx.tenant];
if (tenantData) {
delete tenantData[docId];
@ -247,7 +249,7 @@ EditorData.prototype.cleanDocumentOnExit = async function(ctx, docId) {
}
};
EditorData.prototype.addForceSaveTimerNX = async function(ctx, docId, expireAt) {
EditorData.prototype.addForceSaveTimerNX = async function (ctx, docId, expireAt) {
let tenantTimer = this.forceSaveTimer[ctx.tenant];
if (!tenantTimer) {
this.forceSaveTimer[ctx.tenant] = tenantTimer = {};
@ -256,7 +258,7 @@ EditorData.prototype.addForceSaveTimerNX = async function(ctx, docId, expireAt)
tenantTimer[docId] = expireAt;
}
};
EditorData.prototype.getForceSaveTimer = async function(now) {
EditorData.prototype.getForceSaveTimer = async function (now) {
const res = [];
for (const tenant in this.forceSaveTimer) {
if (this.forceSaveTimer.hasOwnProperty(tenant)) {
@ -286,14 +288,14 @@ function EditorStat() {
}
EditorStat.prototype = Object.create(EditorCommon.prototype);
EditorStat.prototype.constructor = EditorStat;
EditorStat.prototype.addPresenceUniqueUser = async function(ctx, userId, expireAt, userInfo) {
EditorStat.prototype.addPresenceUniqueUser = async function (ctx, userId, expireAt, userInfo) {
let tenantUser = this.uniqueUser[ctx.tenant];
if (!tenantUser) {
this.uniqueUser[ctx.tenant] = tenantUser = {};
}
tenantUser[userId] = {expireAt, userInfo};
};
EditorStat.prototype.getPresenceUniqueUser = async function(ctx, nowUTC) {
EditorStat.prototype.getPresenceUniqueUser = async function (ctx, nowUTC) {
const res = [];
let tenantUser = this.uniqueUser[ctx.tenant];
if (!tenantUser) {
@ -313,18 +315,18 @@ EditorStat.prototype.getPresenceUniqueUser = async function(ctx, nowUTC) {
}
return res;
};
EditorStat.prototype.addPresenceUniqueUsersOfMonth = async function(ctx, userId, period, userInfo) {
EditorStat.prototype.addPresenceUniqueUsersOfMonth = async function (ctx, userId, period, userInfo) {
let tenantUser = this.uniqueUsersOfMonth[ctx.tenant];
if (!tenantUser) {
this.uniqueUsersOfMonth[ctx.tenant] = tenantUser = {};
}
if(!tenantUser[period]) {
if (!tenantUser[period]) {
const expireAt = Date.now() + cfgExpMonthUniqueUsers;
tenantUser[period] = {expireAt, data: {}};
}
tenantUser[period].data[userId] = userInfo;
};
EditorStat.prototype.getPresenceUniqueUsersOfMonth = async function(ctx) {
EditorStat.prototype.getPresenceUniqueUsersOfMonth = async function (ctx) {
const res = {};
const nowUTC = Date.now();
let tenantUser = this.uniqueUsersOfMonth[ctx.tenant];
@ -344,14 +346,14 @@ EditorStat.prototype.getPresenceUniqueUsersOfMonth = async function(ctx) {
return res;
};
EditorStat.prototype.addPresenceUniqueViewUser = async function(ctx, userId, expireAt, userInfo) {
EditorStat.prototype.addPresenceUniqueViewUser = async function (ctx, userId, expireAt, userInfo) {
let tenantUser = this.uniqueViewUser[ctx.tenant];
if (!tenantUser) {
this.uniqueViewUser[ctx.tenant] = tenantUser = {};
}
tenantUser[userId] = {expireAt, userInfo};
};
EditorStat.prototype.getPresenceUniqueViewUser = async function(ctx, nowUTC) {
EditorStat.prototype.getPresenceUniqueViewUser = async function (ctx, nowUTC) {
const res = [];
let tenantUser = this.uniqueViewUser[ctx.tenant];
if (!tenantUser) {
@ -371,18 +373,18 @@ EditorStat.prototype.getPresenceUniqueViewUser = async function(ctx, nowUTC) {
}
return res;
};
EditorStat.prototype.addPresenceUniqueViewUsersOfMonth = async function(ctx, userId, period, userInfo) {
EditorStat.prototype.addPresenceUniqueViewUsersOfMonth = async function (ctx, userId, period, userInfo) {
let tenantUser = this.uniqueViewUsersOfMonth[ctx.tenant];
if (!tenantUser) {
this.uniqueViewUsersOfMonth[ctx.tenant] = tenantUser = {};
}
if(!tenantUser[period]) {
if (!tenantUser[period]) {
const expireAt = Date.now() + cfgExpMonthUniqueUsers;
tenantUser[period] = {expireAt, data: {}};
}
tenantUser[period].data[userId] = userInfo;
};
EditorStat.prototype.getPresenceUniqueViewUsersOfMonth = async function(ctx) {
EditorStat.prototype.getPresenceUniqueViewUsersOfMonth = async function (ctx) {
const res = {};
const nowUTC = Date.now();
let tenantUser = this.uniqueViewUsersOfMonth[ctx.tenant];
@ -401,7 +403,7 @@ EditorStat.prototype.getPresenceUniqueViewUsersOfMonth = async function(ctx) {
}
return res;
};
EditorStat.prototype.setEditorConnections = async function(ctx, countEdit, countLiveView, countView, now, precision) {
EditorStat.prototype.setEditorConnections = async function (ctx, countEdit, countLiveView, countView, now, precision) {
let tenantStat = this.stat[ctx.tenant];
if (!tenantStat) {
this.stat[ctx.tenant] = tenantStat = [];
@ -413,16 +415,16 @@ EditorStat.prototype.setEditorConnections = async function(ctx, countEdit, count
}
tenantStat.splice(0, i);
};
EditorStat.prototype.getEditorConnections = async function(ctx) {
EditorStat.prototype.getEditorConnections = async function (ctx) {
let tenantStat = this.stat[ctx.tenant];
if (!tenantStat) {
this.stat[ctx.tenant] = tenantStat = [];
}
return tenantStat;
};
EditorStat.prototype.setEditorConnectionsCountByShard = async function(_ctx, _shardId, _count) {};
EditorStat.prototype.incrEditorConnectionsCountByShard = async function(_ctx, _shardId, _count) {};
EditorStat.prototype.getEditorConnectionsCount = async function(ctx, connections) {
EditorStat.prototype.setEditorConnectionsCountByShard = async function (_ctx, _shardId, _count) {};
EditorStat.prototype.incrEditorConnectionsCountByShard = async function (_ctx, _shardId, _count) {};
EditorStat.prototype.getEditorConnectionsCount = async function (ctx, connections) {
let count = 0;
if (connections) {
for (let i = 0; i < connections.length; ++i) {
@ -434,23 +436,23 @@ EditorStat.prototype.getEditorConnectionsCount = async function(ctx, connections
}
return count;
};
EditorStat.prototype.setViewerConnectionsCountByShard = async function(_ctx, _shardId, _count) {};
EditorStat.prototype.incrViewerConnectionsCountByShard = async function(_ctx, _shardId, _count) {};
EditorStat.prototype.getViewerConnectionsCount = async function(ctx, connections) {
EditorStat.prototype.setViewerConnectionsCountByShard = async function (_ctx, _shardId, _count) {};
EditorStat.prototype.incrViewerConnectionsCountByShard = async function (_ctx, _shardId, _count) {};
EditorStat.prototype.getViewerConnectionsCount = async function (ctx, connections) {
let count = 0;
if (connections) {
for (let i = 0; i < connections.length; ++i) {
const conn = connections[i];
if (conn.isCloseCoAuthoring || (conn.user && conn.user.view) && ctx.tenant === tenantManager.getTenantByConnection(ctx, conn)) {
if (conn.isCloseCoAuthoring || (conn.user && conn.user.view && ctx.tenant === tenantManager.getTenantByConnection(ctx, conn))) {
count++;
}
}
}
return count;
};
EditorStat.prototype.setLiveViewerConnectionsCountByShard = async function(_ctx, _shardId, _count) {};
EditorStat.prototype.incrLiveViewerConnectionsCountByShard = async function(_ctx, _shardId, _count) {};
EditorStat.prototype.getLiveViewerConnectionsCount = async function(ctx, connections) {
EditorStat.prototype.setLiveViewerConnectionsCountByShard = async function (_ctx, _shardId, _count) {};
EditorStat.prototype.incrLiveViewerConnectionsCountByShard = async function (_ctx, _shardId, _count) {};
EditorStat.prototype.getLiveViewerConnectionsCount = async function (ctx, connections) {
let count = 0;
if (connections) {
for (let i = 0; i < connections.length; ++i) {
@ -462,19 +464,19 @@ EditorStat.prototype.getLiveViewerConnectionsCount = async function(ctx, connect
}
return count;
};
EditorStat.prototype.addShutdown = async function(key, docId) {
EditorStat.prototype.addShutdown = async function (key, docId) {
if (!this.shutdown[key]) {
this.shutdown[key] = {};
}
this.shutdown[key][docId] = 1;
};
EditorStat.prototype.removeShutdown = async function(key, docId) {
EditorStat.prototype.removeShutdown = async function (key, docId) {
if (!this.shutdown[key]) {
this.shutdown[key] = {};
}
delete this.shutdown[key][docId];
};
EditorStat.prototype.getShutdownCount = async function(key) {
EditorStat.prototype.getShutdownCount = async function (key) {
let count = 0;
if (this.shutdown[key]) {
for (const docId in this.shutdown[key]) {
@ -485,19 +487,19 @@ EditorStat.prototype.getShutdownCount = async function(key) {
}
return count;
};
EditorStat.prototype.cleanupShutdown = async function(key) {
EditorStat.prototype.cleanupShutdown = async function (key) {
delete this.shutdown[key];
};
EditorStat.prototype.setLicense = async function(key, val) {
EditorStat.prototype.setLicense = async function (key, val) {
this.license[key] = val;
};
EditorStat.prototype.getLicense = async function(key) {
EditorStat.prototype.getLicense = async function (key) {
return this.license[key] || null;
};
EditorStat.prototype.removeLicense = async function(key) {
EditorStat.prototype.removeLicense = async function (key) {
delete this.license[key];
};
EditorStat.prototype.lockNotification = async function(ctx, notificationType, ttl) {
EditorStat.prototype.lockNotification = async function (ctx, notificationType, ttl) {
//true NaN !== NaN
return this._checkAndLock(ctx, notificationType, notificationType, NaN, ttl);
};
@ -505,4 +507,4 @@ EditorStat.prototype.lockNotification = async function(ctx, notificationType, tt
module.exports = {
EditorData,
EditorStat
}
};

View File

@ -53,7 +53,7 @@ const PATTERN_ENCRYPTED = 'ENCRYPTED;';
// const checkJwtRes = yield docsCoServer.checkJwt(ctx, token, commonDefines.c_oAscSecretType.Session);
// return checkJwtUploadTransformRes(ctx, errorName, checkJwtRes);
// }
function checkJwtUploadTransformRes(ctx, errorName, checkJwtRes){
function checkJwtUploadTransformRes(ctx, errorName, checkJwtRes) {
var res = {err: true, docId: null, userid: null, encrypted: null};
if (checkJwtRes.decoded) {
var doc = checkJwtRes.decoded.document;
@ -74,7 +74,7 @@ function checkJwtUploadTransformRes(ctx, errorName, checkJwtRes){
}
return res;
}
exports.uploadImageFile = function(req, res) {
exports.uploadImageFile = function (req, res) {
return co(function* () {
let httpStatus = 200;
var docId = 'null';
@ -125,15 +125,19 @@ exports.uploadImageFile = function(req, res) {
formatStr = formatChecker.getStringFromFormat(format);
}
//a hash is written at the beginning to avoid errors during parallel upload in co-editing
var strImageName = crypto.randomBytes(16).toString("hex");
var strImageName = crypto.randomBytes(16).toString('hex');
var strPathRel = 'media/' + strImageName + '.' + formatStr;
var strPath = docId + '/' + strPathRel;
buffer = yield utilsDocService.fixImageExifRotation(ctx, buffer);
yield storageBase.putObject(ctx, strPath, buffer, buffer.length);
output[strPathRel] = yield storageBase.getSignedUrl(ctx, utils.getBaseUrlByRequest(ctx, req), strPath,
commonDefines.c_oAscUrlTypes.Session);
output[strPathRel] = yield storageBase.getSignedUrl(
ctx,
utils.getBaseUrlByRequest(ctx, req),
strPath,
commonDefines.c_oAscUrlTypes.Session
);
} else {
httpStatus = 415;
ctx.logger.debug('uploadImageFile format is not supported');

View File

@ -43,7 +43,7 @@ var commondefines = require('./../../Common/sources/commondefines');
var queueService = require('./../../Common/sources/taskqueueRabbitMQ');
var operationContext = require('./../../Common/sources/operationContext');
var pubsubService = require('./pubsubRabbitMQ');
const sqlBase = require("./databaseConnectors/baseConnector");
const sqlBase = require('./databaseConnectors/baseConnector');
var cfgExpFilesCron = config.get('services.CoAuthoring.expire.filesCron');
var cfgExpDocumentsCron = config.get('services.CoAuthoring.expire.documentsCron');
@ -51,15 +51,15 @@ var cfgExpFiles = config.get('services.CoAuthoring.expire.files');
var cfgExpFilesRemovedAtOnce = config.get('services.CoAuthoring.expire.filesremovedatonce');
var cfgForceSaveStep = config.get('services.CoAuthoring.autoAssembly.step');
function getCronStep(cronTime){
const cronJob = new cron.CronJob(cronTime, (() =>{}));
function getCronStep(cronTime) {
const cronJob = new cron.CronJob(cronTime, () => {});
const dates = cronJob.nextDates(2);
return dates[1] - dates[0];
}
const expFilesStep = getCronStep(cfgExpFilesCron);
const expDocumentsStep = getCronStep(cfgExpDocumentsCron);
var checkFileExpire = function(expireSeconds) {
var checkFileExpire = function (expireSeconds) {
return co(function* () {
const ctx = new operationContext.Context();
let currentExpFilesStep = expFilesStep;
@ -100,7 +100,7 @@ var checkFileExpire = function(expireSeconds) {
//todo tenant
//check that no one is in the document
const editorsCount = yield docsCoServer.getEditorsCountPromise(ctx, docId);
if(0 === editorsCount){
if (0 === editorsCount) {
if (yield canvasService.cleanupCache(ctx, docId)) {
currentRemovedCount++;
}
@ -119,7 +119,7 @@ var checkFileExpire = function(expireSeconds) {
}
});
};
var checkDocumentExpire = function() {
var checkDocumentExpire = function () {
return co(function* () {
var queue = null;
var removedCount = 0;
@ -131,7 +131,7 @@ var checkDocumentExpire = function() {
yield ctx.initTenantCache();
const currentDocumentsCron = ctx.getCfg('services.CoAuthoring.expire.documentsCron', cfgExpDocumentsCron);
currentExpDocumentsStep = getCronStep(currentDocumentsCron);
var now = (new Date()).getTime();
var now = new Date().getTime();
const expiredKeys = yield docsCoServer.editorData.getDocumentPresenceExpired(now);
if (expiredKeys.length > 0) {
queue = new queueService();
@ -181,7 +181,7 @@ var checkDocumentExpire = function() {
}
});
};
const forceSaveTimeout = function() {
const forceSaveTimeout = function () {
return co(function* () {
let queue = null;
let pubsub = null;
@ -191,7 +191,7 @@ const forceSaveTimeout = function() {
ctx.logger.info('forceSaveTimeout start');
yield ctx.initTenantCache();
currentForceSaveStep = ctx.getCfg('services.CoAuthoring.autoAssembly.step', cfgForceSaveStep);
const now = (new Date()).getTime();
const now = new Date().getTime();
const expiredKeys = yield docsCoServer.editorData.getForceSaveTimer(now);
if (expiredKeys.length > 0) {
queue = new queueService();
@ -218,9 +218,25 @@ const forceSaveTimeout = function() {
ctx.setDocId(docId);
}
actions.push(docsCoServer.startForceSave(ctx, docId, commondefines.c_oAscForceSaveTypes.Timeout,
undefined, undefined, undefined, undefined,
undefined, undefined, undefined, undefined, queue, pubsub, undefined, true));
actions.push(
docsCoServer.startForceSave(
ctx,
docId,
commondefines.c_oAscForceSaveTypes.Timeout,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
queue,
pubsub,
undefined,
true
)
);
}
}
yield Promise.all(actions);
@ -246,7 +262,7 @@ const forceSaveTimeout = function() {
});
};
exports.startGC = function() {
exports.startGC = function () {
//runtime config is read on start
setTimeout(checkDocumentExpire, expDocumentsStep);
setTimeout(checkFileExpire, expFilesStep);

View File

@ -59,20 +59,29 @@ function initRabbit(pubsub, callback) {
});
pubsub.connection = conn;
pubsub.channelPublish = yield rabbitMQCore.createChannelPromise(conn);
pubsub.exchangePublish = yield rabbitMQCore.assertExchangePromise(pubsub.channelPublish, cfgRabbitExchangePubSub.name,
'fanout', cfgRabbitExchangePubSub.options);
pubsub.exchangePublish = yield rabbitMQCore.assertExchangePromise(
pubsub.channelPublish,
cfgRabbitExchangePubSub.name,
'fanout',
cfgRabbitExchangePubSub.options
);
pubsub.channelReceive = yield rabbitMQCore.createChannelPromise(conn);
var queue = yield rabbitMQCore.assertQueuePromise(pubsub.channelReceive, cfgRabbitQueuePubsub.name, cfgRabbitQueuePubsub.options);
pubsub.channelReceive.bindQueue(queue, cfgRabbitExchangePubSub.name, '');
yield rabbitMQCore.consumePromise(pubsub.channelReceive, queue, (message) => {
if(null != pubsub.channelReceive){
if (message) {
pubsub.emit('message', message.content.toString());
yield rabbitMQCore.consumePromise(
pubsub.channelReceive,
queue,
message => {
if (null != pubsub.channelReceive) {
if (message) {
pubsub.emit('message', message.content.toString());
}
pubsub.channelReceive.ack(message);
}
pubsub.channelReceive.ack(message);
}
}, {noAck: false});
},
{noAck: false}
);
//process messages received while reconnection time
yield repeat(pubsub);
} catch (err) {
@ -84,7 +93,7 @@ function initRabbit(pubsub, callback) {
});
}
function initActive(pubsub, callback) {
return co(function*() {
return co(function* () {
var e = null;
try {
var conn = yield activeMQCore.connetPromise(() => {
@ -116,7 +125,7 @@ function initActive(pubsub, callback) {
const receiver = yield activeMQCore.openReceiverPromise(conn, optionsPubSubReceiver);
//todo ?consumer.dispatchAsync=false&consumer.prefetchSize=1
receiver.add_credit(1);
receiver.on("message", (context) => {
receiver.on('message', context => {
if (context) {
pubsub.emit('message', context.message.body);
}
@ -140,13 +149,12 @@ function clear(pubsub) {
pubsub.channelReceive = null;
}
function repeat(pubsub) {
return co(function*() {
return co(function* () {
for (var i = 0; i < pubsub.publishStore.length; ++i) {
yield publish(pubsub, pubsub.publishStore[i]);
}
pubsub.publishStore.length = 0;
});
}
function publishRabbit(pubsub, data) {
return new Promise((resolve, _reject) => {
@ -188,8 +196,12 @@ function healthCheckRabbit(pubsub) {
if (!pubsub.channelPublish) {
return false;
}
const exchange = yield rabbitMQCore.assertExchangePromise(pubsub.channelPublish, cfgRabbitExchangePubSub.name,
'fanout', cfgRabbitExchangePubSub.options);
const exchange = yield rabbitMQCore.assertExchangePromise(
pubsub.channelPublish,
cfgRabbitExchangePubSub.name,
'fanout',
cfgRabbitExchangePubSub.options
);
return !!exchange;
});
}
@ -231,10 +243,10 @@ util.inherits(PubsubRabbitMQ, events.EventEmitter);
PubsubRabbitMQ.prototype.init = function (callback) {
init(this, callback);
};
PubsubRabbitMQ.prototype.initPromise = function() {
PubsubRabbitMQ.prototype.initPromise = function () {
var t = this;
return new Promise((resolve, reject) => {
init(t, (err) => {
init(t, err => {
if (err) {
reject(err);
} else {
@ -252,11 +264,11 @@ PubsubRabbitMQ.prototype.publish = function (message) {
return Promise.resolve();
}
};
PubsubRabbitMQ.prototype.close = function() {
PubsubRabbitMQ.prototype.close = function () {
this.isClose = true;
return close(this.connection);
};
PubsubRabbitMQ.prototype.healthCheck = function() {
PubsubRabbitMQ.prototype.healthCheck = function () {
return healthCheck(this);
};

View File

@ -39,8 +39,13 @@ const runtimeConfigManager = require('../../../Common/sources/runtimeConfigManag
const router = express.Router();
const rawFileParser = bodyParser.raw(
{inflate: true, limit: config.get('services.CoAuthoring.server.limits_tempfile_upload'), type() {return true;}});
const rawFileParser = bodyParser.raw({
inflate: true,
limit: config.get('services.CoAuthoring.server.limits_tempfile_upload'),
type() {
return true;
}
});
router.get('/', async (req, res) => {
const ctx = new operationContext.Context();
@ -53,8 +58,7 @@ router.get('/', async (req, res) => {
result = JSON.stringify(cfg);
} catch (error) {
ctx.logger.error('config get error: %s', error.stack);
}
finally {
} finally {
res.setHeader('Content-Type', 'application/json');
res.send(result);
ctx.logger.debug('config end');
@ -85,5 +89,4 @@ router.post('/', rawFileParser, async (req, res) => {
}
});
module.exports = router;

View File

@ -32,19 +32,21 @@
'use strict';
const { pipeline } = require('node:stream/promises');
const {pipeline} = require('node:stream/promises');
const express = require('express');
const config = require('config');
const operationContext = require('./../../../Common/sources/operationContext');
const tenantManager = require('./../../../Common/sources/tenantManager');
const utils = require('./../../../Common/sources/utils');
const storage = require('./../../../Common/sources/storage/storage-base');
const urlModule = require("url");
const path = require("path");
const mime = require("mime");
const urlModule = require('url');
const path = require('path');
const mime = require('mime');
const crypto = require('crypto');
const cfgStaticContent = config.has('services.CoAuthoring.server.static_content') ? config.util.cloneDeep(config.get('services.CoAuthoring.server.static_content')) : {};
const cfgStaticContent = config.has('services.CoAuthoring.server.static_content')
? config.util.cloneDeep(config.get('services.CoAuthoring.server.static_content'))
: {};
const cfgCacheStorage = config.get('storage');
const cfgPersistentStorage = utils.deepMergeObjects({}, cfgCacheStorage, config.get('persistentStorage'));
const cfgForgottenFiles = config.get('services.CoAuthoring.server.forgottenfiles');
@ -53,10 +55,15 @@ const cfgErrorFiles = config.get('FileConverter.converter.errorfiles');
const router = express.Router();
function initCacheRouter(cfgStorage, routs) {
const { storageFolderName, fs: { folderPath, secretString: secret } } = cfgStorage;
const {
storageFolderName,
fs: {folderPath, secretString: secret}
} = cfgStorage;
routs.forEach((rout) => {
if (!rout) {return;}
routs.forEach(rout => {
if (!rout) {
return;
}
const rootPath = path.join(folderPath, rout);
@ -77,7 +84,7 @@ function createCacheMiddleware(prefix, rootPath, cfgStorage, secret, rout) {
try {
const urlParsed = urlModule.parse(req.url, true);
const { md5, expires } = urlParsed.query;
const {md5, expires} = urlParsed.query;
const numericExpires = parseInt(expires);
if (!md5 || !numericExpires) {
@ -95,13 +102,7 @@ function createCacheMiddleware(prefix, rootPath, cfgStorage, secret, rout) {
const fullPath = `/${prefix}/${cfgStorage.storageFolderName}/${rout}${uri}`;
const signatureData = numericExpires + decodeURIComponent(fullPath) + secret;
const expectedMd5 = crypto
.createHash('md5')
.update(signatureData)
.digest('base64')
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
const expectedMd5 = crypto.createHash('md5').update(signatureData).digest('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
if (md5 !== expectedMd5) {
res.sendStatus(403);
@ -116,11 +117,11 @@ function createCacheMiddleware(prefix, rootPath, cfgStorage, secret, rout) {
dotfiles: 'deny',
headers: {
'Content-Disposition': 'attachment',
...(filename && { 'Content-Type': mime.getType(filename) })
...(filename && {'Content-Type': mime.getType(filename)})
}
};
res.sendFile(filePath, sendFileOptions, (err) => {
res.sendFile(filePath, sendFileOptions, err => {
if (err) {
operationContext.global.logger.error(err);
res.status(400).end();
@ -159,7 +160,9 @@ if (storage.needServeStatic()) {
}
if (storage.needServeStatic(cfgForgottenFiles)) {
let persistentRouts = [cfgForgottenFiles, cfgErrorFiles];
persistentRouts = persistentRouts.filter((rout) => {return rout && rout.length > 0;});
persistentRouts = persistentRouts.filter(rout => {
return rout && rout.length > 0;
});
if (persistentRouts.length > 0) {
initCacheRouter(cfgPersistentStorage, persistentRouts);
}

View File

@ -43,7 +43,7 @@ const fs = require('fs');
const express = require('express');
const http = require('http');
const path = require('path');
const bodyParser = require("body-parser");
const bodyParser = require('body-parser');
const multer = require('multer');
const apicache = require('apicache');
const docsCoServer = require('./DocsCoServer');
@ -92,36 +92,38 @@ const cfgDownloadMaxBytes = config.get('FileConverter.converter.maxDownloadBytes
const app = express();
app.disable('x-powered-by');
//path.resolve uses __dirname by default(unexpected path in pkg)
app.set("views", path.resolve(process.cwd(), cfgHtmlTemplate));
app.set("view engine", "ejs");
app.set('views', path.resolve(process.cwd(), cfgHtmlTemplate));
app.set('view engine', 'ejs');
const server = http.createServer(app);
let licenseInfo, licenseOriginal, updatePluginsTime, userPlugins;
const updatePluginsCacheExpire = ms("5m");
const updatePluginsCacheExpire = ms('5m');
const updatePlugins = (eventType, filename) => {
operationContext.global.logger.info('update Folder true: %s ; %s', eventType, filename);
userPlugins = undefined;
operationContext.global.logger.info('update Folder true: %s ; %s', eventType, filename);
userPlugins = undefined;
};
const readLicense = async function () {
[licenseInfo, licenseOriginal] = await license.readLicense(cfgLicenseFile);
[licenseInfo, licenseOriginal] = await license.readLicense(cfgLicenseFile);
};
const updateLicense = async () => {
try {
await readLicense();
await docsCoServer.setLicenseInfo(operationContext.global, licenseInfo, licenseOriginal);
operationContext.global.logger.info('End updateLicense');
} catch (err) {
operationContext.global.logger.error('updateLicense error: %s', err.stack);
}
try {
await readLicense();
await docsCoServer.setLicenseInfo(operationContext.global, licenseInfo, licenseOriginal);
operationContext.global.logger.info('End updateLicense');
} catch (err) {
operationContext.global.logger.error('updateLicense error: %s', err.stack);
}
};
operationContext.global.logger.warn('Express server starting...');
if (!(cfgTokenEnableBrowser && cfgTokenEnableRequestInbox && cfgTokenEnableRequestOutbox)) {
operationContext.global.logger.warn('Set services.CoAuthoring.token.enable.browser, services.CoAuthoring.token.enable.request.inbox, ' +
'services.CoAuthoring.token.enable.request.outbox in the Document Server config ' +
'to prevent an unauthorized access to your documents and the substitution of important parameters in Document Server requests.');
operationContext.global.logger.warn(
'Set services.CoAuthoring.token.enable.browser, services.CoAuthoring.token.enable.request.inbox, ' +
'services.CoAuthoring.token.enable.request.outbox in the Document Server config ' +
'to prevent an unauthorized access to your documents and the substitution of important parameters in Document Server requests.'
);
}
updateLicense();
@ -129,297 +131,332 @@ fs.watchFile(cfgLicenseFile, updateLicense);
setInterval(updateLicense, 86400000);
try {
const staticContent = config.get('services.CoAuthoring.server.static_content');
const pluginsUri = config.get('services.CoAuthoring.plugins.uri');
let pluginsPath = undefined;
if (staticContent[pluginsUri]) {
pluginsPath = staticContent[pluginsUri].path;
}
fs.watch(pluginsPath, updatePlugins);
const staticContent = config.get('services.CoAuthoring.server.static_content');
const pluginsUri = config.get('services.CoAuthoring.plugins.uri');
let pluginsPath = undefined;
if (staticContent[pluginsUri]) {
pluginsPath = staticContent[pluginsUri].path;
}
fs.watch(pluginsPath, updatePlugins);
} catch (e) {
operationContext.global.logger.warn('Failed to subscribe to plugin folder updates. When changing the list of plugins, you must restart the server. https://nodejs.org/docs/latest/api/fs.html#fs_availability. %s', e.stack);
operationContext.global.logger.warn(
'Failed to subscribe to plugin folder updates. When changing the list of plugins, you must restart the server. https://nodejs.org/docs/latest/api/fs.html#fs_availability. %s',
e.stack
);
}
// If you want to use 'development' and 'production',
// then with app.settings.env (https://github.com/strongloop/express/issues/936)
// If error handling is needed, now it's like this https://github.com/expressjs/errorhandler
docsCoServer.install(server, () => {
operationContext.global.logger.info('Start callbackFunction');
operationContext.global.logger.info('Start callbackFunction');
server.listen(config.get('services.CoAuthoring.server.port'), () => {
operationContext.global.logger.warn("Express server listening on port %d in %s mode. Version: %s. Build: %s", config.get('services.CoAuthoring.server.port'), app.settings.env, commonDefines.buildVersion, commonDefines.buildNumber);
});
server.listen(config.get('services.CoAuthoring.server.port'), () => {
operationContext.global.logger.warn(
'Express server listening on port %d in %s mode. Version: %s. Build: %s',
config.get('services.CoAuthoring.server.port'),
app.settings.env,
commonDefines.buildVersion,
commonDefines.buildNumber
);
});
app.get('/index.html', (req, res) => {
return co(function*() {
const ctx = new operationContext.Context();
try {
ctx.initFromRequest(req);
yield ctx.initTenantCache();
const [licenseInfo] = yield tenantManager.getTenantLicense(ctx);
const buildVersion = commonDefines.buildVersion;
const buildNumber = commonDefines.buildNumber;
const alias = "";
let buildDate, packageType, customerId = "", multitenancy="";
if (licenseInfo) {
buildDate = licenseInfo.buildDate.toISOString();
packageType = licenseInfo.packageType;
customerId = licenseInfo.customerId;
multitenancy = licenseInfo.multitenancy;
}
let output = `Server is functioning normally. Version: ${buildVersion}. Build: ${buildNumber}`;
output += `. Release date: ${buildDate}. Package type: ${packageType}. Customer Id: ${customerId}`;
output += `. Multitenancy: ${multitenancy}. Alias: ${alias}`;
res.send(output);
} catch (err) {
ctx.logger.error('index.html error: %s', err.stack);
res.sendStatus(400);
}
});
});
app.get('/index.html', (req, res) => {
return co(function* () {
const ctx = new operationContext.Context();
try {
ctx.initFromRequest(req);
yield ctx.initTenantCache();
const [licenseInfo] = yield tenantManager.getTenantLicense(ctx);
const buildVersion = commonDefines.buildVersion;
const buildNumber = commonDefines.buildNumber;
const alias = '';
let buildDate,
packageType,
customerId = '',
multitenancy = '';
if (licenseInfo) {
buildDate = licenseInfo.buildDate.toISOString();
packageType = licenseInfo.packageType;
customerId = licenseInfo.customerId;
multitenancy = licenseInfo.multitenancy;
}
let output = `Server is functioning normally. Version: ${buildVersion}. Build: ${buildNumber}`;
output += `. Release date: ${buildDate}. Package type: ${packageType}. Customer Id: ${customerId}`;
output += `. Multitenancy: ${multitenancy}. Alias: ${alias}`;
res.send(output);
} catch (err) {
ctx.logger.error('index.html error: %s', err.stack);
res.sendStatus(400);
}
});
});
app.use('/', staticRouter);
app.use('/', staticRouter);
const rawFileParser = bodyParser.raw(
{inflate: true, limit: config.get('services.CoAuthoring.server.limits_tempfile_upload'), type() {return true;}});
const urleEcodedParser = bodyParser.urlencoded({ extended: false });
const forms = multer();
const rawFileParser = bodyParser.raw({
inflate: true,
limit: config.get('services.CoAuthoring.server.limits_tempfile_upload'),
type() {
return true;
}
});
const urleEcodedParser = bodyParser.urlencoded({extended: false});
const forms = multer();
app.get('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser, docsCoServer.commandFromServer);
app.post('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser, docsCoServer.commandFromServer);
app.post('/command', utils.checkClientIp, rawFileParser, docsCoServer.commandFromServer);
app.get('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser, docsCoServer.commandFromServer);
app.post('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser, docsCoServer.commandFromServer);
app.post('/command', utils.checkClientIp, rawFileParser, docsCoServer.commandFromServer);
app.get('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
app.post('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
app.post('/converter', utils.checkClientIp, rawFileParser, converterService.convertJson);
app.get('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
app.post('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
app.post('/converter', utils.checkClientIp, rawFileParser, converterService.convertJson);
app.param('docid', (req, res, next, val) => {
if (constants.DOC_ID_REGEX.test(val)) {
next();
} else {
res.sendStatus(403);
}
});
app.param('index', (req, res, next, val) => {
if (!isNaN(parseInt(val))) {
next();
} else {
res.sendStatus(403);
}
});
app.post('/upload/:docid*', rawFileParser, fileUploaderService.uploadImageFile);
app.param('docid', (req, res, next, val) => {
if (constants.DOC_ID_REGEX.test(val)) {
next();
} else {
res.sendStatus(403);
}
});
app.param('index', (req, res, next, val) => {
if (!isNaN(parseInt(val))) {
next();
} else {
res.sendStatus(403);
}
});
app.post('/upload/:docid*', rawFileParser, fileUploaderService.uploadImageFile);
app.post('/downloadas/:docid', rawFileParser, canvasService.downloadAs);
app.post('/savefile/:docid', rawFileParser, canvasService.saveFile);
app.get('/printfile/:docid/:filename', canvasService.printFile);
app.get('/downloadfile/:docid', canvasService.downloadFile);
app.post('/downloadfile/:docid', rawFileParser, canvasService.downloadFile);
app.get('/healthcheck', utils.checkClientIp, docsCoServer.healthCheck);
app.post('/downloadas/:docid', rawFileParser, canvasService.downloadAs);
app.post('/savefile/:docid', rawFileParser, canvasService.saveFile);
app.get('/printfile/:docid/:filename', canvasService.printFile);
app.get('/downloadfile/:docid', canvasService.downloadFile);
app.post('/downloadfile/:docid', rawFileParser, canvasService.downloadFile);
app.get('/healthcheck', utils.checkClientIp, docsCoServer.healthCheck);
app.get('/baseurl', (req, res) => {
const ctx = new operationContext.Context();
try {
ctx.initFromRequest(req);
//todo
// yield ctx.initTenantCache();
res.send(utils.getBaseUrlByRequest(ctx, req));
} catch (err) {
ctx.logger.error('baseurl error: %s', err.stack);
}
});
app.get('/baseurl', (req, res) => {
const ctx = new operationContext.Context();
try {
ctx.initFromRequest(req);
//todo
// yield ctx.initTenantCache();
res.send(utils.getBaseUrlByRequest(ctx, req));
} catch (err) {
ctx.logger.error('baseurl error: %s', err.stack);
}
});
app.get('/robots.txt', (req, res) => {
res.setHeader('Content-Type', 'plain/text');
res.send("User-agent: *\nDisallow: /");
});
app.get('/robots.txt', (req, res) => {
res.setHeader('Content-Type', 'plain/text');
res.send('User-agent: *\nDisallow: /');
});
app.post('/docbuilder', utils.checkClientIp, rawFileParser, (req, res) => {
converterService.builder(req, res);
});
app.get('/info/info.json', utils.checkClientIp, docsCoServer.licenseInfo);
app.use('/info/config', utils.checkClientIp, configRouter);
app.get('/info/plugin/settings', utils.checkClientIp, aiProxyHandler.requestSettings);
app.post('/info/plugin/models', utils.checkClientIp, rawFileParser, aiProxyHandler.requestModels);
app.put('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
app.delete('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
app.get('/internal/connections/edit', docsCoServer.getEditorConnectionsCount);
app.post('/docbuilder', utils.checkClientIp, rawFileParser, (req, res) => {
converterService.builder(req, res);
});
app.get('/info/info.json', utils.checkClientIp, docsCoServer.licenseInfo);
app.use('/info/config', utils.checkClientIp, configRouter);
app.get('/info/plugin/settings', utils.checkClientIp, aiProxyHandler.requestSettings);
app.post('/info/plugin/models', utils.checkClientIp, rawFileParser, aiProxyHandler.requestModels);
app.put('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
app.delete('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
app.get('/internal/connections/edit', docsCoServer.getEditorConnectionsCount);
function checkWopiEnable(req, res, next) {
//todo may be move code into wopiClient or wopiClient.discovery...
const ctx = new operationContext.Context();
ctx.initFromRequest(req);
ctx.initTenantCache()
.then(() => {
const tenWopiEnable = ctx.getCfg('wopi.enable', cfgWopiEnable);
if (tenWopiEnable) {
next();
} else {
res.sendStatus(404);
}
}).catch((err) => {
ctx.logger.error('checkWopiEnable error: %s', err.stack);
res.sendStatus(404);
});
}
function checkWopiDummyEnable(req, res, next) {
//todo may be move code into wopiClient or wopiClient.discovery...
const ctx = new operationContext.Context();
ctx.initFromRequest(req);
ctx.initTenantCache()
.then(() => {
const tenWopiEnable = ctx.getCfg('wopi.enable', cfgWopiEnable);
const tenWopiDummyEnable = ctx.getCfg('wopi.dummy.enable', cfgWopiDummyEnable);
if (tenWopiEnable && tenWopiDummyEnable) {
next();
} else {
res.sendStatus(404);
}
}).catch((err) => {
ctx.logger.error('checkWopiDummyEnable error: %s', err.stack);
res.sendStatus(404);
});
}
//todo dest
const fileForms = multer({limits: {fieldSize: cfgDownloadMaxBytes}});
app.get('/hosting/discovery', checkWopiEnable, utils.checkClientIp, wopiClient.discovery);
app.get('/hosting/capabilities', checkWopiEnable, utils.checkClientIp, wopiClient.collaboraCapabilities);
app.post('/lool/convert-to/:format?', checkWopiEnable, utils.checkClientIp, urleEcodedParser, fileForms.any(), converterService.convertTo);
app.post('/cool/convert-to/:format?', checkWopiEnable, utils.checkClientIp, urleEcodedParser, fileForms.any(), converterService.convertTo);
app.post('/hosting/wopi/:documentType/:mode', checkWopiEnable, urleEcodedParser, forms.none(), utils.lowercaseQueryString, wopiClient.getEditorHtml);
app.post('/hosting/wopi/convert-and-edit/:ext/:targetext', checkWopiEnable, urleEcodedParser, forms.none(), utils.lowercaseQueryString, wopiClient.getConverterHtml);
app.get('/hosting/wopi/convert-and-edit-handler', checkWopiEnable, utils.lowercaseQueryString, converterService.getConverterHtmlHandler);
app.get('/wopi/files/:docid', apicache.middleware("5 minutes"), checkWopiDummyEnable, utils.lowercaseQueryString, wopiClient.dummyCheckFileInfo);
app.post('/wopi/files/:docid', checkWopiDummyEnable, wopiClient.dummyOk);
app.get('/wopi/files/:docid/contents', apicache.middleware("5 minutes"), checkWopiDummyEnable, wopiClient.dummyGetFile);
app.post('/wopi/files/:docid/contents', checkWopiDummyEnable, wopiClient.dummyOk);
function checkWopiEnable(req, res, next) {
//todo may be move code into wopiClient or wopiClient.discovery...
const ctx = new operationContext.Context();
ctx.initFromRequest(req);
ctx
.initTenantCache()
.then(() => {
const tenWopiEnable = ctx.getCfg('wopi.enable', cfgWopiEnable);
if (tenWopiEnable) {
next();
} else {
res.sendStatus(404);
}
})
.catch(err => {
ctx.logger.error('checkWopiEnable error: %s', err.stack);
res.sendStatus(404);
});
}
function checkWopiDummyEnable(req, res, next) {
//todo may be move code into wopiClient or wopiClient.discovery...
const ctx = new operationContext.Context();
ctx.initFromRequest(req);
ctx
.initTenantCache()
.then(() => {
const tenWopiEnable = ctx.getCfg('wopi.enable', cfgWopiEnable);
const tenWopiDummyEnable = ctx.getCfg('wopi.dummy.enable', cfgWopiDummyEnable);
if (tenWopiEnable && tenWopiDummyEnable) {
next();
} else {
res.sendStatus(404);
}
})
.catch(err => {
ctx.logger.error('checkWopiDummyEnable error: %s', err.stack);
res.sendStatus(404);
});
}
//todo dest
const fileForms = multer({limits: {fieldSize: cfgDownloadMaxBytes}});
app.get('/hosting/discovery', checkWopiEnable, utils.checkClientIp, wopiClient.discovery);
app.get('/hosting/capabilities', checkWopiEnable, utils.checkClientIp, wopiClient.collaboraCapabilities);
app.post('/lool/convert-to/:format?', checkWopiEnable, utils.checkClientIp, urleEcodedParser, fileForms.any(), converterService.convertTo);
app.post('/cool/convert-to/:format?', checkWopiEnable, utils.checkClientIp, urleEcodedParser, fileForms.any(), converterService.convertTo);
app.post(
'/hosting/wopi/:documentType/:mode',
checkWopiEnable,
urleEcodedParser,
forms.none(),
utils.lowercaseQueryString,
wopiClient.getEditorHtml
);
app.post(
'/hosting/wopi/convert-and-edit/:ext/:targetext',
checkWopiEnable,
urleEcodedParser,
forms.none(),
utils.lowercaseQueryString,
wopiClient.getConverterHtml
);
app.get('/hosting/wopi/convert-and-edit-handler', checkWopiEnable, utils.lowercaseQueryString, converterService.getConverterHtmlHandler);
app.get('/wopi/files/:docid', apicache.middleware('5 minutes'), checkWopiDummyEnable, utils.lowercaseQueryString, wopiClient.dummyCheckFileInfo);
app.post('/wopi/files/:docid', checkWopiDummyEnable, wopiClient.dummyOk);
app.get('/wopi/files/:docid/contents', apicache.middleware('5 minutes'), checkWopiDummyEnable, wopiClient.dummyGetFile);
app.post('/wopi/files/:docid/contents', checkWopiDummyEnable, wopiClient.dummyOk);
app.use('/ai-proxy', rawFileParser, aiProxyHandler.proxyRequest);
app.use('/ai-proxy', rawFileParser, aiProxyHandler.proxyRequest);
app.post('/dummyCallback', utils.checkClientIp, apicache.middleware("5 minutes"), rawFileParser, (req, res) =>{
const ctx = new operationContext.Context();
ctx.initFromRequest(req);
//yield ctx.initTenantCache();//no need
ctx.logger.debug(`dummyCallback req.body:%s`, req.body);
utils.fillResponseSimple(res, JSON.stringify({error: 0}, "application/json"));
});
app.post('/dummyCallback', utils.checkClientIp, apicache.middleware('5 minutes'), rawFileParser, (req, res) => {
const ctx = new operationContext.Context();
ctx.initFromRequest(req);
//yield ctx.initTenantCache();//no need
ctx.logger.debug(`dummyCallback req.body:%s`, req.body);
utils.fillResponseSimple(res, JSON.stringify({error: 0}, 'application/json'));
});
const sendUserPlugins = (res, data) => {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(data));
};
app.get('/plugins.json', (req, res) => {
//fs.watch is not reliable. Set cache expiry time
if (userPlugins && (new Date() - updatePluginsTime) < updatePluginsCacheExpire) {
sendUserPlugins(res, userPlugins);
return;
}
const sendUserPlugins = (res, data) => {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(data));
};
app.get('/plugins.json', (req, res) => {
//fs.watch is not reliable. Set cache expiry time
if (userPlugins && new Date() - updatePluginsTime < updatePluginsCacheExpire) {
sendUserPlugins(res, userPlugins);
return;
}
if (!config.has('services.CoAuthoring.server.static_content') || !config.has('services.CoAuthoring.plugins.uri')) {
res.sendStatus(404);
return;
}
if (!config.has('services.CoAuthoring.server.static_content') || !config.has('services.CoAuthoring.plugins.uri')) {
res.sendStatus(404);
return;
}
const staticContent = config.get('services.CoAuthoring.server.static_content');
const pluginsUri = config.get('services.CoAuthoring.plugins.uri');
let pluginsPath = undefined;
const pluginsAutostart = config.get('services.CoAuthoring.plugins.autostart');
const staticContent = config.get('services.CoAuthoring.server.static_content');
const pluginsUri = config.get('services.CoAuthoring.plugins.uri');
let pluginsPath = undefined;
const pluginsAutostart = config.get('services.CoAuthoring.plugins.autostart');
if (staticContent[pluginsUri]) {
pluginsPath = staticContent[pluginsUri].path;
}
if (staticContent[pluginsUri]) {
pluginsPath = staticContent[pluginsUri].path;
}
const baseUrl = '../../../..';
utils.listFolders(pluginsPath, true).then((values) => {
return co(function*() {
const configFile = 'config.json';
let stats = null;
const result = [];
for (let i = 0; i < values.length; ++i) {
try {
stats = yield utils.fsStat(path.join(values[i], configFile));
} catch (_err) {
stats = null;
}
const baseUrl = '../../../..';
utils.listFolders(pluginsPath, true).then(values => {
return co(function* () {
const configFile = 'config.json';
let stats = null;
const result = [];
for (let i = 0; i < values.length; ++i) {
try {
stats = yield utils.fsStat(path.join(values[i], configFile));
} catch (_err) {
stats = null;
}
if (stats && stats.isFile) {
result.push( baseUrl + pluginsUri + '/' + path.basename(values[i]) + '/' + configFile);
}
}
if (stats && stats.isFile) {
result.push(baseUrl + pluginsUri + '/' + path.basename(values[i]) + '/' + configFile);
}
}
updatePluginsTime = new Date();
userPlugins = {'url': '', 'pluginsData': result, 'autostart': pluginsAutostart};
sendUserPlugins(res, userPlugins);
});
});
});
app.get('/themes.json', apicache.middleware("5 minutes"), (req, res) => {
return co(function*() {
const themes = [];
const ctx = new operationContext.Context();
try {
ctx.initFromRequest(req);
yield ctx.initTenantCache();
ctx.logger.info('themes.json start');
if (!config.has('services.CoAuthoring.server.static_content') || !config.has('services.CoAuthoring.themes.uri')) {
return;
}
const staticContent = config.get('services.CoAuthoring.server.static_content');
const themesUri = config.get('services.CoAuthoring.themes.uri');
let themesList = [];
updatePluginsTime = new Date();
userPlugins = {url: '', pluginsData: result, autostart: pluginsAutostart};
sendUserPlugins(res, userPlugins);
});
});
});
app.get('/themes.json', apicache.middleware('5 minutes'), (req, res) => {
return co(function* () {
const themes = [];
const ctx = new operationContext.Context();
try {
ctx.initFromRequest(req);
yield ctx.initTenantCache();
ctx.logger.info('themes.json start');
if (!config.has('services.CoAuthoring.server.static_content') || !config.has('services.CoAuthoring.themes.uri')) {
return;
}
const staticContent = config.get('services.CoAuthoring.server.static_content');
const themesUri = config.get('services.CoAuthoring.themes.uri');
let themesList = [];
for (const i in staticContent) {
if (staticContent.hasOwnProperty(i) && themesUri.startsWith(i)) {
const dir = staticContent[i].path + themesUri.substring(i.length);
themesList = yield utils.listObjects(dir, true);
ctx.logger.debug('themes.json dir:%s', dir);
ctx.logger.debug('themes.json themesList:%j', themesList);
for (let j = 0; j < themesList.length; ++j) {
if (themesList[j].endsWith('.json')) {
try {
const data = yield utils.readFile(themesList[j], true);
const text = new TextDecoder('utf-8', {ignoreBOM: false}).decode(data);
themes.push(JSON.parse(text));
} catch (err) {
ctx.logger.error('themes.json file:%s error:%s', themesList[j], err.stack);
}
}
}
break;
}
}
} catch (err) {
ctx.logger.error('themes.json error:%s', err.stack);
} finally {
if (themes.length > 0) {
res.setHeader('Content-Type', 'application/json');
res.send({themes});
} else {
res.sendStatus(404);
}
ctx.logger.info('themes.json end');
}
});
});
app.get('/document_editor_service_worker.js', apicache.middleware("5 min"), async (req, res) => {
const staticContent = config.get('services.CoAuthoring.server.static_content');
if (staticContent['/sdkjs']) {
//make handler only for development version
res.sendFile(path.resolve(staticContent['/sdkjs'].path + "/common/serviceworker/document_editor_service_worker.js"));
} else {
res.sendStatus(404);
}
});
app.use((err, req, res, _next) => {
const ctx = new operationContext.Context();
ctx.initFromRequest(req);
ctx.logger.error('default error handler:%s', err.stack);
res.sendStatus(500);
});
for (const i in staticContent) {
if (staticContent.hasOwnProperty(i) && themesUri.startsWith(i)) {
const dir = staticContent[i].path + themesUri.substring(i.length);
themesList = yield utils.listObjects(dir, true);
ctx.logger.debug('themes.json dir:%s', dir);
ctx.logger.debug('themes.json themesList:%j', themesList);
for (let j = 0; j < themesList.length; ++j) {
if (themesList[j].endsWith('.json')) {
try {
const data = yield utils.readFile(themesList[j], true);
const text = new TextDecoder('utf-8', {ignoreBOM: false}).decode(data);
themes.push(JSON.parse(text));
} catch (err) {
ctx.logger.error('themes.json file:%s error:%s', themesList[j], err.stack);
}
}
}
break;
}
}
} catch (err) {
ctx.logger.error('themes.json error:%s', err.stack);
} finally {
if (themes.length > 0) {
res.setHeader('Content-Type', 'application/json');
res.send({themes});
} else {
res.sendStatus(404);
}
ctx.logger.info('themes.json end');
}
});
});
app.get('/document_editor_service_worker.js', apicache.middleware('5 min'), async (req, res) => {
const staticContent = config.get('services.CoAuthoring.server.static_content');
if (staticContent['/sdkjs']) {
//make handler only for development version
res.sendFile(path.resolve(staticContent['/sdkjs'].path + '/common/serviceworker/document_editor_service_worker.js'));
} else {
res.sendStatus(404);
}
});
app.use((err, req, res, _next) => {
const ctx = new operationContext.Context();
ctx.initFromRequest(req);
ctx.logger.error('default error handler:%s', err.stack);
res.sendStatus(500);
});
});
process.on('uncaughtException', (err) => {
operationContext.global.logger.error('uncaughtException:%s', err.stack);
logger.shutdown(() => {
process.exit(1);
});
process.on('uncaughtException', err => {
operationContext.global.logger.error('uncaughtException:%s', err.stack);
logger.shutdown(() => {
process.exit(1);
});
});

View File

@ -47,8 +47,8 @@ var WAIT_TIMEOUT = 30000;
var LOOP_TIMEOUT = 1000;
var EXEC_TIMEOUT = WAIT_TIMEOUT + utils.getConvertionTimeout(undefined);
exports.shutdown = function(ctx, editorStat, status) {
return co(function*() {
exports.shutdown = function (ctx, editorStat, status) {
return co(function* () {
var res = true;
try {
ctx.logger.debug('shutdown start:' + EXEC_TIMEOUT);
@ -79,7 +79,7 @@ exports.shutdown = function(ctx, editorStat, status) {
var remainingFiles = yield editorStat.getShutdownCount(redisKeyShutdown);
const inSavingStatus = yield sqlBase.getCountWithStatus(ctx, commonDefines.FileStatus.SaveVersion, EXEC_TIMEOUT);
ctx.logger.debug('shutdown remaining files editorStat:%d, db:%d', remainingFiles, inSavingStatus);
if (!isStartWait && (remainingFiles + inSavingStatus) <= 0) {
if (!isStartWait && remainingFiles + inSavingStatus <= 0) {
break;
}
yield utils.sleep(LOOP_TIMEOUT);

View File

@ -60,9 +60,9 @@ function TaskResultData() {
this.password = null;
this.additional = null;
this.innerPasswordChange = null;//not a DB field
this.innerPasswordChange = null; //not a DB field
}
TaskResultData.prototype.completeDefaults = function() {
TaskResultData.prototype.completeDefaults = function () {
if (!this.tenant) {
this.tenant = tenantManager.getDefautTenant();
}
@ -118,13 +118,20 @@ function select(ctx, docId) {
const p1 = addSqlParam(ctx.tenant, values);
const p2 = addSqlParam(docId, values);
const sqlCommand = `SELECT * FROM ${cfgTableResult} WHERE tenant=${p1} AND id=${p2};`;
sqlBase.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}, undefined, undefined, values);
sqlBase.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
},
undefined,
undefined,
values
);
});
}
function toUpdateArray(task, updateTime, isMask, values, setPassword) {
@ -135,23 +142,19 @@ function toUpdateArray(task, updateTime, isMask, values, setPassword) {
}
if (null != task.statusInfo) {
const sqlParam = addSqlParam(task.statusInfo, values);
res.push(`status_info=${sqlParam}` );
res.push(`status_info=${sqlParam}`);
}
if (updateTime) {
const sqlParam = addSqlParam(new Date(), values);
res.push(`last_open_date=${sqlParam}`);
}
if (null != task.indexUser) {
const sqlParam = addSqlParam(task.indexUser, values);
res.push(`user_index=${sqlParam}`);
}
if (null != task.changeId) {
const sqlParam = addSqlParam(task.changeId, values);
res.push(`change_id=${sqlParam}`);
}
if (null != task.callback && !isMask) {
var userCallback = new sqlBase.UserCallback();
@ -187,13 +190,20 @@ function update(ctx, task, setPassword) {
const p1 = addSqlParam(task.tenant, values);
const p2 = addSqlParam(task.key, values);
const sqlCommand = `UPDATE ${cfgTableResult} SET ${sqlSet} WHERE tenant=${p1} AND id=${p2};`;
sqlBase.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}, undefined, undefined, values);
sqlBase.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
},
undefined,
undefined,
values
);
});
}
@ -207,17 +217,24 @@ function updateIf(ctx, task, mask) {
const sqlSet = commandArg.join(', ');
const sqlWhere = commandArgMask.join(' AND ');
const sqlCommand = `UPDATE ${cfgTableResult} SET ${sqlSet} WHERE ${sqlWhere};`;
sqlBase.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}, undefined, undefined, values);
sqlBase.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
},
undefined,
undefined,
values
);
});
}
function restoreInitialPassword(ctx, docId) {
return select(ctx, docId).then((selectRes) => {
return select(ctx, docId).then(selectRes => {
if (selectRes.length > 0) {
var row = selectRes[0];
const docPassword = sqlBase.DocumentPassword.prototype.getDocPassword(ctx, row.password);
@ -241,7 +258,7 @@ function addRandomKey(ctx, task, key, opt_prefix, opt_size) {
return new Promise((resolve, reject) => {
task.tenant = ctx.tenant;
if (undefined !== opt_prefix && undefined !== opt_size) {
task.key = opt_prefix + crypto.randomBytes(opt_size).toString("hex");
task.key = opt_prefix + crypto.randomBytes(opt_size).toString('hex');
} else {
task.key = key + '_' + Math.round(Math.random() * RANDOM_KEY_MAX);
}
@ -256,15 +273,23 @@ function addRandomKey(ctx, task, key, opt_prefix, opt_size) {
const p6 = addSqlParam(task.changeId, values);
const p7 = addSqlParam(task.callback, values);
const p8 = addSqlParam(task.baseurl, values);
const sqlCommand = `INSERT INTO ${cfgTableResult} (tenant, id, status, status_info, last_open_date, user_index, change_id, callback, baseurl)` +
const sqlCommand =
`INSERT INTO ${cfgTableResult} (tenant, id, status, status_info, last_open_date, user_index, change_id, callback, baseurl)` +
` VALUES (${p0}, ${p1}, ${p2}, ${p3}, ${p4}, ${p5}, ${p6}, ${p7}, ${p8});`;
sqlBase.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}, undefined, true, values);
sqlBase.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
},
undefined,
true,
values
);
});
}
function* addRandomKeyTask(ctx, key, opt_prefix, opt_size) {
@ -280,7 +305,7 @@ function* addRandomKeyTask(ctx, key, opt_prefix, opt_size) {
addRes = yield addRandomKey(ctx, task, key, opt_prefix, opt_size);
} catch (_e) {
addRes = null;
ctx.logger.debug("addRandomKeyTask %s exists, try again", task.key);
ctx.logger.debug('addRandomKeyTask %s exists, try again', task.key);
}
if (addRes && addRes.affectedRows > 0) {
break;
@ -299,13 +324,20 @@ function remove(ctx, docId) {
const p1 = addSqlParam(ctx.tenant, values);
const p2 = addSqlParam(docId, values);
const sqlCommand = `DELETE FROM ${cfgTableResult} WHERE tenant=${p1} AND id=${p2};`;
sqlBase.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}, undefined, undefined, values);
sqlBase.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
},
undefined,
undefined,
values
);
});
}
function removeIf(ctx, mask) {
@ -316,13 +348,20 @@ function removeIf(ctx, mask) {
commandArgMask.push('id=' + addSqlParam(mask.key, values));
const sqlWhere = commandArgMask.join(' AND ');
const sqlCommand = `DELETE FROM ${cfgTableResult} WHERE ${sqlWhere};`;
sqlBase.sqlQuery(ctx, sqlCommand, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}, undefined, undefined, values);
sqlBase.sqlQuery(
ctx,
sqlCommand,
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
},
undefined,
undefined,
values
);
});
}

View File

@ -32,7 +32,7 @@
'use strict';
const util = require("util");
const util = require('util');
const config = require('config');
const exifParser = require('exif-parser');
//set global window to fix issue https://github.com/photopea/UTIF.js/issues/130
@ -43,7 +43,7 @@ const Jimp = require('jimp');
const locale = require('windows-locale');
const ms = require('ms');
const { notificationTypes, ...notificationService } = require('../../Common/sources/notificationService');
const {notificationTypes, ...notificationService} = require('../../Common/sources/notificationService');
const cfgStartNotifyFrom = ms(config.get('license.warning_license_expiration'));
const cfgNotificationRuleLicenseExpirationWarning = config.get('notification.rules.licenseExpirationWarning.template');
@ -96,22 +96,9 @@ function localeToLCID(lang) {
}
function humanFriendlyExpirationTime(endTime) {
const month = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
const month = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
return `${month[endTime.getUTCMonth()]} ${endTime.getUTCDate()}, ${endTime.getUTCFullYear()}`
return `${month[endTime.getUTCMonth()]} ${endTime.getUTCDate()}, ${endTime.getUTCFullYear()}`;
}
/**
@ -133,15 +120,21 @@ async function notifyLicenseExpiration(ctx, endDate) {
endDate = currentDate;
}
const formattedExpirationTime = humanFriendlyExpirationTime(endDate);
const applicationName = (process.env.APPLICATION_NAME || "").toUpperCase();
const applicationName = (process.env.APPLICATION_NAME || '').toUpperCase();
if (endDate <= currentDate) {
const tenNotificationRuleLicenseExpirationError = ctx.getCfg('notification.rules.licenseExpirationError.template', cfgNotificationRuleLicenseExpirationError);
const tenNotificationRuleLicenseExpirationError = ctx.getCfg(
'notification.rules.licenseExpirationError.template',
cfgNotificationRuleLicenseExpirationError
);
const title = util.format(tenNotificationRuleLicenseExpirationError.title, applicationName);
const message = util.format(tenNotificationRuleLicenseExpirationError.body, formattedExpirationTime);
ctx.logger.error(message);
await notificationService.notify(ctx, notificationTypes.LICENSE_EXPIRATION_ERROR, title, message);
} else {
const tenNotificationRuleLicenseExpirationWarning = ctx.getCfg('notification.rules.licenseExpirationWarning.template', cfgNotificationRuleLicenseExpirationWarning);
const tenNotificationRuleLicenseExpirationWarning = ctx.getCfg(
'notification.rules.licenseExpirationWarning.template',
cfgNotificationRuleLicenseExpirationWarning
);
const title = util.format(tenNotificationRuleLicenseExpirationWarning.title, applicationName);
const message = util.format(tenNotificationRuleLicenseExpirationWarning.body, formattedExpirationTime);
ctx.logger.warn(message);

View File

@ -33,13 +33,13 @@
'use strict';
const path = require('path');
const { pipeline } = require('node:stream/promises');
const {pipeline} = require('node:stream/promises');
const {URL} = require('url');
const co = require('co');
const jwt = require('jsonwebtoken');
const config = require('config');
const { createReadStream } = require('fs');
const { stat, lstat, readdir } = require('fs/promises');
const {createReadStream} = require('fs');
const {stat, lstat, readdir} = require('fs/promises');
const utf7 = require('utf7');
const mimeDB = require('mime-db');
const xmlbuilder2 = require('xmlbuilder2');
@ -95,33 +95,33 @@ const templateFilesSizeCache = {};
let shutdownFlag = false;
//patch mimeDB
if (!mimeDB["application/vnd.visio2013"]) {
mimeDB["application/vnd.visio2013"] = {extensions: ["vsdx", "vstx", "vssx", "vsdm", "vstm", "vssm"]};
if (!mimeDB['application/vnd.visio2013']) {
mimeDB['application/vnd.visio2013'] = {extensions: ['vsdx', 'vstx', 'vssx', 'vsdm', 'vstm', 'vssm']};
}
const mimeTypesByExt = (function() {
const mimeTypesByExt = (function () {
const mimeTypesByExt = {};
for (const mimeType in mimeDB) {
if (mimeDB.hasOwnProperty(mimeType)) {
const val = mimeDB[mimeType];
if (val.extensions) {
val.extensions.forEach((value) => {
val.extensions.forEach(value => {
if (!mimeTypesByExt[value]) {
mimeTypesByExt[value] = [];
}
mimeTypesByExt[value].push(mimeType);
})
});
}
}
}
return mimeTypesByExt;
})();
async function getTemplatesFolderExts(ctx){
async function getTemplatesFolderExts(ctx) {
//find available template files
if (templatesFolderExtsCache === null) {
const tenNewFileTemplate = ctx.getCfg('services.CoAuthoring.server.newFileTemplate', cfgNewFileTemplate);
const dirContent = await readdir(`${tenNewFileTemplate}/${constants.TEMPLATES_DEFAULT_LOCALE}/`, { withFileTypes: true });
const dirContent = await readdir(`${tenNewFileTemplate}/${constants.TEMPLATES_DEFAULT_LOCALE}/`, {withFileTypes: true});
templatesFolderExtsCache = dirContent
.filter(dirObject => dirObject.isFile())
.reduce((result, item, _index, _array) => {
@ -134,7 +134,7 @@ async function getTemplatesFolderExts(ctx){
}
function discovery(req, res) {
return co(function*() {
return co(function* () {
const xml = xmlbuilder2.create({version: '1.0', encoding: 'utf-8'});
const ctx = new operationContext.Context();
try {
@ -167,7 +167,7 @@ function discovery(req, res) {
const tenWopiHost = ctx.getCfg('wopi.host', cfgWopiHost);
const baseUrl = tenWopiHost || utils.getBaseUrlByRequest(ctx, req);
const names = ['Word','Excel','PowerPoint','Pdf'];
const names = ['Word', 'Excel', 'PowerPoint', 'Pdf'];
const favIconUrls = [tenWopiFavIconUrlWord, tenWopiFavIconUrlCell, tenWopiFavIconUrlSlide, tenWopiFavIconUrlPdf];
const exts = [
{targetext: 'docx', view: tenWopiWordView, edit: tenWopiWordEdit},
@ -177,8 +177,9 @@ function discovery(req, res) {
];
const documentTypes = [`word`, `cell`, `slide`, `pdf`];
//todo check sdkjs-ooxml addon
const addVisio = (tenWopiDiagramView.length > 0 || tenWopiDiagramEdit.length > 0)
&& (constants.PACKAGE_TYPE_OS !== license.packageType || process.env?.NODE_ENV?.startsWith("development-"));
const addVisio =
(tenWopiDiagramView.length > 0 || tenWopiDiagramEdit.length > 0) &&
(constants.PACKAGE_TYPE_OS !== license.packageType || process.env?.NODE_ENV?.startsWith('development-'));
if (addVisio) {
names.push('Visio');
favIconUrls.push(tenWopiFavIconUrlDiagram);
@ -197,9 +198,9 @@ function discovery(req, res) {
templateEnd += `&lt;fs=FULLSCREEN&amp;&gt;&lt;hid=HOST_SESSION_ID&amp;&gt;&lt;rec=RECORDING&amp;&gt;`;
templateEnd += `&lt;sc=SESSION_CONTEXT&amp;&gt;&lt;thm=THEME_ID&amp;&gt;&lt;ui=UI_LLCC&amp;&gt;`;
templateEnd += `&lt;wopisrc=WOPI_SOURCE&amp;&gt;&amp;`;
const xmlZone = xml.ele('wopi-discovery').ele('net-zone', { name: tenWopiWopiZone });
const xmlZone = xml.ele('wopi-discovery').ele('net-zone', {name: tenWopiWopiZone});
//start section for MS WOPI connectors
for(let i = 0; i < names.length; ++i) {
for (let i = 0; i < names.length; ++i) {
const name = names[i];
let favIconUrl = favIconUrls[i];
if (!(favIconUrl.startsWith('http://') || favIconUrl.startsWith('https://'))) {
@ -241,7 +242,7 @@ function discovery(req, res) {
}
//end section for MS WOPI connectors
//start section for collabora nexcloud connectors
for(let i = 0; i < exts.length; ++i) {
for (let i = 0; i < exts.length; ++i) {
const ext = exts[i];
const urlTemplateView = `${templateStart}/${documentTypes[i]}/view?${templateEnd}`;
const urlTemplateEmbedView = `${templateStart}/${documentTypes[i]}/view?embed=1&amp;${templateEnd}`;
@ -249,11 +250,11 @@ function discovery(req, res) {
const urlTemplateEdit = `${templateStart}/${documentTypes[i]}/edit?${templateEnd}`;
const urlTemplateMobileEdit = `${templateStart}/${documentTypes[i]}/edit?mobile=1&amp;${templateEnd}`;
const urlTemplateFormSubmit = `${templateStart}/${documentTypes[i]}/edit?formsubmit=1&amp;${templateEnd}`;
const mimeTypesDuplicate = new Set();//to remove duplicates for each editor(allow html for word and excel)
const mimeTypesDuplicate = new Set(); //to remove duplicates for each editor(allow html for word and excel)
for (let j = 0; j < ext.view.length; ++j) {
const mimeTypes = mimeTypesByExt[ext.view[j]];
if (mimeTypes) {
mimeTypes.forEach((value) => {
mimeTypes.forEach(value => {
if (mimeTypesDuplicate.has(value)) {
return;
} else {
@ -275,7 +276,7 @@ function discovery(req, res) {
for (let j = 0; j < ext.edit.length; ++j) {
const mimeTypes = mimeTypesByExt[ext.edit[j]];
if (mimeTypes) {
mimeTypes.forEach((value) => {
mimeTypes.forEach(value => {
if (mimeTypesDuplicate.has(value)) {
return;
} else {
@ -305,10 +306,16 @@ function discovery(req, res) {
if (tenWopiPublicKeyOld && tenWopiPublicKey) {
const exponent = numberToBase64(tenWopiExponent);
const exponentOld = numberToBase64(tenWopiExponentOld);
xmlDiscovery.ele('proof-key', {
oldvalue: tenWopiPublicKeyOld, oldmodulus: tenWopiModulusOld, oldexponent: exponentOld,
value: tenWopiPublicKey, modulus: tenWopiModulus, exponent
}).up();
xmlDiscovery
.ele('proof-key', {
oldvalue: tenWopiPublicKeyOld,
oldmodulus: tenWopiModulusOld,
oldexponent: exponentOld,
value: tenWopiPublicKey,
modulus: tenWopiModulus,
exponent
})
.up();
}
xmlDiscovery.up();
} catch (err) {
@ -321,10 +328,14 @@ function discovery(req, res) {
});
}
function collaboraCapabilities(req, res) {
return co(function*() {
return co(function* () {
const output = {
"convert-to": {"available": true, "endpoint":"/lool/convert-to"}, "hasMobileSupport": true, "hasProxyPrefix": false, "hasTemplateSaveAs": false,
"hasTemplateSource": true, "productVersion": commonDefines.buildVersion
'convert-to': {available: true, endpoint: '/lool/convert-to'},
hasMobileSupport: true,
hasProxyPrefix: false,
hasTemplateSaveAs: false,
hasTemplateSource: true,
productVersion: commonDefines.buildVersion
};
const ctx = new operationContext.Context();
try {
@ -334,13 +345,13 @@ function collaboraCapabilities(req, res) {
} catch (err) {
ctx.logger.error('collaboraCapabilities error:%s', err.stack);
} finally {
utils.fillResponseSimple(res, JSON.stringify(output), "application/json");
utils.fillResponseSimple(res, JSON.stringify(output), 'application/json');
ctx.logger.info('collaboraCapabilities end');
}
});
}
function isWopiCallback(url) {
return url && url.startsWith("{");
return url && url.startsWith('{');
}
function isWopiUnlockMarker(url) {
return isWopiCallback(url) && !!JSON.parse(url).unlockId;
@ -348,7 +359,7 @@ function isWopiUnlockMarker(url) {
function isWopiModifiedMarker(url) {
if (isWopiCallback(url)) {
const obj = JSON.parse(url);
return obj.fileInfo && obj.fileInfo.LastModifiedTime
return obj.fileInfo && obj.fileInfo.LastModifiedTime;
}
}
function getWopiUnlockMarker(wopiParams) {
@ -361,7 +372,7 @@ function getWopiModifiedMarker(wopiParams, lastModifiedTime) {
return JSON.stringify(Object.assign({fileInfo: {LastModifiedTime: lastModifiedTime}}, wopiParams.userAuth));
}
function getFileTypeByInfo(fileInfo) {
let fileType = fileInfo.BaseFileName ? fileInfo.BaseFileName.substr(fileInfo.BaseFileName.lastIndexOf('.') + 1) : "";
let fileType = fileInfo.BaseFileName ? fileInfo.BaseFileName.substr(fileInfo.BaseFileName.lastIndexOf('.') + 1) : '';
fileType = fileInfo.FileExtension ? fileInfo.FileExtension.substr(1) : fileType;
return fileType.toLowerCase();
}
@ -414,7 +425,7 @@ function parseWopiCallback(ctx, userAuthStr, opt_url) {
return wopiParams;
}
function checkAndInvalidateCache(ctx, docId, fileInfo) {
return co(function*() {
return co(function* () {
const res = {success: true, lockId: undefined};
const selectRes = yield taskResult.select(ctx, docId);
if (selectRes.length > 0) {
@ -438,7 +449,7 @@ function checkAndInvalidateCache(ctx, docId, fileInfo) {
const cacheModified = commonInfo.fileInfo.LastModifiedTime;
ctx.logger.debug('wopiEditor version fileInfo=%s; cache=%s', fileInfoVersion, cacheVersion);
ctx.logger.debug('wopiEditor LastModifiedTime fileInfo=%s; cache=%s', fileInfoModified, cacheModified);
if (fileInfoVersion !== cacheVersion || (fileInfoModified !== cacheModified)) {
if (fileInfoVersion !== cacheVersion || fileInfoModified !== cacheModified) {
var mask = new taskResult.TaskResultData();
mask.tenant = ctx.tenant;
mask.key = docId;
@ -459,7 +470,7 @@ function checkAndInvalidateCache(ctx, docId, fileInfo) {
});
}
function parsePutFileResponse(ctx, postRes) {
let body = null
let body = null;
if (postRes.body) {
try {
//collabora nexcloud connector
@ -480,13 +491,12 @@ async function checkAndReplaceEmptyFile(ctx, fileInfo, wopiSrc, access_token, ac
if (templatesFolderLocalesCache === null) {
const dirContent = await readdir(`${tenNewFileTemplate}/`, {withFileTypes: true});
templatesFolderLocalesCache = dirContent.filter(dirObject => dirObject.isDirectory())
.map(dirObject => dirObject.name);
templatesFolderLocalesCache = dirContent.filter(dirObject => dirObject.isDirectory()).map(dirObject => dirObject.name);
}
const localePrefix = lang || ui || 'en';
let locale = constants.TEMPLATES_FOLDER_LOCALE_COLLISON_MAP[localePrefix] ??
templatesFolderLocalesCache.find(locale => locale.startsWith(localePrefix));
let locale =
constants.TEMPLATES_FOLDER_LOCALE_COLLISON_MAP[localePrefix] ?? templatesFolderLocalesCache.find(locale => locale.startsWith(localePrefix));
if (locale === undefined) {
locale = constants.TEMPLATES_DEFAULT_LOCALE;
}
@ -546,8 +556,17 @@ async function preOpen(ctx, lockId, docId, fileInfo, userAuth, baseUrl, fileType
return true;
}
function getEditorHtml(req, res) {
return co(function*() {
const params = {key: undefined, apiQuery: '', fileInfo: {}, userAuth: {}, queryParams: req.query, token: undefined, documentType: undefined, docs_api_config: {}};
return co(function* () {
const params = {
key: undefined,
apiQuery: '',
fileInfo: {},
userAuth: {},
queryParams: req.query,
token: undefined,
documentType: undefined,
docs_api_config: {}
};
const ctx = new operationContext.Context();
try {
ctx.initFromRequest(req);
@ -572,15 +591,14 @@ function getEditorHtml(req, res) {
const hostSessionId = req.query['hid'];
const lang = req.query['lang'];
const ui = req.query['ui'];
const access_token = req.body['access_token'] || "";
const access_token = req.body['access_token'] || '';
const access_token_ttl = parseInt(req.body['access_token_ttl']) || 0;
const docs_api_config = req.body['docs_api_config'];
if (docs_api_config) {
params.docs_api_config = JSON.parse(docs_api_config);
}
const fileInfo = params.fileInfo = yield checkFileInfo(ctx, wopiSrc, access_token, sc);
const fileInfo = (params.fileInfo = yield checkFileInfo(ctx, wopiSrc, access_token, sc));
if (!fileInfo) {
params.fileInfo = {};
return;
@ -590,7 +608,7 @@ function getEditorHtml(req, res) {
yield checkAndReplaceEmptyFile(ctx, fileInfo, wopiSrc, access_token, access_token_ttl, lang, ui, fileType);
}
const canEdit = (fileInfo.UserCanOnlyComment || fileInfo.UserCanWrite || fileInfo.UserCanReview);
const canEdit = fileInfo.UserCanOnlyComment || fileInfo.UserCanWrite || fileInfo.UserCanReview;
if (!canEdit) {
mode = 'view';
}
@ -599,10 +617,14 @@ function getEditorHtml(req, res) {
ctx.setDocId(fileId);
ctx.logger.debug(`wopiEditor`);
params.key = docId;
const userAuth = params.userAuth = {
wopiSrc, access_token, access_token_ttl,
hostSessionId, userSessionId: docId, mode
};
const userAuth = (params.userAuth = {
wopiSrc,
access_token,
access_token_ttl,
hostSessionId,
userSessionId: docId,
mode
});
//check and invalidate cache
const checkRes = yield checkAndInvalidateCache(ctx, docId, fileInfo);
@ -618,7 +640,7 @@ function getEditorHtml(req, res) {
}
}
tenWopiFileInfoBlockList.forEach((item) => {
tenWopiFileInfoBlockList.forEach(item => {
delete params.fileInfo[item];
});
@ -633,7 +655,7 @@ function getEditorHtml(req, res) {
} finally {
ctx.logger.debug('wopiEditor render params=%j', params);
try {
res.render("editor-wopi", params);
res.render('editor-wopi', params);
} catch (err) {
ctx.logger.error('wopiEditor error:%s', err.stack);
res.sendStatus(400);
@ -643,7 +665,7 @@ function getEditorHtml(req, res) {
});
}
function getConverterHtml(req, res) {
return co(function*() {
return co(function* () {
const params = {statusHandler: undefined};
const ctx = new operationContext.Context();
try {
@ -659,13 +681,20 @@ function getConverterHtml(req, res) {
ctx.setDocId(fileId);
ctx.logger.info('convert-and-edit start');
const access_token = req.body['access_token'] || "";
const access_token = req.body['access_token'] || '';
const access_token_ttl = parseInt(req.body['access_token_ttl']) || 0;
const ext = req.params.ext;
const targetext = req.params.targetext;
if (!(wopiSrc && access_token && access_token_ttl && ext && targetext)) {
ctx.logger.debug('convert-and-edit invalid params: WOPISrc=%s; access_token=%s; access_token_ttl=%s; ext=%s; targetext=%s', wopiSrc, access_token, access_token_ttl, ext, targetext);
ctx.logger.debug(
'convert-and-edit invalid params: WOPISrc=%s; access_token=%s; access_token_ttl=%s; ext=%s; targetext=%s',
wopiSrc,
access_token,
access_token_ttl,
ext,
targetext
);
return;
}
@ -697,7 +726,7 @@ function getConverterHtml(req, res) {
} finally {
ctx.logger.debug('convert-and-edit render params=%j', params);
try {
res.render("convert-and-edit-wopi", params);
res.render('convert-and-edit-wopi', params);
} catch (err) {
ctx.logger.error('convert-and-edit error:%s', err.stack);
res.sendStatus(400);
@ -725,7 +754,7 @@ function putFile(ctx, wopiParams, data, dataStream, dataSize, userLastChangeId,
}
//collabora nexcloud connector sets only UserCanWrite=true
const canEdit = (fileInfo.UserCanOnlyComment || fileInfo.UserCanWrite || fileInfo.UserCanReview);
const canEdit = fileInfo.UserCanOnlyComment || fileInfo.UserCanWrite || fileInfo.UserCanReview;
if (fileInfo && (fileInfo.SupportsUpdate || canEdit)) {
const commonInfo = wopiParams.commonInfo;
//todo add all the users who contributed changes to the document in this PutFile request to X-WOPI-Editors
@ -780,7 +809,17 @@ function putRelativeFile(ctx, wopiSrc, access_token, data, dataStream, dataSize,
ctx.logger.debug('wopi putRelativeFile request uri=%s headers=%j', uri, headers);
//isInJwtToken is true because it passed checkIpFilter for wopi
const isInJwtToken = true;
const postRes = yield utils.postRequestPromise(ctx, uri, data, dataStream, dataSize, tenCallbackRequestTimeout, undefined, isInJwtToken, headers);
const postRes = yield utils.postRequestPromise(
ctx,
uri,
data,
dataStream,
dataSize,
tenCallbackRequestTimeout,
undefined,
isInJwtToken,
headers
);
ctx.logger.debug('wopi putRelativeFile response headers=%j', postRes.response.headers);
ctx.logger.debug('wopi putRelativeFile response body:%s', postRes.body);
res = JSON.parse(postRes.body);
@ -827,13 +866,23 @@ async function renameFile(ctx, wopiParams, name) {
ctx.logger.debug('wopi RenameFile request uri=%s headers=%j', uri, headers);
//isInJwtToken is true because it passed checkIpFilter for wopi
const isInJwtToken = true;
const postRes = await utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, isInJwtToken, headers);
const postRes = await utils.postRequestPromise(
ctx,
uri,
undefined,
undefined,
undefined,
tenCallbackRequestTimeout,
undefined,
isInJwtToken,
headers
);
ctx.logger.debug('wopi RenameFile response headers=%j body=%s', postRes.response.headers, postRes.body);
if (postRes.body) {
res = JSON.parse(postRes.body);
} else {
//sharepoint send empty body(2016 allways, 2019 with same name)
res = {"Name": name};
res = {Name: name};
}
} else {
ctx.logger.info('wopi SupportsRename = false');
@ -936,12 +985,22 @@ function lock(ctx, command, lockId, fileInfo, userAuth) {
return false;
}
const headers = {"X-WOPI-Override": command, "X-WOPI-Lock": lockId};
const headers = {'X-WOPI-Override': command, 'X-WOPI-Lock': lockId};
yield wopiUtils.fillStandardHeaders(ctx, headers, uri, access_token);
ctx.logger.debug('wopi %s request uri=%s headers=%j', command, uri, headers);
//isInJwtToken is true because it passed checkIpFilter for wopi
const isInJwtToken = true;
const postRes = yield utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, isInJwtToken, headers);
const postRes = yield utils.postRequestPromise(
ctx,
uri,
undefined,
undefined,
undefined,
tenCallbackRequestTimeout,
undefined,
isInJwtToken,
headers
);
ctx.logger.debug('wopi %s response headers=%j', command, postRes.response.headers);
} else {
ctx.logger.info('wopi %s SupportsLocks = false', command);
@ -975,12 +1034,22 @@ async function unlock(ctx, wopiParams) {
return;
}
const headers = {"X-WOPI-Override": "UNLOCK", "X-WOPI-Lock": lockId};
const headers = {'X-WOPI-Override': 'UNLOCK', 'X-WOPI-Lock': lockId};
await wopiUtils.fillStandardHeaders(ctx, headers, uri, access_token);
ctx.logger.debug('wopi Unlock request uri=%s headers=%j', uri, headers);
//isInJwtToken is true because it passed checkIpFilter for wopi
const isInJwtToken = true;
const postRes = await utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, isInJwtToken, headers);
const postRes = await utils.postRequestPromise(
ctx,
uri,
undefined,
undefined,
undefined,
tenCallbackRequestTimeout,
undefined,
isInJwtToken,
headers
);
ctx.logger.debug('wopi Unlock response headers=%j', postRes.response.headers);
} else {
ctx.logger.info('wopi SupportsLocks = false');
@ -1003,10 +1072,10 @@ function numberToBase64(val) {
}
//Convert the hexadecimal string to a buffer
const buffer = Buffer.from(hexString, 'hex');
return buffer.toString('base64');
return buffer.toString('base64');
}
function checkIpFilter(ctx, uri){
function checkIpFilter(ctx, uri) {
return co(function* () {
const urlParsed = new URL(uri);
const filterStatus = yield* utils.checkHostFilter(ctx, urlParsed.hostname);
@ -1019,8 +1088,12 @@ function checkIpFilter(ctx, uri){
function getWopiParams(lockId, fileInfo, wopiSrc, access_token, access_token_ttl) {
const commonInfo = {lockId, fileInfo};
const userAuth = {
wopiSrc, access_token, access_token_ttl,
hostSessionId: null, userSessionId: null, mode: null
wopiSrc,
access_token,
access_token_ttl,
hostSessionId: null,
userSessionId: null,
mode: null
};
return {commonInfo, userAuth, LastModifiedTime: null};
}
@ -1028,16 +1101,16 @@ function getWopiParams(lockId, fileInfo, wopiSrc, access_token, access_token_ttl
async function dummyCheckFileInfo(req, res) {
//static output for performance reason
res.json({
BaseFileName: "sample.docx",
OwnerId: "userId",
Size: 100,//no need to set actual size for test
UserId: "userId",//test ignores
UserFriendlyName: "user",
BaseFileName: 'sample.docx',
OwnerId: 'userId',
Size: 100, //no need to set actual size for test
UserId: 'userId', //test ignores
UserFriendlyName: 'user',
Version: 0,
UserCanWrite: true,
SupportsGetLock: true,
SupportsLocks: true,
SupportsUpdate: true,
SupportsUpdate: true
});
}
@ -1052,12 +1125,9 @@ async function dummyGetFile(req, res) {
res.setHeader('Content-Length', sampleFileStat.size);
res.setHeader('Content-Type', mime.getType(tenWopiDummySampleFilePath));
await pipeline(
createReadStream(tenWopiDummySampleFilePath),
res,
);
await pipeline(createReadStream(tenWopiDummySampleFilePath), res);
} catch (err) {
if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
if (err.code === 'ERR_STREAM_PREMATURE_CLOSE') {
//xhr.abort case
ctx.logger.debug('dummyGetFile error: %s', err.stack);
} else {

View File

@ -85,12 +85,24 @@ var MAX_OPEN_FILES = 200;
var TEMP_PREFIX = 'ASC_CONVERT';
var queue = null;
var clientStatsD = statsDClient.getClient();
var exitCodesReturn = [constants.CONVERT_PARAMS, constants.CONVERT_NEED_PARAMS, constants.CONVERT_CORRUPTED,
constants.CONVERT_DRM, constants.CONVERT_DRM_UNSUPPORTED, constants.CONVERT_PASSWORD, constants.CONVERT_LIMITS,
constants.CONVERT_DETECT];
var exitCodesReturn = [
constants.CONVERT_PARAMS,
constants.CONVERT_NEED_PARAMS,
constants.CONVERT_CORRUPTED,
constants.CONVERT_DRM,
constants.CONVERT_DRM_UNSUPPORTED,
constants.CONVERT_PASSWORD,
constants.CONVERT_LIMITS,
constants.CONVERT_DETECT
];
var exitCodesMinorError = [constants.CONVERT_NEED_PARAMS, constants.CONVERT_DRM, constants.CONVERT_DRM_UNSUPPORTED, constants.CONVERT_PASSWORD];
var exitCodesUpload = [constants.NO_ERROR, constants.CONVERT_CORRUPTED, constants.CONVERT_NEED_PARAMS,
constants.CONVERT_DRM, constants.CONVERT_DRM_UNSUPPORTED];
var exitCodesUpload = [
constants.NO_ERROR,
constants.CONVERT_CORRUPTED,
constants.CONVERT_NEED_PARAMS,
constants.CONVERT_DRM,
constants.CONVERT_DRM_UNSUPPORTED
];
var exitCodesCopyOrigin = [constants.CONVERT_NEED_PARAMS, constants.CONVERT_DRM];
let inputLimitsXmlCache;
@ -103,7 +115,7 @@ function TaskQueueDataConvert(ctx, task) {
this.fileFrom = null;
this.fileTo = null;
this.title = cmd.getTitle();
if(constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA !== cmd.getOutputFormat()){
if (constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA !== cmd.getOutputFormat()) {
this.formatTo = cmd.getOutputFormat();
} else {
this.formatTo = constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF;
@ -180,11 +192,11 @@ TaskQueueDataConvert.prototype = {
let xml;
if (t.password || t.savePassword) {
xml = '<TaskQueueDataConvert>';
if(t.password) {
if (t.password) {
const password = yield utils.decryptPassword(ctx, t.password);
xml += t.serializeXmlProp('m_sPassword', password);
}
if(t.savePassword) {
if (t.savePassword) {
const savePassword = yield utils.decryptPassword(ctx, t.savePassword);
xml += t.serializeXmlProp('m_sSavePassword', savePassword);
}
@ -193,7 +205,7 @@ TaskQueueDataConvert.prototype = {
return xml;
});
},
serializeOptions (ctx, isInJwtToken, oformAsPdf) {
serializeOptions(ctx, isInJwtToken, oformAsPdf) {
const tenRequesFilteringAgent = ctx.getCfg('services.CoAuthoring.request-filtering-agent', cfgRequesFilteringAgent);
const tenExternalRequestDirectIfIn = ctx.getCfg('externalRequest.directIfIn', cfgExternalRequestDirectIfIn);
const tenExternalRequestAction = ctx.getCfg('externalRequest.action', cfgExternalRequestAction);
@ -206,11 +218,11 @@ TaskQueueDataConvert.prototype = {
if (allowList.length === 0 && tenExternalRequestDirectIfIn.jwtToken && isInJwtToken) {
allowNetworkRequest = true;
allowPrivateIP = true;
proxyUrl = "";
proxyUrl = '';
proxyUser = null;
proxyHeaders = {};
}
let xml = "";
let xml = '';
xml += '<options>';
if (allowList.length > 0) {
xml += this.serializeXmlProp('allowList', allowList.join(';'));
@ -225,7 +237,7 @@ TaskQueueDataConvert.prototype = {
const pass = proxyUser.password;
xml += this.serializeXmlProp('proxyUser', `${user}:${pass}`);
}
const proxyHeadersStr= [];
const proxyHeadersStr = [];
for (const name in proxyHeaders) {
proxyHeadersStr.push(`${name}:${proxyHeaders[name]}`);
}
@ -325,9 +337,7 @@ function getTempDir() {
var now = new Date();
var newTemp;
while (!newTemp || fs.existsSync(newTemp)) {
var newName = [TEMP_PREFIX, now.getFullYear(), now.getMonth(), now.getDate(),
'-', (Math.random() * 0x100000000 + 1).toString(36)
].join('');
var newName = [TEMP_PREFIX, now.getFullYear(), now.getMonth(), now.getDate(), '-', (Math.random() * 0x100000000 + 1).toString(36)].join('');
newTemp = path.join(tempDir, newName);
}
fs.mkdirSync(newTemp);
@ -350,10 +360,12 @@ function* isUselessConvertion(ctx, task, cmd) {
}
async function changeFormatToExtendedPdf(ctx, dataConvert, cmd) {
const originFormat = cmd.getOriginFormat();
const isOriginFormatWithForms = constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF === originFormat ||
const isOriginFormatWithForms =
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF === originFormat ||
constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_OFORM === originFormat ||
constants.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCXF === originFormat;
const isFormatToPdf = constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF === dataConvert.formatTo ||
const isFormatToPdf =
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF === dataConvert.formatTo ||
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA === dataConvert.formatTo;
if (isFormatToPdf && isOriginFormatWithForms) {
const format = await formatChecker.getDocumentFormatByFile(dataConvert.fileFrom);
@ -365,7 +377,7 @@ async function changeFormatToExtendedPdf(ctx, dataConvert, cmd) {
}
function* replaceEmptyFile(ctx, fileFrom, ext, _lcid) {
const tenNewFileTemplate = ctx.getCfg('services.CoAuthoring.server.newFileTemplate', cfgNewFileTemplate);
if (!fs.existsSync(fileFrom) || 0 === fs.lstatSync(fileFrom).size) {
if (!fs.existsSync(fileFrom) || 0 === fs.lstatSync(fileFrom).size) {
let locale = constants.TEMPLATES_DEFAULT_LOCALE;
if (_lcid) {
let localeNew = lcid.from(_lcid);
@ -452,7 +464,7 @@ function* downloadFileFromStorage(ctx, strPath, dir, opt_specialDir) {
//create dirs
var dirsToCreate = [];
var dirStruct = {};
list.forEach((file) => {
list.forEach(file => {
var curDirPath = dir;
var curDirStruct = dirStruct;
var parts = storage.getRelativePath(strPath, file).split('/');
@ -494,7 +506,7 @@ function* processDownloadFromStorage(ctx, dataConvert, cmd, task, tempDirs, auth
}
if (filesCount > 0) {
concatDir = changesDir;
concatTemplate = "changes0";
concatTemplate = 'changes0';
} else {
dataConvert.fromChanges = false;
task.setFromChanges(dataConvert.fromChanges);
@ -542,7 +554,7 @@ function* processDownloadFromStorage(ctx, dataConvert, cmd, task, tempDirs, auth
dataConvert.fileFrom = path.join(tempDirs.source, 'origin.pdf');
}
if (fs.existsSync(dataConvert.fileFrom)) {
const fileFromNew = path.join(path.dirname(dataConvert.fileFrom), "Editor.bin");
const fileFromNew = path.join(path.dirname(dataConvert.fileFrom), 'Editor.bin');
fs.renameSync(dataConvert.fileFrom, fileFromNew);
dataConvert.fileFrom = fileFromNew;
}
@ -551,8 +563,8 @@ function* processDownloadFromStorage(ctx, dataConvert, cmd, task, tempDirs, auth
yield changeFormatToExtendedPdf(ctx, dataConvert, cmd);
if (task.getFromChanges() && !(task.getFromOrigin() || task.getFromSettings())) {
const sha256 = yield utils.checksumFile('sha256', dataConvert.fileFrom)
if(tenEditor['binaryChanges']) {
const sha256 = yield utils.checksumFile('sha256', dataConvert.fileFrom);
if (tenEditor['binaryChanges']) {
res = yield* processChangesBin(ctx, tempDirs, task, cmd, authorProps, sha256);
} else {
res = yield* processChangesBase64(ctx, tempDirs, task, cmd, authorProps, sha256);
@ -562,7 +574,7 @@ function* processDownloadFromStorage(ctx, dataConvert, cmd, task, tempDirs, auth
}
function* concatFiles(source, template) {
template = template || "Editor";
template = template || 'Editor';
//concatenate EditorN.ext parts in Editor.ext
const list = yield utils.listObjects(source, true);
list.sort(utils.compareStringByLength);
@ -610,11 +622,17 @@ function* processChangesBin(ctx, tempDirs, task, cmd, authorProps, sha256) {
const extChangeInfo = cmd.getExternalChangeInfo();
let extChanges;
if (extChangeInfo) {
extChanges = [{
id: cmd.getDocId(), change_id: 0, change_data: Buffer.alloc(0), user_id: extChangeInfo.user_id,
user_id_original: extChangeInfo.user_id_original, user_name: extChangeInfo.user_name,
change_date: new Date(extChangeInfo.change_date)
}];
extChanges = [
{
id: cmd.getDocId(),
change_id: 0,
change_data: Buffer.alloc(0),
user_id: extChangeInfo.user_id,
user_id_original: extChangeInfo.user_id_original,
user_name: extChangeInfo.user_name,
change_date: new Date(extChangeInfo.change_date)
}
];
}
let streamObj = yield* streamCreateBin(ctx, changesDir, indexFile++, {highWaterMark: tenStreamWriterBufferSize});
@ -648,7 +666,7 @@ function* processChangesBin(ctx, tempDirs, task, cmd, authorProps, sha256) {
yield* streamWriteBin(streamObj, Buffer.from(utils.getChangesFileHeader(), 'utf-8'));
}
const strDate = baseConnector.getDateTime(change.change_date);
changesHistory.changes.push({"documentSha256": sha256, 'created': strDate, 'user': {'id': change.user_id_original, 'name': change.user_name}});
changesHistory.changes.push({documentSha256: sha256, created: strDate, user: {id: change.user_id_original, name: change.user_name}});
}
changesAuthor = change.user_id_original;
changesAuthorUnique = change.user_id;
@ -673,8 +691,13 @@ function* processChangesBin(ctx, tempDirs, task, cmd, authorProps, sha256) {
if (null !== changesAuthorUnique) {
changesIndex = utils.getIndexFromUserId(changesAuthorUnique, changesAuthor);
}
if (null == changesAuthor && null == changesIndex && forceSave && undefined !== forceSave.getAuthorUserId() &&
undefined !== forceSave.getAuthorUserIndex()) {
if (
null == changesAuthor &&
null == changesIndex &&
forceSave &&
undefined !== forceSave.getAuthorUserId() &&
undefined !== forceSave.getAuthorUserIndex()
) {
changesAuthor = forceSave.getAuthorUserId();
changesIndex = forceSave.getAuthorUserIndex();
}
@ -689,7 +712,7 @@ function* streamCreateBin(ctx, changesDir, indexFile, opt_options) {
const fileName = constants.CHANGES_NAME + indexFile + '.bin';
const filePath = path.join(changesDir, fileName);
const writeStream = yield utils.promiseCreateWriteStream(filePath, opt_options);
writeStream.on('error', (err) => {
writeStream.on('error', err => {
//todo integrate error handle in main thread (probable: set flag here and check it in main thread)
ctx.logger.error('WriteStreamError %s', err.stack);
});
@ -730,11 +753,17 @@ function* processChangesBase64(ctx, tempDirs, task, cmd, authorProps, sha256) {
const extChangeInfo = cmd.getExternalChangeInfo();
let extChanges;
if (extChangeInfo) {
extChanges = [{
id: cmd.getDocId(), change_id: 0, change_data: "", user_id: extChangeInfo.user_id,
user_id_original: extChangeInfo.user_id_original, user_name: extChangeInfo.user_name,
change_date: new Date(extChangeInfo.change_date)
}];
extChanges = [
{
id: cmd.getDocId(),
change_id: 0,
change_data: '',
user_id: extChangeInfo.user_id,
user_id_original: extChangeInfo.user_id_original,
user_name: extChangeInfo.user_name,
change_date: new Date(extChangeInfo.change_date)
}
];
}
let streamObj = yield* streamCreate(ctx, changesDir, indexFile++, {highWaterMark: tenStreamWriterBufferSize});
@ -766,7 +795,7 @@ function* processChangesBase64(ctx, tempDirs, task, cmd, authorProps, sha256) {
streamObj = yield* streamCreate(ctx, changesDir, indexFile++);
}
const strDate = baseConnector.getDateTime(change.change_date);
changesHistory.changes.push({"documentSha256": sha256, 'created': strDate, 'user': {'id': change.user_id_original, 'name': change.user_name}});
changesHistory.changes.push({documentSha256: sha256, created: strDate, user: {id: change.user_id_original, name: change.user_name}});
yield* streamWrite(streamObj, '[');
} else {
yield* streamWrite(streamObj, ',');
@ -794,8 +823,13 @@ function* processChangesBase64(ctx, tempDirs, task, cmd, authorProps, sha256) {
if (null !== changesAuthorUnique) {
changesIndex = utils.getIndexFromUserId(changesAuthorUnique, changesAuthor);
}
if (null == changesAuthor && null == changesIndex && forceSave && undefined !== forceSave.getAuthorUserId() &&
undefined !== forceSave.getAuthorUserIndex()) {
if (
null == changesAuthor &&
null == changesIndex &&
forceSave &&
undefined !== forceSave.getAuthorUserId() &&
undefined !== forceSave.getAuthorUserIndex()
) {
changesAuthor = forceSave.getAuthorUserId();
changesIndex = forceSave.getAuthorUserIndex();
}
@ -810,7 +844,7 @@ function* streamCreate(ctx, changesDir, indexFile, opt_options) {
const fileName = constants.CHANGES_NAME + indexFile + '.json';
const filePath = path.join(changesDir, fileName);
const writeStream = yield utils.promiseCreateWriteStream(filePath, opt_options);
writeStream.on('error', (err) => {
writeStream.on('error', err => {
//todo integrate error handle in main thread (probable: set flag here and check it in main thread)
ctx.logger.error('WriteStreamError %s', err.stack);
});
@ -830,7 +864,7 @@ function* streamEnd(streamObj, text) {
function* processUploadToStorage(ctx, dir, storagePath, calcChecksum, opt_specialDirDst, opt_ignorPrefix) {
var list = yield utils.listObjects(dir);
if (opt_ignorPrefix) {
list = list.filter((dir) => !dir.startsWith(opt_ignorPrefix));
list = list.filter(dir => !dir.startsWith(opt_ignorPrefix));
}
if (list.length < MAX_OPEN_FILES) {
yield* processUploadToStorageChunk(ctx, list, dir, storagePath, calcChecksum, opt_specialDirDst);
@ -873,9 +907,9 @@ function* processUploadToStorageErrorFile(ctx, dataConvert, tempDirs, childRes,
//ignore result dir with temp dir inside(see m_sTempDir param) to reduce the amount of data transferred
const ignorePrefix = path.normalize(tempDirs.result);
const format = path.extname(dataConvert.fileFrom).substring(1) || "unknown";
const format = path.extname(dataConvert.fileFrom).substring(1) || 'unknown';
yield* processUploadToStorage(ctx, tempDirs.temp, format + '/' + dataConvert.key , false, tenErrorFiles, ignorePrefix);
yield* processUploadToStorage(ctx, tempDirs.temp, format + '/' + dataConvert.key, false, tenErrorFiles, ignorePrefix);
ctx.logger.debug('processUploadToStorage error complete(id=%s)', dataConvert.key);
}
function writeProcessOutputToLog(ctx, childRes, isDebug) {
@ -899,7 +933,7 @@ function writeProcessOutputToLog(ctx, childRes, isDebug) {
function* postProcess(ctx, cmd, dataConvert, tempDirs, childRes, error, isTimeout) {
var exitCode = 0;
var exitSignal = null;
if(childRes) {
if (childRes) {
exitCode = childRes.status;
exitSignal = childRes.signal;
}
@ -907,7 +941,7 @@ function* postProcess(ctx, cmd, dataConvert, tempDirs, childRes, error, isTimeou
if ((0 !== exitCode && constants.CONVERT_CELLLIMITS !== -exitCode) || null !== exitSignal) {
if (-1 !== exitCodesReturn.indexOf(-exitCode)) {
error = -exitCode;
} else if(isTimeout) {
} else if (isTimeout) {
error = constants.CONVERT_TIMEOUT;
} else {
error = constants.CONVERT;
@ -926,14 +960,14 @@ function* postProcess(ctx, cmd, dataConvert, tempDirs, childRes, error, isTimeou
}
if (-1 !== exitCodesUpload.indexOf(error)) {
if (-1 !== exitCodesCopyOrigin.indexOf(error)) {
const originPath = path.join(path.dirname(dataConvert.fileTo), "origin" + path.extname(dataConvert.fileFrom));
const originPath = path.join(path.dirname(dataConvert.fileTo), 'origin' + path.extname(dataConvert.fileFrom));
if (!fs.existsSync(dataConvert.fileTo)) {
fs.copyFileSync(dataConvert.fileFrom, originPath);
ctx.logger.debug('copyOrigin complete');
}
}
//todo clarify calcChecksum conditions
const calcChecksum = (0 === (constants.AVS_OFFICESTUDIO_FILE_CANVAS & cmd.getOutputFormat()));
const calcChecksum = 0 === (constants.AVS_OFFICESTUDIO_FILE_CANVAS & cmd.getOutputFormat());
yield* processUploadToStorage(ctx, tempDirs.result, dataConvert.key, calcChecksum);
ctx.logger.debug('processUploadToStorage complete');
}
@ -958,7 +992,7 @@ function* postProcess(ctx, cmd, dataConvert, tempDirs, childRes, error, isTimeou
}
}
cmd.setOutputPath(path.basename(dataConvert.fileTo));
if(!cmd.getTitle()){
if (!cmd.getTitle()) {
cmd.setTitle(cmd.getOutputPath());
}
@ -973,7 +1007,8 @@ function* spawnProcess(ctx, builderParams, tempDirs, dataConvert, authorProps, g
const tenX2tPath = ctx.getCfg('FileConverter.converter.x2tPath', cfgX2tPath);
const tenDocbuilderPath = ctx.getCfg('FileConverter.converter.docbuilderPath', cfgDocbuilderPath);
const tenArgs = ctx.getCfg('FileConverter.converter.args', cfgArgs);
let childRes, isTimeout = false;
let childRes,
isTimeout = false;
let childArgs;
if (tenArgs.length > 0) {
childArgs = tenArgs.trim().replace(/ +/g, ' ').split(' ');
@ -1005,7 +1040,7 @@ function* spawnProcess(ctx, builderParams, tempDirs, dataConvert, authorProps, g
try {
const tenSpawnOptions = ctx.getCfg('FileConverter.converter.spawnOptions', cfgSpawnOptions);
//copy to avoid modification of global cfgSpawnOptions
const spawnOptions = Object.assign({}, tenSpawnOptions);;
const spawnOptions = Object.assign({}, tenSpawnOptions);
spawnOptions.env = Object.assign({}, process.env, spawnOptions.env);
if (authorProps.lastModifiedBy && authorProps.modified) {
spawnOptions.env['LAST_MODIFIED_BY'] = authorProps.lastModifiedBy;
@ -1043,7 +1078,7 @@ function* ExecuteTask(ctx, task) {
const tenForgottenFilesName = ctx.getCfg('services.CoAuthoring.server.forgottenfilesname', cfgForgottenFilesName);
var startDate = null;
var curDate = null;
if(clientStatsD) {
if (clientStatsD) {
startDate = curDate = new Date();
}
var resData;
@ -1061,7 +1096,6 @@ function* ExecuteTask(ctx, task) {
let isInJwtToken = cmd.getWithAuthorization();
error = yield* isUselessConvertion(ctx, task, cmd);
if (constants.NO_ERROR !== error) {
;
} else if (cmd.getUrl()) {
const format = cmd.getFormat();
dataConvert.fileFrom = path.join(tempDirs.source, dataConvert.key + '.' + format);
@ -1084,7 +1118,7 @@ function* ExecuteTask(ctx, task) {
if (constants.NO_ERROR === error) {
yield* replaceEmptyFile(ctx, dataConvert.fileFrom, format, cmd.getLCID());
}
if(clientStatsD) {
if (clientStatsD) {
clientStatsD.timing('conv.downloadFile', new Date() - curDate);
curDate = new Date();
}
@ -1094,7 +1128,7 @@ function* ExecuteTask(ctx, task) {
} else if (cmd.getSaveKey() || task.getFromOrigin() || task.getFromSettings()) {
yield* downloadFileFromStorage(ctx, cmd.getDocId(), tempDirs.source);
ctx.logger.debug('downloadFileFromStorage complete');
if(clientStatsD) {
if (clientStatsD) {
clientStatsD.timing('conv.downloadFileFromStorage', new Date() - curDate);
curDate = new Date();
}
@ -1126,45 +1160,53 @@ function* ExecuteTask(ctx, task) {
let isTimeout = false;
if (constants.NO_ERROR === error) {
({childRes, isTimeout} = yield* spawnProcess(ctx, builderParams, tempDirs, dataConvert, authorProps, getTaskTime, task, isInJwtToken));
const canRollback = childRes && 0 !== childRes.status && !isTimeout && task.getFromChanges()
&& constants.AVS_OFFICESTUDIO_FILE_OTHER_OOXML !== dataConvert.formatTo
&& !formatChecker.isOOXFormat(dataConvert.formatTo) && !formatChecker.isBrowserEditorFormat(dataConvert.formatTo)
&& !cmd.getWopiParams();
const canRollback =
childRes &&
0 !== childRes.status &&
!isTimeout &&
task.getFromChanges() &&
constants.AVS_OFFICESTUDIO_FILE_OTHER_OOXML !== dataConvert.formatTo &&
!formatChecker.isOOXFormat(dataConvert.formatTo) &&
!formatChecker.isBrowserEditorFormat(dataConvert.formatTo) &&
!cmd.getWopiParams();
if (canRollback) {
ctx.logger.warn('rollback to save changes to ooxml. See assemblyFormatAsOrigin param. formatTo=%s', formatChecker.getStringFromFormat(dataConvert.formatTo));
ctx.logger.warn(
'rollback to save changes to ooxml. See assemblyFormatAsOrigin param. formatTo=%s',
formatChecker.getStringFromFormat(dataConvert.formatTo)
);
const extOld = path.extname(dataConvert.fileTo);
const extNew = '.' + formatChecker.getStringFromFormat(constants.AVS_OFFICESTUDIO_FILE_OTHER_OOXML);
dataConvert.formatTo = constants.AVS_OFFICESTUDIO_FILE_OTHER_OOXML;
dataConvert.fileTo = dataConvert.fileTo.slice(0, -extOld.length) + extNew;
({childRes, isTimeout} = yield* spawnProcess(ctx, builderParams, tempDirs, dataConvert, authorProps, getTaskTime, task, isInJwtToken));
}
if(clientStatsD) {
if (clientStatsD) {
clientStatsD.timing('conv.spawnSync', new Date() - curDate);
curDate = new Date();
}
}
resData = yield* postProcess(ctx, cmd, dataConvert, tempDirs, childRes, error, isTimeout);
ctx.logger.debug('postProcess');
if(clientStatsD) {
if (clientStatsD) {
clientStatsD.timing('conv.postProcess', new Date() - curDate);
curDate = new Date();
}
if (tempDirs) {
fs.rmSync(tempDirs.temp, { recursive: true, force: true });
fs.rmSync(tempDirs.temp, {recursive: true, force: true});
ctx.logger.debug('deleteFolderRecursive');
if(clientStatsD) {
if (clientStatsD) {
clientStatsD.timing('conv.deleteFolderRecursive', new Date() - curDate);
curDate = new Date();
}
}
if(clientStatsD) {
if (clientStatsD) {
clientStatsD.timing('conv.allconvert', new Date() - startDate);
}
ctx.logger.info('End Task');
return resData;
}
function ackTask(ctx, res, task, ack) {
return co(function*() {
return co(function* () {
try {
if (!res) {
res = createErrorResponse(ctx, task);
@ -1185,7 +1227,7 @@ function receiveTaskSetTimeout(ctx, task, ack, outParams) {
//add DownloadTimeout to upload results
const delay = task.getVisibilityTimeout() * 1000 + ms(cfgDownloadTimeout.wholeCycle);
return setTimeout(() => {
return co(function*() {
return co(function* () {
outParams.isAck = true;
ctx.logger.error('receiveTask timeout %d', delay);
yield ackTask(ctx, null, task, ack);
@ -1219,7 +1261,7 @@ function receiveTask(data, ack) {
}
});
}
function createErrorResponse(ctx, task){
function createErrorResponse(ctx, task) {
if (!task) {
return null;
}
@ -1232,7 +1274,7 @@ function createErrorResponse(ctx, task){
res.setCmd(cmd);
return res;
}
function simulateErrorResponse(data){
function simulateErrorResponse(data) {
const task = new commonDefines.TaskQueueData(JSON.parse(data));
const ctx = new operationContext.Context();
ctx.initFromTaskQueueData(task);
@ -1243,7 +1285,7 @@ function simulateErrorResponse(data){
function run() {
queue = new queueService(simulateErrorResponse);
queue.on('task', receiveTask);
queue.init(true, true, true, false, false, false, (err) => {
queue.init(true, true, true, false, false, false, err => {
if (null != err) {
operationContext.global.logger.error('createTaskQueue error: %s', err.stack);
}

View File

@ -97,8 +97,8 @@ if (cluster.isMaster) {
converter.run();
}
process.on('uncaughtException', (err) => {
operationContext.global.logger.error((new Date).toUTCString() + ' uncaughtException:', err.message);
process.on('uncaughtException', err => {
operationContext.global.logger.error(new Date().toUTCString() + ' uncaughtException:', err.message);
operationContext.global.logger.error(err.stack);
logger.shutdown(() => {
process.exit(1);

View File

@ -34,43 +34,43 @@ const _ = require('lodash');
var packageFile = require('./package.json');
module.exports = function (grunt) {
let addons = grunt.option('addon') || [];
if (!Array.isArray(addons))
{addons = [addons];}
if (!Array.isArray(addons)) {
addons = [addons];
}
addons.forEach((element,index,self) => self[index] = path.join('..', element));
addons.forEach((element, index, self) => (self[index] = path.join('..', element)));
addons = addons.filter(element => grunt.file.isDir(element));
function _merge(target, ...sources) {
if (!sources.length) {return target;}
const source = sources.shift();
if (!sources.length) {
return target;
}
const source = sources.shift();
for (const key in source) {
if (_.isObject(source[key])) {
if (_.isArray(source[key])) {
if (!_.isArray(target[key])){
target[key]=[];
if (!_.isArray(target[key])) {
target[key] = [];
}
target[key].push(...source[key])
}
else {
target[key].push(...source[key]);
} else {
if (!target[key]) {
Object.assign(target, { [key]: {} });
Object.assign(target, {[key]: {}});
}
_merge(target[key], source[key]);
}
}
else {
Object.assign(target, { [key]: source[key] });
} else {
Object.assign(target, {[key]: source[key]});
}
}
}
addons.forEach(element => {
const _path = path.join(element, 'package.json');
if (grunt.file.exists(_path)) {
_merge(packageFile, require(_path));
grunt.log.ok('addon '.green + element + ' is merged successfully'.green);
_merge(packageFile, require(_path));
grunt.log.ok('addon '.green + element + ' is merged successfully'.green);
}
});
@ -78,14 +78,14 @@ module.exports = function (grunt) {
var checkDependencies = {};
for(var i of packageFile.npm) {
for (var i of packageFile.npm) {
checkDependencies[i] = {
options: {
install: true,
continueAfterInstall: true,
packageDir: i
}
}
};
}
grunt.initConfig({
@ -105,13 +105,22 @@ module.exports = function (grunt) {
copyright: {
options: {
position: 'top',
banner: '/*\n' +
' * Copyright (C) ' + process.env['PUBLISHER_NAME'] + ' 2012-<%= grunt.template.today("yyyy") %>. All rights reserved\n' +
' *\n' +
' * ' + process.env['PUBLISHER_URL'] + ' \n' +
' *\n' +
' * Version: ' + process.env['PRODUCT_VERSION'] + ' (build:' + process.env['BUILD_NUMBER'] + ')\n' +
' */\n',
banner:
'/*\n' +
' * Copyright (C) ' +
process.env['PUBLISHER_NAME'] +
' 2012-<%= grunt.template.today("yyyy") %>. All rights reserved\n' +
' *\n' +
' * ' +
process.env['PUBLISHER_URL'] +
' \n' +
' *\n' +
' * Version: ' +
process.env['PRODUCT_VERSION'] +
' (build:' +
process.env['BUILD_NUMBER'] +
')\n' +
' */\n',
linebreak: false
},
files: {
@ -124,7 +133,7 @@ module.exports = function (grunt) {
grunt.registerTask('build-develop', 'Build develop scripts', () => {
grunt.initConfig({
copy: packageFile.grunt["develop-copy"]
copy: packageFile.grunt['develop-copy']
});
});

View File

@ -1,4 +1,3 @@
# Server
[![License](https://img.shields.io/badge/License-GNU%20AGPL%20V3-green.svg?style=flat)](https://www.gnu.org/licenses/agpl-3.0.en.html)
@ -18,9 +17,10 @@ For the document service to work correctly it is necessary to install the follow
2. [Java](https://java.com/en/download/). Necessary for the sdk build.
3. Database (MySQL or PostgreSQL). When installing use the `onlyoffice` password for the `root` user.
* [MySQL Server](http://dev.mysql.com/downloads/windows/installer/) version 5.5 or later
* [PostgreSQL Server](https://www.postgresql.org/download/) version 9.1 or later
- [MySQL Server](http://dev.mysql.com/downloads/windows/installer/) version 5.5 or later
- [PostgreSQL Server](https://www.postgresql.org/download/) version 9.1 or later
4. [Erlang](https://www.erlang.org/download.html)
@ -36,30 +36,31 @@ For the document service to work correctly it is necessary to install the follow
1. Database setup:
* Database setup for MySQL
Run the `schema/mysql/createdb.sql` script for MySQL
- Database setup for MySQL
Run the `schema/mysql/createdb.sql` script for MySQL
* Database setup for PostgreSQL
1. Enter in `psql` (PostgreSQL interactive terminal) with
login and password introduced during installation, then enter commands:
- Database setup for PostgreSQL
```sql
CREATE USER onlyoffice WITH PASSWORD 'onlyoffice';
CREATE DATABASE onlyoffice OWNER onlyoffice;
\c onlyoffice
\i 'schema/postgresql/createdb.sql';
```
1. Enter in `psql` (PostgreSQL interactive terminal) with
login and password introduced during installation, then enter commands:
2. Delete from `server\Common\config\development-windows.json` option `sql`.
```sql
CREATE USER onlyoffice WITH PASSWORD 'onlyoffice';
CREATE DATABASE onlyoffice OWNER onlyoffice;
\c onlyoffice
\i 'schema/postgresql/createdb.sql';
```
2. Delete from `server\Common\config\development-windows.json` option `sql`.
2. Install the Web Monitor for RabbitMQ (see the details for the installation [here](https://www.rabbitmq.com/management.html))
3. Open the command line `cmd` executable.
4. Switch to the installation directory using the `cd /d Installation-directory/sbin` command.
5. Run the following command:
```powershell
rabbitmq-plugins.bat enable rabbitmq_management
```
```powershell
rabbitmq-plugins.bat enable rabbitmq_management
```
6. The Web Monitor is located at the [http://localhost:15672/](http://localhost:15672/) address.
Use the `guest:guest` for the login:password combination.
@ -84,10 +85,10 @@ Notes
All config files for the server part can be found in the `Common\config` folder
* `default.json` - common config files similar for all production versions.
* `production-windows.json` - config files for the production version running on a Windows based platform.
* `production-linux.json` - config files for the production version running on a Linux based platform.
* `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).
- `default.json` - common config files similar for all production versions.
- `production-windows.json` - config files for the production version running on a Windows based platform.
- `production-linux.json` - config files for the production version running on a Linux based platform.
- `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).
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.
@ -95,9 +96,9 @@ In case it is necessary to temporarily edit the config files, create the local.j
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].
[1]: https://forum.onlyoffice.com
[2]: https://github.com/ONLYOFFICE/DocumentServer
[3]: https://stackoverflow.com/questions/tagged/onlyoffice
[1]: https://forum.onlyoffice.com
[2]: https://github.com/ONLYOFFICE/DocumentServer
[3]: https://stackoverflow.com/questions/tagged/onlyoffice
## License

View File

@ -30,76 +30,434 @@
*
*/
"use strict";
'use strict';
const idLanguages = [0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c,
0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a,
0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0032, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039,
0x003a, 0x003b, 0x003c, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0056, 0x0057,
0x005a, 0x005b, 0x005d, 0x005e, 0x005f, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0068, 0x006a, 0x006b, 0x006c,
0x006d, 0x006e, 0x006f, 0x0070, 0x0078, 0x007a, 0x007c, 0x007e, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085,
0x0086, 0x0087, 0x0088, 0x008c, 0x0091, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409,
0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425,
0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x0430, 0x0431, 0x0432, 0x0433,
0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043e, 0x043f, 0x0440, 0x0441, 0x0442, 0x0443,
0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0x0450, 0x0451,
0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f,
0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, 0x0468, 0x0469, 0x046a, 0x046b, 0x046c, 0x046d, 0x046e,
0x046f, 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0477, 0x0478, 0x0479, 0x047a, 0x047c, 0x047e, 0x0480,
0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x048c, 0x048d, 0x0491, 0x0801, 0x0803, 0x0804,
0x0807, 0x0809, 0x080a, 0x080c, 0x0810, 0x0813, 0x0814, 0x0816, 0x0818, 0x0819, 0x081a, 0x081d, 0x0820, 0x082c,
0x082e, 0x083b, 0x083c, 0x083e, 0x0843, 0x0845, 0x0846, 0x0850, 0x0851, 0x0859, 0x085d, 0x085f, 0x0861, 0x086b,
0x0873, 0x0c01, 0x0c04, 0x0c07, 0x0c09, 0x0c0a, 0x0c0c, 0x0c1a, 0x0c3b, 0x0c5f, 0x0c6b, 0x1001, 0x1004, 0x1007,
0x1009, 0x100a, 0x100c, 0x101a, 0x103b, 0x1401, 0x1404, 0x1407, 0x1409, 0x140a, 0x140c, 0x141a, 0x143b, 0x1801,
0x1809, 0x180a, 0x180c, 0x181a, 0x183b, 0x1c01, 0x1c09, 0x1c0a, 0x1c0c, 0x1c1a, 0x1c3b, 0x2001, 0x2009, 0x200a,
0x200c, 0x201a, 0x203b, 0x2401, 0x2409, 0x240a, 0x240c, 0x241a, 0x243b, 0x2801, 0x2809, 0x280a, 0x280c, 0x281a,
0x2c01, 0x2c09, 0x2c0a, 0x2c0c, 0x2c1a, 0x3001, 0x3009, 0x300a, 0x300c, 0x301a, 0x3401, 0x3409, 0x340a, 0x340c,
0x3801, 0x3809, 0x380a, 0x380c, 0x3c01, 0x3c09, 0x3c0a, 0x3c0c, 0x4001, 0x4009, 0x400a, 0x4409, 0x440a, 0x4809,
0x480a, 0x4c0a, 0x500a, 0x540a, 0x641a, 0x681a, 0x6c1a, 0x701a, 0x703b, 0x742c, 0x743b, 0x7804, 0x7814, 0x781a,
0x782c, 0x783b, 0x7843, 0x7850, 0x785d, 0x7c04, 0x7c14, 0x7c1a, 0x7c28, 0x7c2e, 0x7c3b, 0x7c43, 0x7c50, 0x7c5d,
0x7c5f, 0x7c68];
const sLanguages = ['ar', 'bg', 'ca', 'zh_Hans', 'cs', 'da', 'de', 'el', 'en', 'es', 'fi', 'fr', 'he', 'hu', 'is',
'it', 'ja', 'ko', 'nl', 'no', 'pl', 'pt', 'rm', 'ro', 'ru', 'hr', 'sk', 'sq', 'sv', 'th', 'tr', 'ur', 'id', 'uk',
'be', 'sl', 'et', 'lv', 'lt', 'tg', 'fa', 'vi', 'hy', 'az', 'eu', 'hsb', 'mk', 'tn', 'xh', 'zu', 'af', 'ka', 'fo',
'hi', 'mt', 'se', 'ga', 'ms', 'kk', 'ky', 'sw', 'tk', 'uz', 'tt', 'bn', 'pa', 'gu', 'or', 'ta', 'te', 'kn', 'ml',
'as', 'mr', 'sa', 'mn', 'bo', 'cy', 'km', 'lo', 'gl', 'kok', 'syr', 'si', 'iu', 'am', 'tzm', 'ne', 'fy', 'ps',
'fil', 'dv', 'ha', 'yo', 'quz', 'nso', 'ba', 'lb', 'kl', 'ig', 'ii', 'arn', 'moh', 'br', 'ug', 'mi', 'oc', 'co',
'gsw', 'sah', 'qut', 'rw', 'wo', 'prs', 'gd', 'ar_SA', 'bg_BG', 'ca_ES', 'zh_TW', 'cs_CZ', 'da_DK', 'de_DE',
'el_GR', 'en_US', 'es_ES_tradnl', 'fi_FI', 'fr_FR', 'he_IL', 'hu_HU', 'is_IS', 'it_IT', 'ja_JP', 'ko_KR', 'nl_NL',
'nb_NO', 'pl_PL', 'pt_BR', 'rm_CH', 'ro_RO', 'ru_RU', 'hr_HR', 'sk_SK', 'sq_AL', 'sv_SE', 'th_TH', 'tr_TR', 'ur_PK',
'id_ID', 'uk_UA', 'be_BY', 'sl_SI', 'et_EE', 'lv_LV', 'lt_LT', 'tg_Cyrl_TJ', 'fa_IR', 'vi_VN', 'hy_AM',
'az_Latn_AZ', 'eu_ES', 'wen_DE', 'mk_MK', 'st_ZA', 'ts_ZA', 'tn_ZA', 'ven_ZA', 'xh_ZA', 'zu_ZA', 'af_ZA', 'ka_GE',
'fo_FO', 'hi_IN', 'mt_MT', 'se_NO', 'ms_MY', 'kk_KZ', 'ky_KG', 'sw_KE', 'tk_TM', 'uz_Latn_UZ', 'tt_RU', 'bn_IN',
'pa_IN', 'gu_IN', 'or_IN', 'ta_IN', 'te_IN', 'kn_IN', 'ml_IN', 'as_IN', 'mr_IN', 'sa_IN', 'mn_MN', 'bo_CN', 'cy_GB',
'km_KH', 'lo_LA', 'my_MM', 'gl_ES', 'kok_IN', 'mni', 'sd_IN', 'syr_SY', 'si_LK', 'chr_US', 'iu_Cans_CA', 'am_ET',
'tmz', 'ne_NP', 'fy_NL', 'ps_AF', 'fil_PH', 'dv_MV', 'bin_NG', 'fuv_NG', 'ha_Latn_NG', 'ibb_NG', 'yo_NG', 'quz_BO',
'nso_ZA', 'ba_RU', 'lb_LU', 'kl_GL', 'ig_NG', 'kr_NG', 'gaz_ET', 'ti_ER', 'gn_PY', 'haw_US', 'so_SO', 'ii_CN',
'pap_AN', 'arn_CL', 'moh_CA', 'br_FR', 'ug_CN', 'mi_NZ', 'oc_FR', 'co_FR', 'gsw_FR', 'sah_RU', 'qut_GT', 'rw_RW',
'wo_SN', 'prs_AF', 'plt_MG', 'gd_GB', 'ar_IQ', 'ca_ES_valencia', 'zh_CN', 'de_CH', 'en_GB', 'es_MX', 'fr_BE',
'it_CH', 'nl_BE', 'nn_NO', 'pt_PT', 'ro_MO', 'ru_MO', 'sr_Latn_CS', 'sv_FI', 'ur_IN', 'az_Cyrl_AZ', 'dsb_DE',
'se_SE', 'ga_IE', 'ms_BN', 'uz_Cyrl_UZ', 'bn_BD', 'pa_PK', 'mn_Mong_CN', 'bo_BT', 'sd_PK', 'iu_Latn_CA',
'tzm_Latn_DZ', 'ne_IN', 'quz_EC', 'ti_ET', 'ar_EG', 'zh_HK', 'de_AT', 'en_AU', 'es_ES', 'fr_CA', 'sr_Cyrl_CS',
'se_FI', 'tmz_MA', 'quz_PE', 'ar_LY', 'zh_SG', 'de_LU', 'en_CA', 'es_GT', 'fr_CH', 'hr_BA', 'smj_NO', 'ar_DZ',
'zh_MO', 'de_LI', 'en_NZ', 'es_CR', 'fr_LU', 'bs_Latn_BA', 'smj_SE', 'ar_MA', 'en_IE', 'es_PA', 'fr_MC',
'sr_Latn_BA', 'sma_NO', 'ar_TN', 'en_ZA', 'es_DO', 'fr_West', 'sr_Cyrl_BA', 'sma_SE', 'ar_OM', 'en_JM', 'es_VE',
'fr_RE', 'bs_Cyrl_BA', 'sms_FI', 'ar_YE', 'en_CB', 'es_CO', 'fr_CG', 'sr_Latn_RS', 'smn_FI', 'ar_SY', 'en_BZ',
'es_PE', 'fr_SN', 'sr_Cyrl_RS', 'ar_JO', 'en_TT', 'es_AR', 'fr_CM', 'sr_Latn_ME', 'ar_LB', 'en_ZW', 'es_EC',
'fr_CI', 'sr_Cyrl_ME', 'ar_KW', 'en_PH', 'es_CL', 'fr_ML', 'ar_AE', 'en_ID', 'es_UY', 'fr_MA', 'ar_BH', 'en_HK',
'es_PY', 'fr_HT', 'ar_QA', 'en_IN', 'es_BO', 'en_MY', 'es_SV', 'en_SG', 'es_HN', 'es_NI', 'es_PR', 'es_US',
'bs_Cyrl', 'bs_Latn', 'sr_Cyrl', 'sr_Latn', 'smn', 'az_Cyrl', 'sms', 'zh', 'nn', 'bs', 'az_Latn', 'sma', 'uz_Cyrl',
'mn_Cyrl', 'iu_Cans', 'zh_Hant', 'nb', 'sr', 'tg_Cyrl', 'dsb', 'smj', 'uz_Latn', 'mn_Mong', 'iu_Latn', 'tzm_Latn',
'ha_Latn'];
const idLanguages = [
0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012,
0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024,
0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0032, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039,
0x003a, 0x003b, 0x003c, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c,
0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0056, 0x0057, 0x005a, 0x005b, 0x005d, 0x005e, 0x005f, 0x0061, 0x0062, 0x0063,
0x0064, 0x0065, 0x0068, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0078, 0x007a, 0x007c, 0x007e, 0x0080, 0x0081, 0x0082, 0x0083,
0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x008c, 0x0091, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040b,
0x040c, 0x040d, 0x040e, 0x040f, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d,
0x041e, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043e, 0x043f, 0x0440, 0x0441, 0x0442, 0x0443,
0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455,
0x0456, 0x0457, 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, 0x0468,
0x0469, 0x046a, 0x046b, 0x046c, 0x046d, 0x046e, 0x046f, 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0477, 0x0478, 0x0479, 0x047a, 0x047c,
0x047e, 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x048c, 0x048d, 0x0491, 0x0801, 0x0803, 0x0804, 0x0807, 0x0809,
0x080a, 0x080c, 0x0810, 0x0813, 0x0814, 0x0816, 0x0818, 0x0819, 0x081a, 0x081d, 0x0820, 0x082c, 0x082e, 0x083b, 0x083c, 0x083e, 0x0843, 0x0845,
0x0846, 0x0850, 0x0851, 0x0859, 0x085d, 0x085f, 0x0861, 0x086b, 0x0873, 0x0c01, 0x0c04, 0x0c07, 0x0c09, 0x0c0a, 0x0c0c, 0x0c1a, 0x0c3b, 0x0c5f,
0x0c6b, 0x1001, 0x1004, 0x1007, 0x1009, 0x100a, 0x100c, 0x101a, 0x103b, 0x1401, 0x1404, 0x1407, 0x1409, 0x140a, 0x140c, 0x141a, 0x143b, 0x1801,
0x1809, 0x180a, 0x180c, 0x181a, 0x183b, 0x1c01, 0x1c09, 0x1c0a, 0x1c0c, 0x1c1a, 0x1c3b, 0x2001, 0x2009, 0x200a, 0x200c, 0x201a, 0x203b, 0x2401,
0x2409, 0x240a, 0x240c, 0x241a, 0x243b, 0x2801, 0x2809, 0x280a, 0x280c, 0x281a, 0x2c01, 0x2c09, 0x2c0a, 0x2c0c, 0x2c1a, 0x3001, 0x3009, 0x300a,
0x300c, 0x301a, 0x3401, 0x3409, 0x340a, 0x340c, 0x3801, 0x3809, 0x380a, 0x380c, 0x3c01, 0x3c09, 0x3c0a, 0x3c0c, 0x4001, 0x4009, 0x400a, 0x4409,
0x440a, 0x4809, 0x480a, 0x4c0a, 0x500a, 0x540a, 0x641a, 0x681a, 0x6c1a, 0x701a, 0x703b, 0x742c, 0x743b, 0x7804, 0x7814, 0x781a, 0x782c, 0x783b,
0x7843, 0x7850, 0x785d, 0x7c04, 0x7c14, 0x7c1a, 0x7c28, 0x7c2e, 0x7c3b, 0x7c43, 0x7c50, 0x7c5d, 0x7c5f, 0x7c68
];
const sLanguages = [
'ar',
'bg',
'ca',
'zh_Hans',
'cs',
'da',
'de',
'el',
'en',
'es',
'fi',
'fr',
'he',
'hu',
'is',
'it',
'ja',
'ko',
'nl',
'no',
'pl',
'pt',
'rm',
'ro',
'ru',
'hr',
'sk',
'sq',
'sv',
'th',
'tr',
'ur',
'id',
'uk',
'be',
'sl',
'et',
'lv',
'lt',
'tg',
'fa',
'vi',
'hy',
'az',
'eu',
'hsb',
'mk',
'tn',
'xh',
'zu',
'af',
'ka',
'fo',
'hi',
'mt',
'se',
'ga',
'ms',
'kk',
'ky',
'sw',
'tk',
'uz',
'tt',
'bn',
'pa',
'gu',
'or',
'ta',
'te',
'kn',
'ml',
'as',
'mr',
'sa',
'mn',
'bo',
'cy',
'km',
'lo',
'gl',
'kok',
'syr',
'si',
'iu',
'am',
'tzm',
'ne',
'fy',
'ps',
'fil',
'dv',
'ha',
'yo',
'quz',
'nso',
'ba',
'lb',
'kl',
'ig',
'ii',
'arn',
'moh',
'br',
'ug',
'mi',
'oc',
'co',
'gsw',
'sah',
'qut',
'rw',
'wo',
'prs',
'gd',
'ar_SA',
'bg_BG',
'ca_ES',
'zh_TW',
'cs_CZ',
'da_DK',
'de_DE',
'el_GR',
'en_US',
'es_ES_tradnl',
'fi_FI',
'fr_FR',
'he_IL',
'hu_HU',
'is_IS',
'it_IT',
'ja_JP',
'ko_KR',
'nl_NL',
'nb_NO',
'pl_PL',
'pt_BR',
'rm_CH',
'ro_RO',
'ru_RU',
'hr_HR',
'sk_SK',
'sq_AL',
'sv_SE',
'th_TH',
'tr_TR',
'ur_PK',
'id_ID',
'uk_UA',
'be_BY',
'sl_SI',
'et_EE',
'lv_LV',
'lt_LT',
'tg_Cyrl_TJ',
'fa_IR',
'vi_VN',
'hy_AM',
'az_Latn_AZ',
'eu_ES',
'wen_DE',
'mk_MK',
'st_ZA',
'ts_ZA',
'tn_ZA',
'ven_ZA',
'xh_ZA',
'zu_ZA',
'af_ZA',
'ka_GE',
'fo_FO',
'hi_IN',
'mt_MT',
'se_NO',
'ms_MY',
'kk_KZ',
'ky_KG',
'sw_KE',
'tk_TM',
'uz_Latn_UZ',
'tt_RU',
'bn_IN',
'pa_IN',
'gu_IN',
'or_IN',
'ta_IN',
'te_IN',
'kn_IN',
'ml_IN',
'as_IN',
'mr_IN',
'sa_IN',
'mn_MN',
'bo_CN',
'cy_GB',
'km_KH',
'lo_LA',
'my_MM',
'gl_ES',
'kok_IN',
'mni',
'sd_IN',
'syr_SY',
'si_LK',
'chr_US',
'iu_Cans_CA',
'am_ET',
'tmz',
'ne_NP',
'fy_NL',
'ps_AF',
'fil_PH',
'dv_MV',
'bin_NG',
'fuv_NG',
'ha_Latn_NG',
'ibb_NG',
'yo_NG',
'quz_BO',
'nso_ZA',
'ba_RU',
'lb_LU',
'kl_GL',
'ig_NG',
'kr_NG',
'gaz_ET',
'ti_ER',
'gn_PY',
'haw_US',
'so_SO',
'ii_CN',
'pap_AN',
'arn_CL',
'moh_CA',
'br_FR',
'ug_CN',
'mi_NZ',
'oc_FR',
'co_FR',
'gsw_FR',
'sah_RU',
'qut_GT',
'rw_RW',
'wo_SN',
'prs_AF',
'plt_MG',
'gd_GB',
'ar_IQ',
'ca_ES_valencia',
'zh_CN',
'de_CH',
'en_GB',
'es_MX',
'fr_BE',
'it_CH',
'nl_BE',
'nn_NO',
'pt_PT',
'ro_MO',
'ru_MO',
'sr_Latn_CS',
'sv_FI',
'ur_IN',
'az_Cyrl_AZ',
'dsb_DE',
'se_SE',
'ga_IE',
'ms_BN',
'uz_Cyrl_UZ',
'bn_BD',
'pa_PK',
'mn_Mong_CN',
'bo_BT',
'sd_PK',
'iu_Latn_CA',
'tzm_Latn_DZ',
'ne_IN',
'quz_EC',
'ti_ET',
'ar_EG',
'zh_HK',
'de_AT',
'en_AU',
'es_ES',
'fr_CA',
'sr_Cyrl_CS',
'se_FI',
'tmz_MA',
'quz_PE',
'ar_LY',
'zh_SG',
'de_LU',
'en_CA',
'es_GT',
'fr_CH',
'hr_BA',
'smj_NO',
'ar_DZ',
'zh_MO',
'de_LI',
'en_NZ',
'es_CR',
'fr_LU',
'bs_Latn_BA',
'smj_SE',
'ar_MA',
'en_IE',
'es_PA',
'fr_MC',
'sr_Latn_BA',
'sma_NO',
'ar_TN',
'en_ZA',
'es_DO',
'fr_West',
'sr_Cyrl_BA',
'sma_SE',
'ar_OM',
'en_JM',
'es_VE',
'fr_RE',
'bs_Cyrl_BA',
'sms_FI',
'ar_YE',
'en_CB',
'es_CO',
'fr_CG',
'sr_Latn_RS',
'smn_FI',
'ar_SY',
'en_BZ',
'es_PE',
'fr_SN',
'sr_Cyrl_RS',
'ar_JO',
'en_TT',
'es_AR',
'fr_CM',
'sr_Latn_ME',
'ar_LB',
'en_ZW',
'es_EC',
'fr_CI',
'sr_Cyrl_ME',
'ar_KW',
'en_PH',
'es_CL',
'fr_ML',
'ar_AE',
'en_ID',
'es_UY',
'fr_MA',
'ar_BH',
'en_HK',
'es_PY',
'fr_HT',
'ar_QA',
'en_IN',
'es_BO',
'en_MY',
'es_SV',
'en_SG',
'es_HN',
'es_NI',
'es_PR',
'es_US',
'bs_Cyrl',
'bs_Latn',
'sr_Cyrl',
'sr_Latn',
'smn',
'az_Cyrl',
'sms',
'zh',
'nn',
'bs',
'az_Latn',
'sma',
'uz_Cyrl',
'mn_Cyrl',
'iu_Cans',
'zh_Hant',
'nb',
'sr',
'tg_Cyrl',
'dsb',
'smj',
'uz_Latn',
'mn_Mong',
'iu_Latn',
'tzm_Latn',
'ha_Latn'
];
const allLanguages = {};
for (let i = 0; i < idLanguages.length; ++i) {
allLanguages[idLanguages[i]] = sLanguages[i];
allLanguages[idLanguages[i]] = sLanguages[i];
}
exports.sToId = function (str) {
const index = sLanguages.indexOf(str);
return -1 !== index ? idLanguages[index] : -1;
const index = sLanguages.indexOf(str);
return -1 !== index ? idLanguages[index] : -1;
};
exports.allLanguages = allLanguages;

View File

@ -47,105 +47,108 @@ const pathDictionaries = require('config').get('SpellChecker.server.dictDir');
const arrDictionaries = {};
function spell(type, word, id) {
return new Promise(function(resolve, reject) {
let dict = null;
if (arrDictionaries[id]) {
dict = arrDictionaries[id];
} else {
if (arrExistDictionaries[id]) {
let pathTmp = path.join(pathDictionaries, allLanguages[id], allLanguages[id] + '.');
return new Promise(function (resolve, reject) {
let dict = null;
if (arrDictionaries[id]) {
dict = arrDictionaries[id];
} else {
if (arrExistDictionaries[id]) {
let pathTmp = path.join(pathDictionaries, allLanguages[id], allLanguages[id] + '.');
dict = arrDictionaries[id] = new nodehun(pathTmp + 'aff', pathTmp + 'dic');
}
}
dict = arrDictionaries[id] = new nodehun(pathTmp + 'aff', pathTmp + 'dic');
}
}
if (dict) {
if ("spell" === type) {
// use setImmediate because https://github.com/nodejs/node/issues/5691
dict.spell(word)
.then(isCorrect => {
return setImmediate(resolve, isCorrect);
});
} else if ("suggest" === type) {
dict.suggest(word)
.then(suggestions => {
return setImmediate(resolve, suggestions);
});
}
} else {
return setImmediate(resolve, true);
}
});
if (dict) {
if ('spell' === type) {
// use setImmediate because https://github.com/nodejs/node/issues/5691
dict.spell(word).then(isCorrect => {
return setImmediate(resolve, isCorrect);
});
} else if ('suggest' === type) {
dict.suggest(word).then(suggestions => {
return setImmediate(resolve, suggestions);
});
}
} else {
return setImmediate(resolve, true);
}
});
}
exports.install = function (server, callbackFunction) {
'use strict';
'use strict';
utils.listFolders(pathDictionaries, true).then((values) => {
return co(function*() {
let lang;
for (let i = 0; i < values.length; ++i) {
lang = languages.sToId(path.basename(values[i]));
if (-1 !== lang) {
arrExistDictionaries[lang] = 1;
}
}
yield spell('spell', 'color', 0x0409);
callbackFunction();
});
});
utils.listFolders(pathDictionaries, true).then(values => {
return co(function* () {
let lang;
for (let i = 0; i < values.length; ++i) {
lang = languages.sToId(path.basename(values[i]));
if (-1 !== lang) {
arrExistDictionaries[lang] = 1;
}
}
yield spell('spell', 'color', 0x0409);
callbackFunction();
});
});
const sockjs_echo = sockjs.createServer(cfgSockjs);
const sockjs_echo = sockjs.createServer(cfgSockjs);
sockjs_echo.on('connection', function (conn) {
if (!conn) {
logger.error ("null == conn");
return;
}
conn.on('data', function (message) {
try {
let data = JSON.parse(message);
switch (data.type) {
case 'spellCheck': spellCheck(conn, data.spellCheckData);break;
}
} catch (e) {
logger.error("error receiving response: %s", e);
}
});
conn.on('error', function () {
logger.error("On error");
});
conn.on('close', function () {
logger.info("Connection closed or timed out");
});
sockjs_echo.on('connection', function (conn) {
if (!conn) {
logger.error('null == conn');
return;
}
conn.on('data', function (message) {
try {
let data = JSON.parse(message);
switch (data.type) {
case 'spellCheck':
spellCheck(conn, data.spellCheckData);
break;
}
} catch (e) {
logger.error('error receiving response: %s', e);
}
});
conn.on('error', function () {
logger.error('On error');
});
conn.on('close', function () {
logger.info('Connection closed or timed out');
});
sendData(conn, {type: 'init', languages: Object.keys(arrExistDictionaries)});
});
sendData(conn, {type: 'init', languages: Object.keys(arrExistDictionaries)});
});
function sendData(conn, data) {
conn.write(JSON.stringify(data));
}
function sendData(conn, data) {
conn.write(JSON.stringify(data));
}
function spellCheck(conn, data) {
return co(function*() {
let promises = [];
for (let i = 0, length = data.usrWords.length; i < length; ++i) {
promises.push(spell(data.type, data.usrWords[i], data.usrLang[i]));
}
yield Promise.all(promises).then(values => {
data[('spell' === data.type ? 'usrCorrect' : 'usrSuggest')] = values;
});
sendData(conn, {type: 'spellCheck', spellCheckData: data});
});
}
function spellCheck(conn, data) {
return co(function* () {
let promises = [];
for (let i = 0, length = data.usrWords.length; i < length; ++i) {
promises.push(spell(data.type, data.usrWords[i], data.usrLang[i]));
}
yield Promise.all(promises).then(values => {
data['spell' === data.type ? 'usrCorrect' : 'usrSuggest'] = values;
});
sendData(conn, {type: 'spellCheck', spellCheckData: data});
});
}
sockjs_echo.installHandlers(server, {prefix:'/doc/[0-9-.a-zA-Z_=]*/c', log:function (severity, message) {
//TODO: handle severity
logger.info(message);
}});
sockjs_echo.installHandlers(server, {
prefix: '/doc/[0-9-.a-zA-Z_=]*/c',
log: function (severity, message) {
//TODO: handle severity
logger.info(message);
}
});
};
exports.spellSuggest = function (type, word, lang, callbackFunction) {
return co(function*() {
callbackFunction(yield spell(type, word, lang));
});
return co(function* () {
callbackFunction(yield spell(type, word, lang));
});
};

View File

@ -1,146 +1,146 @@
/* AI Integration Styles */
.ai-settings-section {
margin-top: 15px;
margin-bottom: 15px;
margin-top: 15px;
margin-bottom: 15px;
}
.ai-spoiler {
cursor: pointer;
padding: 12px 15px;
background: #F5F5F5;
border: 1px solid #EFEFEF;
border-radius: 3px;
margin-top: 15px;
margin-bottom: 15px;
font-size: 14px;
font-weight: 600;
color: #333333;
user-select: none;
position: relative;
cursor: pointer;
padding: 12px 15px;
background: #f5f5f5;
border: 1px solid #efefef;
border-radius: 3px;
margin-top: 15px;
margin-bottom: 15px;
font-size: 14px;
font-weight: 600;
color: #333333;
user-select: none;
position: relative;
}
.ai-spoiler:hover {
background: #EEEEEE;
background: #eeeeee;
}
.ai-spoiler::after {
content: '▼';
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
transition: transform 0.3s ease;
color: #666666;
content: '▼';
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
transition: transform 0.3s ease;
color: #666666;
}
.ai-spoiler.collapsed::after {
transform: translateY(-50%) rotate(-90deg);
transform: translateY(-50%) rotate(-90deg);
}
.ai-content {
display: block;
overflow: hidden;
transition: max-height 0.3s ease;
border: 1px solid #EFEFEF;
border-top: none;
border-radius: 0 0 3px 3px;
background: white;
display: block;
overflow: hidden;
transition: max-height 0.3s ease;
border: 1px solid #efefef;
border-top: none;
border-radius: 0 0 3px 3px;
background: white;
}
.ai-content.collapsed {
display: none;
display: none;
}
.ai-iframe-container {
position: relative;
background: white;
height: 500px;
position: relative;
background: white;
height: 500px;
}
.ai-iframe {
width: 100%;
height: 500px;
border: none;
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 500px;
border: none;
display: block;
position: absolute;
top: 0;
left: 0;
}
.ai-iframe.hidden {
display: none;
display: none;
}
.ai-iframe-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.9);
display: none;
align-items: center;
justify-content: center;
z-index: 10;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.9);
display: none;
align-items: center;
justify-content: center;
z-index: 10;
}
.ai-iframe-overlay.loading {
display: flex;
display: flex;
}
.ai-loading-text {
font-size: 14px;
color: #666666;
font-size: 14px;
color: #666666;
}
.ai-controls {
padding: 10px 15px;
background: #F9F9F9;
border-top: 1px solid #EFEFEF;
text-align: right;
padding: 10px 15px;
background: #f9f9f9;
border-top: 1px solid #efefef;
text-align: right;
}
.ai-btn {
display: inline-block;
padding: 6px 12px;
margin-left: 8px;
border: 1px solid #CCCCCC;
border-radius: 2px;
background: white;
color: #333333;
font-size: 12px;
cursor: pointer;
text-decoration: none;
transition: all 0.2s ease;
display: inline-block;
padding: 6px 12px;
margin-left: 8px;
border: 1px solid #cccccc;
border-radius: 2px;
background: white;
color: #333333;
font-size: 12px;
cursor: pointer;
text-decoration: none;
transition: all 0.2s ease;
}
.ai-btn:hover {
background: #F5F5F5;
border-color: #AAAAAA;
background: #f5f5f5;
border-color: #aaaaaa;
}
.ai-btn.primary {
background: #3D4A6B;
color: white;
border-color: #3D4A6B;
background: #3d4a6b;
color: white;
border-color: #3d4a6b;
}
.ai-btn.primary:hover {
background: #2E3B54;
border-color: #2E3B54;
background: #2e3b54;
border-color: #2e3b54;
}
.ai-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
opacity: 0.6;
cursor: not-allowed;
}
.ai-btn:disabled:hover {
background: white;
border-color: #CCCCCC;
background: white;
border-color: #cccccc;
}
.ai-btn.primary:disabled:hover {
background: #3D4A6B;
border-color: #3D4A6B;
background: #3d4a6b;
border-color: #3d4a6b;
}

View File

@ -1,62 +1,62 @@
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 11px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 11px;
}
/* button */
.btn-text-default {
background: #fff;
border: 1px solid #cfcfcf;
border-radius: 2px;
color: #444444;
font-size: 11px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
height: 22px;
cursor: pointer;
background: #fff;
border: 1px solid #cfcfcf;
border-radius: 2px;
color: #444444;
font-size: 11px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
height: 22px;
cursor: pointer;
}
.btn-text-default::-moz-focus-inner {
border: 0;
padding: 0;
border: 0;
padding: 0;
}
.btn-text-default.submit {
font-weight: bold;
background-color: #d8dadc;
border: 1px solid transparent;
font-weight: bold;
background-color: #d8dadc;
border: 1px solid transparent;
}
.btn-text-default.submit.primary {
color: #fff;
background-color: #7d858c;
color: #fff;
background-color: #7d858c;
}
.btn-text-default:focus {
outline: 0;
outline-offset: 0;
outline: 0;
outline-offset: 0;
}
.btn-text-default:hover {
background-color: #d8dadc;
background-color: #d8dadc;
}
.btn-text-default.submit:hover {
background-color: #cbced1;
background-color: #cbced1;
}
.btn-text-default.primary:hover {
background-color: #666d73 !important;
color: #fff;
background-color: #666d73 !important;
color: #fff;
}
.btn-text-default:active,
.btn-text-default.active {
background-color: #7d858c !important;
color: white;
-webkit-box-shadow: none;
box-shadow: none;
border: 1px solid transparent;
background-color: #7d858c !important;
color: white;
-webkit-box-shadow: none;
box-shadow: none;
border: 1px solid transparent;
}
.btn-text-default[disabled]:hover,
@ -65,382 +65,380 @@ body {
.btn-text-default[disabled].active,
.btn-text-default.disabled:active,
.btn-text-default.disabled.active {
background-color: #fff !important;
color: #444444;
cursor: default;
background-color: #fff !important;
color: #444444;
cursor: default;
}
.btn-text-default[disabled],
.btn-text-default.disabled {
opacity: 0.65;
opacity: 0.65;
}
.btn-edit {
width: 13px;
height: 13px;
cursor: pointer;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGZSURBVHgBfZI/y4FRGMavx7+SRQaTTQab74CVlBKL/FukDGQhEgsDNh/Apiw+gcXm70DJoEikKMUk7vec8/Yi75O7Tj2d+/4913Wuc6Tz+UyQqev1itvtBr1e/6+nkgP2+z0qlYr4DgaDsNls36HtdotisYhoNAqLxYJyuSz230HFO7DZbISC0+lEp9OBRqNBLpdDq9XCeDx+DfIz8TWZTIhZodFoRMvlknw+H8XjcdrtdrRarYgpU6/XE7MC4oMc4OB8Pie/30/ZbJba7TYlk0k6HA4CDIVCxNyQYrFYoNFoIJ1OQ5Ik5PN5WK1WpFIprNdr8H61WhVn5X2VisXg8XhoNpvRYDAgt9tNbICOxyOVSiVyuVzU7/epXq9TIBAQtrkzxeVygclkQrfbhd1uRzgcRq1Ww3A4FKparRbspyJRo9H4G4TD4RD06XQS3pkt8nq9NJ1OiSVGsVjsqfC3nvekVCrxeDxgMBgQiUTEa2g2m8hkMi8FuXtSq9VIJBK43+8iHB7GJ8BL4vY+N3U6HQqFAsxmM+TqB5Je/SVNoN18AAAAAElFTkSuQmCC');
width: 13px;
height: 13px;
cursor: pointer;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGZSURBVHgBfZI/y4FRGMavx7+SRQaTTQab74CVlBKL/FukDGQhEgsDNh/Apiw+gcXm70DJoEikKMUk7vec8/Yi75O7Tj2d+/4913Wuc6Tz+UyQqev1itvtBr1e/6+nkgP2+z0qlYr4DgaDsNls36HtdotisYhoNAqLxYJyuSz230HFO7DZbISC0+lEp9OBRqNBLpdDq9XCeDx+DfIz8TWZTIhZodFoRMvlknw+H8XjcdrtdrRarYgpU6/XE7MC4oMc4OB8Pie/30/ZbJba7TYlk0k6HA4CDIVCxNyQYrFYoNFoIJ1OQ5Ik5PN5WK1WpFIprNdr8H61WhVn5X2VisXg8XhoNpvRYDAgt9tNbICOxyOVSiVyuVzU7/epXq9TIBAQtrkzxeVygclkQrfbhd1uRzgcRq1Ww3A4FKparRbspyJRo9H4G4TD4RD06XQS3pkt8nq9NJ1OiSVGsVjsqfC3nvekVCrxeDxgMBgQiUTEa2g2m8hkMi8FuXtSq9VIJBK43+8iHB7GJ8BL4vY+N3U6HQqFAsxmM+TqB5Je/SVNoN18AAAAAElFTkSuQmCC');
}
/* div button */
div.btn-text-default {
height: fit-content !important;
min-height: 20px;
height: fit-content !important;
min-height: 20px;
}
/* input, textarea */
.form-control {
border: 1px solid #cfcfcf;
border-radius: 2px;
box-sizing: border-box;
color: #444444;
font-size: 11px;
height: 22px;
padding: 1px 3px;
-webkit-box-shadow: none;
box-shadow: none;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
border: 1px solid #cfcfcf;
border-radius: 2px;
box-sizing: border-box;
color: #444444;
font-size: 11px;
height: 22px;
padding: 1px 3px;
-webkit-box-shadow: none;
box-shadow: none;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
}
.form-control:focus {
border-color: #848484;
outline: 0;
-webkit-box-shadow: none;
box-shadow: none;
border-color: #848484;
outline: 0;
-webkit-box-shadow: none;
box-shadow: none;
}
.form-control[readonly] {
background-color: #fff;
cursor: pointer;
background-color: #fff;
cursor: pointer;
}
.form-control[disabled] {
background-color: #fff;
cursor: default;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
opacity: 0.65;
background-color: #fff;
cursor: default;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
opacity: 0.65;
}
textarea.form-control {
resize: none;
resize: none;
}
input[type='checkbox'].form-control {
height: auto;
margin: 0;
height: auto;
margin: 0;
}
@supports(-webkit-appearance: none) or (-moz-appearance: none) {
input[type='checkbox'].form-control {
-webkit-appearance: none;
-moz-appearance: none;
width: 14px;
height: 14px;
background: #fff;
border: 1px solid #cfcfcf;
border-radius: 2px;
padding: 0;
position: relative;
margin: 0;
}
@supports (-webkit-appearance: none) or (-moz-appearance: none) {
input[type='checkbox'].form-control {
-webkit-appearance: none;
-moz-appearance: none;
width: 14px;
height: 14px;
background: #fff;
border: 1px solid #cfcfcf;
border-radius: 2px;
padding: 0;
position: relative;
margin: 0;
}
input[type='checkbox'].form-control:checked:after {
content: '';
position: absolute;
border: solid #444444;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
width: 3px;
height: 7px;
left: 4px;
}
input[type='checkbox'].form-control:checked:after {
content: '';
position: absolute;
border: solid #444444;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
width: 3px;
height: 7px;
left: 4px;
}
input[type='checkbox'].form-control:disabled {
opacity: .5;
}
input[type='checkbox'].form-control:disabled {
opacity: 0.5;
}
input[type='radio'].form-control {
appearance: none;
-webkit-appearance: none;
border: 2px solid #fff;
border-radius: 100%;
box-shadow: 0 0 0 1px #cfcfcf;
height: 12px;
width: 12px;
accent-color: #444;
margin: 0 0 1px;
background-color: #fff;
}
input[type='radio'].form-control {
appearance: none;
-webkit-appearance: none;
border: 2px solid #fff;
border-radius: 100%;
box-shadow: 0 0 0 1px #cfcfcf;
height: 12px;
width: 12px;
accent-color: #444;
margin: 0 0 1px;
background-color: #fff;
}
input[type='radio'].form-control:checked {
background-color: #444;
}
input[type='radio'].form-control:checked {
background-color: #444;
}
input[type='radio'].form-control:disabled {
opacity: .5;
}
input[type='radio'].form-control:disabled {
opacity: 0.5;
}
}
/* label */
label.link {
border-bottom: 1px dotted #aaa;
cursor: pointer;
border-bottom: 1px dotted #aaa;
cursor: pointer;
}
label.for-combo {
height: 22px;
padding-top: 4px;
height: 22px;
padding-top: 4px;
}
label.header {
font-weight: bold;
font-weight: bold;
}
/* comments */
.user-comment-item {
padding: 5px 0;
width: 100%;
padding: 5px 0;
width: 100%;
}
.user-comment-item .main-actions{
width: 100%;
display: flex;
padding-bottom: 8px;
font-size: 12px;
.user-comment-item .main-actions {
width: 100%;
display: flex;
padding-bottom: 8px;
font-size: 12px;
}
.user-comment-item .form-control.user-check {
margin-right: 5px;
flex-grow: 0;
flex-shrink: 0;
margin-right: 5px;
flex-grow: 0;
flex-shrink: 0;
}
.user-comment-item .user-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: bold;
max-width: 40%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: bold;
max-width: 40%;
}
.user-comment-item .user-message {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-grow: 1;
margin-left: 2px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-grow: 1;
margin-left: 2px;
}
.user-comment-item .btn-edit {
width: 13px;
height: 13px;
margin-left: 5px;
flex-grow: 0;
flex-shrink: 0;
cursor: pointer;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGZSURBVHgBfZI/y4FRGMavx7+SRQaTTQab74CVlBKL/FukDGQhEgsDNh/Apiw+gcXm70DJoEikKMUk7vec8/Yi75O7Tj2d+/4913Wuc6Tz+UyQqev1itvtBr1e/6+nkgP2+z0qlYr4DgaDsNls36HtdotisYhoNAqLxYJyuSz230HFO7DZbISC0+lEp9OBRqNBLpdDq9XCeDx+DfIz8TWZTIhZodFoRMvlknw+H8XjcdrtdrRarYgpU6/XE7MC4oMc4OB8Pie/30/ZbJba7TYlk0k6HA4CDIVCxNyQYrFYoNFoIJ1OQ5Ik5PN5WK1WpFIprNdr8H61WhVn5X2VisXg8XhoNpvRYDAgt9tNbICOxyOVSiVyuVzU7/epXq9TIBAQtrkzxeVygclkQrfbhd1uRzgcRq1Ww3A4FKparRbspyJRo9H4G4TD4RD06XQS3pkt8nq9NJ1OiSVGsVjsqfC3nvekVCrxeDxgMBgQiUTEa2g2m8hkMi8FuXtSq9VIJBK43+8iHB7GJ8BL4vY+N3U6HQqFAsxmM+TqB5Je/SVNoN18AAAAAElFTkSuQmCC');
width: 13px;
height: 13px;
margin-left: 5px;
flex-grow: 0;
flex-shrink: 0;
cursor: pointer;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGZSURBVHgBfZI/y4FRGMavx7+SRQaTTQab74CVlBKL/FukDGQhEgsDNh/Apiw+gcXm70DJoEikKMUk7vec8/Yi75O7Tj2d+/4913Wuc6Tz+UyQqev1itvtBr1e/6+nkgP2+z0qlYr4DgaDsNls36HtdotisYhoNAqLxYJyuSz230HFO7DZbISC0+lEp9OBRqNBLpdDq9XCeDx+DfIz8TWZTIhZodFoRMvlknw+H8XjcdrtdrRarYgpU6/XE7MC4oMc4OB8Pie/30/ZbJba7TYlk0k6HA4CDIVCxNyQYrFYoNFoIJ1OQ5Ik5PN5WK1WpFIprNdr8H61WhVn5X2VisXg8XhoNpvRYDAgt9tNbICOxyOVSiVyuVzU7/epXq9TIBAQtrkzxeVygclkQrfbhd1uRzgcRq1Ww3A4FKparRbspyJRo9H4G4TD4RD06XQS3pkt8nq9NJ1OiSVGsVjsqfC3nvekVCrxeDxgMBgQiUTEa2g2m8hkMi8FuXtSq9VIJBK43+8iHB7GJ8BL4vY+N3U6HQqFAsxmM+TqB5Je/SVNoN18AAAAAElFTkSuQmCC');
}
.user-comment-item .reply-actions,
.user-comment-item .comment-edit {
padding-left: 18px;
padding-bottom: 10px;
padding-left: 18px;
padding-bottom: 10px;
}
.user-comment-item .reply-view {
padding-left: 18px;
padding-left: 18px;
}
.user-comment-item .reply-view .comment-edit{
padding-left: 0;
.user-comment-item .reply-view .comment-edit {
padding-left: 0;
}
.user-comment-item .msg-edit {
width: 100%;
height: 45px;
margin-bottom: 3px;
width: 100%;
height: 45px;
margin-bottom: 3px;
}
.user-comment-item .reply-accept {
margin-bottom: 7px;
margin-bottom: 7px;
}
.user-comment-item .reply-accept label,
.user-comment-item .reply-accept .user-check {
vertical-align: middle;
vertical-align: middle;
}
/* common styles */
.hidden {
display: none;
display: none;
}
.separator.horizontal {
width: 100%;
height: 0;
border-left: none;
border-right: none;
border-top: 1px solid #cbcbcb;
width: 100%;
height: 0;
border-left: none;
border-right: none;
border-top: 1px solid #cbcbcb;
}
.defaultlable {
color: #444444;
cursor: default;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 11px;
font-weight: normal;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
color: #444444;
cursor: default;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 11px;
font-weight: normal;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.defaultcenterlable {
color: #444444;
cursor: default;
text-align: center;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 11px;
font-style: normal;
font-weight: normal;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
margin: 0px;
padding: 0px;
width: 100%;
color: #444444;
cursor: default;
text-align: center;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 11px;
font-style: normal;
font-weight: normal;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
margin: 0px;
padding: 0px;
width: 100%;
}
.aboutlable {
color: #444444;
cursor: default;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 12px;
font-weight: normal;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
color: #444444;
cursor: default;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12px;
font-weight: normal;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
a.aboutlink {
color: #444444;
text-decoration: none;
color: #444444;
text-decoration: none;
}
a.aboutlink:hover {
text-decoration: underline;
text-decoration: underline;
}
a.aboutlink:active {
text-decoration: underline;
text-decoration: underline;
}
.noselect{
-khtml-user-select: none;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
.noselect {
-khtml-user-select: none;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
}
.select2-dropdown,
.select2-container--default .select2-selection--single {
border: 1px solid #cfcfcf !important;
border: 1px solid #cfcfcf !important;
}
.select2-container--default.select2-container--open .select2-selection--single,
.select2-container--default.select2-container--focus:not(.select2-container--disabled) .select2-selection--single{
border-color: #848484 !important;
.select2-container--default.select2-container--focus:not(.select2-container--disabled) .select2-selection--single {
border-color: #848484 !important;
}
.select2-container .select2-selection--single .select2-selection__rendered,
.select2-results__options {
font-size: 11px !important;
font-size: 11px !important;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: 20px !important;
line-height: 20px !important;
}
.select2-container--default .select2-results__option[aria-selected=true] {
color: #ffffff;
.select2-container--default .select2-results__option[aria-selected='true'] {
color: #ffffff;
}
.select2-container--default .select2-selection--single .select2-selection__arrow b{
width: 4px !important;
height: 4px !important;
margin: -1px 1px !important;
border: solid 1px #444 !important;
border-bottom: none !important;
border-right: none !important;
background-image: none;
box-sizing: border-box;
.select2-container--default .select2-selection--single .select2-selection__arrow b {
width: 4px !important;
height: 4px !important;
margin: -1px 1px !important;
border: solid 1px #444 !important;
border-bottom: none !important;
border-right: none !important;
background-image: none;
box-sizing: border-box;
transition: transform 0.2s ease;
transform: rotate(-135deg) translate(1px,1px);
transition: transform 0.2s ease;
transform: rotate(-135deg) translate(1px, 1px);
}
.select2-container--default .select2-search .select2-selection__arrow b {
width: 4px !important;
height: 4px !important;
margin: -1px 1px !important;
border: solid 1px #404040 !important;
border-bottom: none !important;
border-right: none !important;
background-image: none;
box-sizing: border-box;
transition: transform 0.2s ease;
transform: rotate(-135deg) translate(1px,1px);
left: 50%;
position: absolute;
top: 50%;
width: 4px !important;
height: 4px !important;
margin: -1px 1px !important;
border: solid 1px #404040 !important;
border-bottom: none !important;
border-right: none !important;
background-image: none;
box-sizing: border-box;
transition: transform 0.2s ease;
transform: rotate(-135deg) translate(1px, 1px);
left: 50%;
position: absolute;
top: 50%;
}
.select2-search--dropdown {
padding: 0px !important;
padding: 0px !important;
}
.select2-container--default.select2-container--open .select2-selection__arrow b{
transform: rotate(45deg);
.select2-container--default.select2-container--open .select2-selection__arrow b {
transform: rotate(45deg);
}
.select2-container--default .select2-search--dropdown .select2-search__field {
outline: none;
border-color: #cfcfcf;
border-radius: 2px;
font-size: 11px;
outline: none;
border-color: #cfcfcf;
border-radius: 2px;
font-size: 11px;
}
.select2-search.select2-search--dropdown .select2-selection__arrow {
height: 20px;
position: absolute;
top: 1px;
right: 1px;
width: 20px;
height: 20px;
position: absolute;
top: 1px;
right: 1px;
width: 20px;
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
background-color: #d8dadc !important;
background-color: #d8dadc !important;
}
.select2-container--default .select2-results__option--highlighted[aria-selected=true] {
background-color: #7d858c !important;
.select2-container--default .select2-results__option--highlighted[aria-selected='true'] {
background-color: #7d858c !important;
}
.select2-search.select2-search--dropdown .select2-selection__arrow {
cursor: pointer !important
cursor: pointer !important;
}
.select2-container {
max-height : 20px !important;
max-height: 20px !important;
}
.select2-container--default.select2-container--disabled{
opacity: 0.65 !important
.select2-container--default.select2-container--disabled {
opacity: 0.65 !important;
}
/*
* Container style
@ -466,20 +464,24 @@ a.aboutlink:active {
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
transition: background-color .2s linear, opacity .2s linear;
transition:
background-color 0.2s linear,
opacity 0.2s linear;
}
.ps__rail-y {
display: none;
right: 2px; /* there must be 'right' for ps-scrollbar-y-rail */
width: 9px;
margin: 2px 0 2px 0;
right: 2px; /* there must be 'right' for ps-scrollbar-y-rail */
width: 9px;
margin: 2px 0 2px 0;
/* please don't change 'position' */
position: absolute;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
transition: background-color .2s linear, opacity .2s linear;
transition:
background-color 0.2s linear,
opacity 0.2s linear;
}
.ps--active-x > .ps__rail-x,
@ -494,46 +496,46 @@ a.aboutlink:active {
.ps .ps__rail-y:focus,
.ps .ps__rail-x.ps--clicking,
.ps .ps__rail-y.ps--clicking {
background-color: #EEEEEE;
background-color: #eeeeee;
}
/*
* Scrollbar thumb styles
*/
.ps__thumb-x {
position: absolute; /* please don't change 'position' */
bottom: 0; /* there must be 'bottom' for ps-scrollbar-x */
height: 9px;
background-color: rgb(241, 241, 241);
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
visibility: visible;
display: block;
box-sizing: border-box;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAAACXBIWXMAAB2HAAAdhwGP5fFlAAAALElEQVQokWNgoBs4f/78f1JpJnIsIkvTsAQfP378TypNxyD/+PEjyRrJsgkAKS81km7nDNQAAAAASUVORK5CYII=);
image-rendering: pixelated;
background-repeat: no-repeat;
background-position: center 0;
border: 1px solid #cfcfcf;
position: absolute; /* please don't change 'position' */
bottom: 0; /* there must be 'bottom' for ps-scrollbar-x */
height: 9px;
background-color: rgb(241, 241, 241);
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
visibility: visible;
display: block;
box-sizing: border-box;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAAACXBIWXMAAB2HAAAdhwGP5fFlAAAALElEQVQokWNgoBs4f/78f1JpJnIsIkvTsAQfP378TypNxyD/+PEjyRrJsgkAKS81km7nDNQAAAAASUVORK5CYII=);
image-rendering: pixelated;
background-repeat: no-repeat;
background-position: center 0;
border: 1px solid #cfcfcf;
}
.ps__thumb-y {
position: absolute; /* please don't change 'position' */
right: 0; /* there must be 'right' for ps-scrollbar-y */
width: 9px;
background-color: rgb(241, 241, 241);
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
visibility: visible;
display: block;
box-sizing: border-box;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAQAAAAz1Zf0AAAAIUlEQVR42mNgAILz/0GQAQo+/gdBBqLAqE5ydH5k+sgEANHgUH2JtDRHAAAAAElFTkSuQmCC);
image-rendering: pixelated;
background-repeat: no-repeat;
background-position: 0 center;
border: 1px solid #cfcfcf;
position: absolute; /* please don't change 'position' */
right: 0; /* there must be 'right' for ps-scrollbar-y */
width: 9px;
background-color: rgb(241, 241, 241);
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
visibility: visible;
display: block;
box-sizing: border-box;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAQAAAAz1Zf0AAAAIUlEQVR42mNgAILz/0GQAQo+/gdBBqLAqE5ydH5k+sgEANHgUH2JtDRHAAAAAElFTkSuQmCC);
image-rendering: pixelated;
background-repeat: no-repeat;
background-position: 0 center;
border: 1px solid #cfcfcf;
}
.ps__rail-x:hover > .ps__thumb-x {
@ -577,52 +579,51 @@ a.aboutlink:active {
/* loader */
@keyframes rotation {
from {
transform: rotate(0deg);
}
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
to {
transform: rotate(360deg);
}
}
.asc-loader-container {
position: relative;
position: relative;
}
.asc-plugin-loader {
position: absolute;
left: 50%;
top: 50%;
margin-top: -10px;
z-index: 10000;
line-height: 20px;
background-image: none;
background-color: transparent;
color: #444444;
transform: translate(-50%, 0);
position: absolute;
left: 50%;
top: 50%;
margin-top: -10px;
z-index: 10000;
line-height: 20px;
background-image: none;
background-color: transparent;
color: #444444;
transform: translate(-50%, 0);
}
.asc-plugin-loader .asc-loader-image {
height: 20px;
width: 20px;
float: left;
margin-top: -1px;
height: 20px;
width: 20px;
float: left;
margin-top: -1px;
animation-duration: .8s;
animation-name: rotation;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-duration: 0.8s;
animation-name: rotation;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
.asc-loader-image-light {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyOCAyOCI+PGNpcmNsZSBjeD0iMTQiIGN5PSIxNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjEuNSIgcj0iMTAuMjUiIHN0cm9rZS1kYXNoYXJyYXk9IjE2MCUsIDQwJSIgLz48L3N2Zz4=);
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyOCAyOCI+PGNpcmNsZSBjeD0iMTQiIGN5PSIxNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjEuNSIgcj0iMTAuMjUiIHN0cm9rZS1kYXNoYXJyYXk9IjE2MCUsIDQwJSIgLz48L3N2Zz4=);
}
.asc-loader-image-dark {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAyMCI+PGNpcmNsZSBjeD0iMTAiIGN5PSIxMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNDQ0IiBzdHJva2Utd2lkdGg9IjEuNSIgcj0iNy4yNSIgc3Ryb2tlLWRhc2hhcnJheT0iMTYwJSwgNDAlIiAvPjwvc3ZnPg==);
.asc-loader-image-dark {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAyMCI+PGNpcmNsZSBjeD0iMTAiIGN5PSIxMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNDQ0IiBzdHJva2Utd2lkdGg9IjEuNSIgcj0iNy4yNSIgc3Ryb2tlLWRhc2hhcnJheT0iMTYwJSwgNDAlIiAvPjwvc3ZnPg==);
}
.asc-plugin-loader .asc-loader-title {
font-size: 13px;
padding-left: 25px;
min-width: 100px;
font-size: 13px;
padding-left: 25px;
min-width: 100px;
}
/* default scroll */
@ -632,35 +633,35 @@ a.aboutlink:active {
} */
*::-webkit-scrollbar {
width: 9px;
height: 9px;
width: 9px;
height: 9px;
}
*::-webkit-scrollbar-thumb {
border-radius: 2px;
border: 1px solid;
image-rendering: pixelated;
background-repeat: no-repeat;
cursor: default;
border-radius: 2px;
border: 1px solid;
image-rendering: pixelated;
background-repeat: no-repeat;
cursor: default;
}
*::-webkit-scrollbar-track {
cursor: default;
cursor: default;
}
*::-webkit-scrollbar-thumb:vertical {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAQAAAAz1Zf0AAAAIUlEQVR42mNgAILz/0GQAQo+/gdBBqLAqE5ydH5k+sgEANHgUH2JtDRHAAAAAElFTkSuQmCC);
background-position: 0px center;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAQAAAAz1Zf0AAAAIUlEQVR42mNgAILz/0GQAQo+/gdBBqLAqE5ydH5k+sgEANHgUH2JtDRHAAAAAElFTkSuQmCC);
background-position: 0px center;
}
*::-webkit-scrollbar-thumb:horizontal {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAAACXBIWXMAAB2HAAAdhwGP5fFlAAAALElEQVQokWNgoBs4f/78f1JpJnIsIkvTsAQfP378TypNxyD/+PEjyRrJsgkAKS81km7nDNQAAAAASUVORK5CYII=);
background-position: center 0px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAAACXBIWXMAAB2HAAAdhwGP5fFlAAAALElEQVQokWNgoBs4f/78f1JpJnIsIkvTsAQfP378TypNxyD/+PEjyRrJsgkAKS81km7nDNQAAAAASUVORK5CYII=);
background-position: center 0px;
}
*::-webkit-scrollbar-thumb:vertical:hover {
background-position: -7px center;
background-position: -7px center;
}
*::-webkit-scrollbar-thumb:horizontal:hover {
background-position: center -7px;
background-position: center -7px;
}

File diff suppressed because it is too large Load Diff

View File

@ -4,32 +4,32 @@
*/
const AIIntegration = {
// Current state
prevView: null,
currentView: 'settings',
isCollapsed: true,
// Current state
prevView: null,
currentView: 'settings',
isCollapsed: true,
// Callback functions
onSave: null,
onOk: null,
onResetActions: null,
onResetAllSettings: null,
// Callback functions
onSave: null,
onOk: null,
onResetActions: null,
onResetAllSettings: null,
// Initialize the AI integration
init() {
this.createAISection();
this.bindEvents();
this.loadCurrentView();
},
// Initialize the AI integration
init() {
this.createAISection();
this.bindEvents();
this.loadCurrentView();
},
/**
* Create the AI settings section in the DOM
*/
createAISection() {
const targetElement = document.getElementById('ai-settings-section');
if (!targetElement) return;
/**
* Create the AI settings section in the DOM
*/
createAISection() {
const targetElement = document.getElementById('ai-settings-section');
if (!targetElement) return;
targetElement.innerHTML = `
targetElement.innerHTML = `
<div class="ai-spoiler collapsed" id="ai-spoiler">
AI Models Configuration
</div>
@ -52,262 +52,261 @@ const AIIntegration = {
</div>
</div>
`;
},
},
/**
* Bind event handlers
*/
bindEvents() {
const spoiler = document.getElementById('ai-spoiler');
const btnBack = document.getElementById('ai-btn-back');
const btnCancel = document.getElementById('ai-btn-cancel');
const btnSave = document.getElementById('ai-btn-save');
const btnOk = document.getElementById('ai-btn-ok');
const btnResetActions = document.getElementById('ai-btn-reset-actions');
const btnResetAllSettings = document.getElementById('ai-btn-reset-all-settings');
const iframeSettings = document.getElementById('ai-iframe-settings');
const iframeEdit = document.getElementById('ai-iframe-edit');
const iframeList = document.getElementById('ai-iframe-list');
/**
* Bind event handlers
*/
bindEvents() {
const spoiler = document.getElementById('ai-spoiler');
const btnBack = document.getElementById('ai-btn-back');
const btnCancel = document.getElementById('ai-btn-cancel');
const btnSave = document.getElementById('ai-btn-save');
const btnOk = document.getElementById('ai-btn-ok');
const btnResetActions = document.getElementById('ai-btn-reset-actions');
const btnResetAllSettings = document.getElementById('ai-btn-reset-all-settings');
const iframeSettings = document.getElementById('ai-iframe-settings');
const iframeEdit = document.getElementById('ai-iframe-edit');
const iframeList = document.getElementById('ai-iframe-list');
if (spoiler) {
spoiler.addEventListener('click', () => this.toggleSpoiler());
}
if (btnBack) {
btnBack.addEventListener('click', () => this.goBack());
}
if (btnCancel) {
btnCancel.addEventListener('click', () => this.cancel());
}
if (btnSave) {
btnSave.addEventListener('click', () => this.save());
}
if (btnOk) {
btnOk.addEventListener('click', () => this.ok());
}
if (btnResetActions) {
btnResetActions.addEventListener('click', () => this.resetActions());
}
if (btnResetAllSettings) {
btnResetAllSettings.addEventListener('click', () => this.resetAllSettings());
}
if (iframeSettings) {
iframeSettings.addEventListener('load', () => this.onIframeLoad());
}
if (iframeEdit) {
iframeEdit.addEventListener('load', () => this.onIframeLoad());
}
if (iframeList) {
iframeList.addEventListener('load', () => this.onIframeLoad());
}
},
/**
* Toggle the spoiler visibility
*/
toggleSpoiler() {
const spoiler = document.getElementById('ai-spoiler');
const content = document.getElementById('ai-content');
if (!spoiler || !content) return;
this.isCollapsed = !this.isCollapsed;
if (this.isCollapsed) {
spoiler.classList.add('collapsed');
content.classList.add('collapsed');
} else {
spoiler.classList.remove('collapsed');
content.classList.remove('collapsed');
this.loadCurrentView();
}
},
/**
* Load the current view in the iframe
* @returns {void} No return value
*/
loadCurrentView() {
if (this.isCollapsed) return;
const iframeSettings = document.getElementById('ai-iframe-settings');
const iframeEdit = document.getElementById('ai-iframe-edit');
const iframeList = document.getElementById('ai-iframe-list');
if (!iframeSettings || !iframeEdit || !iframeList) return;
// Hide all iframes first
[iframeSettings, iframeEdit, iframeList].forEach(iframe => {
iframe.classList.add('hidden');
});
// Show loading overlay
const overlay = document.getElementById('ai-overlay');
if (overlay) {
overlay.classList.add('loading');
}
// Always reassign src to force reload, then show the appropriate iframe
switch (this.currentView) {
case 'settings':
iframeSettings.src = 'ai/settings.html';
iframeSettings.classList.remove('hidden');
break;
case 'aiModelEdit':
iframeEdit.src = 'ai/aiModelEdit.html';
iframeEdit.classList.remove('hidden');
break;
case 'aiModelsList':
iframeList.src = 'ai/aiModelsList.html';
iframeList.classList.remove('hidden');
break;
default:
iframeSettings.src = 'ai/settings.html';
iframeSettings.classList.remove('hidden');
}
this.updateControls();
},
/**
* Update control buttons visibility based on current view
*/
updateControls() {
const btnBack = document.getElementById('ai-btn-back');
const btnCancel = document.getElementById('ai-btn-cancel');
const btnSave = document.getElementById('ai-btn-save');
const btnOk = document.getElementById('ai-btn-ok');
const btnResetActions = document.getElementById('ai-btn-reset-actions');
const btnResetAllSettings = document.getElementById('ai-btn-reset-all-settings');
// Hide all buttons first
[btnBack, btnCancel, btnSave, btnOk, btnResetActions, btnResetAllSettings].forEach(btn => {
if (btn) btn.style.display = 'none';
});
// Show buttons based on current view
switch (this.currentView) {
case 'settings':
if (btnSave) btnSave.style.display = 'inline-block';
if (btnResetActions) btnResetActions.style.display = 'inline-block';
if (btnResetAllSettings) btnResetAllSettings.style.display = 'inline-block';
break;
case 'aiModelEdit':
if (btnOk) btnOk.style.display = 'inline-block';
if (btnCancel) btnCancel.style.display = 'inline-block';
break;
case 'aiModelsList':
if (btnBack) btnBack.style.display = 'inline-block';
break;
}
},
/**
* Handle iframe load event
* @returns {void} No return value
*/
onIframeLoad() {
const overlay = document.getElementById('ai-overlay');
if (overlay) {
// Hide loading overlay after a short delay
setTimeout(() => {
overlay.classList.remove('loading');
}, 300);
}
},
/**
* Navigate to a specific view
* @param {string} view - The view to navigate to ('settings', 'aiModelEdit', 'aiModelsList')
*/
navigateToView(view) {
this.prevView = this.currentView
this.currentView = view;
this.loadCurrentView();
},
save() {
if (this.onSave) {
this.onSave().then((res) => {
const btnSave = document.getElementById('ai-btn-save');
if (btnSave) {
const originalText = btnSave.textContent;
btnSave.textContent = res ? 'Saved!' : 'Save failed!';
btnSave.disabled = true;
setTimeout(() => {
btnSave.textContent = originalText;
btnSave.disabled = false;
}, 2000);
}
});
}
},
goBack() {
this.navigateToView('settings');
if (this.onBack) {
this.onBack();
}
},
ok() {
this.navigateToView(this.prevView || 'aiModelsList');
if (this.onOk) {
this.onOk();
}
},
cancel() {
this.navigateToView(this.prevView || 'aiModelsList');
},
resetActions() {
if (this.onResetActions) {
this.onResetActions().then((res) => {
const btnResetActions = document.getElementById('ai-btn-reset-actions');
if (btnResetActions) {
const originalText = btnResetActions.textContent;
btnResetActions.textContent = res ? 'Tasks Reset!' : 'Reset Failed!';
btnResetActions.disabled = true;
setTimeout(() => {
btnResetActions.textContent = originalText;
btnResetActions.disabled = false;
}, 2000);
}
});
}
},
resetAllSettings() {
if (this.onResetAllSettings) {
this.onResetAllSettings().then((res) => {
const btnResetAllSettings = document.getElementById('ai-btn-reset-all-settings');
if (btnResetAllSettings) {
const originalText = btnResetAllSettings.textContent;
btnResetAllSettings.textContent = res ? 'Defaults Restored!' : 'Restore Failed!';
btnResetAllSettings.disabled = true;
setTimeout(() => {
btnResetAllSettings.textContent = originalText;
btnResetAllSettings.disabled = false;
}, 2000);
}
});
}
if (spoiler) {
spoiler.addEventListener('click', () => this.toggleSpoiler());
}
if (btnBack) {
btnBack.addEventListener('click', () => this.goBack());
}
if (btnCancel) {
btnCancel.addEventListener('click', () => this.cancel());
}
if (btnSave) {
btnSave.addEventListener('click', () => this.save());
}
if (btnOk) {
btnOk.addEventListener('click', () => this.ok());
}
if (btnResetActions) {
btnResetActions.addEventListener('click', () => this.resetActions());
}
if (btnResetAllSettings) {
btnResetAllSettings.addEventListener('click', () => this.resetAllSettings());
}
if (iframeSettings) {
iframeSettings.addEventListener('load', () => this.onIframeLoad());
}
if (iframeEdit) {
iframeEdit.addEventListener('load', () => this.onIframeLoad());
}
if (iframeList) {
iframeList.addEventListener('load', () => this.onIframeLoad());
}
},
/**
* Toggle the spoiler visibility
*/
toggleSpoiler() {
const spoiler = document.getElementById('ai-spoiler');
const content = document.getElementById('ai-content');
if (!spoiler || !content) return;
this.isCollapsed = !this.isCollapsed;
if (this.isCollapsed) {
spoiler.classList.add('collapsed');
content.classList.add('collapsed');
} else {
spoiler.classList.remove('collapsed');
content.classList.remove('collapsed');
this.loadCurrentView();
}
},
/**
* Load the current view in the iframe
* @returns {void} No return value
*/
loadCurrentView() {
if (this.isCollapsed) return;
const iframeSettings = document.getElementById('ai-iframe-settings');
const iframeEdit = document.getElementById('ai-iframe-edit');
const iframeList = document.getElementById('ai-iframe-list');
if (!iframeSettings || !iframeEdit || !iframeList) return;
// Hide all iframes first
[iframeSettings, iframeEdit, iframeList].forEach(iframe => {
iframe.classList.add('hidden');
});
// Show loading overlay
const overlay = document.getElementById('ai-overlay');
if (overlay) {
overlay.classList.add('loading');
}
// Always reassign src to force reload, then show the appropriate iframe
switch (this.currentView) {
case 'settings':
iframeSettings.src = 'ai/settings.html';
iframeSettings.classList.remove('hidden');
break;
case 'aiModelEdit':
iframeEdit.src = 'ai/aiModelEdit.html';
iframeEdit.classList.remove('hidden');
break;
case 'aiModelsList':
iframeList.src = 'ai/aiModelsList.html';
iframeList.classList.remove('hidden');
break;
default:
iframeSettings.src = 'ai/settings.html';
iframeSettings.classList.remove('hidden');
}
this.updateControls();
},
/**
* Update control buttons visibility based on current view
*/
updateControls() {
const btnBack = document.getElementById('ai-btn-back');
const btnCancel = document.getElementById('ai-btn-cancel');
const btnSave = document.getElementById('ai-btn-save');
const btnOk = document.getElementById('ai-btn-ok');
const btnResetActions = document.getElementById('ai-btn-reset-actions');
const btnResetAllSettings = document.getElementById('ai-btn-reset-all-settings');
// Hide all buttons first
[btnBack, btnCancel, btnSave, btnOk, btnResetActions, btnResetAllSettings].forEach(btn => {
if (btn) btn.style.display = 'none';
});
// Show buttons based on current view
switch (this.currentView) {
case 'settings':
if (btnSave) btnSave.style.display = 'inline-block';
if (btnResetActions) btnResetActions.style.display = 'inline-block';
if (btnResetAllSettings) btnResetAllSettings.style.display = 'inline-block';
break;
case 'aiModelEdit':
if (btnOk) btnOk.style.display = 'inline-block';
if (btnCancel) btnCancel.style.display = 'inline-block';
break;
case 'aiModelsList':
if (btnBack) btnBack.style.display = 'inline-block';
break;
}
},
/**
* Handle iframe load event
* @returns {void} No return value
*/
onIframeLoad() {
const overlay = document.getElementById('ai-overlay');
if (overlay) {
// Hide loading overlay after a short delay
setTimeout(() => {
overlay.classList.remove('loading');
}, 300);
}
},
/**
* Navigate to a specific view
* @param {string} view - The view to navigate to ('settings', 'aiModelEdit', 'aiModelsList')
*/
navigateToView(view) {
this.prevView = this.currentView;
this.currentView = view;
this.loadCurrentView();
},
save() {
if (this.onSave) {
this.onSave().then(res => {
const btnSave = document.getElementById('ai-btn-save');
if (btnSave) {
const originalText = btnSave.textContent;
btnSave.textContent = res ? 'Saved!' : 'Save failed!';
btnSave.disabled = true;
setTimeout(() => {
btnSave.textContent = originalText;
btnSave.disabled = false;
}, 2000);
}
});
}
},
goBack() {
this.navigateToView('settings');
if (this.onBack) {
this.onBack();
}
},
ok() {
this.navigateToView(this.prevView || 'aiModelsList');
if (this.onOk) {
this.onOk();
}
},
cancel() {
this.navigateToView(this.prevView || 'aiModelsList');
},
resetActions() {
if (this.onResetActions) {
this.onResetActions().then(res => {
const btnResetActions = document.getElementById('ai-btn-reset-actions');
if (btnResetActions) {
const originalText = btnResetActions.textContent;
btnResetActions.textContent = res ? 'Tasks Reset!' : 'Reset Failed!';
btnResetActions.disabled = true;
setTimeout(() => {
btnResetActions.textContent = originalText;
btnResetActions.disabled = false;
}, 2000);
}
});
}
},
resetAllSettings() {
if (this.onResetAllSettings) {
this.onResetAllSettings().then(res => {
const btnResetAllSettings = document.getElementById('ai-btn-reset-all-settings');
if (btnResetAllSettings) {
const originalText = btnResetAllSettings.textContent;
btnResetAllSettings.textContent = res ? 'Defaults Restored!' : 'Restore Failed!';
btnResetAllSettings.disabled = true;
setTimeout(() => {
btnResetAllSettings.textContent = originalText;
btnResetAllSettings.disabled = false;
}, 2000);
}
});
}
}
};
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
AIIntegration.init();
AIIntegration.init();
});

File diff suppressed because it is too large Load Diff

View File

@ -1,132 +1,129 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<head>
<title>ONLYOFFICE™</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=IE8"/>
<link href="img/favicon.ico" rel="icon" type="image/x-icon">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=IE8" />
<link href="img/favicon.ico" rel="icon" type="image/x-icon" />
<style type="text/css">
html {
height: 100%;
}
html {
height: 100%;
}
body {
height: 100%;
min-width: 600px;
margin: 0;
padding: 0;
overflow: hidden;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #333333;
}
body {
height: 100%;
min-width: 600px;
margin: 0;
padding: 0;
overflow: hidden;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
color: #333333;
}
#doc-server-header {
height: 80px;
font-size: 18px;
color: #adadad;
}
#doc-server-header {
height: 80px;
font-size: 18px;
color: #adadad;
}
#doc-server-footer {
height: 100px;
font-size: 12px;
line-height: 20px;
}
#doc-server-footer {
height: 100px;
font-size: 12px;
line-height: 20px;
}
#doc-server-status {
font-size: 24px;
font-weight: bold;
}
#doc-server-status {
font-size: 24px;
font-weight: bold;
}
#doc-server-status > div {
display: inline-block;
vertical-align: middle;
text-align: left;
}
#doc-server-status > div {
display: inline-block;
vertical-align: middle;
text-align: left;
}
#doc-server-status > div:first-child {
height: 48px;
}
#doc-server-status > div:first-child {
height: 48px;
}
#status-ok-icon {
width:48px;
margin-right: 15px;
background: url(img/icon-done.png) center no-repeat;
}
#status-ok-icon {
width: 48px;
margin-right: 15px;
background: url(img/icon-done.png) center no-repeat;
}
#status-err-icon {
width:48px;
margin-right: 15px;
background: url(img/icon-cross.png) center no-repeat;
}
#status-err-icon {
width: 48px;
margin-right: 15px;
background: url(img/icon-cross.png) center no-repeat;
}
#status-err-help {
font-size: 18px;
font-weight: normal;
margin-top: 5px;
}
#status-err-help {
font-size: 18px;
font-weight: normal;
margin-top: 5px;
}
</style>
</head>
<body>
</head>
<body>
<script>
document.write(
'<table width="100%" height="100%">' +
'<tr><td id="doc-server-header" valign="bottom" align="center">Thank you for choosing ONLYOFFICE!</td></tr>' +
'<tr><td align="center">' +
'<div id="doc-server-status"><div></div>Please, wait...</div>' +
'</td></tr>' +
'<tr><td id="doc-server-footer" valign="top" align="center">' +
'<div>Any questions?</div>' +
'<div>Explore ONLYOFFICE™ Document Server <a href="https://api.onlyoffice.com/editors/basic" target="_blank">API Documentation</a></div>' +
'<div>or visit our <a href="http://dev.onlyoffice.org/viewforum.php?f=44&sid=505c86017ee42e6005d24fc5b8c6818c" target="_blank">developers forum.</a></div>' +
'</td></tr>' +
'</table>'
);
document.write(
'<table width="100%" height="100%">' +
'<tr><td id="doc-server-header" valign="bottom" align="center">Thank you for choosing ONLYOFFICE!</td></tr>' +
'<tr><td align="center">' +
'<div id="doc-server-status"><div></div>Please, wait...</div>' +
'</td></tr>' +
'<tr><td id="doc-server-footer" valign="top" align="center">' +
'<div>Any questions?</div>' +
'<div>Explore ONLYOFFICE™ Document Server <a href="https://api.onlyoffice.com/editors/basic" target="_blank">API Documentation</a></div>' +
'<div>or visit our <a href="http://dev.onlyoffice.org/viewforum.php?f=44&sid=505c86017ee42e6005d24fc5b8c6818c" target="_blank">developers forum.</a></div>' +
'</td></tr>' +
'</table>'
);
var _createXMLHTTPObject = function() {
var xmlhttp;
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (E) {
xmlhttp = false;
}
}
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
xmlhttp = new XMLHttpRequest();
}
return xmlhttp;
};
var _createXMLHTTPObject = function () {
var xmlhttp;
try {
xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
} catch (E) {
xmlhttp = false;
}
}
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
xmlhttp = new XMLHttpRequest();
}
return xmlhttp;
};
(function(){
try {
var xhrObj = _createXMLHTTPObject();
if (xhrObj) {
var index_html = window["location"]["href"];
var healthcheck_url = index_html.substring(0, index_html.lastIndexOf("/") + 1) + '../healthcheck';
xhrObj.open('GET', healthcheck_url);
xhrObj.onreadystatechange = function() {
if (xhrObj.readyState == 4) {
var serverstatus = document.getElementById('doc-server-status');
if (xhrObj.status == 200 && xhrObj.responseText=="true") {
serverstatus.innerHTML = '<div id="status-ok-icon"></div>Document Server is running';
} else {
serverstatus.innerHTML = '<div id="status-err-icon"></div><div>'+
'<div>Something went wrong during installation</div>' +
'<div id="status-err-help">Make sure that you have followed the <a href="http://helpcenter.onlyoffice.com/server/document.aspx" target="_blank">installation instructions</a></div></div>';
}
}
};
xhrObj.send('');
(function () {
try {
var xhrObj = _createXMLHTTPObject();
if (xhrObj) {
var index_html = window['location']['href'];
var healthcheck_url = index_html.substring(0, index_html.lastIndexOf('/') + 1) + '../healthcheck';
xhrObj.open('GET', healthcheck_url);
xhrObj.onreadystatechange = function () {
if (xhrObj.readyState == 4) {
var serverstatus = document.getElementById('doc-server-status');
if (xhrObj.status == 200 && xhrObj.responseText == 'true') {
serverstatus.innerHTML = '<div id="status-ok-icon"></div>Document Server is running';
} else {
serverstatus.innerHTML =
'<div id="status-err-icon"></div><div>' +
'<div>Something went wrong during installation</div>' +
'<div id="status-err-help">Make sure that you have followed the <a href="http://helpcenter.onlyoffice.com/server/document.aspx" target="_blank">installation instructions</a></div></div>';
}
}
catch (e) {}
})();
}
};
xhrObj.send('');
}
} catch (e) {}
})();
</script>
</body>
</body>
</html>

View File

@ -1,86 +1,76 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://example.com/example.json",
"type": "object",
"required": [
"document",
"editorConfig"
],
"properties": {
"document": {
"$id": "#/properties/document",
"type": "object",
"required": [
"key",
"permissions",
"url"
],
"properties": {
"key": {
"$id": "#/properties/document/properties/key",
"type": "string"
},
"permissions": {
"$id": "#/properties/document/properties/permissions",
"type": "object",
"required": [],
"additionalProperties": true
},
"url": {
"$id": "#/properties/document/properties/url",
"type": "string"
}
},
"additionalProperties": true
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://example.com/example.json",
"type": "object",
"required": ["document", "editorConfig"],
"properties": {
"document": {
"$id": "#/properties/document",
"type": "object",
"required": ["key", "permissions", "url"],
"properties": {
"key": {
"$id": "#/properties/document/properties/key",
"type": "string"
},
"editorConfig": {
"$id": "#/properties/editorConfig",
"type": "object",
"required": [
"callbackUrl",
"mode"
],
"properties": {
"callbackUrl": {
"$id": "#/properties/editorConfig/properties/callbackUrl",
"type": "string"
},
"mode": {
"$id": "#/properties/editorConfig/properties/mode",
"type": "string"
},
"user": {
"$id": "#/properties/editorConfig/properties/user",
"type": "object",
"required": [],
"properties": {
"group": {
"$id": "#/properties/editorConfig/properties/user/properties/group",
"type": "string"
},
"id": {
"$id": "#/properties/editorConfig/properties/user/properties/id",
"anyOf": [
{
"$id": "#/properties/editorConfig/properties/user/properties/id/anyOf/0",
"type": "string"
},
{
"$id": "#/properties/editorConfig/properties/user/properties/id/anyOf/1",
"type": "integer"
}
]
},
"name": {
"$id": "#/properties/editorConfig/properties/user/properties/name",
"type": "string"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
"permissions": {
"$id": "#/properties/document/properties/permissions",
"type": "object",
"required": [],
"additionalProperties": true
},
"url": {
"$id": "#/properties/document/properties/url",
"type": "string"
}
},
"additionalProperties": true
},
"additionalProperties": true
"editorConfig": {
"$id": "#/properties/editorConfig",
"type": "object",
"required": ["callbackUrl", "mode"],
"properties": {
"callbackUrl": {
"$id": "#/properties/editorConfig/properties/callbackUrl",
"type": "string"
},
"mode": {
"$id": "#/properties/editorConfig/properties/mode",
"type": "string"
},
"user": {
"$id": "#/properties/editorConfig/properties/user",
"type": "object",
"required": [],
"properties": {
"group": {
"$id": "#/properties/editorConfig/properties/user/properties/group",
"type": "string"
},
"id": {
"$id": "#/properties/editorConfig/properties/user/properties/id",
"anyOf": [
{
"$id": "#/properties/editorConfig/properties/user/properties/id/anyOf/0",
"type": "string"
},
{
"$id": "#/properties/editorConfig/properties/user/properties/id/anyOf/1",
"type": "integer"
}
]
},
"name": {
"$id": "#/properties/editorConfig/properties/user/properties/name",
"type": "string"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}

View File

@ -31,9 +31,9 @@
*/
const platforms = {
'win32': 'windows',
'darwin': 'mac',
'linux': 'linux'
win32: 'windows',
darwin: 'mac',
linux: 'linux'
};
const platform = platforms[process.platform];

View File

@ -30,7 +30,7 @@
*
*/
const { describe, test, expect, afterAll } = require('@jest/globals');
const {describe, test, expect, afterAll} = require('@jest/globals');
const config = require('../../../Common/node_modules/config');
const baseConnector = require('../../../DocService/sources/databaseConnectors/baseConnector');
@ -38,7 +38,7 @@ const operationContext = require('../../../Common/sources/operationContext');
const taskResult = require('../../../DocService/sources/taskresult');
const commonDefines = require('../../../Common/sources/commondefines');
const constants = require('../../../Common/sources/constants');
const utils = require("../../../Common/sources/utils");
const utils = require('../../../Common/sources/utils');
const configSql = config.get('services.CoAuthoring.sql');
const ctx = new operationContext.Context();
@ -72,7 +72,7 @@ const dbTypes = {
string: function () {
return this[cfgDbType].string;
}
}
};
const insertCases = {
5: 'baseConnector-insert()-tester-5-rows',
@ -91,20 +91,11 @@ const emptyCallbacksCase = [
'baseConnector-getEmptyCallbacks()-tester-1',
'baseConnector-getEmptyCallbacks()-tester-2',
'baseConnector-getEmptyCallbacks()-tester-3',
'baseConnector-getEmptyCallbacks()-tester-4',
];
const documentsWithChangesCase = [
'baseConnector-getDocumentsWithChanges()-tester-0',
'baseConnector-getDocumentsWithChanges()-tester-1'
];
const getExpiredCase = [
'baseConnector-getExpired()-tester-0',
'baseConnector-getExpired()-tester-1',
'baseConnector-getExpired()-tester-2',
];
const getCountWithStatusCase = [
'baseConnector-getCountWithStatusCase()-tester-0'
'baseConnector-getEmptyCallbacks()-tester-4'
];
const documentsWithChangesCase = ['baseConnector-getDocumentsWithChanges()-tester-0', 'baseConnector-getDocumentsWithChanges()-tester-1'];
const getExpiredCase = ['baseConnector-getExpired()-tester-0', 'baseConnector-getExpired()-tester-1', 'baseConnector-getExpired()-tester-2'];
const getCountWithStatusCase = ['baseConnector-getCountWithStatusCase()-tester-0'];
const upsertCases = {
insert: 'baseConnector-upsert()-tester-row-inserted',
update: 'baseConnector-upsert()-tester-row-updated'
@ -123,15 +114,13 @@ function createChanges(changesLength, date) {
const length = changesLength - 1;
for (let i = 1; i <= length; i++) {
objChanges.push(
{
docid: '__ffff_127.0.0.1new.docx41692082262909',
change: '"39;CgAAADcAXwA2ADQAMAACABwAAQAAAAAAAAABAAAALgAAAAAAAAAA"',
time: date,
user: 'uid-18',
useridoriginal: 'uid-1'
}
);
objChanges.push({
docid: '__ffff_127.0.0.1new.docx41692082262909',
change: '"39;CgAAADcAXwA2ADQAMAACABwAAQAAAAAAAAABAAAALgAAAAAAAAAA"',
time: date,
user: 'uid-18',
useridoriginal: 'uid-1'
});
}
return objChanges;
@ -155,13 +144,20 @@ function deleteRowsByIds(table, ids) {
function executeSql(sql, values = []) {
return new Promise((resolve, reject) => {
baseConnector.sqlQuery(ctx, sql, function (error, result) {
if (error) {
reject(error)
} else {
resolve(result)
}
}, false, false, values);
baseConnector.sqlQuery(
ctx,
sql,
function (error, result) {
if (error) {
reject(error);
} else {
resolve(result);
}
},
false,
false,
values
);
});
}
@ -229,7 +225,7 @@ describe('Base database connector', function () {
expect(result.length).toEqual(1);
});
test('Correct return format of requested rows', async function() {
test('Correct return format of requested rows', async function () {
const result = await baseConnector.healthCheck(ctx);
// The [[constructor]] field is referring to a parent class instance, so for Object-like values it is equal to itself.
@ -243,19 +239,23 @@ describe('Base database connector', function () {
});
test('Correct return format of changing in DB', async function () {
const createTableSql = `CREATE TABLE test_table(num ${dbTypes.number()});`
const createTableSql = `CREATE TABLE test_table(num ${dbTypes.number()});`;
const alterTableSql = `INSERT INTO test_table VALUES(1);`;
await executeSql(createTableSql);
const result = await executeSql(alterTableSql);
expect(result).toEqual({ affectedRows: 1 });
expect(result).toEqual({affectedRows: 1});
});
describe('DB tables existence', function () {
const tables = {
[cfgTableResult]: constants.TABLE_RESULT_SCHEMA.map(column => { return { column_name: column } }),
[cfgTableChanges]: constants.TABLE_CHANGES_SCHEMA.map(column => { return { column_name: column } })
[cfgTableResult]: constants.TABLE_RESULT_SCHEMA.map(column => {
return {column_name: column};
}),
[cfgTableChanges]: constants.TABLE_CHANGES_SCHEMA.map(column => {
return {column_name: column};
})
};
for (const table in tables) {
@ -267,7 +267,7 @@ describe('Base database connector', function () {
});
}
const table = "unused_table";
const table = 'unused_table';
test(`${table} table absence`, async function () {
const result = await baseConnector.getTableColumns(ctx, table);
expect(result).toEqual([]);
@ -335,7 +335,7 @@ describe('Base database connector', function () {
const result = await baseConnector.getChangesIndexPromise(ctx, docId);
// We created 10 changes rows, change_id: 0..9, changes index is MAX(change_id).
const expected = [{ change_id: 9 }];
const expected = [{change_id: 9}];
expect(result).toEqual(expected);
});
@ -354,7 +354,7 @@ describe('Base database connector', function () {
});
});
test('Get empty callbacks' , async function () {
test('Get empty callbacks', async function () {
const idCount = 5;
const notNullCallbacks = idCount - 2;
@ -390,10 +390,7 @@ describe('Base database connector', function () {
for (const id of documentsWithChangesCase) {
const task = createTask(id);
await Promise.all([
baseConnector.insertChangesPromise(ctx, objChanges, id, index, user),
insertIntoResultTable(date, task)
]);
await Promise.all([baseConnector.insertChangesPromise(ctx, objChanges, id, index, user), insertIntoResultTable(date, task)]);
}
const resultAfterNewRows = await baseConnector.getDocumentsWithChanges(ctx);
@ -420,7 +417,7 @@ describe('Base database connector', function () {
test('Get Count With Status', async function () {
let countWithStatus;
let unknownStatus = 99;//to avoid collision with running server
let unknownStatus = 99; //to avoid collision with running server
let EXEC_TIMEOUT = 30000 + utils.getConvertionTimeout(undefined);
countWithStatus = await baseConnector.getCountWithStatus(ctx, unknownStatus, EXEC_TIMEOUT);
expect(countWithStatus).toEqual(0);
@ -443,7 +440,7 @@ describe('Base database connector', function () {
const result = await baseConnector.upsert(ctx, task);
// isInsert should be true because of insert operation, insertId should be 1 by default.
const expected = { isInsert: true, insertId: 1 };
const expected = {isInsert: true, insertId: 1};
expect(result).toEqual(expected);
const insertedResult = await getRowsCountById(cfgTableResult, task.key);
@ -463,12 +460,12 @@ describe('Base database connector', function () {
const result = await baseConnector.upsert(ctx, task);
// isInsert should be false because of update operation, insertId should be 2 by updating clause.
const expected = { isInsert: false, insertId: 2 };
const expected = {isInsert: false, insertId: 2};
expect(result).toEqual(expected);
const updatedRow = await executeSql(`SELECT id, baseurl FROM ${cfgTableResult} WHERE id = '${task.key}';`);
const expectedUrlChanges = [{ id: task.key, baseurl: 'some-updated-url' }];
const expectedUrlChanges = [{id: task.key, baseurl: 'some-updated-url'}];
expect(updatedRow).toEqual(expectedUrlChanges);
});
});

View File

@ -30,14 +30,14 @@
*
*/
const { describe, test, expect, afterAll, beforeAll } = require('@jest/globals');
const {describe, test, expect, afterAll, beforeAll} = require('@jest/globals');
const http = require('http');
const { signToken } = require('../../../DocService/sources/DocsCoServer');
const {signToken} = require('../../../DocService/sources/DocsCoServer');
const storage = require('../../../Common/sources/storage/storage-base');
const constants = require('../../../Common/sources/commondefines');
const operationContext = require('../../../Common/sources/operationContext');
const utils = require("../../../Common/sources/utils");
const utils = require('../../../Common/sources/utils');
const config = require('../../../Common/node_modules/config');
@ -70,7 +70,7 @@ function makeRequest(requestBody, timeout = 5000) {
if (cfgTokenEnableRequestOutbox) {
const secret = utils.getSecretByElem(cfgSecretOutbox);
const token = await signToken(ctx, requestBody, cfgTokenAlgorithm, cfgTokenOutboxExpires, constants.c_oAscSecretType.Inbox, secret);
body = JSON.stringify({ token });
body = JSON.stringify({token});
} else {
body = JSON.stringify(requestBody);
}
@ -84,12 +84,12 @@ function makeRequest(requestBody, timeout = 5000) {
'Content-Length': Buffer.byteLength(body)
}
};
const request = http.request(options, (response) => {
const request = http.request(options, response => {
response.setEncoding('utf8');
let data = '';
response.on('data', (chunk) => {
data += chunk
response.on('data', chunk => {
data += chunk;
});
response.on('end', () => {
resolve(data);
@ -97,7 +97,7 @@ function makeRequest(requestBody, timeout = 5000) {
});
});
request.on('error', (error) => {
request.on('error', error => {
reject(error);
clearTimeout(timer);
});
@ -121,10 +121,11 @@ beforeAll(async function () {
afterAll(async function () {
const keys = await storage.listObjects(ctx, '', cfgForgottenFiles);
const keysDirectories = getKeysDirectories(keys);
const deletePromises = keysDirectories.filter(key => key.includes('DocService-DocsCoServer-forgottenFilesCommands'))
const deletePromises = keysDirectories
.filter(key => key.includes('DocService-DocsCoServer-forgottenFilesCommands'))
.map(filteredKey => storage.deletePath(ctx, filteredKey, cfgForgottenFiles));
console.log(`keys:`+JSON.stringify(keys));
console.log(`keysDirectories:`+JSON.stringify(keysDirectories));
console.log(`keys:` + JSON.stringify(keys));
console.log(`keysDirectories:` + JSON.stringify(keysDirectories));
return Promise.allSettled(deletePromises);
});
@ -137,7 +138,7 @@ describe('Command service', function () {
invalidRequests.push({
c: testSubject
});
expected.push({ error: 1});
expected.push({error: 1});
invalidRequests.push({
c: testSubject,
@ -156,13 +157,13 @@ describe('Command service', function () {
return {
c: testSubject,
key
}
};
});
const expected = invalidKeys.map(key => {
return {
key,
error: 1,
error: 1
};
});
@ -181,17 +182,17 @@ describe('Command service', function () {
describe('Forgotten files commands verification', function () {
describe('getForgotten', function () {
const createExpected = ({ key, error }) => {
const validKey = typeof key === 'string' && error === 0
const createExpected = ({key, error}) => {
const validKey = typeof key === 'string' && error === 0;
let urlPattern;
if ("storage-fs" === cfgStorageName || !cfgUseDirectStorageUrls) {
if ("storage-fs" === cfgStorageName) {
if ('storage-fs' === cfgStorageName || !cfgUseDirectStorageUrls) {
if ('storage-fs' === cfgStorageName) {
urlPattern = 'http://localhost:8000/cache/files/forgotten/--key--/output.docx/output.docx';
} else {
urlPattern = 'http://localhost:8000/storage-cache/files/forgotten/--key--/output.docx/output.docx';
}
} else if ("storage-s3" === cfgStorageName) {
let host = cfgEndpoint.slice(0, "https://".length) + cfgBucketName + "." + cfgEndpoint.slice("https://".length);
} else if ('storage-s3' === cfgStorageName) {
let host = cfgEndpoint.slice(0, 'https://'.length) + cfgBucketName + '.' + cfgEndpoint.slice('https://'.length);
if (host[host.length - 1] === '/') {
host = host.slice(0, -1);
}
@ -199,9 +200,9 @@ describe('Command service', function () {
} else {
let host;
if (cfgEndpoint.includes(cfgAccessKeyId)) {
host = cfgEndpoint.slice(0, "https://".length) + cfgEndpoint.slice("https://".length) + '/' + cfgBucketName;
host = cfgEndpoint.slice(0, 'https://'.length) + cfgEndpoint.slice('https://'.length) + '/' + cfgBucketName;
} else {
host = cfgEndpoint.slice(0, "https://".length) + cfgAccessKeyId + "." + cfgEndpoint.slice("https://".length) + '/' + cfgBucketName;
host = cfgEndpoint.slice(0, 'https://'.length) + cfgAccessKeyId + '.' + cfgEndpoint.slice('https://'.length) + '/' + cfgBucketName;
}
if (host[host.length - 1] === '/') {
host = host.slice(0, -1);
@ -209,7 +210,7 @@ describe('Command service', function () {
urlPattern = host + '/files/forgotten/--key--/output.docx';
}
const expected = { key, error };
const expected = {key, error};
if (validKey) {
expected.url = urlPattern.replace('--key--', key);
@ -219,8 +220,8 @@ describe('Command service', function () {
};
const testCases = {
'Single key': { key: testFilesNames.get, error: 0 },
'Not existed key': { key: '--not-existed--', error: 1 },
'Single key': {key: testFilesNames.get, error: 0},
'Not existed key': {key: '--not-existed--', error: 1}
};
for (const testCase in testCases) {
@ -245,7 +246,7 @@ describe('Command service', function () {
});
describe('deleteForgotten', function () {
const createExpected = ({ key, error }) => {
const createExpected = ({key, error}) => {
return {
key,
error
@ -253,8 +254,8 @@ describe('Command service', function () {
};
const testCases = {
'Single key': { key: testFilesNames.delete1, error: 0 },
'Not existed key': { key: '--not-existed--', error: 1 },
'Single key': {key: testFilesNames.delete1, error: 0},
'Not existed key': {key: '--not-existed--', error: 1}
};
for (const testCase in testCases) {
@ -300,7 +301,7 @@ describe('Command service', function () {
const expected = {
error: 0,
keys: alreadyExistedDirectories.keys
}
};
actual.keys?.sort();
expected.keys.sort();

View File

@ -31,7 +31,7 @@
*/
const {jest, describe, test, expect, beforeAll, afterAll} = require('@jest/globals');
jest.mock("fs/promises", () => ({
jest.mock('fs/promises', () => ({
...jest.requireActual('fs/promises'),
cp: jest.fn().mockImplementation((from, to) => fs.writeFileSync(to, testFileData3))
}));
@ -43,15 +43,15 @@ jest.mock('../../../Common/sources/storage/storage-base', () => {
needServeStatic: mockNeedServeStatic
};
});
const { cp } = require('fs/promises');
const {cp} = require('fs/promises');
const http = require('http');
const https = require('https');
const fs = require('fs');
const { Readable } = require('stream');
const {Readable} = require('stream');
let testFileData1 = "test1";
let testFileData2 = "test22";
let testFileData3 = "test333";
let testFileData1 = 'test1';
let testFileData2 = 'test22';
let testFileData3 = 'test333';
let testFileData4 = testFileData3;
const express = require('express');
@ -59,7 +59,7 @@ const operationContext = require('../../../Common/sources/operationContext');
const tenantManager = require('../../../Common/sources/tenantManager');
const storage = require('../../../Common/sources/storage/storage-base');
const utils = require('../../../Common/sources/utils');
const commonDefines = require("../../../Common/sources/commondefines");
const commonDefines = require('../../../Common/sources/commondefines');
const config = require('../../../Common/node_modules/config');
const staticRouter = require('../../../DocService/sources/routes/static');
@ -69,17 +69,17 @@ const cfgPersistentStorage = utils.deepMergeObjects({}, cfgCacheStorage, config.
const ctx = operationContext.global;
const PORT = 3457;
const rand = Math.floor(Math.random() * 1000000);
const testDir = "DocService-DocsCoServer-storage-" + rand;
const testDir = 'DocService-DocsCoServer-storage-' + rand;
const baseUrl = `http://localhost:${PORT}`;
const urlType = commonDefines.c_oAscUrlTypes.Session;
let testFile1 = testDir + "/test1.txt";
let testFile2 = testDir + "/test2.txt";
let testFile3 = testDir + "/test3.txt";
let testFile4 = testDir + "/test4.txt";
let specialDirCache = "";
let specialDirForgotten = "forgotten";
let testFile1 = testDir + '/test1.txt';
let testFile2 = testDir + '/test2.txt';
let testFile3 = testDir + '/test3.txt';
let testFile4 = testDir + '/test4.txt';
let specialDirCache = '';
let specialDirForgotten = 'forgotten';
console.debug(`testDir: ${testDir}`)
console.debug(`testDir: ${testDir}`);
let server;
@ -94,7 +94,7 @@ beforeAll(async () => {
afterAll(async () => {
if (server) {
await new Promise((resolve) => server.close(resolve));
await new Promise(resolve => server.close(resolve));
}
});
@ -117,21 +117,21 @@ function request(url) {
}
function runTestForDir(ctx, isMultitenantMode, specialDir) {
let oldMultitenantMode = tenantManager.isMultitenantMode();
test("start listObjects", async () => {
test('start listObjects', async () => {
//todo set in all tests do not rely on test order
tenantManager.setMultitenantMode(isMultitenantMode);
let list = await storage.listObjects(ctx, testDir, specialDir);
expect(list).toEqual([]);
});
test("putObject", async () => {
test('putObject', async () => {
let buffer = Buffer.from(testFileData1);
let res = await storage.putObject(ctx, testFile1, buffer, buffer.length, specialDir);
expect(res).toEqual(undefined);
let list = await storage.listObjects(ctx, testDir, specialDir);
expect(list.sort()).toEqual([testFile1].sort());
});
test("putObject-stream", async () => {
test('putObject-stream', async () => {
let buffer = Buffer.from(testFileData2);
const stream = Readable.from(buffer);
let res = await storage.putObject(ctx, testFile2, stream, buffer.length, specialDir);
@ -139,20 +139,20 @@ function runTestForDir(ctx, isMultitenantMode, specialDir) {
let list = await storage.listObjects(ctx, testDir, specialDir);
expect(list.sort()).toEqual([testFile1, testFile2].sort());
});
if ("storage-fs" === getStorageCfg(specialDir).name) {
test("UploadObject", async () => {
let res = await storage.uploadObject(ctx, testFile3, "createReadStream.txt", specialDir);
if ('storage-fs' === getStorageCfg(specialDir).name) {
test('UploadObject', async () => {
let res = await storage.uploadObject(ctx, testFile3, 'createReadStream.txt', specialDir);
expect(res).toEqual(undefined);
expect(cp).toHaveBeenCalled();
let list = await storage.listObjects(ctx, testDir, specialDir);
expect(list.sort()).toEqual([testFile1, testFile2, testFile3].sort());
});
} else {
test("uploadObject", async () => {
test('uploadObject', async () => {
const readStream = Readable.from(testFileData3);
readStream.size = testFileData3.length;
const spy = jest.spyOn(fs, 'createReadStream').mockReturnValue(readStream);
let res = await storage.uploadObject(ctx, testFile3, "createReadStream.txt", specialDir);
let res = await storage.uploadObject(ctx, testFile3, 'createReadStream.txt', specialDir);
expect(res).toEqual(undefined);
let list = await storage.listObjects(ctx, testDir, specialDir);
expect(spy).toHaveBeenCalled();
@ -161,33 +161,33 @@ function runTestForDir(ctx, isMultitenantMode, specialDir) {
});
//todo fails with storage-s3
test.skip("uploadObject - stream error handling", async () => {
const streamErrorMessage = new Error("Test stream error");
const mockStream = Readable.from(async function* () {
yield "first chunk\n";
await new Promise(r => setTimeout(r, 5));
throw streamErrorMessage;
}());
test.skip('uploadObject - stream error handling', async () => {
const streamErrorMessage = new Error('Test stream error');
const mockStream = Readable.from(
(async function* () {
yield 'first chunk\n';
await new Promise(r => setTimeout(r, 5));
throw streamErrorMessage;
})()
);
mockStream.size = 1024;
const spy = jest.spyOn(fs, 'createReadStream').mockReturnValue(mockStream);
// Verify that the uploadObject function rejects when the stream emits an error
await expect(storage.uploadObject(ctx, "test-error-file.txt", "nonexistent.txt", specialDir))
.rejects.toThrow(streamErrorMessage);
await expect(storage.uploadObject(ctx, 'test-error-file.txt', 'nonexistent.txt', specialDir)).rejects.toThrow(streamErrorMessage);
spy.mockRestore();
});
test.skip("uploadObject - non-existent file handling", async () => {
test.skip('uploadObject - non-existent file handling', async () => {
const nonExistentFile = 'definitely-does-not-exist-' + Date.now() + '.txt';
// Verify the file actually doesn't exist
expect(fs.existsSync(nonExistentFile)).toBe(false);
// Verify that uploadObject properly handles and propagates the error
await expect(storage.uploadObject(ctx, "test-error-file.txt", nonExistentFile, specialDir))
.rejects.toThrow(/ENOENT/);
await expect(storage.uploadObject(ctx, 'test-error-file.txt', nonExistentFile, specialDir)).rejects.toThrow(/ENOENT/);
});
}
test("copyObject", async () => {
test('copyObject', async () => {
let res = await storage.copyObject(ctx, testFile3, testFile4, specialDir, specialDir);
expect(res).toEqual(undefined);
// let buffer = Buffer.from(testFileData3);
@ -195,53 +195,53 @@ function runTestForDir(ctx, isMultitenantMode, specialDir) {
let list = await storage.listObjects(ctx, testDir, specialDir);
expect(list.sort()).toEqual([testFile1, testFile2, testFile3, testFile4].sort());
});
test("headObject", async () => {
test('headObject', async () => {
let output;
output = await storage.headObject(ctx, testFile1, specialDir);
expect(output).toMatchObject({ContentLength: testFileData1.length});
output = await storage.headObject(ctx, testFile2, specialDir);
output = await storage.headObject(ctx, testFile2, specialDir);
expect(output).toMatchObject({ContentLength: testFileData2.length});
output = await storage.headObject(ctx, testFile3, specialDir);
output = await storage.headObject(ctx, testFile3, specialDir);
expect(output).toMatchObject({ContentLength: testFileData3.length});
output = await storage.headObject(ctx, testFile4, specialDir);
output = await storage.headObject(ctx, testFile4, specialDir);
expect(output).toMatchObject({ContentLength: testFileData4.length});
});
test("getObject", async () => {
test('getObject', async () => {
let output;
output = await storage.getObject(ctx, testFile1, specialDir);
expect(output.toString("utf8")).toEqual(testFileData1);
expect(output.toString('utf8')).toEqual(testFileData1);
output = await storage.getObject(ctx, testFile2, specialDir);
expect(output.toString("utf8")).toEqual(testFileData2);
output = await storage.getObject(ctx, testFile2, specialDir);
expect(output.toString('utf8')).toEqual(testFileData2);
output = await storage.getObject(ctx, testFile3, specialDir);
expect(output.toString("utf8")).toEqual(testFileData3);
output = await storage.getObject(ctx, testFile3, specialDir);
expect(output.toString('utf8')).toEqual(testFileData3);
output = await storage.getObject(ctx, testFile4, specialDir);
expect(output.toString("utf8")).toEqual(testFileData4);
output = await storage.getObject(ctx, testFile4, specialDir);
expect(output.toString('utf8')).toEqual(testFileData4);
});
test("createReadStream", async () => {
test('createReadStream', async () => {
let output, outputText;
output = await storage.createReadStream(ctx, testFile1, specialDir);
expect(output.contentLength).toEqual(testFileData1.length);
outputText = await utils.stream2Buffer(output.readStream);
expect(outputText.toString("utf8")).toEqual(testFileData1);
expect(outputText.toString('utf8')).toEqual(testFileData1);
output = await storage.createReadStream(ctx, testFile2, specialDir);
expect(output.contentLength).toEqual(testFileData2.length);
outputText = await utils.stream2Buffer(output.readStream);
expect(outputText.toString("utf8")).toEqual(testFileData2);
expect(outputText.toString('utf8')).toEqual(testFileData2);
output = await storage.createReadStream(ctx, testFile3, specialDir);
expect(output.contentLength).toEqual(testFileData3.length);
outputText = await utils.stream2Buffer(output.readStream);
expect(outputText.toString("utf8")).toEqual(testFileData3);
expect(outputText.toString('utf8')).toEqual(testFileData3);
});
test("getSignedUrl", async () => {
test('getSignedUrl', async () => {
let url, urls, data;
url = await storage.getSignedUrl(ctx, baseUrl, testFile1, urlType, undefined, undefined, specialDir);
data = await request(url);
@ -259,34 +259,34 @@ function runTestForDir(ctx, isMultitenantMode, specialDir) {
data = await request(url);
expect(data).toEqual(testFileData4);
});
test("getSignedUrls", async () => {
test('getSignedUrls', async () => {
let urls, data;
urls = await storage.getSignedUrls(ctx, baseUrl, testDir, urlType, undefined, specialDir);
data = [];
for(let i in urls) {
for (let i in urls) {
data.push(await request(urls[i]));
}
expect(data.sort()).toEqual([testFileData1, testFileData2, testFileData3, testFileData4].sort());
});
test("getSignedUrlsArrayByArray", async () => {
test('getSignedUrlsArrayByArray', async () => {
let urls, data;
urls = await storage.getSignedUrlsArrayByArray(ctx, baseUrl, [testFile1, testFile2], urlType, specialDir);
data = [];
for(let i = 0; i < urls.length; ++i) {
for (let i = 0; i < urls.length; ++i) {
data.push(await request(urls[i]));
}
expect(data.sort()).toEqual([testFileData1, testFileData2].sort());
});
test("getSignedUrlsByArray", async () => {
test('getSignedUrlsByArray', async () => {
let urls, data;
urls = await storage.getSignedUrlsByArray(ctx, baseUrl, [testFile3, testFile4], undefined, urlType, specialDir);
data = [];
for(let i in urls) {
for (let i in urls) {
data.push(await request(urls[i]));
}
expect(data.sort()).toEqual([testFileData3, testFileData4].sort());
});
test("getSignedUrl with direct URLs enabled", async () => {
test('getSignedUrl with direct URLs enabled', async () => {
let buffer = Buffer.from(testFileData1);
let res = await storage.putObject(ctx, testFile1, buffer, buffer.length, specialDirCache);
expect(res).toEqual(undefined);
@ -300,7 +300,7 @@ function runTestForDir(ctx, isMultitenantMode, specialDir) {
expect(url).toContain(cfgCacheStorage.bucketName);
}
});
test("getSignedUrl with direct URLs disabled", async () => {
test('getSignedUrl with direct URLs disabled', async () => {
let buffer = Buffer.from(testFileData1);
let res = await storage.putObject(ctx, testFile1, buffer, buffer.length, specialDirCache);
expect(res).toEqual(undefined);
@ -313,7 +313,7 @@ function runTestForDir(ctx, isMultitenantMode, specialDir) {
expect(url).toContain('expires');
expect(url).toContain(cfgCacheStorage.storageFolderName);
});
test("deleteObject", async () => {
test('deleteObject', async () => {
let list;
list = await storage.listObjects(ctx, testDir, specialDir);
expect(list.sort()).toEqual([testFile1, testFile2, testFile3, testFile4].sort());
@ -324,7 +324,7 @@ function runTestForDir(ctx, isMultitenantMode, specialDir) {
list = await storage.listObjects(ctx, testDir, specialDir);
expect(list.sort()).toEqual([testFile2, testFile3, testFile4].sort());
});
test("deletePath", async () => {
test('deletePath', async () => {
let list;
list = await storage.listObjects(ctx, testDir, specialDir);
expect(list.sort()).toEqual([testFile2, testFile3, testFile4].sort());
@ -357,7 +357,7 @@ describe('storage forgotten dir with tenants', function () {
});
describe('storage mix common and forgotten dir', function () {
test("putObject", async () => {
test('putObject', async () => {
tenantManager.setMultitenantMode(false);
let buffer = Buffer.from(testFileData1);
@ -373,7 +373,7 @@ describe('storage mix common and forgotten dir', function () {
expect(list.sort()).toEqual([testFile2].sort());
});
test("copyPath", async () => {
test('copyPath', async () => {
let list, res;
res = await storage.copyPath(ctx, testDir, testDir, specialDirCache, specialDirForgotten);
expect(res).toEqual(undefined);
@ -381,7 +381,7 @@ describe('storage mix common and forgotten dir', function () {
list = await storage.listObjects(ctx, testDir, specialDirForgotten);
expect(list.sort()).toEqual([testFile1, testFile2].sort());
});
test("copyObject", async () => {
test('copyObject', async () => {
let list, res;
res = await storage.copyObject(ctx, testFile2, testFile2, specialDirForgotten, specialDirCache);
expect(res).toEqual(undefined);
@ -390,7 +390,7 @@ describe('storage mix common and forgotten dir', function () {
expect(list.sort()).toEqual([testFile1, testFile2].sort());
});
test("deletePath", async () => {
test('deletePath', async () => {
let list, res;
res = await storage.deletePath(ctx, testDir, specialDirCache);
expect(res).toEqual(undefined);

View File

@ -68,7 +68,7 @@ module.exports = {
// ],
// Indicates which provider should be used to instrument code for coverage
coverageProvider: "v8",
coverageProvider: 'v8',
// A list of reporter names that Jest uses when writing coverage reports
// coverageReporters: [
@ -126,7 +126,7 @@ module.exports = {
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
moduleNameMapper: {
'^axios$': '../../Common/node_modules/axios/dist/node/axios.cjs',
'^axios$': '../../Common/node_modules/axios/dist/node/axios.cjs'
},
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
@ -190,9 +190,7 @@ module.exports = {
// testLocationInResults: false,
// The glob patterns Jest uses to detect test files
testMatch: [
"**/?(*.)+(spec|tests).[tj]s?(x)"
],
testMatch: ['**/?(*.)+(spec|tests).[tj]s?(x)']
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [

View File

@ -32,11 +32,7 @@
'use strict';
const {
createHistogram,
performance,
PerformanceObserver,
} = require('node:perf_hooks');
const {createHistogram, performance, PerformanceObserver} = require('node:perf_hooks');
const co = require('co');
const taskResult = require('./../../DocService/sources/taskresult');
@ -44,8 +40,8 @@ const storage = require('./../../Common/sources/storage/storage-base');
const storageFs = require('./../../Common/sources/storage/storage-fs');
const operationContext = require('./../../Common/sources/operationContext');
const utils = require('./../../Common/sources/utils');
const docsCoServer = require("./../../DocService/sources/DocsCoServer");
const gc = require("./../../DocService/sources/gc");
const docsCoServer = require('./../../DocService/sources/DocsCoServer');
const gc = require('./../../DocService/sources/gc');
let ctx = operationContext.global;
@ -61,25 +57,25 @@ async function beforeStart() {
let histogram = createHistogram();
histograms[func.name] = histogram;
return performance.timerify(func, {histogram: histogram});
}
};
addRandomKeyTask = timerify(co.wrap(taskResult.addRandomKeyTask), "addRandomKeyTask");
taskResult.getExpired = timerify(taskResult.getExpired, "getExpired");
taskResult.remove = timerify(taskResult.remove, "remove");
storage.putObject = timerify(storage.putObject, "putObject");
storage.listObjects = timerify(storage.listObjects, "listObjects");
storageFs.deletePath = timerify(storageFs.deletePath, "deletePath");
storageFs.deleteObject = timerify(storageFs.deleteObject, "deleteObject");
docsCoServer.getEditorsCountPromise = timerify(docsCoServer.getEditorsCountPromise, "getEditorsCountPromise");
addRandomKeyTask = timerify(co.wrap(taskResult.addRandomKeyTask), 'addRandomKeyTask');
taskResult.getExpired = timerify(taskResult.getExpired, 'getExpired');
taskResult.remove = timerify(taskResult.remove, 'remove');
storage.putObject = timerify(storage.putObject, 'putObject');
storage.listObjects = timerify(storage.listObjects, 'listObjects');
storageFs.deletePath = timerify(storageFs.deletePath, 'deletePath');
storageFs.deleteObject = timerify(storageFs.deleteObject, 'deleteObject');
docsCoServer.getEditorsCountPromise = timerify(docsCoServer.getEditorsCountPromise, 'getEditorsCountPromise');
const obs = new PerformanceObserver((list) => {
const obs = new PerformanceObserver(list => {
const entries = list.getEntries();
entries.forEach((entry) => {
entries.forEach(entry => {
let duration = Math.round(entry.duration * 1000) / 1000;
console.log(`${entry.name}:${duration}ms`);
});
});
obs.observe({ entryTypes: ['function']});
obs.observe({entryTypes: ['function']});
await docsCoServer.editorData.connect();
}
@ -91,7 +87,7 @@ async function beforeEnd() {
let max = Math.round(histogram.max / 1000) / 1000;
let count = histogram.count;
ctx.logger.info(`histogram ${name}: count=${count}, mean=${mean}ms, min=${min}ms, max=${max}ms`);
}
};
await utils.sleep(1000);
for (let name in histograms) {
logHistogram(histograms[name], name);
@ -116,7 +112,7 @@ async function startTest() {
ctx.logger.error('missing arguments.USAGE: checkFileExpire.js [add-files-count] [file-size-bytes] [key-prefix] [seconds-to-expire]');
return;
}
ctx.logger.info("test started");
ctx.logger.info('test started');
await beforeStart();
await addFileExpire(parseInt(args[0]), parseInt(args[1]), args[2], parseInt(args[4] || 1));
@ -125,14 +121,17 @@ async function startTest() {
await gc.checkFileExpire(args[3]);
await beforeEnd();
ctx.logger.info("test finished");
ctx.logger.info('test finished');
}
startTest().then(()=>{
//delay to log observer events
return utils.sleep(1000);
}).catch((err) => {
ctx.logger.error(err.stack);
}).finally(() => {
process.exit(0);
});
startTest()
.then(() => {
//delay to log observer events
return utils.sleep(1000);
})
.catch(err => {
ctx.logger.error(err.stack);
})
.finally(() => {
process.exit(0);
});

View File

@ -32,18 +32,14 @@
'use strict';
const {
createHistogram,
performance,
PerformanceObserver,
} = require('node:perf_hooks');
const {createHistogram, performance, PerformanceObserver} = require('node:perf_hooks');
const { readdir, mkdir, readFile, writeFile } = require("node:fs/promises");
const path = require("path");
const {readdir, mkdir, readFile, writeFile} = require('node:fs/promises');
const path = require('path');
// const Jimp = require('Jimp');
const utils = require('./../../Common/sources/utils');
const operationContext = require('./../../Common/sources/operationContext');
const utilsDocService = require("./../../DocService/sources/utilsDocService");
const utilsDocService = require('./../../DocService/sources/utilsDocService');
let ctx = operationContext.global;
@ -54,18 +50,18 @@ async function beforeStart() {
let histogram = createHistogram();
histograms[func.name] = histogram;
return performance.timerify(func, {histogram: histogram});
}
};
utilsDocService.convertImageToPng = timerify(utilsDocService.convertImageToPng);
// Jimp.read = timerify(Jimp.read);
const obs = new PerformanceObserver((list) => {
const obs = new PerformanceObserver(list => {
const entries = list.getEntries();
entries.forEach((entry) => {
entries.forEach(entry => {
let duration = Math.round(entry.duration * 1000) / 1000;
console.log(`${entry.name}:${duration}ms`);
});
});
obs.observe({ entryTypes: ['function']});
obs.observe({entryTypes: ['function']});
}
async function beforeEnd() {
@ -75,7 +71,7 @@ async function beforeEnd() {
let max = Math.round(histogram.max / 1000) / 1000;
let count = histogram.count;
ctx.logger.info(`histogram ${name}: count=${count}, mean=${mean}ms, min=${min}ms, max=${max}ms`);
}
};
await utils.sleep(1000);
for (let name in histograms) {
logHistogram(histograms[name], name);
@ -83,13 +79,13 @@ async function beforeEnd() {
}
async function fixInDir(dirIn, dirOut) {
ctx.logger.info("dirIn:%s", dirIn);
ctx.logger.info("dirOut:%s", dirOut);
let dirents = await readdir(dirIn, {withFileTypes : true, recursive: true});
ctx.logger.info('dirIn:%s', dirIn);
ctx.logger.info('dirOut:%s', dirOut);
let dirents = await readdir(dirIn, {withFileTypes: true, recursive: true});
for (let dirent of dirents) {
if (dirent.isFile()) {
let file = dirent.name;
ctx.logger.info("fixInDir:%s", file);
ctx.logger.info('fixInDir:%s', file);
let buffer = await readFile(path.join(dirent.path, file));
let bufferNew = await utilsDocService.convertImageToPng(ctx, buffer);
if (buffer !== bufferNew) {
@ -107,21 +103,23 @@ async function startTest() {
ctx.logger.error('missing arguments.USAGE: convertImageToPng.js "dirIn" "dirOut"');
return;
}
ctx.logger.info("test started");
ctx.logger.info('test started');
await beforeStart();
await fixInDir(args[0], args[1]);
await beforeEnd();
ctx.logger.info("test finished");
ctx.logger.info('test finished');
}
startTest().then(()=>{
//delay to log observer events
return utils.sleep(1000);
}).catch((err) => {
ctx.logger.error(err.stack);
}).finally(() => {
process.exit(0);
});
startTest()
.then(() => {
//delay to log observer events
return utils.sleep(1000);
})
.catch(err => {
ctx.logger.error(err.stack);
})
.finally(() => {
process.exit(0);
});

View File

@ -32,18 +32,14 @@
'use strict';
const {
createHistogram,
performance,
PerformanceObserver,
} = require('node:perf_hooks');
const {createHistogram, performance, PerformanceObserver} = require('node:perf_hooks');
const { readdir, mkdir, readFile, writeFile } = require("node:fs/promises");
const path = require("path");
const {readdir, mkdir, readFile, writeFile} = require('node:fs/promises');
const path = require('path');
// const Jimp = require('Jimp');
const utils = require('./../../Common/sources/utils');
const operationContext = require('./../../Common/sources/operationContext');
const utilsDocService = require("./../../DocService/sources/utilsDocService");
const utilsDocService = require('./../../DocService/sources/utilsDocService');
let ctx = operationContext.global;
@ -54,18 +50,18 @@ async function beforeStart() {
let histogram = createHistogram();
histograms[func.name] = histogram;
return performance.timerify(func, {histogram: histogram});
}
};
utilsDocService.fixImageExifRotation = timerify(utilsDocService.fixImageExifRotation);
// Jimp.read = timerify(Jimp.read);
const obs = new PerformanceObserver((list) => {
const obs = new PerformanceObserver(list => {
const entries = list.getEntries();
entries.forEach((entry) => {
entries.forEach(entry => {
let duration = Math.round(entry.duration * 1000) / 1000;
console.log(`${entry.name}:${duration}ms`);
});
});
obs.observe({ entryTypes: ['function']});
obs.observe({entryTypes: ['function']});
}
async function beforeEnd() {
@ -75,7 +71,7 @@ async function beforeEnd() {
let max = Math.round(histogram.max / 1000) / 1000;
let count = histogram.count;
ctx.logger.info(`histogram ${name}: count=${count}, mean=${mean}ms, min=${min}ms, max=${max}ms`);
}
};
await utils.sleep(1000);
for (let name in histograms) {
logHistogram(histograms[name], name);
@ -83,13 +79,13 @@ async function beforeEnd() {
}
async function fixInDir(dirIn, dirOut) {
ctx.logger.info("dirIn:%s", dirIn);
ctx.logger.info("dirOut:%s", dirOut);
let dirents = await readdir(dirIn, {withFileTypes : true, recursive: true});
ctx.logger.info('dirIn:%s', dirIn);
ctx.logger.info('dirOut:%s', dirOut);
let dirents = await readdir(dirIn, {withFileTypes: true, recursive: true});
for (let dirent of dirents) {
if (dirent.isFile()) {
let file = dirent.name;
ctx.logger.info("fixInDir:%s", file);
ctx.logger.info('fixInDir:%s', file);
let buffer = await readFile(path.join(dirent.path, file));
let bufferNew = await utilsDocService.fixImageExifRotation(ctx, buffer);
if (buffer !== bufferNew) {
@ -107,21 +103,23 @@ async function startTest() {
ctx.logger.error('missing arguments.USAGE: fixImageExifRotation.js "dirIn" "dirOut"');
return;
}
ctx.logger.info("test started");
ctx.logger.info('test started');
await beforeStart();
await fixInDir(args[0], args[1]);
await beforeEnd();
ctx.logger.info("test finished");
ctx.logger.info('test finished');
}
startTest().then(()=>{
//delay to log observer events
return utils.sleep(1000);
}).catch((err) => {
ctx.logger.error(err.stack);
}).finally(() => {
process.exit(0);
});
startTest()
.then(() => {
//delay to log observer events
return utils.sleep(1000);
})
.catch(err => {
ctx.logger.error(err.stack);
})
.finally(() => {
process.exit(0);
});

View File

@ -1,4 +1,4 @@
const { describe, test, expect, afterAll } = require('@jest/globals');
const {describe, test, expect, afterAll} = require('@jest/globals');
const nodemailer = require('../../Common/node_modules/nodemailer');
const operationContext = require('../../Common/sources/operationContext');
@ -13,40 +13,46 @@ const testTimeout = 1000 * 10;
afterAll(function () {
mailService.transportersRelease();
})
});
describe('Mail service', function () {
describe('SMTP', function () {
const { host, port } = defaultTestSMTPServer;
const {host, port} = defaultTestSMTPServer;
test('Transporters life cycle', async function () {
// Accounts created at https://ethereal.email/, all messages in tests goes here: https://ethereal.email/messages
// Ethereial is a special SMTP sever for mailing tests in collaboration with Nodemailer.
const accounts = await Promise.all([nodemailer.createTestAccount(), nodemailer.createTestAccount(), nodemailer.createTestAccount()]);
const auth = accounts.map(account => { return { user: account.user, pass: account.pass }});
auth.forEach(credential => mailService.createTransporter(ctx, host, port, credential, { from: 'some.mail@ethereal.com' }));
test(
'Transporters life cycle',
async function () {
// Accounts created at https://ethereal.email/, all messages in tests goes here: https://ethereal.email/messages
// Ethereial is a special SMTP sever for mailing tests in collaboration with Nodemailer.
const accounts = await Promise.all([nodemailer.createTestAccount(), nodemailer.createTestAccount(), nodemailer.createTestAccount()]);
const auth = accounts.map(account => {
return {user: account.user, pass: account.pass};
});
auth.forEach(credential => mailService.createTransporter(ctx, host, port, credential, {from: 'some.mail@ethereal.com'}));
for (let i = 0; i < auth.length; i++) {
const credentials = auth[i];
const mail = await mailService.send(
host,
credentials.user,
{ to: `some.recipient@server${i + 1}.com`, text: 'simple test text', subject: 'Mail service test' }
);
for (let i = 0; i < auth.length; i++) {
const credentials = auth[i];
const mail = await mailService.send(host, credentials.user, {
to: `some.recipient@server${i + 1}.com`,
text: 'simple test text',
subject: 'Mail service test'
});
expect(mail.envelope).toEqual({ from: 'some.mail@ethereal.com', to: [`some.recipient@server${i + 1}.com`] });
}
expect(mail.envelope).toEqual({from: 'some.mail@ethereal.com', to: [`some.recipient@server${i + 1}.com`]});
}
const accountToBeDeleted = auth[1];
mailService.deleteTransporter(ctx, host, accountToBeDeleted.user);
const accountToBeDeleted = auth[1];
mailService.deleteTransporter(ctx, host, accountToBeDeleted.user);
const errorPromise = mailService.send(
host,
accountToBeDeleted.user,
{ to: 'no.recipient@server.com', text: 'simple test text', subject: 'Mail service test' }
);
const errorPromise = mailService.send(host, accountToBeDeleted.user, {
to: 'no.recipient@server.com',
text: 'simple test text',
subject: 'Mail service test'
});
await expect(errorPromise).rejects.toThrow();
}, testTimeout);
await expect(errorPromise).rejects.toThrow();
},
testTimeout
);
});
});

File diff suppressed because it is too large Load Diff

View File

@ -6,27 +6,24 @@ const GOOD_PORT_REDIRECT = 4667;
const BAD_PORT = 4669;
process.env['NODE_CONFIG'] = JSON.stringify({
"services": {
"CoAuthoring": {
"request-filtering-agent": {
"allowPrivateIPAddress": false,
"allowMetaIPAddress": false,
"allowIPAddressList": [
GOOD_HOST
]
services: {
CoAuthoring: {
'request-filtering-agent': {
allowPrivateIPAddress: false,
allowMetaIPAddress: false,
allowIPAddressList: [GOOD_HOST]
}
}
}
});
// Required modules
const { describe, test, expect, beforeAll, afterAll, it, jest } = require('@jest/globals');
const {describe, test, expect, beforeAll, afterAll, it, jest} = require('@jest/globals');
const http = require('http');
const operationContext = require('../../Common/sources/operationContext');
const utils = require('../../Common/sources/utils');
// Common test parameters
const commonTestParams = {
uri: `http://${GOOD_HOST}:${GOOD_PORT}`,
@ -34,83 +31,76 @@ const commonTestParams = {
limit: 1024 * 1024, // 1MB
authorization: 'Bearer token123',
filterPrivate: true,
headers: { 'Accept': 'application/json' }
headers: {Accept: 'application/json'}
};
const ctx = operationContext.global;
describe('Server-Side Request Forgery (SSRF)', () => {
let goodServer, goodServerRedirect, badServer;
let goodServer, goodServerRedirect, badServer;
beforeAll(() => {
beforeAll(() => {
goodServer = http
.createServer(function (req, res) {
res.write('good');
res.end();
})
.listen(GOOD_PORT);
goodServer = http.createServer(function (req, res) {
res.write('good');
res.end();
}).listen(GOOD_PORT);
goodServerRedirect = http
.createServer(function (req, res) {
console.log(`Received request for: ${req.url}`);
goodServerRedirect = http.createServer(function (req, res) {
console.log(`Received request for: ${req.url}`);
// Set redirect status code (301 for permanent redirect, 302 for temporary)
res.statusCode = 302;
// Set redirect status code (301 for permanent redirect, 302 for temporary)
res.statusCode = 302;
// Set the Location header to the redirect destination
res.setHeader('Location', `http://${BAD_HOST}:${BAD_PORT}`);
// Set the Location header to the redirect destination
res.setHeader('Location', `http://${BAD_HOST}:${BAD_PORT}`);
// You can add other headers if needed
res.setHeader('Content-Type', 'text/plain');
// You can add other headers if needed
res.setHeader('Content-Type', 'text/plain');
// Send a brief message in the body (optional)
res.end(`Redirecting to http://${BAD_HOST}:${BAD_PORT}`);
})
.listen(GOOD_PORT_REDIRECT);
// Send a brief message in the body (optional)
res.end(`Redirecting to http://${BAD_HOST}:${BAD_PORT}`);
}).listen(GOOD_PORT_REDIRECT);
badServer = http
.createServer(function (req, res) {
res.write('bad');
res.end();
})
.listen(BAD_PORT);
});
badServer = http.createServer(function (req, res) {
res.write('bad');
res.end();
}).listen(BAD_PORT);
})
afterAll(() => {
goodServer.close();
goodServerRedirect.close();
badServer.close();
});
afterAll(() => {
goodServer.close();
goodServerRedirect.close();
badServer.close();
});
it('should fetch', async () => {
const result = await utils.downloadUrlPromise(
ctx,
`http://${GOOD_HOST}:${GOOD_PORT}`,
commonTestParams.timeout,
commonTestParams.limit,
null,
false,
null
);
it('should fetch', async () => {
const result = await utils.downloadUrlPromise(
ctx,
`http://${GOOD_HOST}:${GOOD_PORT}`,
commonTestParams.timeout,
commonTestParams.limit,
null,
false,
null
);
expect(result.body.toString()).toBe('good');
});
expect(result.body.toString()).toBe('good');
});
it('should not fetch: denied ip', async () => {
await expect(
utils.downloadUrlPromise(ctx, `http://${BAD_HOST}:${BAD_PORT}`, commonTestParams.timeout, commonTestParams.limit, null, false, null)
).rejects.toThrow();
});
it('should not fetch: denied ip', async () => {
await expect(utils.downloadUrlPromise(
ctx,
`http://${BAD_HOST}:${BAD_PORT}`,
commonTestParams.timeout,
commonTestParams.limit,
null,
false,
null
)).rejects.toThrow();
});
it('should not fetch: redirect to denied ip', async () => {
await expect(utils.downloadUrlPromise(
ctx,
`http://${GOOD_HOST}:${GOOD_PORT_REDIRECT}`,
commonTestParams.timeout,
commonTestParams.limit,
null,
false,
null
)).rejects.toThrow();
});
it('should not fetch: redirect to denied ip', async () => {
await expect(
utils.downloadUrlPromise(ctx, `http://${GOOD_HOST}:${GOOD_PORT_REDIRECT}`, commonTestParams.timeout, commonTestParams.limit, null, false, null)
).rejects.toThrow();
});
});

View File

@ -30,7 +30,7 @@
*
*/
const { describe, test, expect } = require('@jest/globals');
const {describe, test, expect} = require('@jest/globals');
describe('Successful and failure tests', function () {
test('Successful test', function () {

View File

@ -30,7 +30,7 @@
*
*/
const { describe, test, expect } = require('@jest/globals');
const {describe, test, expect} = require('@jest/globals');
const config = require('../../Common/node_modules/config');
const operationContext = require('../../Common/sources/operationContext');
@ -39,12 +39,11 @@ const utils = require('../../Common/sources/utils');
const ctx = new operationContext.Context();
const minimumIterationsByteLength = 4;
describe('AES encryption & decryption', function () {
test('Iterations range', async function () {
const configuration = config.util.cloneDeep(config.get('aesEncrypt.config'));
const encrypted = await utils.encryptPassword(ctx, 'secretstring');
const { iterationsByteLength = 5 } = configuration;
const {iterationsByteLength = 5} = configuration;
const [iterationsHex] = encrypted.split(':');
const iterations = parseInt(iterationsHex, 16);
@ -55,8 +54,8 @@ describe('AES encryption & decryption', function () {
});
test('Correct workflow', async function () {
const encrypted = await utils.encryptPassword(ctx, 'secretstring');
const decrypted = await utils.decryptPassword(ctx, encrypted);
expect(decrypted).toEqual('secretstring');
const encrypted = await utils.encryptPassword(ctx, 'secretstring');
const decrypted = await utils.decryptPassword(ctx, encrypted);
expect(decrypted).toEqual('secretstring');
});
});