/** * * (c) Copyright Ascensio System SIA 2025 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ using System; using System.IO; using System.Net; using System.Collections.Generic; using System.Web.Script.Serialization; using System.Web.Configuration; using System.Linq; using System.Web; using System.Text; using ASC.Api.DocumentConverter; namespace OnlineEditorsExample { public class TrackManager { // read request body public static Dictionary readBody(HttpContext context) { string body; try { // read request body by streams and check if it is correct using (var receiveStream = context.Request.InputStream) using (var readStream = new StreamReader(receiveStream)) { body = readStream.ReadToEnd(); if (string.IsNullOrEmpty(body)) context.Response.Write("{\"error\":1,\"message\":\"Request stream is empty\"}"); } } catch (Exception e) { throw new HttpException((int)HttpStatusCode.BadRequest, e.Message); } var jss = new JavaScriptSerializer(); var fileData = jss.Deserialize>(body); // check if the document token is enabled if (JwtManager.Enabled && JwtManager.SignatureUseForRequest) { string JWTheader = string.IsNullOrEmpty(WebConfigurationManager.AppSettings["files.docservice.header"]) ? "Authorization" : WebConfigurationManager.AppSettings["files.docservice.header"]; string token = null; // if the document token is in the data if (fileData.ContainsKey("token")) { token = JwtManager.Decode(fileData["token"].ToString()); // decode it } else if (context.Request.Headers.AllKeys.Contains(JWTheader, StringComparer.InvariantCultureIgnoreCase)) // if the Authorization header exists { var headerToken = context.Request.Headers.Get(JWTheader).Substring("Bearer ".Length); token = JwtManager.Decode(headerToken); // decode its part after Authorization prefix } else // otherwise, an error occurs { context.Response.Write("{\"error\":1,\"message\":\"JWT expected\"}"); } if (!string.IsNullOrEmpty(token)) // invalid signature error { fileData = jss.Deserialize>(token); if (fileData.ContainsKey("payload")) fileData = (Dictionary)fileData["payload"]; } else { context.Response.Write("{\"error\":1,\"message\":\"JWT validation failed\"}"); } } return fileData; } // file saving process public static int processSave(Dictionary fileData, string fileName, string userAddress) { if (fileData["url"].Equals(null)) { throw new Exception("DownloadUrl is null"); } var downloadUri = (string)fileData["url"]; var curExt = Path.GetExtension(fileName).ToLower(); // get current file extension var downloadExt = "." + (string)fileData["filetype"]; // get the extension of the downloaded file var newFileName = fileName; // convert downloaded file to the file with the current extension if these extensions aren't equal if (!downloadExt.Equals(curExt, StringComparison.InvariantCultureIgnoreCase)) { try { // convert file and give url to a new file Dictionary newFileData; ServiceConverter.GetConvertedData(downloadUri, downloadExt, curExt, ServiceConverter.GenerateRevisionId(downloadUri), false, out newFileData); var newFileUri = newFileData["fileUrl"]; if (string.IsNullOrEmpty(newFileUri)) { // get the correct file name if it already exists newFileName = _Default.GetCorrectName(Path.GetFileNameWithoutExtension(fileName) + downloadExt, userAddress); } else { downloadUri = newFileUri; } } catch (Exception) { newFileName = _Default.GetCorrectName(Path.GetFileNameWithoutExtension(fileName) + downloadExt, userAddress); } } _Default.VerifySSL(); try { var bytesFile = DownloadFile(downloadUri); // download document file var storagePath = _Default.StoragePath(newFileName, userAddress); // get the file path var histDir = _Default.HistoryDir(storagePath); // get the path to the history directory if (!Directory.Exists(histDir)) Directory.CreateDirectory(histDir); var versionDir = _Default.VersionDir(histDir, _Default.GetFileVersion(histDir)); // get the path to the file version if (!Directory.Exists(versionDir)) Directory.CreateDirectory(versionDir); // if the path doesn't exist, create it // get the path to the previous file version and rename the storage path with it File.Copy(_Default.StoragePath(fileName, userAddress), Path.Combine(versionDir, "prev" + curExt)); SaveFile(bytesFile, storagePath);// save document file var bytesChanges = DownloadFile((string)fileData["changesurl"]); // download changes file SaveFile(bytesChanges, Path.Combine(versionDir, "diff.zip")); // save file changes to the diff.zip archive var hist = fileData.ContainsKey("changeshistory") ? (string)fileData["changeshistory"] : null; if (string.IsNullOrEmpty(hist) && fileData.ContainsKey("history")) { var jss = new JavaScriptSerializer(); hist = jss.Serialize(fileData["history"]); } if (!string.IsNullOrEmpty(hist)) { File.WriteAllText(Path.Combine(versionDir, "changes.json"), hist); // write the history changes to the changes.json file } File.WriteAllText(Path.Combine(versionDir, "key.txt"), (string)fileData["key"]); // write the key value to the key.txt file string forcesavePath = _Default.ForcesavePath(newFileName, userAddress, false); // get the path to the forcesaved file version if (!string.IsNullOrEmpty(forcesavePath)) // if the forcesaved file version exists { File.Delete(forcesavePath); // remove it } } catch (Exception) { return 1; } return 0; } // file force saving process public static int processForceSave(Dictionary fileData, string fileName, string userAddress) { if (fileData["url"].Equals(null)) { throw new Exception("DownloadUrl is null"); } var downloadUri = (string)fileData["url"]; string curExt = Path.GetExtension(fileName).ToLower(); // get current file extension var downloadExt = "." + (string)fileData["filetype"]; // get the extension of the downloaded file Boolean newFileName = false; // convert downloaded file to the file with the current extension if these extensions aren't equal if (!curExt.Equals(downloadExt)) { try { // convert file and give url to a new file Dictionary newFileData; var result = ServiceConverter.GetConvertedData(downloadUri, downloadExt, curExt, ServiceConverter.GenerateRevisionId(downloadUri), false, out newFileData); var newFileUri = newFileData["fileUrl"]; if (string.IsNullOrEmpty(newFileUri)) { newFileName = true; } else { downloadUri = newFileUri; } } catch (Exception) { newFileName = true; } } _Default.VerifySSL(); try { var bytesFile = DownloadFile(downloadUri); // download document file string forcesavePath = ""; Boolean isSubmitForm = fileData["forcesavetype"].ToString().Equals("3"); // SubmitForm if (isSubmitForm) // if the form is submitted { if (newFileName) { fileName = _Default.GetCorrectName(Path.GetFileNameWithoutExtension(fileName) + "-form" + downloadExt, userAddress); // get the correct file name if it already exists } else { fileName = _Default.GetCorrectName(Path.GetFileNameWithoutExtension(fileName) + "-form" + curExt, userAddress); } forcesavePath = _Default.StoragePath(fileName, userAddress); } else { if (newFileName) { fileName = _Default.GetCorrectName(Path.GetFileNameWithoutExtension(fileName) + downloadExt, userAddress); } forcesavePath = _Default.ForcesavePath(fileName, userAddress, false); if (string.IsNullOrEmpty(forcesavePath)) // create forcesave path if it doesn't exist { forcesavePath = _Default.ForcesavePath(fileName, userAddress, true); } } SaveFile(bytesFile, forcesavePath);// save document file if (isSubmitForm) { var jss = new JavaScriptSerializer(); var actions = jss.Deserialize>(jss.Serialize(fileData["actions"])); var action = jss.Deserialize>(jss.Serialize(actions[0])); var user = action["userid"].ToString(); // get the user id DocEditor.CreateMeta(fileName, user, "Filling Form", userAddress); // create meta data for the forcesaved file string formsDataUrl = fileData["formsdataurl"].ToString(); if (!string.IsNullOrEmpty(formsDataUrl)) { string formsName = _Default.GetCorrectName(Path.GetFileNameWithoutExtension(fileName) + ".txt", userAddress); string formsPath = _Default.StoragePath(formsName, userAddress); var bytesForms = DownloadFile(formsDataUrl); SaveFile(bytesForms, formsPath); } else { throw new Exception("Document editing service did not return formsDataUrl"); } } } catch (Exception) { return 1; } return 0; } // create a command request public static Dictionary commandRequest(string method, string key, object meta = null) { _Default.VerifySSL(); string documentCommandUrl = WebConfigurationManager.AppSettings["files.docservice.url.site"] + WebConfigurationManager.AppSettings["files.docservice.url.command"]; var request = (HttpWebRequest)WebRequest.Create(documentCommandUrl); request.Method = "POST"; request.ContentType = "application/json"; var body = new Dictionary() { { "c", method }, { "key", key } }; if (meta != null) { body.Add("meta", meta); } // check if a secret key to generate token exists or not if (JwtManager.Enabled && JwtManager.SignatureUseForRequest) { var payload = new Dictionary { { "payload", body } }; var payloadToken = JwtManager.Encode(payload); // encode a payload object into a header token var bodyToken = JwtManager.Encode(body); // encode body into a body token string JWTheader = string.IsNullOrEmpty(WebConfigurationManager.AppSettings["files.docservice.header"]) ? "Authorization" : WebConfigurationManager.AppSettings["files.docservice.header"]; request.Headers.Add(JWTheader, "Bearer " + payloadToken); // add a header Authorization with a header token and Authorization prefix in it body.Add("token", bodyToken); } var bytes = Encoding.UTF8.GetBytes(new JavaScriptSerializer().Serialize(body)); request.ContentLength = bytes.Length; using (var requestStream = request.GetRequestStream()) { // write bytes to the output stream requestStream.Write(bytes, 0, bytes.Length); } string dataResponse; using (var response = request.GetResponse()) // get the response using (var stream = response.GetResponseStream()) { if (stream == null) throw new Exception("Response is null"); using (var reader = new StreamReader(stream)) { dataResponse = reader.ReadToEnd(); // and read it } } // convert stream to json string var jss = new JavaScriptSerializer(); var responseObj = jss.Deserialize>(dataResponse); if (!responseObj["error"].ToString().Equals("0")) { throw new Exception(dataResponse); } return responseObj; } private static void SaveFile(byte[] data, string path) { using (var fs = File.Open(path, FileMode.Create)) { fs.Write(data, 0, data.Length); } } // save file information from the url to the file specified private static byte[] DownloadFile(string url) { if (string.IsNullOrEmpty(url)) throw new ArgumentException("url"); // url isn't specified var req = (HttpWebRequest)WebRequest.Create(url); req.Timeout = 5000; using (var stream = req.GetResponse().GetResponseStream()) // get input stream of the file information from the url { if (stream == null) throw new Exception("stream is null"); using (MemoryStream memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); return memoryStream.ToArray(); } } } } }