mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-02-10 18:05:07 +08:00
346 lines
12 KiB
JavaScript
346 lines
12 KiB
JavaScript
/*
|
||
* (c) Copyright Ascensio System SIA 2010-2023
|
||
*
|
||
* This program is a free software product. You can redistribute it and/or
|
||
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
||
* version 3 as published by the Free Software Foundation. In accordance with
|
||
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
||
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
||
* of any third-party rights.
|
||
*
|
||
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
||
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||
*
|
||
* You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
|
||
* street, Riga, Latvia, EU, LV-1050.
|
||
*
|
||
* The interactive user interfaces in modified source and object code versions
|
||
* of the Program must display Appropriate Legal Notices, as required under
|
||
* Section 5 of the GNU AGPL version 3.
|
||
*
|
||
* Pursuant to Section 7(b) of the License you must retain the original Product
|
||
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
||
* grant you any rights under trademark law for use of our trademarks.
|
||
*
|
||
* All the Product's GUI elements, including illustrations and icon sets, as
|
||
* well as technical writing content are licensed under the terms of the
|
||
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
||
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||
*
|
||
*/
|
||
|
||
'use strict';
|
||
|
||
const crypto = require('crypto');
|
||
var sqlBase = require('./baseConnector');
|
||
var utils = require('./../../Common/sources/utils');
|
||
var constants = require('./../../Common/sources/constants');
|
||
var commonDefines = require('./../../Common/sources/commondefines');
|
||
var tenantManager = require('./../../Common/sources/tenantManager');
|
||
var config = require('config');
|
||
|
||
const cfgTableResult = config.get('services.CoAuthoring.sql.tableResult');
|
||
const cfgTableChanges = config.get('services.CoAuthoring.sql.tableChanges');
|
||
|
||
let addSqlParam = sqlBase.baseConnector.addSqlParameter;
|
||
let concatParams = sqlBase.baseConnector.concatParams;
|
||
|
||
var RANDOM_KEY_MAX = 10000;
|
||
|
||
function TaskResultData() {
|
||
this.tenant = null;
|
||
this.key = null;
|
||
this.status = null;
|
||
this.statusInfo = null;
|
||
this.lastOpenDate = null;
|
||
this.creationDate = null;
|
||
this.userIndex = null;
|
||
this.changeId = null;
|
||
this.callback = null;
|
||
this.baseurl = null;
|
||
this.password = null;
|
||
this.additional = null;
|
||
|
||
this.innerPasswordChange = null;//not a DB field
|
||
}
|
||
TaskResultData.prototype.completeDefaults = function() {
|
||
if (!this.tenant) {
|
||
this.tenant = tenantManager.getDefautTenant();
|
||
}
|
||
if (!this.key) {
|
||
this.key = '';
|
||
}
|
||
if (!this.status) {
|
||
this.status = commonDefines.FileStatus.None;
|
||
}
|
||
if (!this.statusInfo) {
|
||
this.statusInfo = constants.NO_ERROR;
|
||
}
|
||
if (!this.lastOpenDate) {
|
||
this.lastOpenDate = new Date();
|
||
}
|
||
if (!this.creationDate) {
|
||
this.creationDate = new Date();
|
||
}
|
||
if (!this.userIndex) {
|
||
this.userIndex = 1;
|
||
}
|
||
if (!this.changeId) {
|
||
this.changeId = 0;
|
||
}
|
||
if (!this.callback) {
|
||
this.callback = '';
|
||
}
|
||
if (!this.baseurl) {
|
||
this.baseurl = '';
|
||
}
|
||
};
|
||
|
||
function upsert(ctx, task, opt_updateUserIndex) {
|
||
return sqlBase.baseConnector.upsert(ctx, task, opt_updateUserIndex);
|
||
}
|
||
|
||
function select(ctx, docId) {
|
||
return new Promise(function(resolve, reject) {
|
||
let values = [];
|
||
let p1 = addSqlParam(ctx.tenant, values);
|
||
let p2 = addSqlParam(docId, values);
|
||
let sqlCommand = `SELECT * FROM ${cfgTableResult} WHERE tenant=${p1} AND id=${p2};`;
|
||
sqlBase.baseConnector.sqlQuery(ctx, sqlCommand, function(error, result) {
|
||
if (error) {
|
||
reject(error);
|
||
} else {
|
||
resolve(result);
|
||
}
|
||
}, undefined, undefined, values);
|
||
});
|
||
}
|
||
function toUpdateArray(task, updateTime, isMask, values, setPassword) {
|
||
var res = [];
|
||
if (null != task.status) {
|
||
let sqlParam = addSqlParam(task.status, values);
|
||
res.push(`status=${sqlParam}`);
|
||
}
|
||
if (null != task.statusInfo) {
|
||
let sqlParam = addSqlParam(task.statusInfo, values);
|
||
res.push(`status_info=${sqlParam}` );
|
||
|
||
}
|
||
if (updateTime) {
|
||
let sqlParam = addSqlParam(new Date(), values);
|
||
res.push(`last_open_date=${sqlParam}`);
|
||
|
||
}
|
||
if (null != task.indexUser) {
|
||
let sqlParam = addSqlParam(task.indexUser, values);
|
||
res.push(`user_index=${sqlParam}`);
|
||
|
||
}
|
||
if (null != task.changeId) {
|
||
let sqlParam = addSqlParam(task.changeId, values);
|
||
res.push(`change_id=${sqlParam}`);
|
||
|
||
}
|
||
if (null != task.callback && !isMask) {
|
||
var userCallback = new sqlBase.UserCallback();
|
||
userCallback.fromValues(task.indexUser, task.callback);
|
||
let sqlParam = addSqlParam(userCallback.toSQLInsert(), values);
|
||
res.push(`callback=${concatParams('callback', sqlParam)}`);
|
||
}
|
||
if (null != task.baseurl) {
|
||
let sqlParam = addSqlParam(task.baseurl, values);
|
||
res.push(`baseurl=${sqlParam}`);
|
||
}
|
||
if (setPassword) {
|
||
let sqlParam = addSqlParam(task.password, values);
|
||
res.push(`password=${sqlParam}`);
|
||
} else if (null != task.password || setPassword) {
|
||
var documentPassword = new sqlBase.DocumentPassword();
|
||
documentPassword.fromValues(task.password, task.innerPasswordChange);
|
||
let sqlParam = addSqlParam(documentPassword.toSQLInsert(), values);
|
||
res.push(`password=${concatParams('password', sqlParam)}`);
|
||
}
|
||
if (null != task.additional) {
|
||
let sqlParam = addSqlParam(task.additional, values);
|
||
res.push(`additional=${concatParams('additional', sqlParam)}`);
|
||
}
|
||
return res;
|
||
}
|
||
|
||
function update(ctx, task, setPassword) {
|
||
return new Promise(function(resolve, reject) {
|
||
let values = [];
|
||
let updateElems = toUpdateArray(task, true, false, values, setPassword);
|
||
let sqlSet = updateElems.join(', ');
|
||
let p1 = addSqlParam(task.tenant, values);
|
||
let p2 = addSqlParam(task.key, values);
|
||
let sqlCommand = `UPDATE ${cfgTableResult} SET ${sqlSet} WHERE tenant=${p1} AND id=${p2};`;
|
||
sqlBase.baseConnector.sqlQuery(ctx, sqlCommand, function(error, result) {
|
||
if (error) {
|
||
reject(error);
|
||
} else {
|
||
resolve(result);
|
||
}
|
||
}, undefined, undefined, values);
|
||
});
|
||
}
|
||
|
||
function updateIf(ctx, task, mask) {
|
||
return new Promise(function(resolve, reject) {
|
||
let values = [];
|
||
let commandArg = toUpdateArray(task, true, false, values, false);
|
||
let commandArgMask = toUpdateArray(mask, false, true, values, false);
|
||
commandArgMask.push('tenant=' + addSqlParam(mask.tenant, values));
|
||
commandArgMask.push('id=' + addSqlParam(mask.key, values));
|
||
let sqlSet = commandArg.join(', ');
|
||
let sqlWhere = commandArgMask.join(' AND ');
|
||
let sqlCommand = `UPDATE ${cfgTableResult} SET ${sqlSet} WHERE ${sqlWhere};`;
|
||
sqlBase.baseConnector.sqlQuery(ctx, sqlCommand, function(error, result) {
|
||
if (error) {
|
||
reject(error);
|
||
} else {
|
||
resolve(result);
|
||
}
|
||
}, undefined, undefined, values);
|
||
});
|
||
}
|
||
function restoreInitialPassword(ctx, docId) {
|
||
return select(ctx, docId).then(function(selectRes) {
|
||
if (selectRes.length > 0) {
|
||
var row = selectRes[0];
|
||
let docPassword = sqlBase.DocumentPassword.prototype.getDocPassword(ctx, row.password);
|
||
var updateTask = new TaskResultData();
|
||
updateTask.tenant = ctx.tenant;
|
||
updateTask.key = docId;
|
||
if (docPassword.initial) {
|
||
var documentPassword = new sqlBase.DocumentPassword();
|
||
documentPassword.fromValues(docPassword.initial);
|
||
updateTask.password = documentPassword.toSQLInsert();
|
||
return update(ctx, updateTask, true);
|
||
} else if (docPassword.current) {
|
||
updateTask.password = null;
|
||
return update(ctx, updateTask, true);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
function addRandomKey(ctx, task, 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.completeDefaults();
|
||
let values = [];
|
||
let p0 = addSqlParam(task.tenant, values);
|
||
let p1 = addSqlParam(task.key, values);
|
||
let p2 = addSqlParam(task.status, values);
|
||
let p3 = addSqlParam(task.statusInfo, values);
|
||
let p4 = addSqlParam(new Date(), values);
|
||
let p5 = addSqlParam(task.userIndex, values);
|
||
let p6 = addSqlParam(task.changeId, values);
|
||
let p7 = addSqlParam(task.callback, values);
|
||
let p8 = addSqlParam(task.baseurl, values);
|
||
let sqlCommand = `INSERT INTO ${cfgTableResult} (tenant, id, status, status_info, last_open_date, user_index, change_id, callback, baseurl)` +
|
||
` VALUES (${p0}, ${p1}, ${p2}, ${p3}, ${p4}, ${p5}, ${p6}, ${p7}, ${p8});`;
|
||
sqlBase.baseConnector.sqlQuery(ctx, sqlCommand, function(error, result) {
|
||
if (error) {
|
||
reject(error);
|
||
} else {
|
||
resolve(result);
|
||
}
|
||
}, undefined, undefined, values);
|
||
});
|
||
}
|
||
function* addRandomKeyTask(ctx, key, opt_prefix, opt_size) {
|
||
var task = new TaskResultData();
|
||
task.tenant = ctx.tenant;
|
||
task.key = key;
|
||
task.status = commonDefines.FileStatus.WaitQueue;
|
||
//nTryCount чтобы не зависнуть если реально будут проблемы с DB
|
||
var nTryCount = RANDOM_KEY_MAX;
|
||
var addRes = null;
|
||
while (nTryCount-- > 0) {
|
||
try {
|
||
addRes = yield addRandomKey(ctx, task, opt_prefix, opt_size);
|
||
} catch (e) {
|
||
addRes = null;
|
||
//key exist, try again
|
||
}
|
||
if (addRes && addRes.affectedRows > 0) {
|
||
break;
|
||
}
|
||
}
|
||
if (addRes && addRes.affectedRows > 0) {
|
||
return task;
|
||
} else {
|
||
throw new Error('addRandomKeyTask Error');
|
||
}
|
||
}
|
||
|
||
function remove(ctx, docId) {
|
||
return new Promise(function(resolve, reject) {
|
||
let values = [];
|
||
let p1 = addSqlParam(ctx.tenant, values);
|
||
let p2 = addSqlParam(docId, values);
|
||
const sqlCommand = `DELETE FROM ${cfgTableResult} WHERE tenant=${p1} AND id=${p2};`;
|
||
sqlBase.baseConnector.sqlQuery(ctx, sqlCommand, function(error, result) {
|
||
if (error) {
|
||
reject(error);
|
||
} else {
|
||
resolve(result);
|
||
}
|
||
}, undefined, undefined, values);
|
||
});
|
||
}
|
||
function removeIf(ctx, mask) {
|
||
return new Promise(function(resolve, reject) {
|
||
let values = [];
|
||
let commandArgMask = toUpdateArray(mask, false, true, values, false);
|
||
commandArgMask.push('tenant=' + addSqlParam(mask.tenant, values));
|
||
commandArgMask.push('id=' + addSqlParam(mask.key, values));
|
||
let sqlWhere = commandArgMask.join(' AND ');
|
||
const sqlCommand = `DELETE FROM ${cfgTableResult} WHERE ${sqlWhere};`;
|
||
sqlBase.baseConnector.sqlQuery(ctx, sqlCommand, function(error, result) {
|
||
if (error) {
|
||
reject(error);
|
||
} else {
|
||
resolve(result);
|
||
}
|
||
}, undefined, undefined, values);
|
||
});
|
||
}
|
||
function getExpired(ctx, maxCount, expireSeconds) {
|
||
return new Promise(function(resolve, reject) {
|
||
let values = [];
|
||
let expireDate = new Date();
|
||
utils.addSeconds(expireDate, -expireSeconds);
|
||
let sqlParam1 = addSqlParam(expireDate, values);
|
||
let sqlParam2 = addSqlParam(maxCount, values);
|
||
let sqlCommand = `SELECT * FROM ${cfgTableResult} WHERE last_open_date <= ${sqlParam1}` +
|
||
` AND NOT EXISTS(SELECT tenant, id FROM ${cfgTableChanges} WHERE ${cfgTableChanges}.tenant = ${cfgTableResult}.tenant AND ${cfgTableChanges}.id = ${cfgTableResult}.id LIMIT 1) LIMIT ${sqlParam2};`;
|
||
sqlBase.baseConnector.sqlQuery(ctx, sqlCommand, function(error, result) {
|
||
if (error) {
|
||
reject(error);
|
||
} else {
|
||
resolve(result);
|
||
}
|
||
}, undefined, undefined, values);
|
||
});
|
||
}
|
||
|
||
exports.TaskResultData = TaskResultData;
|
||
exports.upsert = upsert;
|
||
exports.select = select;
|
||
exports.update = update;
|
||
exports.updateIf = updateIf;
|
||
exports.restoreInitialPassword = restoreInitialPassword;
|
||
exports.addRandomKeyTask = addRandomKeyTask;
|
||
exports.remove = remove;
|
||
exports.removeIf = removeIf;
|
||
exports.getExpired = getExpired;
|