Compare commits

..

1 Commits

Author SHA1 Message Date
b6a033b68e build(python): update version to 1.15 in pyproject.toml 2026-03-11 17:40:27 +07:00
24 changed files with 161 additions and 198 deletions

View File

@ -15,10 +15,6 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: '1.23'
- name: Submodule Update
run: |
cd ${{ github.workspace }}

3
.gitmodules vendored
View File

@ -2,6 +2,9 @@
path = web/documentserver-example/nodejs/public/assets/document-templates
url = https://github.com/ONLYOFFICE/document-templates
branch = main/default
[submodule "web/documentserver-example/nodejs/public/assets/document-formats"]
path = web/documentserver-example/nodejs/public/assets/document-formats
url = https://github.com/ONLYOFFICE/document-formats
[submodule "web/documentserver-example/nodejs/public/assets/plugin-aiautofill"]
path = web/documentserver-example/nodejs/public/assets/plugin-aiautofill
url = https://github.com/ONLYOFFICE/plugin-aiautofill.git

View File

@ -1,6 +1,5 @@
# Change Log
- nodejs: use formats, languages, maxFileSize, urls to services, jwt header and prefix from document server meta
- nodejs: wopi CopyPasteRestrictions for anonymous
- update insertImage formats
- new mobile index page view

View File

@ -42,6 +42,8 @@ const siteUrl = configServer.get('siteUrl');
const enableForgotten = configServer.get('enableForgotten');
const cfgSignatureEnable = configServer.get('token.enable');
const cfgSignatureUseForRequest = configServer.get('token.useforrequest');
const cfgSignatureAuthorizationHeader = configServer.get('token.authorizationHeader');
const cfgSignatureAuthorizationHeaderPrefix = configServer.get('token.authorizationHeaderPrefix');
const cfgSignatureSecretExpiresIn = configServer.get('token.expiresIn');
const cfgSignatureSecret = configServer.get('token.secret');
const verifyPeerOff = configServer.get('verify_peer_off');
@ -87,16 +89,16 @@ app.use(favicon(`${__dirname}/public/images/favicon.ico`)); // use favicon
app.use(bodyParser.json()); // connect middleware that parses json
app.use(bodyParser.urlencoded({ extended: false })); // connect middleware that parses urlencoded bodies
app.get('/', async (req, res) => { // define a handler for default page
app.get('/', (req, res) => { // define a handler for default page
try {
req.DocManager = new DocManager(req, res);
res.render('index', { // render index template with the parameters specified
preloaderUrl: siteUrl + configServer.get('preloaderUrl'),
storedFiles: await req.DocManager.getStoredFiles(),
storedFiles: req.DocManager.getStoredFiles(),
params: req.DocManager.getCustomParams(),
users,
languages: (await documentService.config()).langObject,
languages: configServer.get('languages'),
serverVersion: config.get('version'),
enableForgotten,
});
@ -133,14 +135,14 @@ app.get('/forgotten', async (req, res) => {
function getForgottenFile(key) {
return new Promise((resolve, reject) => {
documentService.commandRequest('getForgotten', key, async (err, data) => {
documentService.commandRequest('getForgotten', key, (err, data) => {
if (err) {
reject(err);
} else {
const parsedData = JSON.parse(data);
resolve({
name: parsedData.key,
documentType: await fileUtility.getFileType(parsedData.url),
documentType: fileUtility.getFileType(parsedData.url),
url: parsedData.url,
});
}
@ -181,7 +183,7 @@ app.delete('/forgotten', (req, res) => { // define a handler for removing forgot
}
});
app.get('/download', async (req, res) => { // define a handler for downloading files
app.get('/download', (req, res) => { // define a handler for downloading files
req.DocManager = new DocManager(req, res);
const fileName = fileUtility.getFileName(req.query.fileName);
@ -190,10 +192,9 @@ app.get('/download', async (req, res) => { // define a handler for downloading f
if (!!userAddress
&& cfgSignatureEnable && cfgSignatureUseForRequest) {
const authorization = req.get((await documentService.config()).authorization.header);
const authorizationPrefix = (await documentService.config()).authorization.prefix;
if (authorization && authorization.startsWith(authorizationPrefix)) {
token = authorization.substring(authorizationPrefix.length);
const authorization = req.get(cfgSignatureAuthorizationHeader);
if (authorization && authorization.startsWith(cfgSignatureAuthorizationHeaderPrefix)) {
token = authorization.substring(cfgSignatureAuthorizationHeaderPrefix.length);
}
try {
@ -233,13 +234,12 @@ app.get('/data', (req, res) => { // define a handler for getting sample ai form
});
});
app.get('/history', async (req, res) => {
app.get('/history', (req, res) => {
req.DocManager = new DocManager(req, res);
if (cfgSignatureEnable && cfgSignatureUseForRequest) {
const authorization = req.get((await documentService.config()).authorization.header);
const authorizationPrefix = (await documentService.config()).authorization.prefix;
if (authorization && authorization.startsWith(authorizationPrefix)) {
const token = authorization.substring(authorizationPrefix.length);
const authorization = req.get(cfgSignatureAuthorizationHeader);
if (authorization && authorization.startsWith(cfgSignatureAuthorizationHeaderPrefix)) {
const token = authorization.substring(cfgSignatureAuthorizationHeaderPrefix.length);
try {
jwt.verify(token, cfgSignatureSecret);
} catch (err) {
@ -277,7 +277,7 @@ app.get('/history', async (req, res) => {
filestream.pipe(res); // send file information to the response by streams
});
app.post('/upload', async (req, res) => { // define a handler for uploading files
app.post('/upload', (req, res) => { // define a handler for uploading files
req.DocManager = new DocManager(req, res);
req.DocManager.storagePath(''); // mkdir if not exist
@ -286,13 +286,13 @@ app.post('/upload', async (req, res) => { // define a handler for uploading file
const uploadDirTmp = path.join(uploadDir, 'tmp'); // and create directory for temporary files if it doesn't exist
req.DocManager.createDirectory(uploadDirTmp);
const fileSizeLimit = (await documentService.config()).limits.maxFileSize;
const fileSizeLimit = configServer.get('maxFileSize');
// create a new incoming form
const form = new formidable.IncomingForm({ maxFileSize: fileSizeLimit, maxTotalFileSize: fileSizeLimit });
form.uploadDir = uploadDirTmp; // and write there all the necessary parameters
form.keepExtensions = true;
form.parse(req, async (err, fields, files) => { // parse this form
form.parse(req, (err, fields, files) => { // parse this form
if (err) { // if an error occurs
// DocManager.cleanFolderRecursive(uploadDirTmp, true); // clean the folder with temporary files
res.writeHead(200, { 'Content-Type': 'application/json' });
@ -321,11 +321,11 @@ app.post('/upload', async (req, res) => { // define a handler for uploading file
return;
}
const exts = await fileUtility.getSuppotredExtensions(); // all the supported file extensions
const exts = fileUtility.getSuppotredExtensions(); // all the supported file extensions
const curExt = fileUtility.getFileExtension(file.originalFilename, true);
const documentType = await fileUtility.getFileType(file.originalFilename);
const documentType = fileUtility.getFileType(file.originalFilename);
if (exts.indexOf(curExt) === -1 || (await fileUtility.getFormatActions(curExt)).length === 0) {
if (exts.indexOf(curExt) === -1 || fileUtility.getFormatActions(curExt).length === 0) {
// DocManager.cleanFolderRecursive(uploadDirTmp, true); // if not, clean the folder with temporary files
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write('{ "error": "File type is not supported" }');
@ -376,19 +376,19 @@ app.post('/create', (req, res) => {
const userAddress = req.DocManager.curUserHostAddress();
req.DocManager.historyPath(fileName, userAddress, true);
urllib.request(fileUrl, { method: 'GET' }, async (err, data) => {
urllib.request(fileUrl, { method: 'GET' }, (err, data) => {
// check if the file size exceeds the maximum file size
if ((await documentService.config()).limits.maxFileSize < data.length || data.length <= 0) {
if (configServer.get('maxFileSize') < data.length || data.length <= 0) {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write(JSON.stringify({ error: 'File size is incorrect' }));
res.end();
return;
}
const exts = await fileUtility.getSuppotredExtensions(); // all the supported file extensions
const exts = fileUtility.getSuppotredExtensions(); // all the supported file extensions
const curExt = fileUtility.getFileExtension(fileName, true);
if (exts.indexOf(curExt) === -1 || (await fileUtility.getFormatActions(curExt)).length === 0) {
if (exts.indexOf(curExt) === -1 || fileUtility.getFormatActions(curExt).length === 0) {
// and write the error status and message to the response
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write(JSON.stringify({ error: 'File type is not supported' }));
@ -413,7 +413,7 @@ app.post('/create', (req, res) => {
}
});
app.post('/convert', async (req, res) => { // define a handler for converting files
app.post('/convert', (req, res) => { // define a handler for converting files
req.DocManager = new DocManager(req, res);
const fileName = fileUtility.getFileName(req.body.filename);
@ -471,7 +471,7 @@ app.post('/convert', async (req, res) => { // define a handler for converting fi
if (status !== 200) throw new Error(`Conversion service returned status: ${status}`);
// write a file with a new extension, but with the content from the origin file
if ((await fileUtility.getFileType(correctName)) !== null) {
if (fileUtility.getFileType(correctName) !== null) {
fileSystem.writeFileSync(req.DocManager.storagePath(correctName), data);
} else {
writeResult(newFileUri.replace('http://localhost/', siteUrl), result, 'FileTypeIsNotSupported');
@ -507,7 +507,7 @@ app.post('/convert', async (req, res) => { // define a handler for converting fi
try {
// check if the file with such an extension can be converted
if (((await fileUtility.getConvertExtensions()).indexOf(fileExt) !== -1) || ('fileExt' in req.body)) {
if ((fileUtility.getConvertExtensions().indexOf(fileExt) !== -1) || ('fileExt' in req.body)) {
const storagePath = req.DocManager.storagePath(fileName);
const stat = fileSystem.statSync(storagePath);
let key = fileUri + stat.mtime.getTime();
@ -525,11 +525,11 @@ app.post('/convert', async (req, res) => { // define a handler for converting fi
}
});
app.get('/files', async (req, res) => { // define a handler for getting files information
app.get('/files', (req, res) => { // define a handler for getting files information
try {
req.DocManager = new DocManager(req, res);
// get the information about the files from the storage path
const filesInDirectoryInfo = await req.DocManager.getFilesInfo();
const filesInDirectoryInfo = req.DocManager.getFilesInfo();
res.setHeader('Content-Type', 'application/json');
res.write(JSON.stringify(filesInDirectoryInfo)); // transform files information into the json string
} catch (ex) {
@ -540,12 +540,12 @@ app.get('/files', async (req, res) => { // define a handler for getting files in
res.end();
});
app.get('/files/file/:fileId', async (req, res) => { // define a handler for getting file information by its id
app.get('/files/file/:fileId', (req, res) => { // define a handler for getting file information by its id
try {
req.DocManager = new DocManager(req, res);
const { fileId } = req.params;
// get the information about the file specified by a file id
const fileInfoById = await req.DocManager.getFilesInfo(fileId);
const fileInfoById = req.DocManager.getFilesInfo(fileId);
res.setHeader('Content-Type', 'application/json');
res.write(JSON.stringify(fileInfoById));
} catch (ex) {
@ -1020,7 +1020,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
if (Object.hasOwn(req.body, 'token')) { // if request body has its own token
body = documentService.readToken(req.body.token); // read and verify it
} else {
const checkJwtHeaderRes = await documentService.checkJwtHeader(req); // otherwise, check jwt token headers
const checkJwtHeaderRes = documentService.checkJwtHeader(req); // otherwise, check jwt token headers
if (checkJwtHeaderRes) { // if they exist
if (checkJwtHeaderRes.payload) {
body = checkJwtHeaderRes.payload; // get the payload object
@ -1102,7 +1102,7 @@ app.get('/config', async (req, res) => {
res.end();
});
app.get('/editor', async (req, res) => { // define a handler for editing document
app.get('/editor', (req, res) => { // define a handler for editing document
try {
req.DocManager = new DocManager(req, res);
@ -1144,7 +1144,7 @@ app.get('/editor', async (req, res) => { // define a handler for editing documen
type = 'desktop';
}
const fileType = await fileUtility.getFileType(fileName);
const fileType = fileUtility.getFileType(fileName);
const templatesImageUrl = req.DocManager.getTemplateImageUrl(fileType);
const createUrl = req.DocManager.getCreateUrl(fileType, userid, type, lang);
let templates = null;
@ -1197,10 +1197,9 @@ app.get('/editor', async (req, res) => { // define a handler for editing documen
const directUrl = req.DocManager.getDownloadUrl(fileName);
let mode = req.query.mode || 'edit'; // mode: view/edit/review/comment/fillForms/embedded
// check if this file can be edited
let canEdit = (await fileUtility.getEditExtensions()).indexOf(fileExt.slice(1)) !== -1;
let canEdit = fileUtility.getEditExtensions().indexOf(fileExt.slice(1)) !== -1; // check if this file can be edited
if (((!canEdit && mode === 'edit') || mode === 'fillForms')
&& (await fileUtility.getFillExtensions()).indexOf(fileExt.slice(1)) !== -1) {
&& fileUtility.getFillExtensions().indexOf(fileExt.slice(1)) !== -1) {
mode = 'fillForms';
canEdit = true;
}
@ -1251,7 +1250,7 @@ app.get('/editor', async (req, res) => { // define a handler for editing documen
// file config data
const argss = {
apiUrl: siteUrl + (await documentService.config()).urls.api.replace('/', ''),
apiUrl: siteUrl + configServer.get('apiUrl'),
file: {
name: fileName,
ext: fileUtility.getFileExtension(fileName, true),
@ -1409,9 +1408,9 @@ app.post('/historyObj', (req, res) => {
res.end();
});
app.get('/formats', async (req, res) => {
app.get('/formats', (req, res) => {
try {
const formats = await documentService.formats();
const formats = fileUtility.getFormats();
res.json({
formats,
});

View File

@ -17,10 +17,14 @@
"wopi": {
"discovery": "hosting/discovery"
},
"commandUrl": "command",
"converterUrl": "converter",
"apiUrl": "web-apps/apps/api/documents/api.js",
"preloaderUrl": "web-apps/apps/api/documents/preload.html",
"exampleUrl": null,
"storageFolder": "./files",
"storagePath": "/files",
"maxFileSize": 1073741824,
"maxNameLength": 50,
"enableForgotten": true,
"mobileRegEx": "android|avantgo|playbook|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino",
@ -28,10 +32,61 @@
"enable": false,
"useforrequest": true,
"algorithmRequest": "HS256",
"authorizationHeader": "Authorization",
"authorizationHeaderPrefix": "Bearer ",
"secret": "secret",
"expiresIn": "5m"
},
"verify_peer_off": true
"verify_peer_off": true,
"languages": {
"en": "English",
"sq-AL": "Albanian (Albania)",
"ar": "Arabic",
"hy": "Armenian",
"az": "Azerbaijani",
"eu": "Basque",
"be": "Belarusian",
"bg": "Bulgarian",
"ca": "Catalan",
"zh": "Chinese (Simplified)",
"zh-TW": "Chinese (Traditional)",
"cs": "Czech",
"da": "Danish",
"nl": "Dutch",
"en-GB": "English (United Kingdom)",
"fi": "Finnish",
"fr": "French",
"gl": "Galego",
"de": "German",
"el": "Greek",
"he-IL": "Hebrew (Israel)",
"hu": "Hungarian",
"id": "Indonesian",
"it": "Italian",
"ja": "Japanese",
"ko": "Korean",
"lo": "Lao",
"lv": "Latvian",
"ms": "Malay (Malaysia)",
"no": "Norwegian",
"pl": "Polish",
"pt": "Portuguese (Brazil)",
"pt-PT": "Portuguese (Portugal)",
"ro": "Romanian",
"ru": "Russian",
"sr-Cyrl-RS": "Serbian (Cyrillic)",
"sr-Latn-RS": "Serbian (Latin)",
"si": "Sinhala (Sri Lanka)",
"sk": "Slovak",
"sl": "Slovenian",
"es": "Spanish",
"sv": "Swedish",
"tr": "Turkish",
"uk": "Ukrainian",
"ur": "Urdu",
"vi": "Vietnamese",
"aa-AA": "Test Language"
}
},
"plugins": {
"pluginsData": []

View File

@ -1,6 +1,7 @@
{
"server": {
"siteUrl": "/",
"maxFileSize": 104857600,
"storageFolder": "/var/lib/onlyoffice/documentserver-example/files",
"enableForgotten": false
}

View File

@ -1,6 +1,7 @@
{
"server": {
"siteUrl": "/",
"maxFileSize": 104857600,
"enableForgotten": false
}
}

View File

@ -315,7 +315,7 @@ DocManager.prototype.changesUser = function changesUser(fileName, userAddress, v
};
// get all the stored files
DocManager.prototype.getStoredFiles = async function getStoredFiles() {
DocManager.prototype.getStoredFiles = function getStoredFiles() {
const userAddress = this.curUserHostAddress();
const directory = this.storageRootPath(userAddress);
this.createDirectory(directory);
@ -335,10 +335,8 @@ DocManager.prototype.getStoredFiles = async function getStoredFiles() {
const item = { // create an object with element data
time,
name: storedFiles[i],
// eslint-disable-next-line no-await-in-loop
documentType: await fileUtility.getFileType(storedFiles[i]),
// eslint-disable-next-line no-await-in-loop
actions: await fileUtility.getFormatActions(fileUtility.getFileExtension(storedFiles[i], true)),
documentType: fileUtility.getFileType(storedFiles[i]),
actions: fileUtility.getFormatActions(fileUtility.getFileExtension(storedFiles[i], true)),
version: version + 1,
};
@ -587,10 +585,10 @@ DocManager.prototype.cleanFolderRecursive = function cleanFolderRecursive(folder
};
// get files information
DocManager.prototype.getFilesInfo = async function getFilesInfo(fileId) {
DocManager.prototype.getFilesInfo = function getFilesInfo(fileId) {
const userAddress = this.curUserHostAddress();
const directory = this.storageRootPath(userAddress);
const filesInDirectory = await this.getStoredFiles(); // get all the stored files from the folder
const filesInDirectory = this.getStoredFiles(); // get all the stored files from the folder
const responseArray = [];
let responseObject;
// run through all the files from the directory

View File

@ -20,7 +20,6 @@
const urlModule = require('url');
const urllib = require('urllib');
const jwt = require('jsonwebtoken');
const { getLangNameFromCode } = require('language-name-map');
const configServer = require('config').get('server');
const fileUtility = require('./fileUtility');
const guidManager = require('./guidManager');
@ -28,78 +27,16 @@ const guidManager = require('./guidManager');
const siteUrl = configServer.get('siteUrl'); // the path to the editors installation
const cfgSignatureEnable = configServer.get('token.enable');
const cfgSignatureUseForRequest = configServer.get('token.useforrequest');
const cfgSignatureAuthorizationHeader = configServer.get('token.authorizationHeader');
const cfgSignatureAuthorizationHeaderPrefix = configServer.get('token.authorizationHeaderPrefix');
const cfgSignatureSecretExpiresIn = configServer.get('token.expiresIn');
const cfgSignatureSecret = configServer.get('token.secret');
const cfgSignatureSecretAlgorithmRequest = configServer.get('token.algorithmRequest');
let configCache;
let formatsCache;
const pendingPromise = {
config: null,
formats: null,
};
const documentService = {};
documentService.userIp = null;
async function fetchMeta(path) {
if (pendingPromise[path]) return pendingPromise[path];
pendingPromise[path] = fetch(`${siteUrl}meta/${path}`)
.then((r) => {
let data;
try {
if (r.status !== 200) throw new Error(`Failed to fetch ${path}. Response status: ${r.status}`);
data = r.json();
} catch (e) {
console.log(e);
}
return data;
})
.then((data) => {
pendingPromise[path] = null;
return data;
});
return pendingPromise[path];
}
documentService.config = async function config() {
if (!configCache) {
configCache = await fetchMeta('config');
configCache.langObject = Object.fromEntries(['en', ...configCache.langs.filter((v) => v !== 'en')].map((k) => {
switch (k) {
case 'pt-pt': return [k, 'Portuguese (Portugal)'];
case 'sr-cyrl': return [k, 'Serbian (Cyrillic)'];
case 'zh-tw': return [k, 'Chinese (Traditional)'];
default:
try {
return [k, getLangNameFromCode(k).name];
} catch {
return [k, k];
}
}
}));
setTimeout(() => {
configCache = null;
}, 1000 * 60 * 60);
}
return configCache;
};
documentService.formats = async function formats() {
if (!formatsCache) {
formatsCache = await fetchMeta('formats');
setTimeout(() => {
formatsCache = null;
}, 1000 * 60 * 60);
}
return formatsCache;
};
// get the url of the converted file (synchronous)
documentService.getConvertedUriSync = function getConvertedUriSync(
documentUri,
@ -114,7 +51,7 @@ documentService.getConvertedUriSync = function getConvertedUriSync(
};
// get the url of the converted file
documentService.getConvertedUri = async function getConvertedUri(
documentService.getConvertedUri = function getConvertedUri(
documentUri,
fromExtension,
toExtension,
@ -145,8 +82,7 @@ documentService.getConvertedUri = async function getConvertedUri(
region: lang,
};
// get the absolute converter url
const uri = siteUrl + (await documentService.config()).urls.converter.replace('/', '');
const uri = siteUrl + configServer.get('converterUrl'); // get the absolute converter url
const headers = {
'Content-Type': 'application/json',
Accept: 'application/json',
@ -154,8 +90,7 @@ documentService.getConvertedUri = async function getConvertedUri(
if (cfgSignatureEnable && cfgSignatureUseForRequest) { // if the signature is enabled and it can be used for request
// write signature authorization header
const { authorization } = (await documentService.config());
headers[authorization.header] = authorization.prefix + this.fillJwtByUrl(uri, params);
headers[cfgSignatureAuthorizationHeader] = cfgSignatureAuthorizationHeaderPrefix + this.fillJwtByUrl(uri, params);
params.token = documentService.getToken(params); // get token and save it to the parameters
}
@ -264,7 +199,7 @@ documentService.getResponseUri = function getResponseUri(json) {
};
// create a command request
documentService.commandRequest = async function commandRequest(method, documentRevisionId, callback, meta = null) {
documentService.commandRequest = function commandRequest(method, documentRevisionId, callback, meta = null) {
const revisionId = documentService.generateRevisionId(documentRevisionId); // generate the document key value
const params = { // create a parameter object with command method and the document key value in it
c: method,
@ -275,13 +210,12 @@ documentService.commandRequest = async function commandRequest(method, documentR
params.meta = meta;
}
const uri = siteUrl + (await documentService.config()).urls.command.replace('/', ''); // get the absolute command url
const uri = siteUrl + configServer.get('commandUrl'); // get the absolute command url
const headers = { // create a headers object
'Content-Type': 'application/json',
};
if (cfgSignatureEnable && cfgSignatureUseForRequest) {
const { authorization } = (await documentService.config());
headers[authorization.header] = authorization.prefix + this.fillJwtByUrl(uri, params);
headers[cfgSignatureAuthorizationHeader] = cfgSignatureAuthorizationHeaderPrefix + this.fillJwtByUrl(uri, params);
params.token = documentService.getToken(params);
}
@ -299,15 +233,13 @@ documentService.commandRequest = async function commandRequest(method, documentR
};
// check jwt token headers
documentService.checkJwtHeader = async function checkJwtHeader(req) {
documentService.checkJwtHeader = function checkJwtHeader(req) {
let decoded = null;
// get signature authorization header from the request
const authorization = req.get((await documentService.config()).authorization.header);
const authorizationPrefix = (await documentService.config()).authorization.prefix;
const authorization = req.get(cfgSignatureAuthorizationHeader); // get signature authorization header from the request
// if authorization header exists and it starts with the authorization header prefix
if (authorization && authorization.startsWith(authorizationPrefix)) {
if (authorization && authorization.startsWith(cfgSignatureAuthorizationHeaderPrefix)) {
// the resulting token starts after the authorization header prefix
const token = authorization.substring(authorizationPrefix.length);
const token = authorization.substring(cfgSignatureAuthorizationHeaderPrefix.length);
try {
decoded = jwt.verify(token, cfgSignatureSecret); // verify signature on jwt token using signature secret
} catch (err) {

View File

@ -17,10 +17,14 @@
*/
const pathModule = require('path');
const documentService = require('./documentService');
const supportedFormats = require('../public/assets/document-formats/onlyoffice-docs-formats.json'); // eslint-disable-line
const fileUtility = {};
fileUtility.getFormats = function getFormats() {
return supportedFormats;
};
// get file name from the given url
fileUtility.getFileNameFromUrl = function getFileNameFromUrl(url, withoutExtension) {
if (!url) return '';
@ -59,9 +63,8 @@ fileUtility.getFileExtension = function getFileExtension(path, withoutDot, isUrl
};
// get file type from the given path
fileUtility.getFileType = async function getFileType(path) {
fileUtility.getFileType = function getFileType(path) {
const ext = fileUtility.getFileExtension(path, true); // get the file extension from the given path
const supportedFormats = await documentService.formats();
for (let i = 0; i < supportedFormats.length; i++) {
if (supportedFormats[i].name === ext && supportedFormats[i].type !== '') return supportedFormats[i].type;
@ -78,34 +81,34 @@ fileUtility.fileType = {
diagram: 'diagram',
};
fileUtility.getFormatActions = async function getExtensionActions(ext) {
return (await documentService.formats()).filter((format) => format.name === ext)[0]?.actions || [];
fileUtility.getFormatActions = function getExtensionActions(ext) {
return supportedFormats.filter((format) => format.name === ext)[0]?.actions || [];
};
fileUtility.getSuppotredExtensions = async function getSuppotredExtensions() {
return (await documentService.formats()).reduce((extensions, format) => [...extensions, format.name], []);
fileUtility.getSuppotredExtensions = function getSuppotredExtensions() {
return supportedFormats.reduce((extensions, format) => [...extensions, format.name], []);
};
fileUtility.getViewExtensions = async function getViewExtensions() {
return (await documentService.formats()).filter(
fileUtility.getViewExtensions = function getViewExtensions() {
return supportedFormats.filter(
(format) => format.actions.includes('view'),
).reduce((extensions, format) => [...extensions, format.name], []);
};
fileUtility.getEditExtensions = async function getEditExtensions() {
return (await documentService.formats()).filter(
fileUtility.getEditExtensions = function getEditExtensions() {
return supportedFormats.filter(
(format) => format.actions.includes('edit') || format.actions.includes('lossy-edit'),
).reduce((extensions, format) => [...extensions, format.name], []);
};
fileUtility.getFillExtensions = async function getFillExtensions() {
return (await documentService.formats()).filter(
fileUtility.getFillExtensions = function getFillExtensions() {
return supportedFormats.filter(
(format) => format.actions.includes('fill'),
).reduce((extensions, format) => [...extensions, format.name], []);
};
fileUtility.getConvertExtensions = async function getConvertExtensions() {
return (await documentService.formats()).filter(
fileUtility.getConvertExtensions = function getConvertExtensions() {
return supportedFormats.filter(
(format) => format.actions.includes('auto-convert'),
).reduce((extensions, format) => [...extensions, format.name], []);
};

View File

@ -21,7 +21,6 @@ const tokenValidator = require('./tokenValidator');
const filesController = require('./filesController');
const utils = require('./utils');
const DocManager = require('../docManager');
const documentService = require('../documentService');
const fileUtility = require('../fileUtility');
const users = require('../users');
@ -59,7 +58,7 @@ exports.registerRoutes = function registerRoutes(app) {
try {
// get all the stored files
const files = await req.DocManager.getStoredFiles();
const files = req.DocManager.getStoredFiles();
// run through all the files and write the corresponding information to each file
// eslint-disable-next-line no-restricted-syntax
@ -89,7 +88,7 @@ exports.registerRoutes = function registerRoutes(app) {
params: req.DocManager.getCustomParams(),
users,
preloaderUrl: siteUrl + configServer.get('preloaderUrl'),
languages: (await documentService.config()).langObject,
languages: configServer.get('languages'),
enableForgotten: configServer.get('enableForgotten'),
editNewExts,
});

View File

@ -20,7 +20,6 @@
"he": "^1.2.0",
"jsonwebtoken": "^9.0.2",
"jwa": "^2.0.0",
"language-name-map": "^0.3.0",
"log4js": "^6.9.1",
"mime": "^2.4.6",
"serve-favicon": "^2.5.0",
@ -2427,12 +2426,6 @@
"safe-buffer": "^5.0.1"
}
},
"node_modules/language-name-map": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/language-name-map/-/language-name-map-0.3.0.tgz",
"integrity": "sha512-uoBHtfY6h4S2RoIpyqvQGhynX2hshQu/9S4ySbppGxG5VwEsiWZJ83xSjzx25Mb+Bmc+WxpQC0H54eNZVMWLuA==",
"license": "BSD-2-Clause"
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@ -5698,11 +5691,6 @@
}
}
},
"language-name-map": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/language-name-map/-/language-name-map-0.3.0.tgz",
"integrity": "sha512-uoBHtfY6h4S2RoIpyqvQGhynX2hshQu/9S4ySbppGxG5VwEsiWZJ83xSjzx25Mb+Bmc+WxpQC0H54eNZVMWLuA=="
},
"levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",

View File

@ -25,7 +25,6 @@
"he": "^1.2.0",
"jsonwebtoken": "^9.0.2",
"jwa": "^2.0.0",
"language-name-map": "^0.3.0",
"log4js": "^6.9.1",
"mime": "^2.4.6",
"serve-favicon": "^2.5.0",

View File

@ -14,7 +14,7 @@ class CheckAndDecodeJWTPayload
/**
* Handle an incoming request.
*
* @param Closure(Request): (Response) $next
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{

View File

@ -11,7 +11,7 @@ class EnsureForgottenPageEnabled
/**
* Handle an incoming request.
*
* @param Closure(Request): (Response) $next
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{

View File

@ -14,7 +14,7 @@ class EnsureJWTTokenIsPresent
/**
* Handle an incoming request.
*
* @param Closure(Request): (Response) $next
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{

View File

@ -12,7 +12,7 @@ class EnsureUserDirectoryExists
/**
* Handle an incoming request.
*
* @param Closure(Request): (Response) $next
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{

View File

@ -1,7 +1,5 @@
<?php
use App\Providers\AppServiceProvider;
return [
AppServiceProvider::class,
App\Providers\AppServiceProvider::class,
];

View File

@ -6229,16 +6229,16 @@
},
{
"name": "laravel/pint",
"version": "v1.28.0",
"version": "v1.27.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
"reference": "1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9"
"reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/pint/zipball/1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9",
"reference": "1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9",
"url": "https://api.github.com/repos/laravel/pint/zipball/54cca2de13790570c7b6f0f94f37896bee4abcb5",
"reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5",
"shasum": ""
},
"require": {
@ -6249,14 +6249,13 @@
"php": "^8.2.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.94.2",
"illuminate/view": "^12.54.1",
"larastan/larastan": "^3.9.3",
"friendsofphp/php-cs-fixer": "^3.93.1",
"illuminate/view": "^12.51.0",
"larastan/larastan": "^3.9.2",
"laravel-zero/framework": "^12.0.5",
"mockery/mockery": "^1.6.12",
"nunomaduro/termwind": "^2.4.0",
"pestphp/pest": "^3.8.5",
"shipfastlabs/agent-detector": "^1.0.2"
"nunomaduro/termwind": "^2.3.3",
"pestphp/pest": "^3.8.5"
},
"bin": [
"builds/pint"
@ -6293,7 +6292,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
"time": "2026-03-10T20:37:18+00:00"
"time": "2026-02-10T20:00:20+00:00"
},
{
"name": "laravel/sail",
@ -8727,6 +8726,6 @@
"platform": {
"php": "^8.2"
},
"platform-dev": {},
"plugin-api-version": "2.9.0"
"platform-dev": [],
"plugin-api-version": "2.6.0"
}

View File

@ -1,7 +1,5 @@
<?php
use App\Models\User;
return [
/*
@ -64,7 +62,7 @@ return [
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => env('AUTH_MODEL', User::class),
'model' => env('AUTH_MODEL', App\Models\User::class),
],
// 'users' => [

View File

@ -2,13 +2,12 @@
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
/**
* @extends Factory<User>
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory
{

View File

@ -51,11 +51,6 @@
- msgspec
- :who:
:why: BSD-3-Clause
:versions: []
:when: 2025-11-07 10:13:51.477550000 Z
- - :approve
- pyjwt
- :who:
:why: MIT
:versions: []
:versions:
- 0.20.0
:when: 2025-11-07 10:13:51.477550000 Z

View File

@ -5,7 +5,7 @@ requires = [
[project]
name = "online-editor-example"
version = "1.6.0"
version = "1.15.0"
requires-python = ">=3.11.4"
dependencies = [
"django>=3.1.3",