/** * * (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.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text.RegularExpressions; using System.Web; using System.Web.Configuration; using System.Web.Script.Serialization; using System.Web.UI; using ASC.Api.DocumentConverter; namespace OnlineEditorsExample { public partial class _Default : Page { //get server version public static string GetVersion() { return WebConfigurationManager.AppSettings["version"]; } // get the virtual path public static string VirtualPath { get { return Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ? WebConfigurationManager.AppSettings["storage-path"] + "/" : HttpRuntime.AppDomainAppVirtualPath + (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/") + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(null) + "/"; } } private static bool? _ismono; public static bool IsMono { get { return _ismono.HasValue ? _ismono.Value : (_ismono = (bool?)(Type.GetType("Mono.Runtime") != null)).Value; } } // get maximum file size private static long MaxFileSize { get { long size; long.TryParse(WebConfigurationManager.AppSettings["filesize-max"], out size); return size > 0 ? size : 5*1024*1024; } } // get all the supported file extensions private static List FileExts { get { return ViewedExts.Concat(EditedExts).Concat(ConvertExts).Concat(FillFormsExts).ToList(); } } // file extensions that can be viewed private static List ViewedExts { get { return FormatManager.ViewableExtensions(); } } public static List FillFormsExts { get { return FormatManager.FillableExtensions(); } } // file extensions that can be edited public static List EditedExts { get { return FormatManager.EditableExtensions(); } } // file extensions that can be converted public static List ConvertExts { get { return FormatManager.ConvertibleExtensions(); } } private static string _fileName; // get current user host address public static string CurUserHostAddress(string userAddress) { return Regex.Replace(userAddress ?? HttpContext.Current.Request.UserHostAddress, "[^0-9a-zA-Z.=]", "_"); } // get the storage path of the given file public static string StoragePath(string fileName, string userAddress) { var directory = ""; if (Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"])) { directory = WebConfigurationManager.AppSettings["storage-path"] + "\\"; } else { directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\"; } if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); // if the file directory doesn't exist, make it } return directory + (fileName.Contains("\\") ? fileName : Path.GetFileName(fileName)); } // get the path to the history file version public static string HistoryPath(string fileName, string userAddress, string version, string file) { var directory = ""; if (Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"])) { directory = WebConfigurationManager.AppSettings["storage-path"] + "\\"; } else { directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\"; } var filepath = directory + Path.GetFileName(fileName) + "-hist" + "\\" + version + "\\" + file; return filepath; } // get the path to the forcesaved file version public static string ForcesavePath(string fileName, string userAddress, Boolean create) { var directory = ""; if (Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"])) { directory = WebConfigurationManager.AppSettings["storage-path"] + "\\"; } else { directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\"; } if (!Directory.Exists(directory)) // the directory with host address doesn't exist { return ""; } directory = directory + Path.GetFileName(fileName) + "-hist" + "\\"; // get the path to the history of the given file if (!Directory.Exists(directory)) { if (create) // create history directory if it doesn't exist { Directory.CreateDirectory(directory); } else // the history directory doesn't exist and we are not supposed to create it { return ""; } } directory = directory + Path.GetFileName(fileName); // get the path to the given file if (!File.Exists(directory)) { if (!create) { return ""; } } return directory; } // create the path to the file history public static string HistoryDir(string storagePath) { return storagePath += "-hist"; } // get the path to the specified file version by its history directory public static string VersionDir(string histPath, int version) { return Path.Combine(histPath, version.ToString()); } // get the path to the specified file version by the file name and the user address public static string VersionDir(string fileName, string userAddress, int version) { return VersionDir(HistoryDir(StoragePath(fileName, userAddress)), version); } // get the last file version by its history directory public static int GetFileVersion(string historyPath) { if (!Directory.Exists(historyPath)) return 1; return Directory.EnumerateDirectories(historyPath).Count() + 1; // run through all the file versions and count them } // get the last file version by the file name and the user address public static int GetFileVersion(string fileName, string userAddress) { return GetFileVersion(HistoryDir(StoragePath(fileName, userAddress))); } // get url to the original file public static string FileUri(string fileName, Boolean forDocumentServer) { var uri = new UriBuilder(GetServerUrl(forDocumentServer)); uri.Path = VirtualPath + fileName; // get full url address to the file return uri.ToString(); } // get server url public static string GetServerUrl(Boolean forDocumentServer) { if (forDocumentServer && !WebConfigurationManager.AppSettings["files.docservice.url.example"].Equals("")) { return WebConfigurationManager.AppSettings["files.docservice.url.example"]; } else { var uri = new UriBuilder(HttpContext.Current.Request.Url) { Query = "" }; var requestHost = HttpContext.Current.Request.Headers["Host"]; if (!string.IsNullOrEmpty(requestHost)) uri = new UriBuilder(uri.Scheme + "://" + requestHost); return uri.ToString(); } } // get the document type public static string DocumentType(string fileName) { var ext = Path.GetExtension(fileName).ToLower(); if (FormatManager.PdfExtensions().Contains(ext)) return "pdf"; // pdf for pdf extensions if (FormatManager.DocumentExtensions().Contains(ext)) return "word"; // word for text document extensions if (FormatManager.SpreadsheetExtensions().Contains(ext)) return "cell"; // cell for spreadsheet extensions if (FormatManager.PresentationExtensions().Contains(ext)) return "slide"; // slide for presentation extensions return "word"; // the default document type is word } protected string UrlPreloadScripts = WebConfigurationManager.AppSettings["files.docservice.url.site"] + WebConfigurationManager.AppSettings["files.docservice.url.preloader"]; protected void Page_Load(object sender, EventArgs e) { } // uploading a file by the HtthContext object public static string DoUpload(HttpContext context) { var httpPostedFile = context.Request.Files[0]; if (HttpContext.Current.Request.Browser.Browser.ToUpper() == "IE") // check from which browser the request came for { var files = httpPostedFile.FileName.Split(new char[] { '\\' }); _fileName = files[files.Length - 1]; // get file name } else { _fileName = httpPostedFile.FileName; } var curSize = httpPostedFile.ContentLength; if (MaxFileSize < curSize || curSize <= 0) // check if the file size exceeds the maximum file size { throw new Exception("File size is incorrect"); } var curExt = (Path.GetExtension(_fileName) ?? "").ToLower(); if (!FileExts.Contains(curExt)) // check if the file extension is supported by the editor { throw new Exception("File type is not supported"); } _fileName = GetCorrectName(_fileName); // get the correct file name if such a name already exists var savedFileName = StoragePath(_fileName, null); // get the storage path to the uploading file httpPostedFile.SaveAs(savedFileName); // and save it // get file meta information or create the default one var id = context.Request.Cookies.GetOrDefault("uid", null); var user = Users.getUser(id); // get the user DocEditor.CreateMeta(_fileName, user.id, user.name, null); return _fileName; } // uploading a file by the file url and the request public static string DoUpload(string fileUri, HttpRequest request) { _fileName = GetCorrectName(Path.GetFileName(fileUri)); // get the correct file name if such a name already exists var curExt = (Path.GetExtension(_fileName) ?? "").ToLower(); if (!FileExts.Contains(curExt)) // check if the file extension is supported by the editor { throw new Exception("File type is not supported"); } var req = (HttpWebRequest)WebRequest.Create(fileUri); try { VerifySSL(); using (var stream = req.GetResponse().GetResponseStream()) // get response stream of the uploading file { if (stream == null) throw new Exception("stream is null"); const int bufferSize = 4096; using (var fs = File.Open(StoragePath(_fileName, null), FileMode.Create)) { var buffer = new byte[bufferSize]; int readed; while ((readed = stream.Read(buffer, 0, bufferSize)) != 0) { fs.Write(buffer, 0, readed); // write bytes to the output stream } } } // get file meta information or create the default one var id = request.Cookies.GetOrDefault("uid", null); var user = Users.getUser(id); // get the user DocEditor.CreateMeta(_fileName, user.id, user.name, null); } catch (Exception) { } return _fileName; } public static string DoSaveAs(HttpContext context) { string fileData; try { using (var receiveStream = context.Request.InputStream) using (var readStream = new StreamReader(receiveStream)) { fileData = readStream.ReadToEnd(); if (string.IsNullOrEmpty(fileData)) return "{\"error\":\"Request stream is empty\"}"; } } catch (Exception e) { throw new HttpException((int)HttpStatusCode.BadRequest, e.Message); } var jss = new JavaScriptSerializer(); var body = jss.Deserialize>(fileData); var fileUrl = (string) body["url"]; var title = (string) body["title"]; var fileName = GetCorrectName(title); var extension = "." + (Path.GetExtension(fileName).ToLower() ?? "").Trim('.'); var allExt = ConvertExts.Concat(EditedExts).Concat(ViewedExts).Concat(FillFormsExts).ToArray(); if (!allExt.Contains(extension)) { return "{\"error\":\"File type is not supported\"}"; } var req = (HttpWebRequest)WebRequest.Create(fileUrl); VerifySSL(); using (var stream = req.GetResponse().GetResponseStream()) { if (stream == null || req.GetResponse().ContentLength <= 0 || req.GetResponse().ContentLength > MaxFileSize) { return "{\"error\": \"File size is incorrect\"}"; } const int bufferSize = 4096; using (var fs = File.Open(StoragePath(fileName, null), FileMode.Create)) { var buffer = new byte[bufferSize]; int readed; while ((readed = stream.Read(buffer, 0, bufferSize)) != 0) { fs.Write(buffer, 0, readed); // write bytes to the output stream } } } var id = context.Request.Cookies.GetOrDefault("uid", null); var user = Users.getUser(id); // get the user DocEditor.CreateMeta(fileName, user.id, user.name, null); return "{\"file\": \"" + fileName + "\"}"; } // converting a file public static string DoConvert(HttpContext context) { string fileData; try { using (var receiveStream = context.Request.InputStream) using (var readStream = new StreamReader(receiveStream)) { fileData = readStream.ReadToEnd(); if (string.IsNullOrEmpty(fileData)) 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 body = jss.Deserialize>(fileData); _fileName = Path.GetFileName(body["filename"].ToString()); var filePass = body["filePass"] != null ? body["filePass"].ToString() : null; var lang = context.Request.Cookies.GetOrDefault("ulang", null); var extension = (Path.GetExtension(_fileName).ToLower() ?? "").Trim('.'); string conversionExtension = "ooxml"; // set the default conversion extension as ooxml object fileExt; // change the conversion extension if it was provided in the request body if (body.TryGetValue("fileExt", out fileExt) && !String.IsNullOrEmpty(fileExt.ToString())) { conversionExtension = fileExt.ToString(); } object keepOriginal; bool removeOriginal = true; if (body.TryGetValue("keepOriginal", out keepOriginal) && !String.IsNullOrEmpty(keepOriginal.ToString())) { removeOriginal = keepOriginal.ToString().ToLower() != "true"; } // check if the file with such an extension can be converted if (ConvertExts.Contains("." + extension) || conversionExtension != "ooxml") { // generate document key var key = ServiceConverter.GenerateRevisionId(FileUri(_fileName, true)); var fileUrl = new UriBuilder(_Default.GetServerUrl(true)); fileUrl.Path = HttpRuntime.AppDomainAppVirtualPath + (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/") + "webeditor.ashx"; fileUrl.Query = "type=download&fileName=" + HttpUtility.UrlEncode(_fileName) + "&userAddress=" + HttpUtility.UrlEncode(CurUserHostAddress(HttpContext.Current.Request.UserHostAddress)); // get the url and file type of the converted file Dictionary newFileData; var result = ServiceConverter.GetConvertedData(fileUrl.ToString() , extension, conversionExtension, key, true, out newFileData, filePass, lang, _fileName); if (result != 100) { return "{ \"step\" : \"" + result + "\", \"filename\" : \"" + _fileName + "\"}"; } var newFileUri = newFileData["fileUrl"]; var newFileType = newFileData["fileType"]; if (!FormatManager.All().Any(f => f.Name == newFileType && f.Type != "")) { return "{\"step\": \"" + result + "\", \"filename\": \"" + newFileUri + "\", \"error\": \"FileTypeIsNotSupported\"}"; } // get a file name of an internal file extension with an index if the file with such a name already exists var fileName = GetCorrectName(Path.GetFileNameWithoutExtension(_fileName) + "." + newFileType); var req = (HttpWebRequest)WebRequest.Create(newFileUri); VerifySSL(); using (var stream = req.GetResponse().GetResponseStream()) // get response stream of the converting file { if (stream == null) throw new Exception("Stream is null"); const int bufferSize = 4096; using (var fs = File.Open(StoragePath(fileName, null), FileMode.Create)) { var buffer = new byte[bufferSize]; int readed; while ((readed = stream.Read(buffer, 0, bufferSize)) != 0) { fs.Write(buffer, 0, readed); // write bytes to the output stream } } } if (removeOriginal) { // remove the original file and its history if it exists var storagePath = StoragePath(_fileName, null); var histDir = HistoryDir(storagePath); File.Delete(storagePath); if (Directory.Exists(histDir)) Directory.Delete(histDir, true); } // create meta information about the converted file with user id and name specified _fileName = fileName; var id = context.Request.Cookies.GetOrDefault("uid", null); var user = Users.getUser(id); // get the user DocEditor.CreateMeta(_fileName, user.id, user.name, null); return "{\"step\": \"" + result + "\", \"filename\": \"" + _fileName + "\"}"; } return "{ \"filename\" : \"" + _fileName + "\"}"; } // get the correct file name if such a name already exists public static string GetCorrectName(string fileName, string userAddress = null) { int maxName; int.TryParse(WebConfigurationManager.AppSettings["filename-max"], out maxName); var baseName = Path.GetFileNameWithoutExtension(fileName); // get file name without extension if (baseName.Length > maxName){ baseName = baseName.Substring(0, maxName) + "[...]"; } var ext = Path.GetExtension(fileName).ToLower(); // get file extension var name = baseName + ext; // get full file name // if the file with such a name already exists in this directory for (var i = 1; File.Exists(StoragePath(name, userAddress)); i++) { name = baseName + " (" + i + ")" + ext; // add an index after its base name } return name; } // get all the stored files from the folder protected static List GetStoredFiles() { var directory = ""; if (Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"])) { directory = WebConfigurationManager.AppSettings["storage-path"] + "\\"; } else { directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(null) + "\\"; } if (!Directory.Exists(directory)) return new List(); var directoryInfo = new DirectoryInfo(directory); // read the user host directory contents // get the list of stored files from the host directory var storedFiles = directoryInfo.GetFiles("*.*", SearchOption.TopDirectoryOnly).ToList(); storedFiles.Sort((a, b) => b.LastWriteTimeUtc.CompareTo(a.LastWriteTimeUtc)); // sort files by the modification date return storedFiles; } // get files information public static List> GetFilesInfo(string fileId = null) { var files = new List>(); // run through all the files from the directory foreach (var file in GetStoredFiles()) { // write file parameters to the file object var dictionary = new Dictionary(); dictionary.Add("version", GetFileVersion(file.Name, null)); dictionary.Add("id", ServiceConverter.GenerateRevisionId(_Default.CurUserHostAddress(null) + "/" + file.Name + "/" + File.GetLastWriteTime(_Default.StoragePath(file.Name, null)).GetHashCode())); dictionary.Add("contentLength", Math.Round(file.Length / 1024.0, 2) + " KB"); dictionary.Add("pureContentLength", file.Length); dictionary.Add("title", file.Name); dictionary.Add("updated", file.LastWriteTime.ToString()); if (fileId != null) { // if file id is defined and it is equal to the document key value if (fileId.Equals(dictionary["id"])) { files.Add(dictionary); // add file object to the files break; } } else { files.Add(dictionary); } } return files; } // enable certificate ignore public static void VerifySSL() { // hack. http://ubuntuforums.org/showthread.php?t=1841740 if(WebConfigurationManager.AppSettings["files.docservice.verify-peer-off"].Equals("true")) { ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; } } public static Dictionary GetLanguages() { var languages = new Dictionary(); String[] couples = (WebConfigurationManager.AppSettings["files.docservice.languages"] ?? "").Split('|'); foreach (string couple in couples) { String[] tmp = couple.Split(':'); languages.Add(tmp[0],tmp[1]); } return languages; } public static string GetDirectUrlParam() { string isEnabledDirectUrl = HttpUtility.ParseQueryString(HttpContext.Current.Request.Url.Query).Get("directUrl"); return "&directUrl=" + (isEnabledDirectUrl != null ? isEnabledDirectUrl : "false"); } // get direct url flag public static bool IsEnabledDirectUrl() { string isEnabledDirectUrl = HttpUtility.ParseQueryString(HttpContext.Current.Request.Url.Query).Get("directUrl"); return isEnabledDirectUrl != null ? Convert.ToBoolean(isEnabledDirectUrl) : false; } } }