/* * * (c) Copyright Ascensio System Limited 2010-2016 * * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html * * You can contact Ascensio System SIA by email at sales@onlyoffice.com * * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. * * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains * relevant author attributions when distributing the software. If the display of the logo in its graphic * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" * in every copy of the program you distribute. * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. * */ var express = require("express"); var path = require("path"); var favicon = require("serve-favicon"); var bodyParser = require("body-parser"); var fileSystem = require("fs"); var formidable = require("formidable"); var syncRequest = require("sync-request"); var config = require("./config"); var docManager = require("./helpers/docManager"); var documentService = require("./helpers/documentService"); var fileUtility = require("./helpers/fileUtility"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; String.prototype.hashCode = function () { for (var ret = 0, i = 0, len = this.length; i < len; i++) { ret = (31 * ret + this.charCodeAt(i)) << 0; } return ret; }; String.prototype.format = function () { var text = this.toString(); if (!arguments.length) return text; for (var i = 0; i < arguments.length; i++) { text = text.replace(new RegExp("\\{" + i + "\\}", "gi"), arguments[i]); } return text; }; var app = express(); app.set("views", path.join(__dirname, "views")); app.set("view engine", "ejs") app.use(function (req, res, next) { res.setHeader('Access-Control-Allow-Origin', '*'); next(); }); app.use(express.static(path.join(__dirname, "public"))); app.use(favicon(__dirname + "/public/images/favicon.ico")); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.get("/", function (req, res) { try { docManager.init(__dirname, req, res); res.render("index", { preloaderUrl: config.preloaderUrl, convertExts: config.convertedDocs.join(","), editedExts: config.editedDocs.join(","), storedFiles: docManager.getStoredFiles(), params: docManager.getCustomParams() }); } catch (ex) { res.status(500); res.render("error", { message: ex.message, error: ex }); return; } }); app.post("/upload", function (req, res) { docManager.init(__dirname, req, res); docManager.storagePath(""); //mkdir if not exist var userIp = docManager.curUserHostAddress(); var uploadDir = "./public/" + config.storageFolder + "/" + userIp; var form = new formidable.IncomingForm(); form.uploadDir = uploadDir; form.keepExtensions = true; form.parse(req, function (err, fields, files) { var file = files.uploadedFile; file.name = docManager.getCorrectName(file.name); if (config.maxFileSize < file.size || file.size <= 0) { fileSystem.unlinkSync(file.path); res.writeHead(200, { "Content-Type": "text/plain" }); res.write("{ \"error\": \"File size is incorrect\"}"); res.end(); return; } var exts = new Array().concat(config.viewedDocs, config.editedDocs, config.convertedDocs); var curExt = fileUtility.getFileExtension(file.name); if (exts.indexOf(curExt) == -1) { fileSystem.unlinkSync(file.path); res.writeHead(200, { "Content-Type": "text/plain" }); res.write("{ \"error\": \"File type is not supported\"}"); res.end(); return; } fileSystem.rename(file.path, uploadDir + "/" + file.name, function (err) { res.writeHead(200, { "Content-Type": "text/plain" }); if (err) { res.write("{ \"error\": \"" + err + "\"}"); } else { res.write("{ \"filename\": \"" + file.name + "\"}"); var userid = req.query.userid ? req.query.userid : "uid-1"; var firstname = req.query.firstname ? req.query.firstname : "Jonn"; var lastname = req.query.lastname ? req.query.lastname : "Smith"; docManager.saveFileData(file.name, userid, firstname + " " + lastname); docManager.getFileData(file.name, docManager.curUserHostAddress()); } res.end(); }); }); }); app.get("/convert", function (req, res) { var fileName = req.query.filename; var fileUri = docManager.getFileUri(fileName); var fileExt = fileUtility.getFileExtension(fileName); var fileType = fileUtility.getFileType(fileName); var internalFileExt = docManager.getInternalExtension(fileType); var response = res; var writeResult = function (filename, step, error) { var result = {}; if (filename != null) result["filename"] = filename; if (step != null) result["step"] = step; if (error != null) result["error"] = error; response.write(JSON.stringify(result)); response.end(); } var callback = function (err, data) { if (err) { if (err.name === "ConnectionTimeoutError") { writeResult(fileName, 0, null); return; } else { throw { message: err }; } } try { var responseUri = documentService.getResponseUri(data.toString()) var result = responseUri.key; var newFileUri = responseUri.value; if (result != 100) { writeResult(fileName, result, null) return; } var correctName = docManager.getCorrectName(fileUtility.getFileName(fileName, true) + internalFileExt); var file = syncRequest("GET", newFileUri); fileSystem.writeFileSync(docManager.storagePath(correctName), file.getBody()); fileSystem.unlinkSync(docManager.storagePath(fileName)); writeResult(correctName, null, null) } catch (ex) { writeResult(null, null, ex.message) } } try { if (config.convertedDocs.indexOf(fileExt) != -1) { var key = documentService.generateRevisionId(fileUri); var res = documentService.getConvertedUriAsync(fileUri, fileExt, internalFileExt, key, callback); } else { writeResult(fileName, null, null) } } catch (ex) { writeResult(null, null, ex.message) } }); app.post("/track", function (req, res) { docManager.init(__dirname, req, res); var userAddress = req.query.useraddress; var fileName = req.query.filename; var version = 0; var processTrack = function (response, body, fileName, userAddress) { var processSave = function (body, fileName, userAddress, newVersion) { var downloadUri = body.url; var curExt = fileUtility.getFileExtension(fileName); var downloadExt = fileUtility.getFileExtension(downloadUri); if (downloadExt != curExt) { var key = documentService.generateRevisionId(downloadUri); try { downloadUri = documentService.getConvertedUri(downloadUri, downloadExt, curExt, key); } catch (ex) { fileName = docManager.getCorrectName(fileUtility.getFileName(fileName, true) + downloadExt, userAddress) } } try { var path = docManager.storagePath(fileName, userAddress); if (newVersion) { var historyPath = docManager.historyPath(fileName, userAddress); if (historyPath == "") { historyPath = docManager.historyPath(fileName, userAddress, true); if (!fileSystem.existsSync(historyPath)) { fileSystem.mkdirSync(historyPath); } } var count_version = docManager.countVersion(historyPath); version = count_version + 1; versionPath = docManager.versionPath(fileName, userAddress, version); if (!fileSystem.existsSync(versionPath)) { fileSystem.mkdirSync(versionPath); } var downloadZip = body.changesurl; if (downloadZip) { var path_changes = docManager.diffPath(fileName, userAddress, version); var diffZip = syncRequest("GET", downloadZip); fileSystem.writeFileSync(path_changes, diffZip.getBody()); } var changeshistory = body.changeshistory; if (changeshistory) { var path_changes_json = docManager.changesPath(fileName, userAddress, version); fileSystem.writeFileSync(path_changes_json, body.changeshistory); } var path_key = docManager.keyPath(fileName, userAddress, version); fileSystem.writeFileSync(path_key, body.key); var path_prev = docManager.prevFilePath(fileName, userAddress, version); fileSystem.writeFileSync(path_prev, fileSystem.readFileSync(path)); } var file = syncRequest("GET", downloadUri); fileSystem.writeFileSync(path, file.getBody()); } catch (ex) { } } if (body.status == 1) { //Editing if (body.actions && body.actions[0].type == 0) { //finished edit var user = body.actions[0].userid; if (body.users.indexOf(user) == -1) { var key = body.key; try { documentService.commandRequest("forcesave", key); } catch (ex) { } } } } else if (body.status == 2 || body.status == 3) { //MustSave, Corrupted processSave(body, fileName, userAddress, true); } else if (body.status == 6 || body.status == 7) { //MustForceSave, CorruptedForceSave processSave(body, fileName, userAddress); } response.write("{\"error\":0}"); response.end(); } var readbody = function (request, response, fileName, userAddress) { var content = ""; request.on('data', function (data) { content += data; }); request.on('end', function () { var body = JSON.parse(content); processTrack(response, body, fileName, userAddress); }); } if (req.body.hasOwnProperty("status")) { processTrack(res, req.body, fileName, userAddress); } else { readbody(req, res, fileName, userAddress); } }); app.get("/editor", function (req, res) { try { docManager.init(__dirname, req, res); var fileExt = req.query.fileExt; var history = []; var prevUrl = []; var diff = []; var lang = docManager.getLang(); var userid = req.query.userid ? req.query.userid : "uid-1"; var firstname = req.query.firstname ? req.query.firstname : "Jonn"; var lastname = req.query.lastname ? req.query.lastname : "Smith"; if (fileExt != null) { var fileName = docManager.createDemo((req.query.create ? "new." : "sample.") + fileExt, userid, firstname + " " + lastname); var redirectPath = docManager.getProtocol() + "://" + docManager.req.get("host") + "/editor?fileName=" + encodeURIComponent(fileName) + docManager.getCustomParams(); res.redirect(redirectPath); return; } var userAddress = docManager.curUserHostAddress(); var fileName = req.query.fileName; var key = docManager.getKey(fileName); var url = docManager.getFileUri(fileName); var mode = req.query.mode || "edit"; //mode: view/edit var type = req.query.type || "desktop"; //type: embedded/mobile/desktop var canEdit = config.editedDocs.indexOf(fileUtility.getFileExtension(fileName)) != -1; var historyPath = docManager.historyPath(fileName, userAddress); var countVersion = 1; changes = null; if (historyPath != '') { countVersion = docManager.countVersion(historyPath) + 1; var prev_path = docManager.getlocalFileUri(fileName, 1) + "/prev" + fileUtility.getFileExtension(fileName); var diff_path = null; for (var i = 1; i < countVersion; i++) { var keyPath = docManager.keyPath(fileName, userAddress, i); var keyVersion = "" + fileSystem.readFileSync(keyPath); history.push(docManager.getHistory(fileName, changes, keyVersion, i)); prevUrl.push(prev_path); prev_path = docManager.getlocalFileUri(fileName, i) + "/prev" + fileUtility.getFileExtension(fileName); diff.push(diff_path); diff_path = docManager.getlocalFileUri(fileName, i) + "/diff.zip"; var changesFile = docManager.changesPath(fileName, userAddress, i); var changes = docManager.getChanges(changesFile); } prevUrl.push(prev_path); diff.push(diff_path); } else { prevUrl.push(url) } history.push(docManager.getHistory(fileName, changes, key, countVersion)); var argss = { apiUrl: config.apiUrl, file: { name: fileName, ext: fileUtility.getFileExtension(fileName, true), uri: url, version: countVersion }, editor: { type: type, documentType: fileUtility.getFileType(fileName), key: key, callbackUrl: docManager.getCallback(fileName), isEdit: canEdit, mode: canEdit && mode != "view" ? "edit" : "view", canBackToFolder: type != "embedded", getServerUrl: docManager.getServerUrl(), curUserHostAddress: docManager.curUserHostAddress(), lang: lang, userid: userid, firstname: firstname, lastname: lastname }, history: history, setHistoryData: { url: prevUrl || "", //из файла прочитать ссылки urlDiff: diff || "" } }; res.render("editor", argss); } catch (ex) { res.status(500); res.render("error", { message: ex.message, error: ex }); return; } }); app.use(function (req, res, next) { var err = new Error("Not Found"); err.status = 404; next(err); }); app.use(function (err, req, res, next) { res.status(err.status || 500); res.render("error", { message: err.message }); }); module.exports = app;