mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-02-10 18:05:07 +08:00
Merge pull request 'fix/bugfix-9' (#88) from fix/bugfix-9 into release/v9.2.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/server/pulls/88
This commit is contained in:
@ -1108,13 +1108,18 @@ const jwtKeyCache = Object.create(null);
|
||||
/**
|
||||
* Gets or creates a cached symmetric key for JWT verification (HS256/HS384/HS512).
|
||||
* Caches crypto.KeyObject to avoid expensive key creation on every request.
|
||||
* @param {string} secret - JWT symmetric secret
|
||||
* @returns {crypto.KeyObject} Cached secret key object
|
||||
* Uses the same validation approach as jsonwebtoken library.
|
||||
* @param {string|Buffer} secret - JWT symmetric secret
|
||||
* @returns {crypto.KeyObject|undefined} Cached secret key object, or undefined when secret is missing/invalid
|
||||
*/
|
||||
function getJwtHsKey(secret) {
|
||||
let res = jwtKeyCache[secret];
|
||||
if (!res) {
|
||||
res = jwtKeyCache[secret] = crypto.createSecretKey(Buffer.from(secret, 'utf8'));
|
||||
if (!res && secret != null) {
|
||||
try {
|
||||
res = jwtKeyCache[secret] = crypto.createSecretKey(typeof secret === 'string' ? Buffer.from(secret, 'utf8') : secret);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1951,18 +1951,9 @@ exports.install = function (server, app, callbackFunction) {
|
||||
yield canvasService.openDocument(ctx, conn, cmd);
|
||||
break;
|
||||
}
|
||||
case 'clientLog': {
|
||||
const level = data.level?.toLowerCase();
|
||||
if ('trace' === level || 'debug' === level || 'info' === level || 'warn' === level || 'error' === level || 'fatal' === level) {
|
||||
ctx.logger[level]('clientLog: %s', data.msg);
|
||||
}
|
||||
if ('error' === level && tenErrorFiles && docId) {
|
||||
const destDir = 'browser/' + docId;
|
||||
yield storage.copyPath(ctx, docId, destDir, undefined, tenErrorFiles);
|
||||
yield* saveErrorChanges(ctx, docId, destDir);
|
||||
}
|
||||
case 'clientLog':
|
||||
yield handleClientLog(ctx, conn, docId, data, tenErrorFiles);
|
||||
break;
|
||||
}
|
||||
case 'extendSession':
|
||||
ctx.logger.debug('extendSession idletime: %d', data.idletime);
|
||||
conn.sessionIsSendWarning = false;
|
||||
@ -2186,6 +2177,10 @@ exports.install = function (server, app, callbackFunction) {
|
||||
userIndex
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (hvals?.length <= 0 && editorStatProxy?.deleteKey) {
|
||||
yield editorStatProxy.deleteKey(docId);
|
||||
}
|
||||
}
|
||||
const sessionType = isView ? 'view' : 'edit';
|
||||
const sessionTimeMs = new Date().getTime() - conn.sessionTimeConnect;
|
||||
@ -2196,6 +2191,31 @@ exports.install = function (server, app, callbackFunction) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle client log message and create error files once per connection on first error.
|
||||
* @param {object} ctx - Operation context
|
||||
* @param {object} conn - Socket connection
|
||||
* @param {string} docId - Document identifier
|
||||
* @param {{level?: string, msg?: string}} data - Client log data
|
||||
* @param {object} tenErrorFiles - Error files storage configuration
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function handleClientLog(ctx, conn, docId, data, tenErrorFiles) {
|
||||
const level = data.level?.toLowerCase();
|
||||
if ('trace' === level || 'debug' === level || 'info' === level || 'warn' === level || 'error' === level || 'fatal' === level) {
|
||||
ctx.logger[level]('clientLog: %s', data.msg);
|
||||
}
|
||||
if ('error' === level && tenErrorFiles && docId && !conn.clientError) {
|
||||
conn.clientError = true;
|
||||
const destDir = 'browser/' + docId;
|
||||
const list = await storage.listObjects(ctx, destDir, tenErrorFiles);
|
||||
if (list.length === 0) {
|
||||
await storage.copyPath(ctx, docId, destDir, undefined, tenErrorFiles);
|
||||
await saveErrorChanges(ctx, docId, destDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -3252,7 +3272,16 @@ exports.install = function (server, app, callbackFunction) {
|
||||
return res;
|
||||
}
|
||||
|
||||
function* saveErrorChanges(ctx, docId, destDir) {
|
||||
/**
|
||||
* Save document changes to error files storage for debugging purposes.
|
||||
* Retrieves changes from database and creates JSON chunks stored as separate files.
|
||||
*
|
||||
* @param {object} ctx - Operation context with configuration and logger
|
||||
* @param {string} docId - Document identifier to retrieve changes for
|
||||
* @param {string} destDir - Destination directory path in storage for error files
|
||||
* @returns {Promise<void>} Resolves when all changes are saved to storage
|
||||
*/
|
||||
async function saveErrorChanges(ctx, docId, destDir) {
|
||||
const tenEditor = getEditorConfig(ctx);
|
||||
const tenMaxRequestChanges = ctx.getCfg('services.CoAuthoring.server.maxRequestChanges', cfgMaxRequestChanges);
|
||||
const tenErrorFiles = ctx.getCfg('FileConverter.converter.errorfiles', cfgErrorFiles);
|
||||
@ -3262,12 +3291,12 @@ exports.install = function (server, app, callbackFunction) {
|
||||
let changes;
|
||||
const changesPrefix = destDir + '/' + constants.CHANGES_NAME + '/' + constants.CHANGES_NAME + '.json.';
|
||||
do {
|
||||
changes = yield sqlBase.getChangesPromise(ctx, docId, index, index + tenMaxRequestChanges);
|
||||
changes = await sqlBase.getChangesPromise(ctx, docId, index, index + tenMaxRequestChanges);
|
||||
if (changes.length > 0) {
|
||||
let buffer;
|
||||
if (tenEditor['binaryChanges']) {
|
||||
const buffers = changes.map(elem => elem.change_data);
|
||||
buffers.unshift(Buffer.from(utils.getChangesFileHeader(), 'utf-8'));
|
||||
buffers.unshift(Buffer.from(utils.getChangesFileHeader(), 'utf8'));
|
||||
buffer = Buffer.concat(buffers);
|
||||
} else {
|
||||
let changesJSON = indexChunk > 1 ? ',[' : '[';
|
||||
@ -3279,7 +3308,7 @@ exports.install = function (server, app, callbackFunction) {
|
||||
changesJSON += ']\r\n';
|
||||
buffer = Buffer.from(changesJSON, 'utf8');
|
||||
}
|
||||
yield storage.putObject(ctx, changesPrefix + (indexChunk++).toString().padStart(3, '0'), buffer, buffer.length, tenErrorFiles);
|
||||
await storage.putObject(ctx, changesPrefix + (indexChunk++).toString().padStart(3, '0'), buffer, buffer.length, tenErrorFiles);
|
||||
}
|
||||
index += tenMaxRequestChanges;
|
||||
} while (changes && tenMaxRequestChanges === changes.length);
|
||||
|
||||
Reference in New Issue
Block a user