Merge branch release/v8.3.0 into master

This commit is contained in:
papacarlo
2025-02-05 17:22:07 +00:00
28 changed files with 577 additions and 584 deletions

View File

@ -55,12 +55,12 @@
- pg 8.11.3 ([MIT](https://raw.githubusercontent.com/brianc/node-postgres/master/LICENSE))
- redis 4.6.11 ([MIT](https://raw.githubusercontent.com/redis/node-redis/master/LICENSE))
- retry 0.12.0 ([MIT](https://raw.githubusercontent.com/tim-kos/node-retry/master/License))
- socket.io 4.7.1 ([MIT](https://raw.githubusercontent.com/socketio/socket.io/main/LICENSE))
- socket.io 4.8.1 ([MIT](https://raw.githubusercontent.com/socketio/socket.io/main/LICENSE))
- underscore 1.13.1 ([MIT](https://raw.githubusercontent.com/jashkenas/underscore/master/LICENSE))
- utf7 1.0.2 ([BSD](https://www.npmjs.com/package/utf7))
- windows-locale 1.0.1 ([MIT](https://raw.githubusercontent.com/TiagoDanin/Windows-Locale/master/LICENSE))
- xmlbuilder2 3.0.2 ([MIT](https://raw.githubusercontent.com/oozcitak/xmlbuilder2/master/LICENSE))
- @expo/spawn-async 1.3.0 ([MIT](https://raw.githubusercontent.com/TritonDataCenter/node-spawn-async/master/LICENSE))
- @expo/spawn-async 1.7.2 ([MIT](https://raw.githubusercontent.com/TritonDataCenter/node-spawn-async/master/LICENSE))
- bytes 3.0.0 ([MIT](https://raw.githubusercontent.com/visionmedia/bytes.js/master/LICENSE))
- co 4.6.0 ([MIT](https://raw.githubusercontent.com/tj/co/master/LICENSE))
- config 2.0.1 ([MIT](https://github.com/node-config/node-config/blob/master/LICENSE))

View File

@ -21,8 +21,8 @@
"host": "localhost",
"port": 587,
"auth": {
"user": "onlyoffice",
"pass": "onlyoffice"
"user": "",
"pass": ""
}
},
"connectionConfiguration": {
@ -112,14 +112,67 @@
"persistentStorage": {
},
"rabbitmq": {
"url": "amqp://guest:guest@localhost:5672",
"url": "amqp://localhost:5672",
"socketOptions": {},
"exchangepubsub": "ds.pubsub",
"queueconverttask": "ds.converttask",
"queueconvertresponse": "ds.convertresponse",
"exchangeconvertdead": "ds.exchangeconvertdead",
"queueconvertdead": "ds.convertdead",
"queuedelayed": "ds.delayed"
"exchangepubsub": {
"name": "ds.pubsub",
"options": {
"durable": true
}
},
"queuepubsub": {
"name": "",
"options": {
"autoDelete": true,
"exclusive": true,
"arguments": {
"x-queue-type": "classic"
}
}
},
"queueconverttask": {
"name": "ds.converttask6",
"options": {
"durable": true,
"maxPriority": 6,
"arguments": {
"x-queue-type": "classic"
}
}
},
"queueconvertresponse": {
"name": "ds.convertresponse",
"options": {
"durable": true,
"arguments": {
"x-queue-type": "classic"
}
}
},
"exchangeconvertdead": {
"name": "ds.exchangeconvertdead",
"options": {
"durable": true
}
},
"queueconvertdead": {
"name": "ds.convertdead",
"options": {
"durable": true,
"arguments": {
"x-queue-type": "classic"
}
}
},
"queuedelayed": {
"name": "ds.delayed",
"options": {
"durable": true,
"arguments": {
"x-queue-type": "classic"
}
}
}
},
"activemq": {
"connectOptions": {
@ -173,24 +226,27 @@
"favIconUrlCell" : "/web-apps/apps/spreadsheeteditor/main/resources/img/favicon.ico",
"favIconUrlSlide" : "/web-apps/apps/presentationeditor/main/resources/img/favicon.ico",
"favIconUrlPdf" : "/web-apps/apps/pdfeditor/main/resources/img/favicon.ico",
"favIconUrlDiagram" : "/web-apps/apps/visioeditor/main/resources/img/favicon.ico",
"fileInfoBlockList" : ["FileUrl"],
"pdfView": ["djvu", "xps", "oxps"],
"pdfEdit": ["pdf"],
"forms": ["pdf"],
"wordView": ["doc", "dotm", "dot", "fodt", "ott", "rtf", "mht", "mhtml", "html", "htm", "xml", "epub", "fb2", "sxw", "stw", "wps", "wpt", "docxf", "oform"],
"wordView": ["doc", "dotm", "dot", "fodt", "ott", "rtf", "mht", "mhtml", "html", "htm", "xml", "epub", "fb2", "sxw", "stw", "wps", "wpt", "pages", "docxf", "oform"],
"wordEdit": ["docx", "dotx", "docm", "odt", "txt"],
"cellView": ["xls", "xlsb", "xltm", "xlt", "fods", "ots", "sxc", "xml", "et", "ett"],
"cellView": ["xls", "xlsb", "xltm", "xlt", "fods", "ots", "sxc", "xml", "et", "ett", "numbers"],
"cellEdit": ["xlsx", "xltx", "xlsm", "ods", "csv"],
"slideView": ["ppt", "ppsx", "ppsm", "pps", "potm", "pot", "fodp", "otp", "sxi", "dps", "dpt"],
"slideView": ["ppt", "ppsx", "ppsm", "pps", "potm", "pot", "fodp", "otp", "sxi", "dps", "dpt", "key"],
"slideEdit": ["pptx", "potx", "pptm", "odp"],
"publicKey": "BgIAAACkAABSU0ExAAgAAAEAAQBpTpiJQ2hD8plpGTfEEmcq4IKyr31HikXpuVSBraMfqyodn2PGXBJ3daNSmdPOc0Nz4HO9Auljn8YYXDPBdpiABptSKvEDPF23Q+Qytg0+vCRyondyBcW91w7KLzXce3fnk8ZfJ8QtbZPL9m11wJIWZueQF+l0HKYx4lty+nccbCanytFTADkGQ3SnmExGEF3rBz6I9+OcrDDK9NKPJgEmCiuyei/d4XbPgKls3EIG0h38X5mVF2VytfWm2Yu850B6z3N4MYhj4b4vsYT62zEC4pMRUeb8dIBy4Jsmr3avtmeO00MUH6DVyPC8nirixj2YIOPKk13CdVqGDSXA3cvl",
"modulus": "5cvdwCUNhlp1wl2TyuMgmD3G4iqevPDI1aAfFEPTjme2r3avJpvgcoB0/OZREZPiAjHb+oSxL77hY4gxeHPPekDnvIvZpvW1cmUXlZlf/B3SBkLcbKmAz3bh3S96sisKJgEmj9L0yjCsnOP3iD4H610QRkyYp3RDBjkAU9HKpyZsHHf6clviMaYcdOkXkOdmFpLAdW32y5NtLcQnX8aT53d73DUvyg7XvcUFcneiciS8Pg22MuRDt108A/EqUpsGgJh2wTNcGMafY+kCvXPgc0NzztOZUqN1dxJcxmOfHSqrH6OtgVS56UWKR32vsoLgKmcSxDcZaZnyQ2hDiZhOaQ==",
"diagramView": [],
"diagramEdit": [],
"publicKey": "",
"modulus": "",
"exponent": 65537,
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDly93AJQ2GWnXC\nXZPK4yCYPcbiKp688MjVoB8UQ9OOZ7avdq8mm+BygHT85lERk+ICMdv6hLEvvuFj\niDF4c896QOe8i9mm9bVyZReVmV/8HdIGQtxsqYDPduHdL3qyKwomASaP0vTKMKyc\n4/eIPgfrXRBGTJindEMGOQBT0cqnJmwcd/pyW+Ixphx06ReQ52YWksB1bfbLk20t\nxCdfxpPnd3vcNS/KDte9xQVyd6JyJLw+DbYy5EO3XTwD8SpSmwaAmHbBM1wYxp9j\n6QK9c+BzQ3PO05lSo3V3ElzGY58dKqsfo62BVLnpRYpHfa+yguAqZxLENxlpmfJD\naEOJmE5pAgMBAAECggEALiL+RKOr0Xu8BOgQ0j1DwA03LxVrhXe6etmJI+JySTcd\ngKENjWziZVrRIi2DvUm5qMMl7WhSwslKK1eexxZJY7xASqSxcEoIwgz17T07/jxm\nfIdUBiUKDZ1Kv8PWmIr3oKW+fkXWi/m1zlIe0qXRpTmsGNEsHQLEqi0rmaiXTXOR\n/2Ldwi6kZR3sWFx97YS4Mx/pueGJTXEai6AVEZzN5Gog6xD8HXR1Rvq+hhd+MocG\nfnU4HgilKRfoJlWd9FOscgSufKG0L3ViO4fSKU46l5aullDYUk5ECMWiwuKSqSE7\nqD45jI3mbOre7S4u3S3TWdD3lzwiXL49LdwKlEC4mQKBgQD0sLr0GH4Wr+QX2xJE\nuA/Cb8QW41l8iSCBTRZZR/sJOd+o3rbcVidlzO/EbZblXG4ZPDmRjgBCGKIP5EZi\n0DsL+Wv32WOo44LpxJGhqExbm0H1iZ1zZ97l0P8fvIhHE42gmaLToOIGDhPSXGvv\nzlqOHbGbq4jsERc1jp1bej5q6wKBgQDwaueIc4pRchH98QYidcyr8Vwg9KhbnfYX\ny3W4RPlZtBdF34iJaio+ASzugo/zy1RTcVrsCskYWXyKDUQz1yu0iCng+fDCUnTm\nXGmEoEGNhk4vTJOt7hBav1/Ja/dUipGf6mXUuanwJ0e+1/Et/B0ah5X1Um5AyNZI\nM+SyRz3u+wKBgQCjvtUNXoqaghCBCmB6TjZ1prexnWkYFugCv2SSUMIk1W7gIlJ6\ntsjcrj1R1Qii6qzfBFd+GWoA0V06h0e2/qRVCg//p6GytrW33IycgvS+ZPLJ7tLI\nFR2r66WfRlpoPiSL8eRt/P7kkG0hXCn7K7ub2TEu/Ka/W1yNwad6PR8iCwKBgQC8\nXcZSrtQsxAc8w99emJVoEo9wcsCGJ9ltA0iUu9XyZpvlbyJ3J+s48YrWxQ0sop7L\nUgE+96Rfo51kPMi3JVtk81p8ntf4KMrWwokaFMXHsPcJMCJ1IBVIRLE0C5eZcYhv\nlyN57I4tT1lzOZYJxYK4Cot/zrn7oF/j6mTBGfh4iQKBgQCiJMUxRz01/czH/XSX\ngo3dVbHQ4FEOufWnE3Eb93S8r0/eq1RM118rb0TqzuiadW2xYDU4nucWQlrlmq0d\nFY/m+Hy97pqyk6jmoU5I/D+ssBIoYHWLnH9/xfvDEk2JGSJSHtzu0D4EDC/rgQ49\nMbYsO5oUrF8tPlhj5vzbf3GKLA==\n-----END PRIVATE KEY-----\n",
"publicKeyOld": "BgIAAACkAABSU0ExAAgAAAEAAQBpTpiJQ2hD8plpGTfEEmcq4IKyr31HikXpuVSBraMfqyodn2PGXBJ3daNSmdPOc0Nz4HO9Auljn8YYXDPBdpiABptSKvEDPF23Q+Qytg0+vCRyondyBcW91w7KLzXce3fnk8ZfJ8QtbZPL9m11wJIWZueQF+l0HKYx4lty+nccbCanytFTADkGQ3SnmExGEF3rBz6I9+OcrDDK9NKPJgEmCiuyei/d4XbPgKls3EIG0h38X5mVF2VytfWm2Yu850B6z3N4MYhj4b4vsYT62zEC4pMRUeb8dIBy4Jsmr3avtmeO00MUH6DVyPC8nirixj2YIOPKk13CdVqGDSXA3cvl",
"modulusOld": "5cvdwCUNhlp1wl2TyuMgmD3G4iqevPDI1aAfFEPTjme2r3avJpvgcoB0/OZREZPiAjHb+oSxL77hY4gxeHPPekDnvIvZpvW1cmUXlZlf/B3SBkLcbKmAz3bh3S96sisKJgEmj9L0yjCsnOP3iD4H610QRkyYp3RDBjkAU9HKpyZsHHf6clviMaYcdOkXkOdmFpLAdW32y5NtLcQnX8aT53d73DUvyg7XvcUFcneiciS8Pg22MuRDt108A/EqUpsGgJh2wTNcGMafY+kCvXPgc0NzztOZUqN1dxJcxmOfHSqrH6OtgVS56UWKR32vsoLgKmcSxDcZaZnyQ2hDiZhOaQ==",
"privateKey": "",
"publicKeyOld": "",
"modulusOld": "",
"exponentOld": 65537,
"privateKeyOld": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDly93AJQ2GWnXC\nXZPK4yCYPcbiKp688MjVoB8UQ9OOZ7avdq8mm+BygHT85lERk+ICMdv6hLEvvuFj\niDF4c896QOe8i9mm9bVyZReVmV/8HdIGQtxsqYDPduHdL3qyKwomASaP0vTKMKyc\n4/eIPgfrXRBGTJindEMGOQBT0cqnJmwcd/pyW+Ixphx06ReQ52YWksB1bfbLk20t\nxCdfxpPnd3vcNS/KDte9xQVyd6JyJLw+DbYy5EO3XTwD8SpSmwaAmHbBM1wYxp9j\n6QK9c+BzQ3PO05lSo3V3ElzGY58dKqsfo62BVLnpRYpHfa+yguAqZxLENxlpmfJD\naEOJmE5pAgMBAAECggEALiL+RKOr0Xu8BOgQ0j1DwA03LxVrhXe6etmJI+JySTcd\ngKENjWziZVrRIi2DvUm5qMMl7WhSwslKK1eexxZJY7xASqSxcEoIwgz17T07/jxm\nfIdUBiUKDZ1Kv8PWmIr3oKW+fkXWi/m1zlIe0qXRpTmsGNEsHQLEqi0rmaiXTXOR\n/2Ldwi6kZR3sWFx97YS4Mx/pueGJTXEai6AVEZzN5Gog6xD8HXR1Rvq+hhd+MocG\nfnU4HgilKRfoJlWd9FOscgSufKG0L3ViO4fSKU46l5aullDYUk5ECMWiwuKSqSE7\nqD45jI3mbOre7S4u3S3TWdD3lzwiXL49LdwKlEC4mQKBgQD0sLr0GH4Wr+QX2xJE\nuA/Cb8QW41l8iSCBTRZZR/sJOd+o3rbcVidlzO/EbZblXG4ZPDmRjgBCGKIP5EZi\n0DsL+Wv32WOo44LpxJGhqExbm0H1iZ1zZ97l0P8fvIhHE42gmaLToOIGDhPSXGvv\nzlqOHbGbq4jsERc1jp1bej5q6wKBgQDwaueIc4pRchH98QYidcyr8Vwg9KhbnfYX\ny3W4RPlZtBdF34iJaio+ASzugo/zy1RTcVrsCskYWXyKDUQz1yu0iCng+fDCUnTm\nXGmEoEGNhk4vTJOt7hBav1/Ja/dUipGf6mXUuanwJ0e+1/Et/B0ah5X1Um5AyNZI\nM+SyRz3u+wKBgQCjvtUNXoqaghCBCmB6TjZ1prexnWkYFugCv2SSUMIk1W7gIlJ6\ntsjcrj1R1Qii6qzfBFd+GWoA0V06h0e2/qRVCg//p6GytrW33IycgvS+ZPLJ7tLI\nFR2r66WfRlpoPiSL8eRt/P7kkG0hXCn7K7ub2TEu/Ka/W1yNwad6PR8iCwKBgQC8\nXcZSrtQsxAc8w99emJVoEo9wcsCGJ9ltA0iUu9XyZpvlbyJ3J+s48YrWxQ0sop7L\nUgE+96Rfo51kPMi3JVtk81p8ntf4KMrWwokaFMXHsPcJMCJ1IBVIRLE0C5eZcYhv\nlyN57I4tT1lzOZYJxYK4Cot/zrn7oF/j6mTBGfh4iQKBgQCiJMUxRz01/czH/XSX\ngo3dVbHQ4FEOufWnE3Eb93S8r0/eq1RM118rb0TqzuiadW2xYDU4nucWQlrlmq0d\nFY/m+Hy97pqyk6jmoU5I/D+ssBIoYHWLnH9/xfvDEk2JGSJSHtzu0D4EDC/rgQ49\nMbYsO5oUrF8tPlhj5vzbf3GKLA==\n-----END PRIVATE KEY-----\n",
"privateKeyOld": "",
"refreshLockInterval": "10m",
"dummy" : {
"enable": false,
@ -427,7 +483,7 @@
},
"binaryChanges": false,
"websocketMaxPayloadSize": "1.5MB",
"maxChangesSize": "0mb"
"maxChangesSize": "150MB"
},
"sockjs": {
"sockjs_url": "",

View File

@ -50,7 +50,6 @@ function InputCommand(data, copyExplicit) {
this['username'] = data['username'];
this['tokenSession'] = data['tokenSession'];
this['tokenDownload'] = data['tokenDownload'];
this['tokenHistory'] = data['tokenHistory'];
this['data'] = data['data'];
this['editorid'] = data['editorid'];
this['format'] = data['format'];
@ -84,7 +83,6 @@ function InputCommand(data, copyExplicit) {
this['savekey'] = data['savekey'];
this['userconnectionid'] = data['userconnectionid'];
this['responsekey'] = data['responsekey'];
this['docconnectionid'] = data['docconnectionid'];
this['jsonparams'] = data['jsonparams'];
this['lcid'] = data['lcid'];
this['useractionid'] = data['useractionid'];
@ -101,7 +99,6 @@ function InputCommand(data, copyExplicit) {
this['savepassword'] = data['savepassword'];
this['withoutPassword'] = data['withoutPassword'];
this['outputurls'] = data['outputurls'];
this['closeonerror'] = data['closeonerror'];
this['serverVersion'] = data['serverVersion'];
this['rediskey'] = data['rediskey'];
this['nobase64'] = data['nobase64'];
@ -127,7 +124,6 @@ function InputCommand(data, copyExplicit) {
this['username'] = undefined;
this['tokenSession'] = undefined;//string validate
this['tokenDownload'] = undefined;//string validate
this['tokenHistory'] = undefined;//string validate
this['data'] = undefined;//string
//to open
this['editorid'] = undefined;//int
@ -152,7 +148,6 @@ function InputCommand(data, copyExplicit) {
this['savekey'] = undefined;//int document id to save
this['userconnectionid'] = undefined;//string internal
this['responsekey'] = undefined;
this['docconnectionid'] = undefined;//string internal
this['jsonparams'] = undefined;//string
this['lcid'] = undefined;
this['useractionid'] = undefined;
@ -165,7 +160,6 @@ function InputCommand(data, copyExplicit) {
this['savepassword'] = undefined;
this['withoutPassword'] = undefined;
this['outputurls'] = undefined;
this['closeonerror'] = undefined;
this['serverVersion'] = undefined;
this['rediskey'] = undefined;
this['nobase64'] = true;
@ -218,9 +212,6 @@ InputCommand.prototype = {
getTokenDownload: function() {
return this['tokenDownload'];
},
getTokenHistory: function() {
return this['tokenHistory'];
},
getData: function() {
return this['data'];
},
@ -359,12 +350,6 @@ InputCommand.prototype = {
setResponseKey: function(data) {
this['responsekey'] = data;
},
getDocConnectionId: function() {
return this['docconnectionid'];
},
setDocConnectionId: function(data) {
this['docconnectionid'] = data;
},
getJsonParams: function() {
return this['jsonparams'];
},
@ -447,12 +432,6 @@ InputCommand.prototype = {
getOutputUrls: function() {
return this['outputurls'];
},
getCloseOnError: function() {
return this['closeonerror'];
},
setCloseOnError: function(data) {
this['closeonerror'] = data;
},
getServerVersion: function() {
return this['serverVersion'];
},

View File

@ -233,6 +233,7 @@ exports.CONVERT_ICU = -92;
exports.CONVERT_LIMITS = -93;
exports.CONVERT_TEMPORARY = -94;
exports.CONVERT_DETECT = -95;
exports.CONVERT_CELLLIMITS = -96;
exports.CONVERT_DEAD_LETTER = -99;
exports.UPLOAD = -100;
exports.UPLOAD_CONTENT_LENGTH = -101;
@ -248,11 +249,14 @@ exports.VKEY_TIME_INCORRECT = -125;
exports.EDITOR_CHANGES = -160;
exports.PASSWORD = -180;
exports.QUEUE_PRIORITY_VERY_LOW = 0;
exports.QUEUE_PRIORITY_LOW = 1;
exports.QUEUE_PRIORITY_NORMAL = 2;
exports.QUEUE_PRIORITY_HIGH = 3;
exports.QUEUE_PRIORITY_VERY_HIGH = 4;
//Quorum queues internally only support two priorities: high and normal.
//Messages without a priority set will be mapped to normal as will priorities 0 - 4.
//Messages with a priority higher than 4 will be mapped to high.
exports.QUEUE_PRIORITY_VERY_LOW = 2;
exports.QUEUE_PRIORITY_LOW = 3;
exports.QUEUE_PRIORITY_NORMAL = 4;
exports.QUEUE_PRIORITY_HIGH = 5;
exports.QUEUE_PRIORITY_VERY_HIGH = 6;
exports.EDITOR_TYPE_WORD = 0;
exports.EDITOR_TYPE_SPREADSHEET = 1;

View File

@ -59,7 +59,8 @@ exports.readLicense = async function () {
startDate: startDate,
endDate: null,
customerId: "",
alias: ""
alias: "",
multitenancy: false
}, null];
};

View File

@ -39,7 +39,6 @@ var utils = require('./utils');
var constants = require('./constants');
var rabbitMQCore = require('./rabbitMQCore');
var activeMQCore = require('./activeMQCore');
const logger = require('./logger');
const commonDefines = require('./commondefines');
const operationContext = require('./operationContext');
@ -57,7 +56,6 @@ var cfgActiveQueueConvertResponse = constants.ACTIVEMQ_QUEUE_PREFIX + config.get
var cfgActiveQueueConvertDead = constants.ACTIVEMQ_QUEUE_PREFIX + config.get('activemq.queueconvertdead');
var cfgActiveQueueDelayed = constants.ACTIVEMQ_QUEUE_PREFIX + config.get('activemq.queuedelayed');
const optionsExchnangeDead = {durable: true};
function initRabbit(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAddResponseReceive, isEmitDead, isAddDelayed, callback) {
return co(function* () {
var e = null;
@ -72,24 +70,22 @@ function initRabbit(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAdd
});
taskqueue.connection = conn;
var bAssertTaskQueue = false;
var optionsTaskQueue = {
durable: true,
maxPriority: constants.QUEUE_PRIORITY_VERY_HIGH,
let optionsTaskQueueDefault = {
messageTtl: cfgQueueRetentionPeriod * 1000,
deadLetterExchange: cfgRabbitExchangeConvertDead
deadLetterExchange: cfgRabbitExchangeConvertDead.name
};
let optionsTaskQueue = {...optionsTaskQueueDefault, ...cfgRabbitQueueConvertTask.options};
if (isAddTask) {
taskqueue.channelConvertTask = yield rabbitMQCore.createConfirmChannelPromise(conn);
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertTask, cfgRabbitQueueConvertTask,
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertTask, cfgRabbitQueueConvertTask.name,
optionsTaskQueue);
bAssertTaskQueue = true;
}
var bAssertResponseQueue = false;
var optionsResponseQueue = {durable: true};
if (isAddResponse) {
taskqueue.channelConvertResponse = yield rabbitMQCore.createConfirmChannelPromise(conn);
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertResponse, cfgRabbitQueueConvertResponse,
optionsResponseQueue);
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertResponse, cfgRabbitQueueConvertResponse.name,
cfgRabbitQueueConvertResponse.options);
bAssertResponseQueue = true;
}
var optionsReceive = {noAck: false};
@ -97,10 +93,10 @@ 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,
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertTaskReceive, cfgRabbitQueueConvertTask.name,
optionsTaskQueue);
}
yield rabbitMQCore.consumePromise(taskqueue.channelConvertTaskReceive, cfgRabbitQueueConvertTask,
yield rabbitMQCore.consumePromise(taskqueue.channelConvertTaskReceive, cfgRabbitQueueConvertTask.name,
function (message) {
co(function* () {
let ack = function() {
@ -118,10 +114,10 @@ function initRabbit(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAdd
if (isAddResponseReceive) {
taskqueue.channelConvertResponseReceive = yield rabbitMQCore.createChannelPromise(conn);
if (!bAssertResponseQueue) {
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertResponseReceive, cfgRabbitQueueConvertResponse,
optionsResponseQueue);
yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertResponseReceive, cfgRabbitQueueConvertResponse.name,
cfgRabbitQueueConvertResponse.options);
}
yield rabbitMQCore.consumePromise(taskqueue.channelConvertResponseReceive, cfgRabbitQueueConvertResponse,
yield rabbitMQCore.consumePromise(taskqueue.channelConvertResponseReceive, cfgRabbitQueueConvertResponse.name,
function (message) {
if (message) {
taskqueue.emit('response', message.content.toString(), function() {
@ -131,21 +127,20 @@ function initRabbit(taskqueue, isAddTask, isAddResponse, isAddTaskReceive, isAdd
}, optionsReceive);
}
if (isAddDelayed) {
let optionsDelayedQueue = {
durable: true,
deadLetterExchange: cfgRabbitExchangeConvertDead
let optionsDelayedQueueDefault = {
deadLetterExchange: cfgRabbitExchangeConvertDead.name
};
let optionsDelayedQueue = {...optionsDelayedQueueDefault, ...cfgRabbitQueueDelayed.options};
taskqueue.channelDelayed = yield rabbitMQCore.createConfirmChannelPromise(conn);
yield rabbitMQCore.assertQueuePromise(taskqueue.channelDelayed, cfgRabbitQueueDelayed, optionsDelayedQueue);
yield rabbitMQCore.assertQueuePromise(taskqueue.channelDelayed, cfgRabbitQueueDelayed.name, optionsDelayedQueue);
}
if (isEmitDead) {
taskqueue.channelConvertDead = yield rabbitMQCore.createChannelPromise(conn);
yield rabbitMQCore.assertExchangePromise(taskqueue.channelConvertDead, cfgRabbitExchangeConvertDead, 'fanout',
optionsExchnangeDead);
var queue = yield rabbitMQCore.assertQueuePromise(taskqueue.channelConvertDead, cfgRabbitQueueConvertDead,
{durable: true});
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, '');
taskqueue.channelConvertDead.bindQueue(queue, cfgRabbitExchangeConvertDead.name, '');
yield rabbitMQCore.consumePromise(taskqueue.channelConvertDead, queue, function(message) {
if (null != taskqueue.channelConvertDead) {
if (message) {
@ -369,7 +364,7 @@ function addTaskRabbit(taskqueue, content, priority, callback, opt_expiration, o
if (undefined !== opt_headers) {
options.headers = opt_headers;
}
taskqueue.channelConvertTask.sendToQueue(cfgRabbitQueueConvertTask, content, options, callback);
taskqueue.channelConvertTask.sendToQueue(cfgRabbitQueueConvertTask.name, content, options, callback);
}
function addTaskActive(taskqueue, content, priority, callback, opt_expiration, opt_headers) {
var msg = {durable: true, priority: priority, body: content, ttl: cfgQueueRetentionPeriod * 1000};
@ -401,7 +396,7 @@ function addTaskString(taskqueue, task, priority, opt_expiration, opt_headers) {
}
function addResponseRabbit(taskqueue, content, callback) {
var options = {persistent: true};
taskqueue.channelConvertResponse.sendToQueue(cfgRabbitQueueConvertResponse, content, options, callback);
taskqueue.channelConvertResponse.sendToQueue(cfgRabbitQueueConvertResponse.name, content, options, callback);
}
function addResponseActive(taskqueue, content, callback) {
var msg = {durable: true, body: content};
@ -418,7 +413,7 @@ function closeActive(conn) {
}
function addDelayedRabbit(taskqueue, content, ttl, callback) {
var options = {persistent: true, expiration: ttl.toString()};
taskqueue.channelDelayed.sendToQueue(cfgRabbitQueueDelayed, content, options, callback);
taskqueue.channelDelayed.sendToQueue(cfgRabbitQueueDelayed.name, content, options, callback);
}
function addDelayedActive(taskqueue, content, ttl, callback) {
var msg = {durable: true, body: content, ttl: ttl};
@ -433,8 +428,8 @@ function healthCheckRabbit(taskqueue) {
if (!taskqueue.channelConvertDead) {
return false;
}
const exchange = yield rabbitMQCore.assertExchangePromise(taskqueue.channelConvertDead, cfgRabbitExchangeConvertDead,
'fanout', optionsExchnangeDead);
const exchange = yield rabbitMQCore.assertExchangePromise(taskqueue.channelConvertDead, cfgRabbitExchangeConvertDead.name,
'fanout', cfgRabbitExchangeConvertDead.options);
return !!exchange;
});
}

View File

@ -246,7 +246,8 @@ function fixTenantLicense(ctx, licenseInfo, licenseInfoTenant) {
async function getTenantLicense(ctx) {
let res = licenseTuple;
if (isMultitenantMode(ctx) && !isDefaultTenant(ctx)) {
if (licenseInfo.alias) {
//todo alias is deprecated. remove one year after 8.3
if (licenseInfo.multitenancy || licenseInfo.alias) {
let tenantPath = utils.removeIllegalCharacters(ctx.tenant);
let licensePath = path.join(cfgTenantsBaseDir, tenantPath, cfgTenantsFilenameLicense);
let licenseTupleTenant = nodeCache.get(licensePath);
@ -263,7 +264,7 @@ async function getTenantLicense(ctx) {
res = [...res];
res[0] = {...res[0]};
res.type = constants.LICENSE_RESULT.Error;
ctx.logger.error('getTenantLicense error: missing "alias" field');
ctx.logger.error('getTenantLicense error: missing "multitenancy" or "alias" field');
}
}
return res;
@ -301,8 +302,10 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) {
const startDate = res.startDate;
if (oLicense['end_date']) {
res.endDate = new Date(oLicense['end_date']);
} else {
//spread copy do not copy date
res.endDate = new Date(res.endDate);
}
const endDate = res.endDate;
if (oLicense['customer_id']) {
res.customerId = oLicense['customer_id']
@ -312,6 +315,10 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) {
res.alias = oLicense['alias'];
}
if (oLicense['multitenancy']) {
res.multitenancy = oLicense['multitenancy'];
}
if (true === oLicense['timelimited']) {
res.mode |= c_LM.Limited;
}
@ -352,14 +359,14 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) {
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 <= endDate) {
if (startDate <= checkStartDate && checkDate <= res.endDate) {
res.type = c_LR.Success;
} else if (startDate > checkStartDate) {
res.type = c_LR.NotBefore;
ctx.logger.warn('License: License not active before start_date:%s.', startDate.toISOString());
} else if (timeLimited) {
// 30 days after end license = limited mode with 20 Connections
if (endDate.setDate(checkDate.getDate() + 30) >= checkDate) {
if (res.endDate.setUTCDate(res.endDate.getUTCDate() + 30) >= checkDate) {
res.type = c_LR.SuccessLimit;
res.connections = Math.min(res.connections, constants.LICENSE_CONNECTIONS);
res.connectionsView = Math.min(res.connectionsView, constants.LICENSE_CONNECTIONS);

View File

@ -95,15 +95,14 @@ var ANDROID_SAFE_FILENAME = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY
BigInt.prototype.toJSON = function() { return this.toString() };
var g_oIpFilterRules = new Map();
function getIpFilterRules(rules) {
var res = [];
for (var i = 0; i < rules.length; ++i) {
var rule = rules[i];
var regExpStr = rule['address'].split('*').map(escapeStringRegexp).join('.*');
var exp = new RegExp('^' + regExpStr + '$', 'i');
res.push({allow: rule['allowed'], exp: exp});
function getIpFilterRule(address) {
let exp = g_oIpFilterRules.get(address);
if (!exp) {
let regExpStr = address.split('*').map(escapeStringRegexp).join('.*');
exp = new RegExp('^' + regExpStr + '$', 'i');
g_oIpFilterRules.set(address, exp);
}
return res;
return exp;
}
const pemfileCache = new NodeCache({stdTTL: ms(cfgExpPemStdTtl) / 1000, checkperiod: ms(cfgExpPemCheckPeriod) / 1000, errorOnMissing: false, useClones: true});
@ -457,12 +456,12 @@ function downloadUrlPromiseWithoutRedirect(ctx, uri, optTimeout, optLimit, opt_A
.on('error', fError);
if (optTimeout && optTimeout.wholeCycle) {
timeoutId = setTimeout(function() {
raiseError(ro, 'ETIMEDOUT', 'Error: whole request cycle timeout');
raiseError(ro, 'ETIMEDOUT', `Error: whole request cycle timeout: ${optTimeout.wholeCycle}`);
}, ms(optTimeout.wholeCycle));
}
});
}
function postRequestPromise(ctx, uri, postData, postDataStream, postDataSize, optTimeout, opt_Authorization, opt_headers) {
function postRequestPromise(ctx, uri, postData, postDataStream, postDataSize, optTimeout, opt_Authorization, opt_isInJwtToken, opt_headers) {
return new Promise(function(resolve, reject) {
const tenTenantRequestDefaults = ctx.getCfg('services.CoAuthoring.requestDefaults', cfgRequestDefaults);
const tenTokenOutboxHeader = ctx.getCfg('services.CoAuthoring.token.outbox.header', cfgTokenOutboxHeader);
@ -473,8 +472,14 @@ function postRequestPromise(ctx, uri, postData, postDataStream, postDataSize, op
let connectionAndInactivity = optTimeout && optTimeout.connectionAndInactivity && ms(optTimeout.connectionAndInactivity);
let options = config.util.extendDeep({}, tenTenantRequestDefaults);
Object.assign(options, {uri: urlParsed, encoding: 'utf8', timeout: connectionAndInactivity});
//baseRequest creates new agent(win-ca injects in globalAgent)
options.agentOptions = https.globalAgent.options;
if (!addExternalRequestOptions(ctx, uri, opt_isInJwtToken, options)) {
reject(new Error('Block external request. See externalRequest config options'));
return;
}
if (!options.agent) {
//baseRequest creates new agent(win-ca injects in globalAgent)
options.agentOptions = https.globalAgent.options;
}
if (postData) {
options.body = postData;
}
@ -519,7 +524,7 @@ function postRequestPromise(ctx, uri, postData, postDataStream, postDataSize, op
});
if (optTimeout && optTimeout.wholeCycle) {
setTimeout(function() {
raiseError(ro, 'ETIMEDOUT', 'Error whole request cycle timeout');
raiseError(ro, 'ETIMEDOUT', `Error: whole request cycle timeout: ${optTimeout.wholeCycle}`);
}, ms(optTimeout.wholeCycle));
}
if (postDataStream && !postData) {
@ -533,6 +538,7 @@ exports.mapAscServerErrorToOldError = function(error) {
var res = -1;
switch (error) {
case constants.NO_ERROR :
case constants.CONVERT_CELLLIMITS :
res = 0;
break;
case constants.TASK_QUEUE :
@ -873,14 +879,13 @@ function* pipeFiles(from, to) {
exports.pipeFiles = co.wrap(pipeFiles);
function checkIpFilter(ctx, ipString, opt_hostname) {
const tenIpFilterRules = ctx.getCfg('services.CoAuthoring.ipfilter.rules', cfgIpFilterRules);
const tenIpFilterErrorCode = ctx.getCfg('services.CoAuthoring.ipfilter.errorcode', cfgIpFilterErrorCode);
var status = 0;
var ip4;
var ip6;
if (ipaddr.isValid(ipString)) {
var ip = ipaddr.parse(ipString);
if ('ipv6' == ip.kind()) {
if ('ipv6' === ip.kind()) {
if (ip.isIPv4MappedAddress()) {
ip4 = ip.toIPv4Address().toString();
}
@ -890,16 +895,13 @@ function checkIpFilter(ctx, ipString, opt_hostname) {
ip6 = ip.toIPv4MappedAddress().toNormalizedString();
}
}
let ipFilterRules = g_oIpFilterRules.get(ctx.tenant);
if (!ipFilterRules) {
ipFilterRules = getIpFilterRules(tenIpFilterRules);
g_oIpFilterRules.set(ctx.tenant, ipFilterRules);
}
for (var i = 0; i < ipFilterRules.length; ++i) {
var rule = ipFilterRules[i];
if ((opt_hostname && rule.exp.test(opt_hostname)) || (ip4 && rule.exp.test(ip4)) || (ip6 && rule.exp.test(ip6))) {
if (!rule.allow) {
for (let i = 0; i < tenIpFilterRules.length; ++i) {
let rule = tenIpFilterRules[i];
let exp = getIpFilterRule(rule.address);
if ((opt_hostname && exp.test(opt_hostname)) || (ip4 && exp.test(ip4)) || (ip6 && exp.test(ip6))) {
if (!rule.allowed) {
const tenIpFilterErrorCode = ctx.getCfg('services.CoAuthoring.ipfilter.errorcode', cfgIpFilterErrorCode);
status = tenIpFilterErrorCode;
}
break;
@ -1077,7 +1079,8 @@ exports.encryptPassword = async function (ctx, password) {
const iterations = Math.floor(Math.random() * (greaterNumber - lowerNumber)) + lowerNumber;
const encryptionKey = await pbkdf2Promise(tenSecret, salt, iterations, keyByteLength, 'sha512');
const cipher = crypto.createCipheriv('aes-256-gcm', encryptionKey, initializationVector);
//todo chacha20-poly1305 (clean db)
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);
@ -1119,7 +1122,7 @@ exports.decryptPassword = async function (ctx, password) {
] = pointerArray;
const decryptionKey = await pbkdf2Promise(tenSecret, salt, parseInt(iterations, 16), keyByteLength, 'sha512');
const decipher = crypto.createDecipheriv('aes-256-gcm', decryptionKey, initializationVector);
const decipher = crypto.createDecipheriv('aes-256-gcm', decryptionKey, initializationVector, {authTagLength:16});
decipher.setAuthTag(authTag);
return Buffer.concat([decipher.update(encryptedData, 'binary'), decipher.final()]).toString();
@ -1152,6 +1155,7 @@ exports.convertLicenseInfoToFileParams = function(licenseInfo) {
license.users_expire = licenseInfo.usersExpire / constants.LICENSE_EXPIRE_USERS_ONE_DAY;
license.customer_id = licenseInfo.customerId;
license.alias = licenseInfo.alias;
license.multitenancy = licenseInfo.multitenancy;
return license;
};
exports.convertLicenseInfoToServerParams = function(licenseInfo) {

View File

@ -885,9 +885,9 @@
"integrity": "sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg=="
},
"@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
},
"@tediousjs/connection-string": {
"version": "0.4.4",
@ -904,11 +904,6 @@
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
"integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A=="
},
"@types/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
},
"@types/cors": {
"version": "2.8.17",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
@ -1563,16 +1558,15 @@
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
},
"engine.io": {
"version": "6.5.5",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz",
"integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==",
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.3.tgz",
"integrity": "sha512-2hkLItQMBkoYSagneiisupWGvsQlWXqzhSMvsjaM8GYbnfUsX7tzYQq9QARnate5LRedVTX+MbkSZAANAr3NtQ==",
"requires": {
"@types/cookie": "^0.4.1",
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.4.1",
"cookie": "~1.0.2",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
@ -1580,27 +1574,22 @@
},
"dependencies": {
"cookie": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="
},
"debug": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"requires": {
"ms": "2.1.2"
"ms": "^2.1.3"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}
}
},
@ -3383,31 +3372,31 @@
}
},
"socket.io": {
"version": "4.7.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.1.tgz",
"integrity": "sha512-W+utHys2w//dhFjy7iQQu9sGd3eokCjGbl2r59tyLqNiJJBdIebn3GAKEXBr3osqHTObJi2die/25bCx2zsaaw==",
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
"integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
"requires": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"cors": "~2.8.5",
"debug": "~4.3.2",
"engine.io": "~6.5.0",
"engine.io": "~6.6.0",
"socket.io-adapter": "~2.5.2",
"socket.io-parser": "~4.2.4"
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"requires": {
"ms": "2.1.2"
"ms": "^2.1.3"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}
}
},
@ -3445,17 +3434,17 @@
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"requires": {
"ms": "2.1.2"
"ms": "^2.1.3"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}
}
},
@ -3763,7 +3752,7 @@
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
},
"webidl-conversions": {
"version": "3.0.1",

View File

@ -40,7 +40,7 @@
"pg": "8.11.3",
"redis": "4.6.11",
"retry": "0.12.0",
"socket.io": "4.7.1",
"socket.io": "4.8.1",
"underscore": "1.13.1",
"utf7": "1.0.2",
"windows-locale": "1.0.1",

View File

@ -157,7 +157,8 @@ const cfgTableChanges = config.get('services.CoAuthoring.sql.tableChanges');
const EditorTypes = {
document : 0,
spreadsheet : 1,
presentation : 2
presentation : 2,
diagram : 3
};
const defaultHttpPort = 80, defaultHttpsPort = 443; // Default ports (for http and https)
@ -736,6 +737,7 @@ async function getOriginalParticipantsId(ctx, docId) {
async function sendServerRequest(ctx, uri, dataObject, opt_checkAndFixAuthorizationLength) {
const tenCallbackRequestTimeout = ctx.getCfg('services.CoAuthoring.server.callbackRequestTimeout', cfgCallbackRequestTimeout);
const tenTokenEnableRequestInbox = ctx.getCfg('services.CoAuthoring.token.enable.request.inbox', cfgTokenEnableRequestInbox);
ctx.logger.debug('postData request: url = %s;data = %j', uri, dataObject);
let auth;
@ -751,7 +753,8 @@ async function sendServerRequest(ctx, uri, dataObject, opt_checkAndFixAuthorizat
dataObject.setToken(bodyToken);
}
let headers = {'Content-Type': 'application/json'};
let postRes = await utils.postRequestPromise(ctx, uri, JSON.stringify(dataObject), undefined, undefined, tenCallbackRequestTimeout, auth, headers);
//isInJwtToken is true because callbackUrl is required field in jwt token
let postRes = await utils.postRequestPromise(ctx, uri, JSON.stringify(dataObject), undefined, undefined, tenCallbackRequestTimeout, auth, tenTokenEnableRequestInbox, headers);
ctx.logger.debug('postData response: data = %s', postRes.body);
return postRes.body;
}
@ -850,7 +853,7 @@ function* setForceSave(ctx, docId, forceSave, cmd, success, url) {
let data = {type: forceSaveType, time: forceSave.getTime(), success: success};
if(commonDefines.c_oAscForceSaveTypes.Form === forceSaveType || commonDefines.c_oAscForceSaveTypes.Internal === forceSaveType) {
let code = success ? commonDefines.c_oAscServerCommandErrors.NoError : commonDefines.c_oAscServerCommandErrors.UnknownError;
data = {code: code, time: null, inProgress: false};
data = {code: code, time: forceSave.getTime(), inProgress: false};
if (commonDefines.c_oAscForceSaveTypes.Internal === forceSaveType) {
data.url = url;
}
@ -879,7 +882,7 @@ async function checkForceSaveCache(ctx, convertInfo) {
return res;
}
async function applyForceSaveCache(ctx, docId, forceSave, type, opt_userConnectionId, opt_userConnectionDocId,
opt_responseKey, opt_formdata, opt_userId, opt_userIndex) {
opt_responseKey, opt_formdata, opt_userId, opt_userIndex, opt_prevTime) {
let res = {ok: false, notModified: false, inProgress: false, startedForceSave: null};
if (!forceSave) {
res.notModified = true;
@ -890,24 +893,26 @@ async function applyForceSaveCache(ctx, docId, forceSave, type, opt_userConnecti
if (commonDefines.c_oAscForceSaveTypes.Form === type || commonDefines.c_oAscForceSaveTypes.Internal === type || !forceSave.ended) {
//c_oAscForceSaveTypes.Form has uniqueue options {'documentLayout': {'isPrint': true}}; dont use it for other types
let forceSaveCached = forceSaveCache.cmd?.getForceSave()?.getType();
let cacheHasSameOptions = (commonDefines.c_oAscForceSaveTypes.Form === type &&
commonDefines.c_oAscForceSaveTypes.Form === forceSaveCached) ||
(commonDefines.c_oAscForceSaveTypes.Form !== type &&
commonDefines.c_oAscForceSaveTypes.Form !== forceSaveCached)
let cacheHasSameOptions = (commonDefines.c_oAscForceSaveTypes.Form === type && commonDefines.c_oAscForceSaveTypes.Form === forceSaveCached) ||
(commonDefines.c_oAscForceSaveTypes.Form !== type && commonDefines.c_oAscForceSaveTypes.Form !== forceSaveCached);
if (forceSaveCache.hasValidCache && cacheHasSameOptions) {
let cmd = forceSaveCache.cmd;
cmd.setUserConnectionDocId(opt_userConnectionDocId);
cmd.setUserConnectionId(opt_userConnectionId);
cmd.setResponseKey(opt_responseKey);
cmd.setFormData(opt_formdata);
if (cmd.getForceSave()) {
cmd.getForceSave().setType(type);
cmd.getForceSave().setAuthorUserId(opt_userId);
cmd.getForceSave().setAuthorUserIndex(opt_userIndex);
if (commonDefines.c_oAscForceSaveTypes.Internal === type && forceSave.time === opt_prevTime) {
res.notModified = true;
} else {
let cmd = forceSaveCache.cmd;
cmd.setUserConnectionDocId(opt_userConnectionDocId);
cmd.setUserConnectionId(opt_userConnectionId);
cmd.setResponseKey(opt_responseKey);
cmd.setFormData(opt_formdata);
if (cmd.getForceSave()) {
cmd.getForceSave().setType(type);
cmd.getForceSave().setAuthorUserId(opt_userId);
cmd.getForceSave().setAuthorUserIndex(opt_userIndex);
}
//todo timeout because commandSfcCallback make request?
await canvasService.commandSfcCallback(ctx, cmd, true, false);
res.ok = true;
}
//todo timeout because commandSfcCallback make request?
await canvasService.commandSfcCallback(ctx, cmd, true, false);
res.ok = true;
} else {
await editorData.checkAndSetForceSave(ctx, docId, forceSave.time, forceSave.index, false, false, null);
res.startedForceSave = await editorData.checkAndStartForceSave(ctx, docId);
@ -930,7 +935,8 @@ async function applyForceSaveCache(ctx, docId, forceSave, type, opt_userConnecti
}
async function startForceSave(ctx, docId, type, opt_userdata, opt_formdata, opt_userId, opt_userConnectionId,
opt_userConnectionDocId, opt_userIndex, opt_responseKey, opt_baseUrl,
opt_queue, opt_pubsub, opt_conn, opt_initShardKey, opt_jsonParams, opt_changeInfo) {
opt_queue, opt_pubsub, opt_conn, opt_initShardKey, opt_jsonParams, opt_changeInfo,
opt_prevTime) {
const tenForceSaveUsingButtonWithoutChanges = ctx.getCfg('services.CoAuthoring.server.forceSaveUsingButtonWithoutChanges', cfgForceSaveUsingButtonWithoutChanges);
ctx.logger.debug('startForceSave start');
let res = {code: commonDefines.c_oAscServerCommandErrors.NoError, time: null, inProgress: false};
@ -961,7 +967,7 @@ async function startForceSave(ctx, docId, type, opt_userdata, opt_formdata, opt_
forceSave = await editorData.getForceSave(ctx, docId);
}
let applyCacheRes = await applyForceSaveCache(ctx, docId, forceSave, type, opt_userConnectionId,
opt_userConnectionDocId, opt_responseKey, opt_formdata, opt_userId, opt_userIndex);
opt_userConnectionDocId, opt_responseKey, opt_formdata, opt_userId, opt_userIndex, opt_prevTime);
startedForceSave = applyCacheRes.startedForceSave;
if (applyCacheRes.notModified) {
let selectRes = await taskResult.select(ctx, docId);
@ -1045,12 +1051,37 @@ let saveRelativeFromChanges = co.wrap(function*(ctx, conn, responseKey, data) {
}
}
if (!forceSaveRes) {
forceSaveRes = yield startForceSave(ctx, docId, commonDefines.c_oAscForceSaveTypes.Internal, undefined, undefined, undefined, conn.user.id, conn.docId, undefined, responseKey);
forceSaveRes = yield startForceSave(ctx, docId, commonDefines.c_oAscForceSaveTypes.Internal, undefined, undefined, undefined, conn.user.id, conn.docId, undefined, responseKey,
undefined, undefined, undefined, undefined, undefined, undefined, undefined, data.time);
}
if (commonDefines.c_oAscServerCommandErrors.NoError !== forceSaveRes.code || forceSaveRes.inProgress) {
sendDataRpc(ctx, conn, responseKey, forceSaveRes);
}
})
async function startWopiRPC(ctx, docId, userId, userIdOriginal, data) {
let res;
let selectRes = await taskResult.select(ctx, docId);
let row = selectRes.length > 0 ? selectRes[0] : null;
if (row) {
if (row.callback) {
let userIndex = utils.getIndexFromUserId(userId, userIdOriginal);
let uri = sqlBase.UserCallback.prototype.getCallbackByUserIndex(ctx, row.callback, userIndex);
let wopiParams = wopiClient.parseWopiCallback(ctx, uri, row.callback);
if (wopiParams) {
switch (data.type) {
case 'wopi_RenameFile':
res = await wopiClient.renameFile(ctx, wopiParams, data.name);
break;
case 'wopi_RefreshFile':
res = await wopiClient.refreshFile(ctx, wopiParams, row.baseurl);
break;
}
}
}
}
return res;
}
function* startRPC(ctx, conn, responseKey, data) {
let docId = conn.docId;
ctx.logger.debug('startRPC start responseKey:%s , %j', responseKey, data);
@ -1074,21 +1105,11 @@ function* startRPC(ctx, conn, responseKey, data) {
break;
}
case 'wopi_RenameFile':
let renameRes;
let selectRes = yield taskResult.select(ctx, docId);
let row = selectRes.length > 0 ? selectRes[0] : null;
if (row) {
if (row.callback) {
let userIndex = utils.getIndexFromUserId(conn.user.id, conn.user.idOriginal);
let uri = sqlBase.UserCallback.prototype.getCallbackByUserIndex(ctx, row.callback, userIndex);
let wopiParams = wopiClient.parseWopiCallback(ctx, uri, row.callback);
if (wopiParams) {
renameRes = yield wopiClient.renameFile(ctx, wopiParams, data.name);
}
}
}
sendDataRpc(ctx, conn, responseKey, renameRes);
case 'wopi_RefreshFile': {
let res = yield startWopiRPC(ctx, conn.docId, conn.user.id, conn.user.idOriginal, data);
sendDataRpc(ctx, conn, responseKey, res);
break;
}
case 'pathurls':
let outputData = new canvasService.OutputData(data.type);
yield* canvasService.commandPathUrls(ctx, conn, data.data, outputData);
@ -1256,17 +1277,15 @@ function closeUsersConnection(ctx, docId, usersMap, isOriginalId, code, descript
}
}
}
function* dropUsersFromDocument(ctx, docId, users) {
if (Array.isArray(users)) {
yield publish(ctx, {type: commonDefines.c_oPublishType.drop, ctx: ctx, docId: docId, users: users, description: ''});
}
async function dropUsersFromDocument(ctx, docId, opt_users) {
await publish(ctx, {type: commonDefines.c_oPublishType.drop, ctx: ctx, docId: docId, users: opt_users, description: ''});
}
function dropUserFromDocument(ctx, docId, userId, description) {
function dropUserFromDocument(ctx, docId, users, description) {
var elConnection;
for (var i = 0, length = connections.length; i < length; ++i) {
elConnection = connections[i];
if (elConnection.docId === docId && userId === elConnection.user.idOriginal && !elConnection.isCloseCoAuthoring) {
if (elConnection.docId === docId && !elConnection.isCloseCoAuthoring && (!users || users.includes(elConnection.user.idOriginal)) ) {
sendDataDrop(ctx, elConnection, description);
}
}
@ -1497,6 +1516,9 @@ function getOpenFormatByEditor(editorType) {
case EditorTypes.presentation:
res = constants.AVS_OFFICESTUDIO_FILE_CANVAS_PRESENTATION;
break;
case EditorTypes.diagram:
res = constants.AVS_OFFICESTUDIO_FILE_DRAW_VSDX;
break;
default:
res = constants.AVS_OFFICESTUDIO_FILE_CANVAS_WORD;
break;
@ -1661,13 +1683,6 @@ exports.install = function(server, callbackFunction) {
ctx.logger.debug('Server shutdown receive data');
return;
}
if (conn.isCiriticalError && ('message' == data.type || 'getLock' == data.type || 'saveChanges' == data.type ||
'isSaveLock' == data.type)) {
ctx.logger.warn("conn.isCiriticalError send command: type = %s", data.type);
sendDataDisconnectReason(ctx, conn, constants.ACCESS_DENIED_CODE, constants.ACCESS_DENIED_REASON);
conn.disconnect(true);
return;
}
if ((conn.isCloseCoAuthoring || (conn.user && conn.user.view)) &&
('getLock' == data.type || 'saveChanges' == data.type || 'isSaveLock' == data.type)) {
ctx.logger.warn("conn.user.view||isCloseCoAuthoring access deny: type = %s", data.type);
@ -1714,11 +1729,6 @@ exports.install = function(server, callbackFunction) {
case 'close':
yield* closeDocument(ctx, conn);
break;
case 'versionHistory' : {
let cmd = new commonDefines.InputCommand(data.cmd);
yield* versionHistory(ctx, conn, cmd);
break;
}
case 'openDocument' : {
var cmd = new commonDefines.InputCommand(data.message);
cmd.fillFromConnection(conn);
@ -1762,6 +1772,13 @@ exports.install = function(server, callbackFunction) {
ctx.logger.debug("unknown command %j", data);
break;
}
if (clientStatsD) {
let isSendMetric = 'auth' === data.type || 'getLock' === data.type || 'saveChanges' === data.type;
if (isSendMetric) {
clientStatsD.timing('coauth.data.' + data.type, new Date() - startDate);
}
}
} catch (e) {
ctx.logger.error("error receiving response: type = %s %s", (data && data.type) ? data.type : 'null', e.stack);
}
@ -1830,7 +1847,7 @@ exports.install = function(server, callbackFunction) {
}
}
} else {
if (!conn.isCloseCoAuthoring) {
if (!conn.isCloseCoAuthoring && !isView) {
modifyConnectionEditorToView(ctx, conn);
conn.isCloseCoAuthoring = true;
yield addPresence(ctx, conn, true);
@ -1857,11 +1874,11 @@ exports.install = function(server, callbackFunction) {
yield publish(ctx, {type: commonDefines.c_oPublishType.participantsState, ctx: ctx, docId: docId, userId: tmpUser.id, participantsTimestamp: participantsTimestamp, participants: participants}, docId, tmpUser.id);
tmpUser.view = tmpView;
// For this user, we remove the lock from saving
yield editorData.unlockSave(ctx, docId, conn.user.id);
// editors only
if (false === isView) {
// For this user, we remove the lock from saving
yield editorData.unlockSave(ctx, docId, conn.user.id);
bHasEditors = yield* hasEditors(ctx, docId, hvals);
bHasChanges = yield hasChanges(ctx, docId);
@ -1922,42 +1939,6 @@ exports.install = function(server, callbackFunction) {
}
}
function* versionHistory(ctx, conn, cmd) {
const tenTokenEnableBrowser = ctx.getCfg('services.CoAuthoring.token.enable.browser', cfgTokenEnableBrowser);
var docIdOld = conn.docId;
var docIdNew = cmd.getDocId();
//check jwt
if (tenTokenEnableBrowser) {
var checkJwtRes = yield checkJwt(ctx, cmd.getTokenHistory(), commonDefines.c_oAscSecretType.Browser);
if (checkJwtRes.decoded) {
fillVersionHistoryFromJwt(ctx, checkJwtRes.decoded, cmd);
docIdNew = cmd.getDocId();
cmd.setWithAuthorization(true);
} else {
sendData(ctx, conn, {type: "expiredToken", code: checkJwtRes.code, description: checkJwtRes.description});
return;
}
}
if (docIdOld !== docIdNew) {
//remove presence(other data was removed before in closeDocument)
yield removePresence(ctx, conn);
var hvals = yield editorData.getPresence(ctx, docIdOld, connections);
if (hvals.length <= 0) {
yield editorData.removePresenceDocument(ctx, docIdOld);
}
//apply new
conn.docId = docIdNew;
yield addPresence(ctx, conn, true);
if (tenTokenEnableBrowser) {
let sessionToken = yield fillJwtByConnection(ctx, conn);
sendDataRefreshToken(ctx, conn, sessionToken);
}
}
//open
yield canvasService.openDocument(ctx, conn, cmd, null);
}
// Getting changes for the document (either from the cache or accessing the database, but only if there were saves)
function* getDocumentChanges(ctx, docId, optStartIndex, optEndIndex) {
// If during that moment, while we were waiting for a response from the database, everyone left, then nothing needs to be sent
@ -2077,13 +2058,16 @@ exports.install = function(server, callbackFunction) {
});
}
function sendFileError(ctx, conn, errorId, code) {
ctx.logger.warn('error description: errorId = %s', errorId);
conn.isCiriticalError = true;
function sendFileError(ctx, conn, errorId, code, opt_notWarn) {
if (opt_notWarn) {
ctx.logger.debug('error description: errorId = %s', errorId);
} else {
ctx.logger.warn('error description: errorId = %s', errorId);
}
sendData(ctx, conn, {type: 'error', description: errorId, code: code});
}
function* sendFileErrorAuth(ctx, conn, sessionId, errorId, code) {
function* sendFileErrorAuth(ctx, conn, sessionId, errorId, code, opt_notWarn) {
const tenTokenEnableBrowser = ctx.getCfg('services.CoAuthoring.token.enable.browser', cfgTokenEnableBrowser);
conn.sessionId = sessionId;//restore old
@ -2093,6 +2077,9 @@ exports.install = function(server, callbackFunction) {
});
//closing could happen during async action
if (constants.CONN_CLOSED !== conn.conn.readyState) {
modifyConnectionEditorToView(ctx, conn);
conn.isCloseCoAuthoring = true;
// We put it in an array, because we need to send data to open/save the document
connections.push(conn);
yield addPresence(ctx, conn, true);
@ -2100,7 +2087,7 @@ exports.install = function(server, callbackFunction) {
let sessionToken = yield fillJwtByConnection(ctx, conn);
sendDataRefreshToken(ctx, conn, sessionToken);
}
sendFileError(ctx, conn, errorId, code);
sendFileError(ctx, conn, errorId, code, opt_notWarn);
}
}
@ -2320,14 +2307,14 @@ exports.install = function(server, callbackFunction) {
openCmd.userid = fileInfo.UserId;
}
}
let permissionsEdit = !fileInfo.ReadOnly && fileInfo.UserCanWrite && queryParams.formsubmit !== "1";
let permissionsFillForm = permissionsEdit || queryParams.formsubmit === "1";
let permissionsEdit = !fileInfo.ReadOnly && fileInfo.UserCanWrite && queryParams?.formsubmit !== "1";
let permissionsFillForm = permissionsEdit || queryParams?.formsubmit === "1";
let permissions = {
edit: permissionsEdit,
review: (fileInfo.SupportsReviewing === false) ? false : (fileInfo.UserCanReview === false ? false : fileInfo.UserCanReview),
copy: fileInfo.CopyPasteRestrictions !== "CurrentDocumentOnly" && fileInfo.CopyPasteRestrictions !== "BlockAll",
print: !fileInfo.DisablePrint && !fileInfo.HidePrintOption,
chat: queryParams.dchat!=="1",
chat: queryParams?.dchat!=="1",
fillForms: permissionsFillForm
};
//todo (review: undefiend)
@ -2338,11 +2325,6 @@ exports.install = function(server, callbackFunction) {
//not '=' because if it jwt from previous version, we must use values from data
Object.assign(data.permissions, permissions);
}
//issuer for secret
if (decoded.iss) {
data.iss = decoded.iss;
}
return res;
}
function validateAuthToken(data, decoded) {
@ -2464,29 +2446,25 @@ exports.install = function(server, callbackFunction) {
ctx.logger.warn('fillDataFromJwt token has invalid format');
res = false;
}
//issuer for secret
if (decoded.iss) {
data.iss = decoded.iss;
}
return res;
}
function fillVersionHistoryFromJwt(ctx, decoded, cmd) {
function fillVersionHistoryFromJwt(ctx, decoded, data) {
let openCmd = data.openCmd;
data.mode = 'view';
data.coEditingMode = 'strict';
data.docid = decoded.key;
openCmd.url = decoded.url;
if (decoded.changesUrl && decoded.previous) {
let versionMatch = cmd.getServerVersion() === commonDefines.buildVersion;
let openPreviousVersion = cmd.getDocId() === decoded.previous.key;
let versionMatch = openCmd.serverVersion === commonDefines.buildVersion;
let openPreviousVersion = openCmd.id === decoded.previous.key;
if (versionMatch && openPreviousVersion) {
cmd.setUrl(decoded.previous.url);
cmd.setDocId(decoded.previous.key);
data.docid = decoded.previous.key;
openCmd.url = decoded.previous.url;
} else {
ctx.logger.warn('fillVersionHistoryFromJwt serverVersion mismatch or mismatch between previous url and changes. serverVersion=%s docId=%s', cmd.getServerVersion(), cmd.getDocId());
cmd.setUrl(decoded.url);
cmd.setDocId(decoded.key);
ctx.logger.warn('fillVersionHistoryFromJwt serverVersion mismatch or mismatch between previous url and changes. serverVersion=%s docId=%s', openCmd.serverVersion, openCmd.id);
}
} else {
cmd.setUrl(decoded.url);
cmd.setDocId(decoded.key);
}
return true;
}
function* auth(ctx, conn, data) {
@ -2515,19 +2493,23 @@ exports.install = function(server, callbackFunction) {
} else if (decoded.editorConfig && undefined !== decoded.editorConfig.ds_sessionTimeConnect) {
//reconnection
fillDataFromJwtRes = fillDataFromJwt(ctx, decoded, data);
} else if (decoded.version) {//version required, but maybe add new type like jwtSession?
//version history
fillDataFromJwtRes = fillVersionHistoryFromJwt(ctx, decoded, data);
} else {
//opening
let validationErr = validateAuthToken(data, decoded);
if (!validationErr) {
fillDataFromJwtRes = fillDataFromJwt(ctx, decoded, data);
} else if (tenTokenRequiredParams) {
ctx.logger.error("auth missing required parameter %s (since 7.1 version)", validationErr);
sendDataDisconnectReason(ctx, conn, constants.JWT_ERROR_CODE, constants.JWT_ERROR_REASON);
conn.disconnect(true);
return;
} else {
ctx.logger.warn("auth missing required parameter %s (since 7.1 version)", validationErr);
fillDataFromJwtRes = fillDataFromJwt(ctx, decoded, data);
ctx.logger.error("auth missing required parameter %s (since 7.1 version)", validationErr);
if (tenTokenRequiredParams) {
sendDataDisconnectReason(ctx, conn, constants.JWT_ERROR_CODE, constants.JWT_ERROR_REASON);
conn.disconnect(true);
return;
} else {
fillDataFromJwtRes = fillDataFromJwt(ctx, decoded, data);
}
}
}
if(!fillDataFromJwtRes) {
@ -2599,7 +2581,7 @@ exports.install = function(server, callbackFunction) {
upsertRes = yield canvasService.commandOpenStartPromise(ctx, docId, utils.getBaseUrlByConnection(ctx, conn), data.documentCallbackUrl, format);
curIndexUser = upsertRes.insertId;
//todo update additional in commandOpenStartPromise
if ((upsertRes.isInsert || (wopiParams && 2 === curIndexUser)) && (undefined !== data.timezoneOffset || ctx.shardKey || ctx.wopiSrc)) {
if ((upsertRes.isInsert || (wopiParams && 2 === curIndexUser)) && (undefined !== data.timezoneOffset || data.headingsColor || ctx.shardKey || ctx.wopiSrc)) {
//todo insert in commandOpenStartPromise. insert here for database compatibility
if (false === canvasService.hasAdditionalCol) {
let selectRes = yield taskResult.select(ctx, docId);
@ -2609,9 +2591,9 @@ exports.install = function(server, callbackFunction) {
let task = new taskResult.TaskResultData();
task.tenant = ctx.tenant;
task.key = docId;
if (undefined !== data.timezoneOffset) {
if (undefined !== data.timezoneOffset || data.headingsColor) {
//todo duplicate created_at because CURRENT_TIMESTAMP uses server timezone
openedAtStr = sqlBase.DocumentAdditional.prototype.setOpenedAt(Date.now(), data.timezoneOffset);
openedAtStr = sqlBase.DocumentAdditional.prototype.setOpenedAt(Date.now(), data.timezoneOffset, data.headingsColor);
task.additional = openedAtStr;
}
if (ctx.shardKey) {
@ -2743,24 +2725,27 @@ exports.install = function(server, callbackFunction) {
var updateIfRes = yield taskResult.updateIf(ctx, updateTask, updateMask);
if (!(updateIfRes.affectedRows > 0)) {
// error version
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Update Version error', constants.UPDATE_VERSION_CODE);
//log level is debug because error handled via refreshFile
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Update Version error', constants.UPDATE_VERSION_CODE, true);
return;
}
} else if (commonDefines.FileStatus.UpdateVersion === status) {
modifyConnectionEditorToView(ctx, conn);
conn.isCloseCoAuthoring = true;
if (bIsRestore) {
// error version
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Update Version error', constants.UPDATE_VERSION_CODE);
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Update Version error', constants.UPDATE_VERSION_CODE, true);
return;
} else {
modifyConnectionEditorToView(ctx, conn);
conn.isCiriticalError = true;
}
} else if (commonDefines.FileStatus.None === status && conn.encrypted) {
//ok
} else if (bIsRestore) {
// Other error
let code = null === status ? constants.NO_CACHE_CODE : undefined;
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Other error', code);
if(null === status) {
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Other error', constants.NO_CACHE_CODE, true);
} else {
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Other error');
}
return;
}
}
@ -2801,17 +2786,17 @@ exports.install = function(server, callbackFunction) {
if (wopiLockRes) {
yield* authRestore(ctx, conn, data.sessionId);
} else {
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Restore error. Wopi lock error.', constants.RESTORE_CODE);
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Restore error. Wopi lock error.', constants.RESTORE_CODE, true);
}
} else {
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Restore error. Locks not checked.', constants.RESTORE_CODE);
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Restore error. Locks not checked.', constants.RESTORE_CODE, true);
}
} else {
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Restore error. Document modified.', constants.RESTORE_CODE);
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'Restore error. Document modified.', constants.RESTORE_CODE, true);
}
} catch (err) {
ctx.logger.error("DataBase error: %s", err.stack);
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'DataBase error', constants.RESTORE_CODE);
yield* sendFileErrorAuth(ctx, conn, data.sessionId, 'DataBase error', constants.RESTORE_CODE, true);
}
} else {
yield* authRestore(ctx, conn, data.sessionId);
@ -2884,7 +2869,7 @@ exports.install = function(server, callbackFunction) {
}
let lockDocument = null;
let waitAuthUserId;
if (!bIsRestore && 2 === countNoView && !tmpUser.view) {
if (!bIsRestore && 2 === countNoView && !tmpUser.view && firstParticipantNoView) {
// lock a document
const lockRes = yield editorData.lockAuth(ctx, docId, firstParticipantNoView.id, 2 * tenExpLockDoc);
if (constants.CONN_CLOSED === conn.conn.readyState) {
@ -3110,6 +3095,7 @@ exports.install = function(server, callbackFunction) {
fCheckLock = _checkLockExcel;
break;
case EditorTypes.presentation:
case EditorTypes.diagram:
// PP
fCheckLock = _checkLockPresentation;
break;
@ -3563,9 +3549,7 @@ exports.install = function(server, callbackFunction) {
let lockDocumentTimer, cmd;
switch (data.type) {
case commonDefines.c_oPublishType.drop:
for (i = 0; i < data.users.length; ++i) {
dropUserFromDocument(ctx, data.docId, data.users[i], data.description);
}
dropUserFromDocument(ctx, data.docId, data.users, data.description);
break;
case commonDefines.c_oPublishType.closeConnection:
closeUsersConnection(ctx, data.docId, data.usersMap, data.isOriginalId, data.code, data.description);
@ -3643,13 +3627,7 @@ exports.install = function(server, callbackFunction) {
output.fromObject(data.output);
var outputData = output.getData();
var docConnectionId = cmd.getDocConnectionId();
var docId;
if(docConnectionId){
docId = docConnectionId;
} else {
docId = cmd.getDocId();
}
var docId = cmd.getDocId();
if (cmd.getUserConnectionId()) {
participants = getParticipantUser(docId, cmd.getUserConnectionId());
} else {
@ -4252,6 +4230,7 @@ function* commandLicense(ctx) {
async function proxyCommand(ctx, req, params) {
const tenCallbackRequestTimeout = ctx.getCfg('services.CoAuthoring.server.callbackRequestTimeout', cfgCallbackRequestTimeout);
const tenTokenEnableRequestInbox = ctx.getCfg('services.CoAuthoring.token.enable.request.inbox', cfgTokenEnableRequestInbox);
//todo gen shardkey as in sdkjs
const shardkey = params.key;
const baseUrl = utils.getBaseUrlByRequest(ctx, req);
@ -4260,7 +4239,8 @@ async function proxyCommand(ctx, req, params) {
url += `&${name}=${encodeURIComponent(req.query[name])}`;
}
ctx.logger.info('commandFromServer proxy request with "key" to correctly process commands in sharded cluster to url:%s', url);
return await utils.postRequestPromise(ctx, url, req.body, null, req.body.length, tenCallbackRequestTimeout, undefined, req.headers);
//isInJwtToken is true because 'command' is always internal
return await utils.postRequestPromise(ctx, url, req.body, null, req.body.length, tenCallbackRequestTimeout, undefined, tenTokenEnableRequestInbox, req.headers);
}
/**
* Server commands handler.
@ -4293,13 +4273,11 @@ function* commandHandle(ctx, params, req, output) {
break;
}
case 'drop': {
if (params.userid) {
yield publish(ctx, {type: commonDefines.c_oPublishType.drop, ctx: ctx, docId: docId, users: [params.userid], description: params.description});
} else if (params.users) {
if (params.users) {
const users = (typeof params.users === 'string') ? JSON.parse(params.users) : params.users;
yield* dropUsersFromDocument(ctx, docId, users);
yield dropUsersFromDocument(ctx, docId, users);
} else {
output.error = commonDefines.c_oAscServerCommandErrors.UnknownCommand;
yield dropUsersFromDocument(ctx, docId);
}
break;
}

View File

@ -160,9 +160,9 @@ function getOpenedAt(row) {
return;
}
function getOpenedAtJSONParams(row) {
let openedAt = getOpenedAt(row);
if (openedAt) {
return {'documentLayout': {'openedAt': openedAt}};
let documentLayout = row && sqlBase.DocumentAdditional.prototype.getDocumentLayout(row.additional);
if (documentLayout) {
return {'documentLayout': documentLayout};
}
return undefined;
}
@ -190,12 +190,10 @@ async function getOutputData(ctx, cmd, outputData, key, optConn, optAdditionalOu
case commonDefines.FileStatus.Ok:
if(commonDefines.FileStatus.Ok === status) {
outputData.setStatus('ok');
} else if (optConn && (optConn.user.view || optConn.isCloseCoAuthoring)) {
if (optConn.isCiriticalError) {
outputData.setStatus(constants.FILE_STATUS_UPDATE_VERSION);
} else {
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)) {
@ -528,7 +526,10 @@ function* commandOpen(ctx, conn, cmd, outputData, opt_upsertRes, opt_bIsRestore)
cmd.setForgotten(cmd.getDocId());
}
//add task
cmd.setOutputFormat(docsCoServer.getOpenFormatByEditor(conn.editorType));
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);
@ -583,7 +584,10 @@ function* commandReopen(ctx, conn, cmd, outputData) {
if (upsertRes.affectedRows > 0) {
//add task
cmd.setUrl(null);//url may expire
cmd.setOutputFormat(docsCoServer.getOpenFormatByEditor(conn.editorType));
if (!cmd.getOutputFormat()) {
//todo remove getOpenFormatByEditor after 8.2.1
cmd.setOutputFormat(docsCoServer.getOpenFormatByEditor(conn.editorType));
}
cmd.setEmbeddedFonts(false);
if (isPassword) {
cmd.setUserConnectionId(conn.user.id);

View File

@ -370,14 +370,16 @@ function getEmptyCallbacks(ctx) {
function getTableColumns(ctx, tableName) {
return new Promise(function(resolve, reject) {
const sqlCommand = `SELECT column_name as "column_name" FROM information_schema.COLUMNS WHERE TABLE_NAME = '${tableName}';`;
let values = [];
let sqlParam = addSqlParameter(tableName, values);
const sqlCommand = `SELECT column_name as "column_name" FROM information_schema.COLUMNS WHERE TABLE_NAME = ${sqlParam};`;
dbInstance.sqlQuery(ctx, sqlCommand, function(error, result) {
if (error) {
reject(error);
} else {
resolve(result);
}
});
}, undefined, undefined, values);
});
}

View File

@ -166,9 +166,9 @@ DocumentAdditional.prototype.fromString = function(str) {
return JSON.parse(currentValue);
});
};
DocumentAdditional.prototype.setOpenedAt = function(time, timezoneOffset) {
DocumentAdditional.prototype.setOpenedAt = function(time, timezoneOffset, headingsColor) {
let additional = new DocumentAdditional();
additional.data.push({time: time, timezoneOffset: timezoneOffset});
additional.data.push({time, timezoneOffset, headingsColor});
return additional.toSQLInsert();
};
DocumentAdditional.prototype.getOpenedAt = function(str) {
@ -182,6 +182,17 @@ DocumentAdditional.prototype.getOpenedAt = function(str) {
});
return res;
};
DocumentAdditional.prototype.getDocumentLayout = function(str) {
let res;
let val = new DocumentAdditional();
val.fromString(str);
val.data.forEach((elem) => {
if (undefined !== elem.timezoneOffset) {
res = {openedAt: elem.time - (elem.timezoneOffset * 60 * 1000), headingsColor: elem.headingsColor};
}
});
return res;
}
DocumentAdditional.prototype.setShardKey = function(shardKey) {
let additional = new DocumentAdditional();

View File

@ -156,7 +156,9 @@ function concatParams(val1, val2) {
}
async function getTableColumns(ctx, tableName) {
const result = await executeQuery(ctx, `SELECT column_name FROM DBA_TAB_COLUMNS WHERE table_name = '${tableName.toUpperCase()}';`);
let values = [];
let 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() }});
}

View File

@ -199,8 +199,10 @@ function concatParams(...parameters) {
}
function getTableColumns(ctx, tableName) {
const sqlCommand = `SELECT column_name FROM information_schema.COLUMNS WHERE TABLE_NAME = '${tableName}' AND TABLE_SCHEMA = 'dbo';`;
return executeQuery(ctx, sqlCommand);
let values = [];
let sqlParam = addSqlParameter(tableName, values);
const sqlCommand = `SELECT column_name FROM information_schema.COLUMNS WHERE TABLE_NAME = ${sqlParam} AND TABLE_SCHEMA = 'dbo';`;
return executeQuery(ctx, sqlCommand, values);
}
function getDocumentsWithChanges(ctx) {

View File

@ -171,7 +171,9 @@ function concatParams(firstParameter, secondParameter) {
}
function getTableColumns(ctx, tableName) {
return executeQuery(ctx, `SELECT LOWER(column_name) AS column_name FROM user_tab_columns WHERE table_name = '${tableName.toUpperCase()}'`);
let values = [];
let sqlParam = addSqlParameter(tableName.toUpperCase(), values);
return executeQuery(ctx, `SELECT LOWER(column_name) AS column_name FROM user_tab_columns WHERE table_name = ${sqlParam}`, values);
}
function getEmptyCallbacks(ctx) {

View File

@ -34,8 +34,6 @@
const crypto = require('crypto');
var multiparty = require('multiparty');
var co = require('co');
var jwt = require('jsonwebtoken');
var taskResult = require('./taskresult');
const utilsDocService = require('./utilsDocService');
var docsCoServer = require('./DocsCoServer');
var utils = require('./../../Common/sources/utils');
@ -52,46 +50,6 @@ const cfgTokenEnableBrowser = config.get('services.CoAuthoring.token.enable.brow
const PATTERN_ENCRYPTED = 'ENCRYPTED;';
exports.uploadTempFile = function(req, res) {
return co(function* () {
var docId = 'uploadTempFile';
let ctx = new operationContext.Context();
try {
ctx.initFromRequest(req);
yield ctx.initTenantCache();
ctx.logger.info('uploadTempFile start');
let params;
let authRes = yield docsCoServer.getRequestParams(ctx, req, true);
if(authRes.code === constants.NO_ERROR){
params = authRes.params;
} else {
utils.fillResponse(req, res, new commonDefines.ConvertStatus(authRes.code), false);
return;
}
docId = params.key;
ctx.setDocId(docId);
ctx.logger.debug('Start uploadTempFile');
if (docId && constants.DOC_ID_REGEX.test(docId) && req.body && Buffer.isBuffer(req.body)) {
var task = yield* taskResult.addRandomKeyTask(ctx, docId);
var strPath = task.key + '/' + docId + '.tmp';
yield storageBase.putObject(ctx, strPath, req.body, req.body.length);
var url = yield storageBase.getSignedUrl(ctx, utils.getBaseUrlByRequest(ctx, req), strPath,
commonDefines.c_oAscUrlTypes.Temporary);
utils.fillResponse(req, res, new commonDefines.ConvertStatus(constants.NO_ERROR, url), false);
} else {
if (!constants.DOC_ID_REGEX.test(docId)) {
ctx.logger.warn('Error uploadTempFile unexpected key');
}
utils.fillResponse(req, res, new commonDefines.ConvertStatus(constants.UNKNOWN), false);
}
} catch (e) {
ctx.logger.error('Error uploadTempFile: %s', e.stack);
utils.fillResponse(req, res, new commonDefines.ConvertStatus(constants.UNKNOWN), false);
} finally {
ctx.logger.info('uploadTempFile end');
}
});
};
function* checkJwtUpload(ctx, errorName, token){
let checkJwtRes = yield docsCoServer.checkJwt(ctx, token, commonDefines.c_oAscSecretType.Session);
return checkJwtUploadTransformRes(ctx, errorName, checkJwtRes);
@ -117,96 +75,6 @@ function checkJwtUploadTransformRes(ctx, errorName, checkJwtRes){
}
return res;
}
exports.uploadImageFileOld = function(req, res) {
return co(function* () {
let ctx = new operationContext.Context();
ctx.initFromRequest(req);
yield ctx.initTenantCache();
var docId = req.params.docid;
ctx.setDocId(docId);
ctx.logger.debug('Start uploadImageFileOld');
const tenImageSize = ctx.getCfg('services.CoAuthoring.server.limits_image_size', cfgImageSize);
const tenTokenEnableBrowser = ctx.getCfg('services.CoAuthoring.token.enable.browser', cfgTokenEnableBrowser);
if (tenTokenEnableBrowser) {
var checkJwtRes = yield* checkJwtUpload(ctx, 'uploadImageFileOld', req.query['token']);
if(!checkJwtRes.err){
docId = checkJwtRes.docId || docId;
ctx.setDocId(docId);
ctx.setUserId(checkJwtRes.userid);
} else {
res.sendStatus(403);
return;
}
}
var listImages = [];
if (docId) {
var isError = false;
var form = new multiparty.Form();
form.on('error', function(err) {
ctx.logger.error('Error parsing form:%s', err.toString());
res.sendStatus(400);
});
form.on('part', function(part) {
if (!part.filename) {
// ignore field's content
part.resume();
}
if (part.filename) {
if (part.byteCount > tenImageSize) {
isError = true;
}
if (isError) {
part.resume();
} else {
//a hash is written at the beginning to avoid errors during parallel upload in co-editing
var strImageName = crypto.randomBytes(16).toString("hex");
var strPath = docId + '/media/' + strImageName + '.jpg';
listImages.push(strPath);
utils.stream2Buffer(part).then(function(buffer) {
return storageBase.putObject(ctx, strPath, buffer, buffer.length);
}).then(function() {
part.resume();
}).catch(function(err) {
ctx.logger.error('Upload putObject:%s', err.stack);
isError = true;
part.resume();
});
}
}
part.on('error', function(err) {
ctx.logger.error('Error parsing form part:%s', err.toString());
});
});
form.once('close', function() {
if (isError) {
res.sendStatus(400);
} else {
storageBase.getSignedUrlsByArray(ctx, utils.getBaseUrlByRequest(ctx, req), listImages, docId,
commonDefines.c_oAscUrlTypes.Session).then(function(urls) {
var outputData = {'type': 0, 'error': constants.NO_ERROR, 'urls': urls, 'input': req.query};
var output = '<html><head><script type="text/javascript">function load(){ parent.postMessage("';
output += JSON.stringify(outputData).replace(/"/g, '\\"');
output += '", "*"); }</script></head><body onload="load()"></body></html>';
//res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Content-Type', 'text/html');
res.send(output);
ctx.logger.debug('End uploadImageFileOld:%s', output);
}
).catch(function(err) {
ctx.logger.error('error getSignedUrlsByArray:%s', err.stack);
res.sendStatus(400);
});
}
});
form.parse(req);
} else {
ctx.logger.debug('Error params uploadImageFileOld');
res.sendStatus(400);
}
});
};
exports.uploadImageFile = function(req, res) {
return co(function* () {
let httpStatus = 200;

View File

@ -42,10 +42,10 @@ var rabbitMQCore = require('./../../Common/sources/rabbitMQCore');
var activeMQCore = require('./../../Common/sources/activeMQCore');
const cfgQueueType = config.get('queue.type');
var cfgRabbitExchangePubSub = config.get('rabbitmq.exchangepubsub');
const cfgRabbitExchangePubSub = config.get('rabbitmq.exchangepubsub');
const cfgRabbitQueuePubsub = config.get('rabbitmq.queuepubsub');
var cfgActiveTopicPubSub = constants.ACTIVEMQ_TOPIC_PREFIX + config.get('activemq.topicpubsub');
const optionsExchange = {durable: true};
function initRabbit(pubsub, callback) {
return co(function* () {
var e = null;
@ -60,12 +60,12 @@ function initRabbit(pubsub, callback) {
});
pubsub.connection = conn;
pubsub.channelPublish = yield rabbitMQCore.createChannelPromise(conn);
pubsub.exchangePublish = yield rabbitMQCore.assertExchangePromise(pubsub.channelPublish, cfgRabbitExchangePubSub,
'fanout', {durable: true});
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, '', {autoDelete: true, exclusive: true});
pubsub.channelReceive.bindQueue(queue, cfgRabbitExchangePubSub, '');
var queue = yield rabbitMQCore.assertQueuePromise(pubsub.channelReceive, cfgRabbitQueuePubsub.name, cfgRabbitQueuePubsub.options);
pubsub.channelReceive.bindQueue(queue, cfgRabbitExchangePubSub.name, '');
yield rabbitMQCore.consumePromise(pubsub.channelReceive, queue, function (message) {
if(null != pubsub.channelReceive){
if (message) {
@ -189,8 +189,8 @@ function healthCheckRabbit(pubsub) {
if (!pubsub.channelPublish) {
return false;
}
const exchange = yield rabbitMQCore.assertExchangePromise(pubsub.channelPublish, cfgRabbitExchangePubSub,
'fanout', optionsExchange);
const exchange = yield rabbitMQCore.assertExchangePromise(pubsub.channelPublish, cfgRabbitExchangePubSub.name,
'fanout', cfgRabbitExchangePubSub.options);
return !!exchange;
});
}

View File

@ -158,15 +158,16 @@ docsCoServer.install(server, () => {
let [licenseInfo] = yield tenantManager.getTenantLicense(ctx);
let buildVersion = commonDefines.buildVersion;
let buildNumber = commonDefines.buildNumber;
let buildDate, packageType, customerId = "", alias = "";
let buildDate, packageType, customerId = "", alias = "", multitenancy="";
if (licenseInfo) {
buildDate = licenseInfo.buildDate.toISOString();
packageType = licenseInfo.packageType;
customerId = licenseInfo.customerId;
alias = licenseInfo.alias;
multitenancy = licenseInfo.multitenancy;
}
let output = `Server is functioning normally. Version: ${buildVersion}. Build: ${buildNumber}`;
output += `. Release date: ${buildDate}. Package type: ${packageType}. Customer Id: ${customerId}. Alias: ${alias}`;
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);
@ -190,10 +191,6 @@ docsCoServer.install(server, () => {
app.post('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
app.post('/converter', utils.checkClientIp, rawFileParser, converterService.convertJson);
app.get('/FileUploader.ashx', utils.checkClientIp, rawFileParser, fileUploaderService.uploadTempFile);
app.post('/FileUploader.ashx', utils.checkClientIp, rawFileParser, fileUploaderService.uploadTempFile);
app.param('docid', (req, res, next, val) => {
if (constants.DOC_ID_REGEX.test(val)) {
next();
@ -208,8 +205,6 @@ docsCoServer.install(server, () => {
res.sendStatus(403);
}
});
//'*' for backward compatible
app.post('/uploadold/:docid*', fileUploaderService.uploadImageFileOld);
app.post('/upload/:docid*', rawFileParser, fileUploaderService.uploadImageFile);
app.post('/downloadas/:docid', rawFileParser, canvasService.downloadAs);
@ -398,6 +393,10 @@ docsCoServer.install(server, () => {
}
});
});
app.get('/document_editor_service_worker.js', apicache.middleware("5 min"), async (req, res) => {
//make handler only for development version
res.sendFile(path.resolve("../../sdkjs/common/serviceworker/document_editor_service_worker.js"));
});
app.use((err, req, res, next) => {
let ctx = new operationContext.Context();
ctx.initFromRequest(req);

View File

@ -224,13 +224,13 @@ function restoreInitialPassword(ctx, docId) {
});
}
function addRandomKey(ctx, task, opt_prefix, opt_size) {
function addRandomKey(ctx, task, key, opt_prefix, opt_size) {
return new Promise(function(resolve, reject) {
task.tenant = ctx.tenant;
if (undefined !== opt_prefix && undefined !== opt_size) {
task.key = opt_prefix + crypto.randomBytes(opt_size).toString("hex");
} else {
task.key = task.key + '_' + Math.round(Math.random() * RANDOM_KEY_MAX);
task.key = key + '_' + Math.round(Math.random() * RANDOM_KEY_MAX);
}
task.completeDefaults();
let values = [];
@ -251,7 +251,7 @@ function addRandomKey(ctx, task, opt_prefix, opt_size) {
} else {
resolve(result);
}
}, undefined, undefined, values);
}, undefined, true, values);
});
}
function* addRandomKeyTask(ctx, key, opt_prefix, opt_size) {
@ -264,10 +264,10 @@ function* addRandomKeyTask(ctx, key, opt_prefix, opt_size) {
var addRes = null;
while (nTryCount-- > 0) {
try {
addRes = yield addRandomKey(ctx, task, opt_prefix, opt_size);
addRes = yield addRandomKey(ctx, task, key, opt_prefix, opt_size);
} catch (e) {
addRes = null;
//key exist, try again
ctx.logger.debug("addRandomKeyTask %s exists, try again", task.key);
}
if (addRes && addRes.affectedRows > 0) {
break;

View File

@ -57,6 +57,7 @@ const taskResult = require('./taskresult');
const canvasService = require('./canvasservice');
const converterService = require('./converterservice');
const mime = require('mime');
const license = require('./../../Common/sources/license');
const cfgTokenOutboxAlgorithm = config.get('services.CoAuthoring.token.outbox.algorithm');
const cfgTokenOutboxExpires = config.get('services.CoAuthoring.token.outbox.expires');
@ -75,11 +76,14 @@ const cfgWopiCellView = config.get('wopi.cellView');
const cfgWopiCellEdit = config.get('wopi.cellEdit');
const cfgWopiSlideView = config.get('wopi.slideView');
const cfgWopiSlideEdit = config.get('wopi.slideEdit');
const cfgWopiDiagramView = config.get('wopi.diagramView');
const cfgWopiDiagramEdit = config.get('wopi.diagramEdit');
const cfgWopiForms = config.get('wopi.forms');
const cfgWopiFavIconUrlWord = config.get('wopi.favIconUrlWord');
const cfgWopiFavIconUrlCell = config.get('wopi.favIconUrlCell');
const cfgWopiFavIconUrlSlide = config.get('wopi.favIconUrlSlide');
const cfgWopiFavIconUrlPdf = config.get('wopi.favIconUrlPdf');
const cfgWopiFavIconUrlDiagram = config.get('wopi.favIconUrlDiagram');
const cfgWopiPublicKey = config.get('wopi.publicKey');
const cfgWopiModulus = config.get('wopi.modulus');
const cfgWopiExponent = config.get('wopi.exponent');
@ -98,6 +102,11 @@ let templatesFolderExtsCache = null;
const templateFilesSizeCache = {};
let shutdownFlag = false;
//patch mimeDB
if (!mimeDB["application/vnd.visio2013"]) {
mimeDB["application/vnd.visio2013"] = {extensions: ["vsdx", "vstx", "vssx", "vsdm", "vstm", "vssm"]};
}
let mimeTypesByExt = (function() {
let mimeTypesByExt = {};
for (let mimeType in mimeDB) {
@ -149,11 +158,14 @@ function discovery(req, res) {
const tenWopiCellEdit = ctx.getCfg('wopi.cellEdit', cfgWopiCellEdit);
const tenWopiSlideView = ctx.getCfg('wopi.slideView', cfgWopiSlideView);
const tenWopiSlideEdit = ctx.getCfg('wopi.slideEdit', cfgWopiSlideEdit);
const tenWopiDiagramView = ctx.getCfg('wopi.diagramView', cfgWopiDiagramView);
const tenWopiDiagramEdit = ctx.getCfg('wopi.diagramEdit', cfgWopiDiagramEdit);
const tenWopiForms = ctx.getCfg('wopi.forms', cfgWopiForms);
const tenWopiFavIconUrlWord = ctx.getCfg('wopi.favIconUrlWord', cfgWopiFavIconUrlWord);
const tenWopiFavIconUrlCell = ctx.getCfg('wopi.favIconUrlCell', cfgWopiFavIconUrlCell);
const tenWopiFavIconUrlSlide = ctx.getCfg('wopi.favIconUrlSlide', cfgWopiFavIconUrlSlide);
const tenWopiFavIconUrlPdf = ctx.getCfg('wopi.favIconUrlSlide', cfgWopiFavIconUrlPdf);
const tenWopiFavIconUrlPdf = ctx.getCfg('wopi.favIconUrlPdf', cfgWopiFavIconUrlPdf);
const tenWopiFavIconUrlDiagram = ctx.getCfg('wopi.favIconUrlDiagram', cfgWopiFavIconUrlDiagram);
const tenWopiPublicKey = ctx.getCfg('wopi.publicKey', cfgWopiPublicKey);
const tenWopiModulus = ctx.getCfg('wopi.modulus', cfgWopiModulus);
const tenWopiExponent = ctx.getCfg('wopi.exponent', cfgWopiExponent);
@ -172,6 +184,15 @@ function discovery(req, res) {
{targetext: null, view: tenWopiPdfView, edit: tenWopiPdfEdit}
];
let documentTypes = [`word`, `cell`, `slide`, `pdf`];
//todo check sdkjs-ooxml addon
let 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);
exts.push({targetext: null, view: tenWopiDiagramView, edit: tenWopiDiagramEdit});
documentTypes.push(`diagram`);
}
let templatesFolderExtsCache = yield getTemplatesFolderExts(ctx);
let formsExts = tenWopiForms.reduce((result, item, index, array) => {
@ -236,10 +257,16 @@ function discovery(req, res) {
let urlTemplateEdit = `${templateStart}/${documentTypes[i]}/edit?${templateEnd}`;
let urlTemplateMobileEdit = `${templateStart}/${documentTypes[i]}/edit?mobile=1&amp;${templateEnd}`;
let urlTemplateFormSubmit = `${templateStart}/${documentTypes[i]}/edit?formsubmit=1&amp;${templateEnd}`;
let mimeTypesDuplicate = new Set();//to remove duplicates for each editor(allow html for word and excel)
for (let j = 0; j < ext.view.length; ++j) {
let mimeTypes = mimeTypesByExt[ext.view[j]];
if (mimeTypes) {
mimeTypes.forEach((value) => {
if (mimeTypesDuplicate.has(value)) {
return;
} else {
mimeTypesDuplicate.add(value);
}
let xmlApp = xmlZone.ele('app', {name: value});
xmlApp.ele('action', {name: 'view', ext: '', default: 'true', urlsrc: urlTemplateView}).up();
xmlApp.ele('action', {name: 'embedview', ext: '', urlsrc: urlTemplateEmbedView}).up();
@ -252,10 +279,16 @@ function discovery(req, res) {
});
}
}
mimeTypesDuplicate.clear();
for (let j = 0; j < ext.edit.length; ++j) {
let mimeTypes = mimeTypesByExt[ext.edit[j]];
if (mimeTypes) {
mimeTypes.forEach((value) => {
if (mimeTypesDuplicate.has(value)) {
return;
} else {
mimeTypesDuplicate.add(value);
}
let xmlApp = xmlZone.ele('app', {name: value});
if (formsExts[ext.edit[j]]) {
xmlApp.ele('action', {name: 'edit', ext: '', default: 'true', requires: 'locks,update', urlsrc: urlTemplateEdit}).up();
@ -501,6 +534,40 @@ async function checkAndReplaceEmptyFile(ctx, fileInfo, wopiSrc, access_token, ac
}
}
}
function createDocId(ctx, wopiSrc, mode, fileInfo) {
let fileId = wopiSrc.substring(wopiSrc.lastIndexOf('/') + 1);
let docId = undefined;
if ('view' !== mode) {
docId = `${fileId}`;
} else {
//todo rename operation requires lock
fileInfo.SupportsRename = false;
//todo change docId to avoid empty cache after editors are gone
if (fileInfo.LastModifiedTime) {
docId = `view.${fileId}.${fileInfo.LastModifiedTime}`;
} else {
docId = `view.${fileId}.${fileInfo.Version}`;
}
}
docId = docId.replace(constants.DOC_ID_REPLACE_REGEX, '_').substring(0, constants.DOC_ID_MAX_LENGTH);
return docId;
}
async function preOpen(ctx, lockId, docId, fileInfo, userAuth, baseUrl, fileType) {
//todo move to lock and common info saving to websocket connection
//save common info
if (undefined === lockId) {
//Use deterministic(not random) lockId to fix issues with forgotten openings due to integrator failures
lockId = docId;
let commonInfo = JSON.stringify({lockId: lockId, fileInfo: fileInfo});
await canvasService.commandOpenStartPromise(ctx, docId, baseUrl, commonInfo, fileType);
}
//Lock
if ('view' !== userAuth.mode) {
let lockRes = await lock(ctx, 'LOCK', lockId, fileInfo, userAuth);
return !!lockRes;
}
return true;
}
function getEditorHtml(req, res) {
return co(function*() {
let params = {key: undefined, apiQuery: '', fileInfo: {}, userAuth: {}, queryParams: req.query, token: undefined, documentType: undefined, docs_api_config: {}};
@ -550,20 +617,8 @@ function getEditorHtml(req, res) {
mode = 'view';
}
//docId
let docId = undefined;
if ('view' !== mode) {
docId = `${fileId}`;
} else {
//todo rename operation requires lock
fileInfo.SupportsRename = false;
//todo change docId to avoid empty cache after editors are gone
if (fileInfo.LastModifiedTime) {
docId = `view.${fileId}.${fileInfo.LastModifiedTime}`;
} else {
docId = `view.${fileId}.${fileInfo.Version}`;
}
}
docId = docId.replace(constants.DOC_ID_REPLACE_REGEX, '_').substring(0, constants.DOC_ID_MAX_LENGTH);
let docId = createDocId(ctx, wopiSrc, mode, fileInfo);
ctx.setDocId(fileId);
ctx.logger.debug(`wopiEditor`);
params.key = docId;
let userAuth = params.userAuth = {
@ -573,27 +628,15 @@ function getEditorHtml(req, res) {
//check and invalidate cache
let checkRes = yield checkAndInvalidateCache(ctx, docId, fileInfo);
let lockId = checkRes.lockId;
if (!checkRes.success) {
params.fileInfo = {};
return;
}
if (!shutdownFlag) {
//save common info
if (undefined === lockId) {
//Use deterministic(not random) lockId to fix issues with forgotten openings due to integrator failures
lockId = docId;
let commonInfo = JSON.stringify({lockId: lockId, fileInfo: fileInfo});
yield canvasService.commandOpenStartPromise(ctx, docId, utils.getBaseUrlByRequest(ctx, req), commonInfo, fileType);
}
//Lock
if ('view' !== mode) {
let lockRes = yield lock(ctx, 'LOCK', lockId, fileInfo, userAuth);
if (!lockRes) {
params.fileInfo = {};
return;
}
let preOpenRes = yield preOpen(ctx, checkRes.lockId, docId, fileInfo, userAuth, utils.getBaseUrlByRequest(ctx, req), fileType);
if (!preOpenRes) {
params.fileInfo = {};
return;
}
}
@ -719,7 +762,9 @@ function putFile(ctx, wopiParams, data, dataStream, dataSize, userLastChangeId,
headers['Content-Type'] = mime.getType(getFileTypeByInfo(fileInfo));
ctx.logger.debug('wopi PutFile request uri=%s headers=%j', uri, headers);
postRes = yield utils.postRequestPromise(ctx, uri, data, dataStream, dataSize, tenCallbackRequestTimeout, undefined, headers);
//isInJwtToken is true because it passed checkIpFilter for wopi
let isInJwtToken = true;
postRes = yield utils.postRequestPromise(ctx, uri, data, dataStream, dataSize, tenCallbackRequestTimeout, undefined, isInJwtToken, headers);
ctx.logger.debug('wopi PutFile response headers=%j', postRes.response.headers);
ctx.logger.debug('wopi PutFile response body:%s', postRes.body);
} else {
@ -754,7 +799,9 @@ function putRelativeFile(ctx, wopiSrc, access_token, data, dataStream, dataSize,
headers['Content-Type'] = mime.getType(suggestedExt);
ctx.logger.debug('wopi putRelativeFile request uri=%s headers=%j', uri, headers);
let postRes = yield utils.postRequestPromise(ctx, uri, data, dataStream, dataSize, tenCallbackRequestTimeout, undefined, headers);
//isInJwtToken is true because it passed checkIpFilter for wopi
let isInJwtToken = true;
let 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);
@ -793,7 +840,9 @@ function renameFile(ctx, wopiParams, name) {
yield fillStandardHeaders(ctx, headers, uri, userAuth.access_token);
ctx.logger.debug('wopi RenameFile request uri=%s headers=%j', uri, headers);
let postRes = yield utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, headers);
//isInJwtToken is true because it passed checkIpFilter for wopi
let isInJwtToken = true;
let postRes = yield 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);
@ -812,6 +861,47 @@ function renameFile(ctx, wopiParams, name) {
return res;
});
}
async function refreshFile(ctx, wopiParams, baseUrl) {
let res = {};
try {
ctx.logger.info('wopi RefreshFile start');
let userAuth = wopiParams.userAuth;
if (!userAuth) {
return;
}
const tenTokenEnableBrowser = ctx.getCfg('services.CoAuthoring.token.enable.browser', cfgTokenEnableBrowser);
const tenTokenOutboxAlgorithm = ctx.getCfg('services.CoAuthoring.token.outbox.algorithm', cfgTokenOutboxAlgorithm);
const tenTokenOutboxExpires = ctx.getCfg('services.CoAuthoring.token.outbox.expires', cfgTokenOutboxExpires);
const fileInfo = await checkFileInfo(ctx, userAuth.wopiSrc, userAuth.access_token);
const fileType = getFileTypeByInfo(fileInfo);
const docId = createDocId(ctx, userAuth.wopiSrc, userAuth.mode, res.fileInfo);
res.key = docId;
res.userAuth = userAuth;
res.fileInfo = fileInfo;
res.queryParams = undefined;
if (tenTokenEnableBrowser) {
let options = {algorithm: tenTokenOutboxAlgorithm, expiresIn: tenTokenOutboxExpires};
let secret = await tenantManager.getTenantSecret(ctx, commonDefines.c_oAscSecretType.Browser);
res.token = jwt.sign(res, secret, options);
}
let checkRes = await checkAndInvalidateCache(ctx, docId, fileInfo);
if (!checkRes.success) {
res = {};
return;
}
let preOpenRes = await preOpen(ctx, checkRes.lockId, docId, fileInfo, userAuth, baseUrl, fileType);
if (!preOpenRes) {
res = {};
}
} catch (err) {
ctx.logger.error('wopi error RefreshFile:%s', err.stack);
} finally {
ctx.logger.info('wopi RefreshFile end');
}
return res;
}
function checkFileInfo(ctx, wopiSrc, access_token, opt_sc) {
return co(function* () {
let fileInfo = undefined;
@ -830,8 +920,7 @@ function checkFileInfo(ctx, wopiSrc, access_token, opt_sc) {
}
yield fillStandardHeaders(ctx, headers, uri, access_token);
ctx.logger.debug('wopi checkFileInfo request uri=%s headers=%j', uri, headers);
//todo false? (true because it passed checkIpFilter for wopi)
//todo use directIfIn
//isInJwtToken is true because it passed checkIpFilter for wopi
let isInJwtToken = true;
let getRes = yield utils.downloadUrlPromise(ctx, uri, tenDownloadTimeout, undefined, undefined, isInJwtToken, headers);
ctx.logger.debug(`wopi checkFileInfo headers=%j body=%s`, getRes.response.headers, getRes.body);
@ -866,7 +955,9 @@ function lock(ctx, command, lockId, fileInfo, userAuth) {
let headers = {"X-WOPI-Override": command, "X-WOPI-Lock": lockId};
yield fillStandardHeaders(ctx, headers, uri, access_token);
ctx.logger.debug('wopi %s request uri=%s headers=%j', command, uri, headers);
let postRes = yield utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, headers);
//isInJwtToken is true because it passed checkIpFilter for wopi
let isInJwtToken = true;
let 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);
@ -903,7 +994,9 @@ async function unlock(ctx, wopiParams) {
let headers = {"X-WOPI-Override": "UNLOCK", "X-WOPI-Lock": lockId};
await fillStandardHeaders(ctx, headers, uri, access_token);
ctx.logger.debug('wopi Unlock request uri=%s headers=%j', uri, headers);
let postRes = await utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, headers);
//isInJwtToken is true because it passed checkIpFilter for wopi
let isInJwtToken = true;
let 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');
@ -961,13 +1054,14 @@ async function fillStandardHeaders(ctx, headers, url, access_token) {
if (tenWopiPrivateKey && tenWopiPrivateKeyOld) {
headers['X-WOPI-Proof'] = await generateProofSign(url, access_token, timeStamp, tenWopiPrivateKey);
headers['X-WOPI-ProofOld'] = await generateProofSign(url, access_token, timeStamp, tenWopiPrivateKeyOld);
headers['X-WOPI-TimeStamp'] = timeStamp;
headers['X-WOPI-ClientVersion'] = commonDefines.buildVersion + '.' + commonDefines.buildNumber;
// todo
// headers['X-WOPI-CorrelationId '] = "";
// headers['X-WOPI-SessionId'] = "";
}
headers['Authorization'] = `Bearer ${access_token}`;
headers['X-WOPI-TimeStamp'] = timeStamp;
headers['X-WOPI-ClientVersion'] = commonDefines.buildVersion + '.' + commonDefines.buildNumber;
// todo
// headers['X-WOPI-CorrelationId '] = "";
// headers['X-WOPI-SessionId'] = "";
//remove redundant header https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/common-headers#request-headers
// headers['Authorization'] = `Bearer ${access_token}`;
}
function checkIpFilter(ctx, uri){
@ -1072,6 +1166,7 @@ exports.putFile = putFile;
exports.parsePutFileResponse = parsePutFileResponse;
exports.putRelativeFile = putRelativeFile;
exports.renameFile = renameFile;
exports.refreshFile = refreshFile;
exports.lock = lock;
exports.unlock = unlock;
exports.fillStandardHeaders = fillStandardHeaders;

View File

@ -5,11 +5,11 @@
"requires": true,
"dependencies": {
"@expo/spawn-async": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.3.0.tgz",
"integrity": "sha1-Abik9ruhC3kmY/knLfZsfpAWba0=",
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.7.2.tgz",
"integrity": "sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==",
"requires": {
"cross-spawn": "^5.1.0"
"cross-spawn": "^7.0.3"
}
},
"bytes": {
@ -31,13 +31,13 @@
}
},
"cross-spawn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"requires": {
"lru-cache": "^4.0.1",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
}
},
"invert-kv": {
@ -48,7 +48,7 @@
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
"json5": {
"version": "1.0.2",
@ -66,50 +66,36 @@
"invert-kv": "^3.0.0"
}
},
"lru-cache": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
"integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==",
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
}
},
"minimist": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g=="
},
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"requires": {
"shebang-regex": "^1.0.0"
"shebang-regex": "^3.0.0"
}
},
"shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
},
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"requires": {
"isexe": "^2.0.0"
}
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
}
}
}

View File

@ -5,7 +5,7 @@
"private": true,
"bin": "sources/convertermaster.js",
"dependencies": {
"@expo/spawn-async": "1.3.0",
"@expo/spawn-async": "1.7.2",
"bytes": "3.0.0",
"co": "4.6.0",
"config": "2.0.1",

View File

@ -901,7 +901,8 @@ function* postProcess(ctx, cmd, dataConvert, tempDirs, childRes, error, isTimeou
exitCode = childRes.status;
exitSignal = childRes.signal;
}
if (0 !== exitCode || null !== exitSignal) {
//CONVERT_CELLLIMITS is not an error, but an indicator that data was lost during opening (can be displayed as an error)
if ((0 !== exitCode && constants.CONVERT_CELLLIMITS !== -exitCode) || null !== exitSignal) {
if (-1 !== exitCodesReturn.indexOf(-exitCode)) {
error = -exitCode;
} else if(isTimeout) {

View File

@ -210,17 +210,17 @@
</tr>
<tr>
<td id="build-type">Type:</td>
<td><span id="lic-valid-type">Valid: </span><span id="lic-valid"></span></td>
<td><span>Start date: </span><span id="lic-start"></span></td>
<td id="lic-limit-edit"></td>
</tr>
<tr>
<td id="build-version">Version:</td>
<td id="trial"></td>
<td><span id="lic-valid-type">Valid: </span><span id="lic-valid"></span></td>
<td id="lic-limit-view"></td>
</tr>
<tr>
<td id="build-date">Release date:</td>
<td></td>
<td id="trial"></td>
<td></td>
</tr>
</table>
@ -321,11 +321,19 @@
var licType = licenseInfo.type;
elem = document.getElementById('lic-valid');
elem.innerText = licdate.toLocaleDateString();
var isInvalid = 2 === licType || 1 === licType || 6 === licType || 16 === licType || 11 === licType;
var isInvalid = 2 === licType || 1 === licType || 6 === licType || 11 === licType;
var isUpdateUnavailible = !isLimited && new Date(serverInfo.date) > licdate;
if (isInvalid || isUpdateUnavailible) {
elem.classList.add('critical');
}
if (licenseInfo.startDate) {
var licdateStart = new Date(licenseInfo.startDate);
elem = document.getElementById('lic-start');
elem.innerText = licdateStart.toLocaleDateString();
if (16 === licType || licdateStart > new Date(serverInfo.date)) {
elem.classList.add('critical');
}
}
elem = document.getElementById('trial');
elem.innerText = (licenseInfo.mode & 1) ? 'Trial' : '';

6
npm-shrinkwrap.json generated
View File

@ -1962,9 +1962,9 @@
}
},
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"requires": {
"path-key": "^3.1.0",

View File

@ -1,2 +1,2 @@
USE onlyoffice;
-- USE onlyoffice;
DROP TABLE IF EXISTS doc_changes, task_result;