mirror of
https://github.com/ONLYOFFICE/document-server-integration.git
synced 2026-03-22 08:22:02 +08:00
Compare commits
46 Commits
pyproject-
...
docs-meta
| Author | SHA1 | Date | |
|---|---|---|---|
| ad78dc8cac | |||
| 8e5b2e7d59 | |||
| dbdac17948 | |||
| cf923450ba | |||
| 248d2fe65c | |||
| 409d111da1 | |||
| 7f5924fded | |||
| e56322f71b | |||
| 7b9623ce6a | |||
| b43af4a42b | |||
| 8778d492a1 | |||
| 3c7aa7707c | |||
| b528be73d8 | |||
| dc9ff1ae4a | |||
| 91551f4664 | |||
| 8271719817 | |||
| 395e2d1299 | |||
| 7d9d2fdf3d | |||
| 3a0a713c5a | |||
| 496092c09f | |||
| c0a870458b | |||
| 35da4e1de1 | |||
| 11974256a9 | |||
| f69fabb44a | |||
| 976d7072a9 | |||
| 8272c83660 | |||
| c73aae1c4b | |||
| 4340c34c23 | |||
| 3eff9b469b | |||
| eabda30bf7 | |||
| 548f24aaff | |||
| c1ec722b9f | |||
| 92a1aff932 | |||
| 4fe6e961d3 | |||
| e612717b0b | |||
| e0e0bc96bf | |||
| c3739fb08a | |||
| c22dbea9bf | |||
| 606a14ce8f | |||
| 4cb50c752b | |||
| c304b5f526 | |||
| f02726d138 | |||
| 85b0fdc33f | |||
| 0e8c99aaab | |||
| 5a4b47c4bd | |||
| 9775c8e175 |
4
.github/workflows/licenses-go.yml
vendored
4
.github/workflows/licenses-go.yml
vendored
@ -15,6 +15,10 @@ 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
3
.gitmodules
vendored
@ -2,9 +2,6 @@
|
||||
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
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
# 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
|
||||
|
||||
@ -42,8 +42,6 @@ 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');
|
||||
@ -89,16 +87,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('/', (req, res) => { // define a handler for default page
|
||||
app.get('/', async (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: req.DocManager.getStoredFiles(),
|
||||
storedFiles: await req.DocManager.getStoredFiles(),
|
||||
params: req.DocManager.getCustomParams(),
|
||||
users,
|
||||
languages: configServer.get('languages'),
|
||||
languages: (await documentService.config()).langObject,
|
||||
serverVersion: config.get('version'),
|
||||
enableForgotten,
|
||||
});
|
||||
@ -135,14 +133,14 @@ app.get('/forgotten', async (req, res) => {
|
||||
|
||||
function getForgottenFile(key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
documentService.commandRequest('getForgotten', key, (err, data) => {
|
||||
documentService.commandRequest('getForgotten', key, async (err, data) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
const parsedData = JSON.parse(data);
|
||||
resolve({
|
||||
name: parsedData.key,
|
||||
documentType: fileUtility.getFileType(parsedData.url),
|
||||
documentType: await fileUtility.getFileType(parsedData.url),
|
||||
url: parsedData.url,
|
||||
});
|
||||
}
|
||||
@ -183,7 +181,7 @@ app.delete('/forgotten', (req, res) => { // define a handler for removing forgot
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/download', (req, res) => { // define a handler for downloading files
|
||||
app.get('/download', async (req, res) => { // define a handler for downloading files
|
||||
req.DocManager = new DocManager(req, res);
|
||||
|
||||
const fileName = fileUtility.getFileName(req.query.fileName);
|
||||
@ -192,9 +190,10 @@ app.get('/download', (req, res) => { // define a handler for downloading files
|
||||
|
||||
if (!!userAddress
|
||||
&& cfgSignatureEnable && cfgSignatureUseForRequest) {
|
||||
const authorization = req.get(cfgSignatureAuthorizationHeader);
|
||||
if (authorization && authorization.startsWith(cfgSignatureAuthorizationHeaderPrefix)) {
|
||||
token = authorization.substring(cfgSignatureAuthorizationHeaderPrefix.length);
|
||||
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);
|
||||
}
|
||||
|
||||
try {
|
||||
@ -234,12 +233,13 @@ app.get('/data', (req, res) => { // define a handler for getting sample ai form
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/history', (req, res) => {
|
||||
app.get('/history', async (req, res) => {
|
||||
req.DocManager = new DocManager(req, res);
|
||||
if (cfgSignatureEnable && cfgSignatureUseForRequest) {
|
||||
const authorization = req.get(cfgSignatureAuthorizationHeader);
|
||||
if (authorization && authorization.startsWith(cfgSignatureAuthorizationHeaderPrefix)) {
|
||||
const token = authorization.substring(cfgSignatureAuthorizationHeaderPrefix.length);
|
||||
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);
|
||||
try {
|
||||
jwt.verify(token, cfgSignatureSecret);
|
||||
} catch (err) {
|
||||
@ -277,7 +277,7 @@ app.get('/history', (req, res) => {
|
||||
filestream.pipe(res); // send file information to the response by streams
|
||||
});
|
||||
|
||||
app.post('/upload', (req, res) => { // define a handler for uploading files
|
||||
app.post('/upload', async (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', (req, res) => { // define a handler for uploading files
|
||||
const uploadDirTmp = path.join(uploadDir, 'tmp'); // and create directory for temporary files if it doesn't exist
|
||||
req.DocManager.createDirectory(uploadDirTmp);
|
||||
|
||||
const fileSizeLimit = configServer.get('maxFileSize');
|
||||
const fileSizeLimit = (await documentService.config()).limits.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, (err, fields, files) => { // parse this form
|
||||
form.parse(req, async (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', (req, res) => { // define a handler for uploading files
|
||||
return;
|
||||
}
|
||||
|
||||
const exts = fileUtility.getSuppotredExtensions(); // all the supported file extensions
|
||||
const exts = await fileUtility.getSuppotredExtensions(); // all the supported file extensions
|
||||
const curExt = fileUtility.getFileExtension(file.originalFilename, true);
|
||||
const documentType = fileUtility.getFileType(file.originalFilename);
|
||||
const documentType = await fileUtility.getFileType(file.originalFilename);
|
||||
|
||||
if (exts.indexOf(curExt) === -1 || fileUtility.getFormatActions(curExt).length === 0) {
|
||||
if (exts.indexOf(curExt) === -1 || (await 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' }, (err, data) => {
|
||||
urllib.request(fileUrl, { method: 'GET' }, async (err, data) => {
|
||||
// check if the file size exceeds the maximum file size
|
||||
if (configServer.get('maxFileSize') < data.length || data.length <= 0) {
|
||||
if ((await documentService.config()).limits.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 = fileUtility.getSuppotredExtensions(); // all the supported file extensions
|
||||
const exts = await fileUtility.getSuppotredExtensions(); // all the supported file extensions
|
||||
const curExt = fileUtility.getFileExtension(fileName, true);
|
||||
|
||||
if (exts.indexOf(curExt) === -1 || fileUtility.getFormatActions(curExt).length === 0) {
|
||||
if (exts.indexOf(curExt) === -1 || (await 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', (req, res) => { // define a handler for converting files
|
||||
app.post('/convert', async (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', (req, res) => { // define a handler for converting files
|
||||
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 (fileUtility.getFileType(correctName) !== null) {
|
||||
if ((await 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', (req, res) => { // define a handler for converting files
|
||||
|
||||
try {
|
||||
// check if the file with such an extension can be converted
|
||||
if ((fileUtility.getConvertExtensions().indexOf(fileExt) !== -1) || ('fileExt' in req.body)) {
|
||||
if (((await 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', (req, res) => { // define a handler for converting files
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/files', (req, res) => { // define a handler for getting files information
|
||||
app.get('/files', async (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 = req.DocManager.getFilesInfo();
|
||||
const filesInDirectoryInfo = await 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', (req, res) => { // define a handler for getting files informat
|
||||
res.end();
|
||||
});
|
||||
|
||||
app.get('/files/file/:fileId', (req, res) => { // define a handler for getting file information by its id
|
||||
app.get('/files/file/:fileId', async (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 = req.DocManager.getFilesInfo(fileId);
|
||||
const fileInfoById = await 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 = documentService.checkJwtHeader(req); // otherwise, check jwt token headers
|
||||
const checkJwtHeaderRes = await 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', (req, res) => { // define a handler for editing document
|
||||
app.get('/editor', async (req, res) => { // define a handler for editing document
|
||||
try {
|
||||
req.DocManager = new DocManager(req, res);
|
||||
|
||||
@ -1144,7 +1144,7 @@ app.get('/editor', (req, res) => { // define a handler for editing document
|
||||
type = 'desktop';
|
||||
}
|
||||
|
||||
const fileType = fileUtility.getFileType(fileName);
|
||||
const fileType = await fileUtility.getFileType(fileName);
|
||||
const templatesImageUrl = req.DocManager.getTemplateImageUrl(fileType);
|
||||
const createUrl = req.DocManager.getCreateUrl(fileType, userid, type, lang);
|
||||
let templates = null;
|
||||
@ -1197,9 +1197,10 @@ app.get('/editor', (req, res) => { // define a handler for editing document
|
||||
const directUrl = req.DocManager.getDownloadUrl(fileName);
|
||||
let mode = req.query.mode || 'edit'; // mode: view/edit/review/comment/fillForms/embedded
|
||||
|
||||
let canEdit = fileUtility.getEditExtensions().indexOf(fileExt.slice(1)) !== -1; // check if this file can be edited
|
||||
// check if this file can be edited
|
||||
let canEdit = (await fileUtility.getEditExtensions()).indexOf(fileExt.slice(1)) !== -1;
|
||||
if (((!canEdit && mode === 'edit') || mode === 'fillForms')
|
||||
&& fileUtility.getFillExtensions().indexOf(fileExt.slice(1)) !== -1) {
|
||||
&& (await fileUtility.getFillExtensions()).indexOf(fileExt.slice(1)) !== -1) {
|
||||
mode = 'fillForms';
|
||||
canEdit = true;
|
||||
}
|
||||
@ -1250,7 +1251,7 @@ app.get('/editor', (req, res) => { // define a handler for editing document
|
||||
|
||||
// file config data
|
||||
const argss = {
|
||||
apiUrl: siteUrl + configServer.get('apiUrl'),
|
||||
apiUrl: siteUrl + (await documentService.config()).urls.api.replace('/', ''),
|
||||
file: {
|
||||
name: fileName,
|
||||
ext: fileUtility.getFileExtension(fileName, true),
|
||||
@ -1408,9 +1409,9 @@ app.post('/historyObj', (req, res) => {
|
||||
res.end();
|
||||
});
|
||||
|
||||
app.get('/formats', (req, res) => {
|
||||
app.get('/formats', async (req, res) => {
|
||||
try {
|
||||
const formats = fileUtility.getFormats();
|
||||
const formats = await documentService.formats();
|
||||
res.json({
|
||||
formats,
|
||||
});
|
||||
|
||||
@ -17,14 +17,10 @@
|
||||
"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",
|
||||
@ -32,61 +28,10 @@
|
||||
"enable": false,
|
||||
"useforrequest": true,
|
||||
"algorithmRequest": "HS256",
|
||||
"authorizationHeader": "Authorization",
|
||||
"authorizationHeaderPrefix": "Bearer ",
|
||||
"secret": "secret",
|
||||
"expiresIn": "5m"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
"verify_peer_off": true
|
||||
},
|
||||
"plugins": {
|
||||
"pluginsData": []
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{
|
||||
"server": {
|
||||
"siteUrl": "/",
|
||||
"maxFileSize": 104857600,
|
||||
"storageFolder": "/var/lib/onlyoffice/documentserver-example/files",
|
||||
"enableForgotten": false
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{
|
||||
"server": {
|
||||
"siteUrl": "/",
|
||||
"maxFileSize": 104857600,
|
||||
"enableForgotten": false
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,7 +315,7 @@ DocManager.prototype.changesUser = function changesUser(fileName, userAddress, v
|
||||
};
|
||||
|
||||
// get all the stored files
|
||||
DocManager.prototype.getStoredFiles = function getStoredFiles() {
|
||||
DocManager.prototype.getStoredFiles = async function getStoredFiles() {
|
||||
const userAddress = this.curUserHostAddress();
|
||||
const directory = this.storageRootPath(userAddress);
|
||||
this.createDirectory(directory);
|
||||
@ -335,8 +335,10 @@ DocManager.prototype.getStoredFiles = function getStoredFiles() {
|
||||
const item = { // create an object with element data
|
||||
time,
|
||||
name: storedFiles[i],
|
||||
documentType: fileUtility.getFileType(storedFiles[i]),
|
||||
actions: fileUtility.getFormatActions(fileUtility.getFileExtension(storedFiles[i], true)),
|
||||
// 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)),
|
||||
version: version + 1,
|
||||
};
|
||||
|
||||
@ -585,10 +587,10 @@ DocManager.prototype.cleanFolderRecursive = function cleanFolderRecursive(folder
|
||||
};
|
||||
|
||||
// get files information
|
||||
DocManager.prototype.getFilesInfo = function getFilesInfo(fileId) {
|
||||
DocManager.prototype.getFilesInfo = async function getFilesInfo(fileId) {
|
||||
const userAddress = this.curUserHostAddress();
|
||||
const directory = this.storageRootPath(userAddress);
|
||||
const filesInDirectory = this.getStoredFiles(); // get all the stored files from the folder
|
||||
const filesInDirectory = await this.getStoredFiles(); // get all the stored files from the folder
|
||||
const responseArray = [];
|
||||
let responseObject;
|
||||
// run through all the files from the directory
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
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');
|
||||
@ -27,16 +28,78 @@ 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,
|
||||
@ -51,7 +114,7 @@ documentService.getConvertedUriSync = function getConvertedUriSync(
|
||||
};
|
||||
|
||||
// get the url of the converted file
|
||||
documentService.getConvertedUri = function getConvertedUri(
|
||||
documentService.getConvertedUri = async function getConvertedUri(
|
||||
documentUri,
|
||||
fromExtension,
|
||||
toExtension,
|
||||
@ -82,7 +145,8 @@ documentService.getConvertedUri = function getConvertedUri(
|
||||
region: lang,
|
||||
};
|
||||
|
||||
const uri = siteUrl + configServer.get('converterUrl'); // get the absolute converter url
|
||||
// get the absolute converter url
|
||||
const uri = siteUrl + (await documentService.config()).urls.converter.replace('/', '');
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
@ -90,7 +154,8 @@ documentService.getConvertedUri = function getConvertedUri(
|
||||
|
||||
if (cfgSignatureEnable && cfgSignatureUseForRequest) { // if the signature is enabled and it can be used for request
|
||||
// write signature authorization header
|
||||
headers[cfgSignatureAuthorizationHeader] = cfgSignatureAuthorizationHeaderPrefix + this.fillJwtByUrl(uri, params);
|
||||
const { authorization } = (await documentService.config());
|
||||
headers[authorization.header] = authorization.prefix + this.fillJwtByUrl(uri, params);
|
||||
params.token = documentService.getToken(params); // get token and save it to the parameters
|
||||
}
|
||||
|
||||
@ -199,7 +264,7 @@ documentService.getResponseUri = function getResponseUri(json) {
|
||||
};
|
||||
|
||||
// create a command request
|
||||
documentService.commandRequest = function commandRequest(method, documentRevisionId, callback, meta = null) {
|
||||
documentService.commandRequest = async 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,
|
||||
@ -210,12 +275,13 @@ documentService.commandRequest = function commandRequest(method, documentRevisio
|
||||
params.meta = meta;
|
||||
}
|
||||
|
||||
const uri = siteUrl + configServer.get('commandUrl'); // get the absolute command url
|
||||
const uri = siteUrl + (await documentService.config()).urls.command.replace('/', ''); // get the absolute command url
|
||||
const headers = { // create a headers object
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
if (cfgSignatureEnable && cfgSignatureUseForRequest) {
|
||||
headers[cfgSignatureAuthorizationHeader] = cfgSignatureAuthorizationHeaderPrefix + this.fillJwtByUrl(uri, params);
|
||||
const { authorization } = (await documentService.config());
|
||||
headers[authorization.header] = authorization.prefix + this.fillJwtByUrl(uri, params);
|
||||
params.token = documentService.getToken(params);
|
||||
}
|
||||
|
||||
@ -233,13 +299,15 @@ documentService.commandRequest = function commandRequest(method, documentRevisio
|
||||
};
|
||||
|
||||
// check jwt token headers
|
||||
documentService.checkJwtHeader = function checkJwtHeader(req) {
|
||||
documentService.checkJwtHeader = async function checkJwtHeader(req) {
|
||||
let decoded = null;
|
||||
const authorization = req.get(cfgSignatureAuthorizationHeader); // get signature authorization header from the request
|
||||
// get signature authorization header from the request
|
||||
const authorization = req.get((await documentService.config()).authorization.header);
|
||||
const authorizationPrefix = (await documentService.config()).authorization.prefix;
|
||||
// if authorization header exists and it starts with the authorization header prefix
|
||||
if (authorization && authorization.startsWith(cfgSignatureAuthorizationHeaderPrefix)) {
|
||||
if (authorization && authorization.startsWith(authorizationPrefix)) {
|
||||
// the resulting token starts after the authorization header prefix
|
||||
const token = authorization.substring(cfgSignatureAuthorizationHeaderPrefix.length);
|
||||
const token = authorization.substring(authorizationPrefix.length);
|
||||
try {
|
||||
decoded = jwt.verify(token, cfgSignatureSecret); // verify signature on jwt token using signature secret
|
||||
} catch (err) {
|
||||
|
||||
@ -17,14 +17,10 @@
|
||||
*/
|
||||
|
||||
const pathModule = require('path');
|
||||
const supportedFormats = require('../public/assets/document-formats/onlyoffice-docs-formats.json'); // eslint-disable-line
|
||||
const documentService = require('./documentService');
|
||||
|
||||
const fileUtility = {};
|
||||
|
||||
fileUtility.getFormats = function getFormats() {
|
||||
return supportedFormats;
|
||||
};
|
||||
|
||||
// get file name from the given url
|
||||
fileUtility.getFileNameFromUrl = function getFileNameFromUrl(url, withoutExtension) {
|
||||
if (!url) return '';
|
||||
@ -63,8 +59,9 @@ fileUtility.getFileExtension = function getFileExtension(path, withoutDot, isUrl
|
||||
};
|
||||
|
||||
// get file type from the given path
|
||||
fileUtility.getFileType = function getFileType(path) {
|
||||
fileUtility.getFileType = async 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;
|
||||
@ -81,34 +78,34 @@ fileUtility.fileType = {
|
||||
diagram: 'diagram',
|
||||
};
|
||||
|
||||
fileUtility.getFormatActions = function getExtensionActions(ext) {
|
||||
return supportedFormats.filter((format) => format.name === ext)[0]?.actions || [];
|
||||
fileUtility.getFormatActions = async function getExtensionActions(ext) {
|
||||
return (await documentService.formats()).filter((format) => format.name === ext)[0]?.actions || [];
|
||||
};
|
||||
|
||||
fileUtility.getSuppotredExtensions = function getSuppotredExtensions() {
|
||||
return supportedFormats.reduce((extensions, format) => [...extensions, format.name], []);
|
||||
fileUtility.getSuppotredExtensions = async function getSuppotredExtensions() {
|
||||
return (await documentService.formats()).reduce((extensions, format) => [...extensions, format.name], []);
|
||||
};
|
||||
|
||||
fileUtility.getViewExtensions = function getViewExtensions() {
|
||||
return supportedFormats.filter(
|
||||
fileUtility.getViewExtensions = async function getViewExtensions() {
|
||||
return (await documentService.formats()).filter(
|
||||
(format) => format.actions.includes('view'),
|
||||
).reduce((extensions, format) => [...extensions, format.name], []);
|
||||
};
|
||||
|
||||
fileUtility.getEditExtensions = function getEditExtensions() {
|
||||
return supportedFormats.filter(
|
||||
fileUtility.getEditExtensions = async function getEditExtensions() {
|
||||
return (await documentService.formats()).filter(
|
||||
(format) => format.actions.includes('edit') || format.actions.includes('lossy-edit'),
|
||||
).reduce((extensions, format) => [...extensions, format.name], []);
|
||||
};
|
||||
|
||||
fileUtility.getFillExtensions = function getFillExtensions() {
|
||||
return supportedFormats.filter(
|
||||
fileUtility.getFillExtensions = async function getFillExtensions() {
|
||||
return (await documentService.formats()).filter(
|
||||
(format) => format.actions.includes('fill'),
|
||||
).reduce((extensions, format) => [...extensions, format.name], []);
|
||||
};
|
||||
|
||||
fileUtility.getConvertExtensions = function getConvertExtensions() {
|
||||
return supportedFormats.filter(
|
||||
fileUtility.getConvertExtensions = async function getConvertExtensions() {
|
||||
return (await documentService.formats()).filter(
|
||||
(format) => format.actions.includes('auto-convert'),
|
||||
).reduce((extensions, format) => [...extensions, format.name], []);
|
||||
};
|
||||
|
||||
@ -21,6 +21,7 @@ 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');
|
||||
|
||||
@ -58,7 +59,7 @@ exports.registerRoutes = function registerRoutes(app) {
|
||||
|
||||
try {
|
||||
// get all the stored files
|
||||
const files = req.DocManager.getStoredFiles();
|
||||
const files = await req.DocManager.getStoredFiles();
|
||||
|
||||
// run through all the files and write the corresponding information to each file
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
@ -88,7 +89,7 @@ exports.registerRoutes = function registerRoutes(app) {
|
||||
params: req.DocManager.getCustomParams(),
|
||||
users,
|
||||
preloaderUrl: siteUrl + configServer.get('preloaderUrl'),
|
||||
languages: configServer.get('languages'),
|
||||
languages: (await documentService.config()).langObject,
|
||||
enableForgotten: configServer.get('enableForgotten'),
|
||||
editNewExts,
|
||||
});
|
||||
|
||||
12
web/documentserver-example/nodejs/package-lock.json
generated
12
web/documentserver-example/nodejs/package-lock.json
generated
@ -20,6 +20,7 @@
|
||||
"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",
|
||||
@ -2426,6 +2427,12 @@
|
||||
"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",
|
||||
@ -5691,6 +5698,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"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",
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
"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",
|
||||
|
||||
Submodule web/documentserver-example/nodejs/public/assets/document-formats deleted from 7d7576a3fe
@ -14,7 +14,7 @@ class CheckAndDecodeJWTPayload
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
||||
@ -11,7 +11,7 @@ class EnsureForgottenPageEnabled
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
||||
@ -14,7 +14,7 @@ class EnsureJWTTokenIsPresent
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
||||
@ -12,7 +12,7 @@ class EnsureUserDirectoryExists
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use App\Providers\AppServiceProvider;
|
||||
|
||||
return [
|
||||
App\Providers\AppServiceProvider::class,
|
||||
AppServiceProvider::class,
|
||||
];
|
||||
|
||||
25
web/documentserver-example/php-laravel/composer.lock
generated
25
web/documentserver-example/php-laravel/composer.lock
generated
@ -6229,16 +6229,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/pint",
|
||||
"version": "v1.27.1",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/pint.git",
|
||||
"reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5"
|
||||
"reference": "1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/pint/zipball/54cca2de13790570c7b6f0f94f37896bee4abcb5",
|
||||
"reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5",
|
||||
"url": "https://api.github.com/repos/laravel/pint/zipball/1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9",
|
||||
"reference": "1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -6249,13 +6249,14 @@
|
||||
"php": "^8.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.93.1",
|
||||
"illuminate/view": "^12.51.0",
|
||||
"larastan/larastan": "^3.9.2",
|
||||
"friendsofphp/php-cs-fixer": "^3.94.2",
|
||||
"illuminate/view": "^12.54.1",
|
||||
"larastan/larastan": "^3.9.3",
|
||||
"laravel-zero/framework": "^12.0.5",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"nunomaduro/termwind": "^2.3.3",
|
||||
"pestphp/pest": "^3.8.5"
|
||||
"nunomaduro/termwind": "^2.4.0",
|
||||
"pestphp/pest": "^3.8.5",
|
||||
"shipfastlabs/agent-detector": "^1.0.2"
|
||||
},
|
||||
"bin": [
|
||||
"builds/pint"
|
||||
@ -6292,7 +6293,7 @@
|
||||
"issues": "https://github.com/laravel/pint/issues",
|
||||
"source": "https://github.com/laravel/pint"
|
||||
},
|
||||
"time": "2026-02-10T20:00:20+00:00"
|
||||
"time": "2026-03-10T20:37:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/sail",
|
||||
@ -8726,6 +8727,6 @@
|
||||
"platform": {
|
||||
"php": "^8.2"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.6.0"
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.9.0"
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
@ -62,7 +64,7 @@ return [
|
||||
'providers' => [
|
||||
'users' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => env('AUTH_MODEL', App\Models\User::class),
|
||||
'model' => env('AUTH_MODEL', User::class),
|
||||
],
|
||||
|
||||
// 'users' => [
|
||||
|
||||
@ -2,12 +2,13 @@
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
* @extends Factory<User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
|
||||
@ -51,6 +51,11 @@
|
||||
- msgspec
|
||||
- :who:
|
||||
:why: BSD-3-Clause
|
||||
:versions:
|
||||
- 0.20.0
|
||||
:versions: []
|
||||
:when: 2025-11-07 10:13:51.477550000 Z
|
||||
- - :approve
|
||||
- pyjwt
|
||||
- :who:
|
||||
:why: MIT
|
||||
:versions: []
|
||||
:when: 2025-11-07 10:13:51.477550000 Z
|
||||
|
||||
@ -5,7 +5,7 @@ requires = [
|
||||
|
||||
[project]
|
||||
name = "online-editor-example"
|
||||
version = "1.15.0"
|
||||
version = "1.6.0"
|
||||
requires-python = ">=3.11.4"
|
||||
dependencies = [
|
||||
"django>=3.1.3",
|
||||
|
||||
Reference in New Issue
Block a user