Compare commits

..

7 Commits

Author SHA1 Message Date
4be81ac373 nodejs: message to editor when saving a copy 2021-11-09 14:48:14 +03:00
1b91eca26e nodejs: docxf 2021-11-09 10:52:37 +03:00
e026beb5b6 nodejs: filling on mobile 2021-11-08 17:00:16 +03:00
ee5874e86c nodejs: revert filling in docx 2021-11-08 17:00:16 +03:00
7c7c32e9e7 nodejs: hide submit button 2021-11-08 17:00:15 +03:00
1cbd2ffd61 nodejs: oform 2021-11-08 17:00:15 +03:00
30baa26cd8 nodejs: onRequestSaveAs event 2021-11-08 17:00:14 +03:00
248 changed files with 2931 additions and 12224 deletions

View File

@ -1,31 +0,0 @@
name: Lint Java
on:
workflow_dispatch:
push:
branches: [master, main]
paths: ['web/documentserver-example/java/**']
pull_request:
branches: [master, main, develop]
paths: ['web/documentserver-example/java/**']
jobs:
lint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./web/documentserver-example/java
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Install Java 11
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '11'
- name: Run linter
run: |
mvn -version
mvn package

View File

@ -1,35 +0,0 @@
name: ESLint
on:
workflow_dispatch:
push:
branches: [master, main]
paths: ['web/documentserver-example/nodejs/**']
pull_request:
branches: [master, main, develop]
paths: ['web/documentserver-example/nodejs/**']
env:
NODE_VERSION: 16
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./web/documentserver-example/nodejs
steps:
- name: Install NodeJS
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
- name: Code Checkout
uses: actions/checkout@v3
- name: Install Dependencies
run: npm ci
- name: Code Linting
run: npm run lint

View File

@ -1,29 +0,0 @@
name: PHPCs
on:
workflow_dispatch:
push:
branches: [master, main]
paths: ['web/documentserver-example/php/**']
pull_request:
branches: [master, main, develop]
paths: ['web/documentserver-example/php/**']
jobs:
lint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./web/documentserver-example/php
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
tools: cs2pr, phpcs
- name: Run phpcs
run: phpcs -q --extensions=php,module,inc,install,test,profile,theme,css,info,txt,md,yml --ignore=node_modules,bower_components,vendor ./

View File

@ -1,40 +0,0 @@
name: PyLint
on:
workflow_dispatch:
push:
branches: [master, main]
paths: ['web/documentserver-example/python/**']
pull_request:
branches: [master, main, develop]
paths: ['web/documentserver-example/python/**']
jobs:
lint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./web/documentserver-example/python
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install flake8
pip install pylint
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint Flake8
run: |
flake8 ./**/*.py --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 ./**/*.py --count --max-complexity=10 --max-line-length=79 --statistics
- name: Lint Pylint
run: |
pylint ./**/*.py

View File

@ -1,31 +0,0 @@
name: Rubocop
on:
workflow_dispatch:
push:
branches: [master, main]
paths: ['web/documentserver-example/ruby/**']
pull_request:
branches: [master, main, develop]
paths: ['web/documentserver-example/ruby/**']
jobs:
lint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./web/documentserver-example/ruby
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.0'
bundler-cache: true
- name: Install dependencies
run: |
bundle install
- name: Rubocop
run: |
gem install rubocop
rubocop

View File

@ -1,31 +0,0 @@
name: Lint Spring
on:
workflow_dispatch:
push:
branches: [master, main]
paths: ['web/documentserver-example/java-spring/**']
pull_request:
branches: [master, main, develop]
paths: ['web/documentserver-example/java-spring/**']
jobs:
lint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./web/documentserver-example/java-spring
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Install Java 11
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '11'
- name: Run linter
run: |
mvn -version
mvn package

View File

@ -1,39 +0,0 @@
# Change Log
## 1.4.0
- nodejs: option to send directUrl
- opening file on client by directUrl
- offline viewer for anonymous
- added hy, eu, zh-TW, ms, pt-PT
## 1.3.1
- charp: fix references
- ruby: update rails
## 1.3.0
- update empty files
- anonymous without chat
- changed jwt implementation in csharp, csharp-mvc, php, ruby
## 1.2.0
- ruby v3.0
- set filetype in setHistoryData
- read filetype from input request
- creating file on WOPI
- upload on WOPI page
- fix xss
- set userInfoGroups
- check JWT on downloading history
- upload dialog on mobile
- anonymous without id
- renaming from editor
- new skin languages
- ignore certificate
## 1.1.0
- creating docxf
- opening docxf, oform
## 1.0.0
- added java spring

View File

@ -1,11 +1,10 @@
## Integration examples
Test examples are simple document management systems that can be built into your application for testing.
Do NOT use these integration examples on your own server without proper code modifications!
In case you enabled any of the test examples, disable it before going for production.
Test examples are simple document management systems that can be built into your
application for testing (please, do not use it for production without proper code
modifications).
These examples show the way to integrate [ONLYOFFICE Docs][2] into your own website or application using one of the programming languages.
The package contains examples written in .Net (C# MVC), .Net (C#), Java, Node.js, PHP and Ruby.
These examples show the way to integrate [ONLYOFFICE Docs][2] into your own website or application using one of the programming languages. The package contains examples written in .Net (C# MVC), .Net (C#), Java, Node.js, PHP and Ruby.
You should change `http://documentserver` to your server address in these files:
* [.Net (C# MVC)](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/csharp-mvc) - `web/documentserver-example/csharp-mvc/web.appsettings.config`
@ -67,15 +66,6 @@ The methods described below are available for all of the test examples.
| **Response** | **Code:** 200 OK <br />**Content on success:**<br /> `[{ "version": <file_version>, "id": <file_id>, "contentLength": <file_size_in_kilobytes>, "pureContentLength": <file_size_in_bytes>, "title": <file_name>, "updated": <last_change_date>}]`<br />**Content on error:**<br /> `"File not found"` |
| **Sample** | `curl -X GET http://localhost/files/{fileId}` |
## Important security info
Please keep in mind the following security aspects when you are using test examples:
* There is no protection of the storage from unauthorized access since there is no need for authorization.
* There are no checks against parameter substitution in links, since the parameters are generated by the code according to the pre-arranged scripts.
* There are no data checks in requests of saving the file after editing, since each test example is intended for requests only from ONLYOFFICE Document Server.
* There are no prohibitions on using test examples from other sites, since they are intended to interact with ONLYOFFICE Document Server from another domain.
## Project Information
Official website: [https://www.onlyoffice.com](https://www.onlyoffice.com/?utm_source=github&utm_medium=cpc&utm_campaign=GitHubIntegrationEx)

View File

@ -24,15 +24,11 @@ jQuery.UI - jQuery UI is an open source library of interface components —
License: MIT
License File: jQuery.UI.license
JWT - JWT (JSON Web Token) Implementation for .NET (Public Domain) (https://github.com/jwt-dotnet/jwt/)
License: MIT
License File: JWT.license
Microsoft.Web.Infrastructure - This package contains the Microsoft.Web.Infrastructure assembly that lets you dynamically register HTTP modules at run time. (https://www.microsoft.com/web/webpi/eula/aspnetmvc3update-eula.htm)
License: MS-EULA License
License File: Microsoft.Web.Infrastructure.license
Newtonsoft.Json - Json.NET is a popular high-performance JSON framework for .NET (https://github.com/JamesNK/Newtonsoft.Json)
Newtonsoft.Json - Json.NET is a popular high-performance JSON framework for .NET (https://licenses.nuget.org/MIT)
License: MIT
License File: Newtonsoft.Json.license

View File

@ -1,6 +0,0 @@
<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 3C0 1.34315 1.34315 0 3 0H22.9167L30 7.08333V37C30 38.6569 28.6569 40 27 40H3C1.34315 40 0 38.6569 0 37V3Z" fill="#27ABA3"/>
<path d="M22.9165 0L29.9998 7.08333H25.9165C24.2597 7.08333 22.9165 5.74019 22.9165 4.08333V0Z" fill="#008078"/>
<rect x="6.5" y="15.5" width="17" height="5" stroke="white"/>
<rect x="6.5" y="23.5" width="17" height="5" stroke="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 477 B

View File

@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 5C5 3.89543 5.89543 3 7 3H16C17.1046 3 18 3.89543 18 5V8H17V6H6V18H17V16H18V19C18 20.1046 17.1046 21 16 21H7C5.89543 21 5 20.1046 5 19V5ZM13 4H10V5H13V4ZM12 19.5C12 19.7761 11.7761 20 11.5 20C11.2239 20 11 19.7761 11 19.5C11 19.2239 11.2239 19 11.5 19C11.7761 19 12 19.2239 12 19.5Z" fill="#444444"/>
<rect x="7" y="9" width="1" height="6" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 8V9L11 9V15H12V16H9V15H10V9H9V8H12Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 10H18V14H15H14H13V15H14H18C18.5523 15 19 14.5523 19 14V10C19 9.44772 18.5523 9 18 9H14H13V10H14H15Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 790 B

View File

@ -87,6 +87,10 @@
}
@media (max-width: 1008px) {
#portal-info {
width: 65vw;
}
.left-panel {
margin-left: 0;
}
@ -124,10 +128,6 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.main-panel {
left: 0;
padding: 48px 18px 24px;
@ -312,9 +312,6 @@
.tableRow td:first-child {
max-width: 17%;
}
#portal-info {
max-width: 60vw;
}
}
.downloadContentCellShift:after {
@ -366,10 +363,6 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.copy {
width: 100%;
text-align: center;
@ -443,58 +436,6 @@
display: none;
width: 1%;
}
/* Mobile Upload*/
.blockUI.blockMsg.blockPage.ui-dialog.ui-widget.ui-corner-all.ui-widget-content.ui-draggable {
width: 344px !important;
box-shadow: 0px 7px 15px rgba(85, 85, 85, 0.1);
border-radius: 2px;
top: 10% !important;
margin-left: -172px !important;
}
.ui-dialog .ui-dialog-titlebar {
padding: 0;
}
.ui-dialog .ui-dialog-content {
padding: 0 !important;
}
#mainProgress {
margin: 24px 16px 0 !important;
}
.blockTitle {
padding: 10px 10px 6px 16px !important;
font-size: 14px !important;
}
#mainProgress .describeUpload {
padding: 8px 0 !important;
}
.dialog-close {
margin: 0 !important;
}
.step-descr{
line-height: 150%;
}
.step {
line-height: 160%;
}
.buttonsMobile{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.button.gray{
margin: 0;
}
.button, .button:hover{
display: flex;
justify-content: center;
padding: 0 !important;
width: 144px;
height: 56px;
margin-bottom: 24px !important;
}
}
@media (max-width: 560px) and (min-width: 510px) {

View File

@ -22,7 +22,6 @@
}
body {
display: block;
background: #FFFFFF;
color: #333333;
font-family: Open Sans;
@ -72,7 +71,6 @@ header img {
}
.main {
display: table;
height: calc(100% - 112px);
min-height: 536px;
}
@ -99,10 +97,6 @@ header img {
width: 896px;
}
#portal-info {
max-width: 65vw;
}
.portal-name {
color: #FF6F3D;
font-size: 24px;
@ -163,10 +157,6 @@ label .checkbox {
background-image: url("images/file_pptx.svg");
}
.try-editor.form {
background-image: url("images/file_docxf.svg");
}
.create-sample {
color: #666666;
line-height: 24px;
@ -734,9 +724,12 @@ html {
width: 30vw;
min-width: 200px;
max-width: 400px;
margin-top: 20px;
}
.user-descr > b {
margin-left: 25px;
}
.portal-descr:nth-child(3) {
margin-bottom: 20px;
}

View File

@ -25,7 +25,6 @@ using System.Web;
using System.Web.Configuration;
using System.Web.Script.Serialization;
using OnlineEditorsExampleMVC.Models;
using System.Net;
namespace OnlineEditorsExampleMVC.Helpers
{
@ -45,7 +44,7 @@ namespace OnlineEditorsExampleMVC.Helpers
// get all the supported file extensions
public static List<string> FileExts
{
get { return ViewedExts.Concat(EditedExts).Concat(ConvertExts).Concat(FillFormExts).ToList(); }
get { return ViewedExts.Concat(EditedExts).Concat(ConvertExts).ToList(); }
}
// get file extensions that can be viewed
@ -54,11 +53,6 @@ namespace OnlineEditorsExampleMVC.Helpers
get { return (WebConfigurationManager.AppSettings["files.docservice.viewed-docs"] ?? "").Split(new char[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); }
}
public static List<string> FillFormExts
{
get { return (WebConfigurationManager.AppSettings["files.docservice.fillform-docs"] ?? "").Split(new char[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); }
}
// get file extensions that can be edited
public static List<string> EditedExts
{
@ -80,37 +74,19 @@ namespace OnlineEditorsExampleMVC.Helpers
// get the storage path of the file
public static string StoragePath(string fileName, string userAddress = null)
{
var directory = "";
if (!string.IsNullOrEmpty(WebConfigurationManager.AppSettings["storage-path"]) && Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]))
{
directory = WebConfigurationManager.AppSettings["storage-path"] + "\\";
}
else
{
directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\";
}
var directory = HttpRuntime.AppDomainAppPath + CurUserHostAddress(userAddress) + "\\";
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
return directory + (fileName.Contains("\\") ? fileName : Path.GetFileName(fileName));
return directory + Path.GetFileName(fileName);
}
// get the path to the forcesaved file version
public static string ForcesavePath(string fileName, string userAddress, Boolean create)
{
// create the directory to this file version
var directory = "";
if (!string.IsNullOrEmpty(WebConfigurationManager.AppSettings["storage-path"]) && Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]))
{
directory = WebConfigurationManager.AppSettings["storage-path"] + "\\";
}
else
{
directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\";
}
var directory = HttpRuntime.AppDomainAppPath + CurUserHostAddress(userAddress) + "\\";
if (!Directory.Exists(directory))
{
return "";
@ -191,16 +167,7 @@ namespace OnlineEditorsExampleMVC.Helpers
// get all the stored files from the user host address
public static List<FileInfo> GetStoredFiles()
{
var directory = "";
if (!string.IsNullOrEmpty(WebConfigurationManager.AppSettings["storage-path"]) && Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]))
{
directory = WebConfigurationManager.AppSettings["storage-path"] + "\\";
}
else
{
directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(null) + "\\";
}
var directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(null) + "\\";
if (!Directory.Exists(directory)) return new List<FileInfo>();
var directoryInfo = new DirectoryInfo(directory);
@ -242,8 +209,7 @@ namespace OnlineEditorsExampleMVC.Helpers
{
var uri = new UriBuilder(GetServerUrl(forDocumentServer))
{
Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
Path = HttpRuntime.AppDomainAppVirtualPath + "/"
+ CurUserHostAddress() + "/"
+ fileName,
Query = ""
@ -257,7 +223,8 @@ namespace OnlineEditorsExampleMVC.Helpers
{
var uri = new UriBuilder(GetServerUrl(true))
{
Path = HttpRuntime.AppDomainAppVirtualPath + "/" + path,
Path = HttpRuntime.AppDomainAppVirtualPath + "/"
+ path,
Query = ""
};
@ -293,7 +260,7 @@ namespace OnlineEditorsExampleMVC.Helpers
+ "webeditor.ashx",
Query = "type=track"
+ "&fileName=" + HttpUtility.UrlEncode(fileName)
+ "&userAddress=" + HttpUtility.UrlEncode(CurUserHostAddress(HttpContext.Current.Request.UserHostAddress))
+ "&userAddress=" + HttpUtility.UrlEncode(HttpContext.Current.Request.UserHostAddress)
};
return callbackUrl.ToString();
}
@ -312,30 +279,10 @@ namespace OnlineEditorsExampleMVC.Helpers
return createUrl.ToString();
}
// create the public history url
public static string GetHistoryDownloadUrl(string filename, string version, string file, Boolean isServer = true)
{
var userAddress = "&userAddress=" + HttpUtility.UrlEncode(CurUserHostAddress(HttpContext.Current.Request.UserHostAddress));
var downloadUrl = new UriBuilder(GetServerUrl(isServer))
{
Path =
HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "webeditor.ashx",
Query = "type=downloadhistory"
+ "&fileName=" + HttpUtility.UrlEncode(filename)
+ userAddress
+ "&ver=" + version
+ "&file="+ file
};
return downloadUrl.ToString();
}
// get url to download a file
public static string GetDownloadUrl(string fileName, Boolean isServer = true)
public static string GetDownloadUrl(string fileName)
{
var userAddress = isServer ? "&userAddress=" + HttpUtility.UrlEncode(CurUserHostAddress(HttpContext.Current.Request.UserHostAddress)) : "";
var downloadUrl = new UriBuilder(GetServerUrl(isServer))
var downloadUrl = new UriBuilder(GetServerUrl(true))
{
Path =
HttpRuntime.AppDomainAppVirtualPath
@ -343,7 +290,7 @@ namespace OnlineEditorsExampleMVC.Helpers
+ "webeditor.ashx",
Query = "type=download"
+ "&fileName=" + HttpUtility.UrlEncode(fileName)
+ userAddress
+ "&userAddress=" + HttpUtility.UrlEncode(HttpContext.Current.Request.UserHostAddress)
};
return downloadUrl.ToString();
}
@ -420,27 +367,5 @@ namespace OnlineEditorsExampleMVC.Helpers
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<string, string> GetLanguages()
{
var languages = new Dictionary<string, string>();
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;
}
}
}

View File

@ -143,8 +143,6 @@ namespace OnlineEditorsExampleMVC.Helpers
requestStream.Write(bytes, 0, bytes.Length); // and write the serialized body object to it
}
DocManagerHelper.VerifySSL();
string dataResponse;
using (var response = request.GetResponse())
using (var stream = response.GetResponseStream()) // get the response stream

View File

@ -16,12 +16,12 @@
*
*/
using JWT;
using JWT.Algorithms;
using JWT.Builder;
using JWT.Serializers;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Web.Configuration;
using System.Web.Script.Serialization;
namespace OnlineEditorsExampleMVC.Helpers
{
@ -30,19 +30,31 @@ namespace OnlineEditorsExampleMVC.Helpers
private static readonly string Secret;
public static readonly bool Enabled;
private static readonly JavaScriptSerializer Serializer;
static JwtManager()
{
Secret = WebConfigurationManager.AppSettings["files.docservice.secret"] ?? ""; // get token secret from the config parameters
Enabled = !string.IsNullOrEmpty(Secret); // check if the token is enabled
Serializer = new JavaScriptSerializer(); // define java script serializer
}
// encode a payload object into a token using a secret key
public static string Encode(IDictionary<string, object> payload)
{
var encoder = new JwtEncoder(new HMACSHA256Algorithm(),
new JsonNetSerializer(),
new JwtBase64UrlEncoder());
return encoder.Encode(payload, Secret);
// define the hashing algorithm and the token type
var header = new Dictionary<string, object>
{
{ "alg", "HS256" },
{ "typ", "JWT" }
};
// three parts of token
var encHeader = Base64UrlEncode(Serializer.Serialize(header)); // header
var encPayload = Base64UrlEncode(Serializer.Serialize(payload)); // payload
var hashSum = Base64UrlEncode(CalculateHash(encHeader, encPayload)); // signature
return string.Format("{0}.{1}.{2}", encHeader, encPayload, hashSum);
}
// decode a token into a payload object using a secret key
@ -50,11 +62,52 @@ namespace OnlineEditorsExampleMVC.Helpers
{
if (!Enabled || string.IsNullOrEmpty(token)) return "";
return JwtBuilder.Create()
.WithAlgorithm(new HMACSHA256Algorithm())
.WithSecret(Secret)
.MustVerifySignature()
.Decode(token);
var split = token.Split('.');
if (split.Length != 3) return "";
var hashSum = Base64UrlEncode(CalculateHash(split[0], split[1])); // get signature
if (hashSum != split[2]) return ""; // and check if it is equal to the signature from the token
return Base64UrlDecode(split[1]); // decode payload
}
// generate a hash code based on a key using the HMAC method
private static byte[] CalculateHash(string encHeader, string encPayload)
{
using (var hasher = new HMACSHA256(Encoding.UTF8.GetBytes(Secret)))
{
var bytes = Encoding.UTF8.GetBytes(string.Format("{0}.{1}", encHeader, encPayload));
return hasher.ComputeHash(bytes);
}
}
// encode a string into the base64 value
private static string Base64UrlEncode(string str)
{
return Base64UrlEncode(Encoding.UTF8.GetBytes(str));
}
// encode bytes into the base64 value
private static string Base64UrlEncode(byte[] bytes)
{
return Convert.ToBase64String(bytes)
.TrimEnd('=').Replace('+', '-').Replace('/', '_');
}
// decode a base64 value into the string
private static string Base64UrlDecode(string payload)
{
var b64 = payload.Replace('_', '/').Replace('-', '+');
switch (b64.Length%4)
{
case 2:
b64 += "==";
break;
case 3:
b64 += "=";
break;
}
var bytes = Convert.FromBase64String(b64);
return Encoding.UTF8.GetString(bytes);
}
}
}

View File

@ -76,9 +76,7 @@ namespace OnlineEditorsExampleMVC.Helpers
if (token != null && !token.Equals("")) // invalid signature error
{
fileData = jss.Deserialize<Dictionary<string, object>>(token);
if (fileData.ContainsKey("payload"))
fileData = (Dictionary<string, object>)fileData["payload"];
fileData = (Dictionary<string, object>)jss.Deserialize<Dictionary<string, object>>(token)["payload"];
}
else
{
@ -97,11 +95,7 @@ namespace OnlineEditorsExampleMVC.Helpers
}
var downloadUri = (string)fileData["url"];
string curExt = Path.GetExtension(fileName).ToLower(); // get current file extension
var downloadExt = fileData.ContainsKey("filetype")
? "." + (string)fileData["filetype"]
: Path.GetExtension(downloadUri).ToLower() ?? ""; // TODO: Delete in version 7.0 or higher. Support for versions below 7.0
string downloadExt = Path.GetExtension(downloadUri).ToLower() ?? ""; // 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
@ -128,8 +122,6 @@ namespace OnlineEditorsExampleMVC.Helpers
}
}
DocManagerHelper.VerifySSL();
var storagePath = DocManagerHelper.StoragePath(newFileName, userAddress); // get the file path
var histDir = DocManagerHelper.HistoryDir(storagePath); // get the path to the history directory
if (!Directory.Exists(histDir)) Directory.CreateDirectory(histDir);
@ -175,11 +167,7 @@ namespace OnlineEditorsExampleMVC.Helpers
var downloadUri = (string)fileData["url"];
string curExt = Path.GetExtension(fileName).ToLower(); // get current file extension
var downloadExt = fileData.ContainsKey("filetype")
? "." + (string)fileData["filetype"]
: Path.GetExtension(downloadUri).ToLower(); // TODO: Delete in version 7.0 or higher. Support for versions below 7.0
string downloadExt = Path.GetExtension(downloadUri).ToLower(); // 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
@ -205,8 +193,6 @@ namespace OnlineEditorsExampleMVC.Helpers
}
}
DocManagerHelper.VerifySSL();
string forcesavePath = "";
Boolean isSubmitForm = fileData["forcesavetype"].ToString().Equals("3"); // SubmitForm
@ -249,10 +235,8 @@ namespace OnlineEditorsExampleMVC.Helpers
}
// create a command request
public static void commandRequest(string method, string key, object meta = null)
public static void commandRequest(string method, string key)
{
DocManagerHelper.VerifySSL();
string documentCommandUrl = WebConfigurationManager.AppSettings["files.docservice.url.site"] + WebConfigurationManager.AppSettings["files.docservice.url.command"];
var request = (HttpWebRequest)WebRequest.Create(documentCommandUrl);
@ -264,11 +248,6 @@ namespace OnlineEditorsExampleMVC.Helpers
{ "key", key }
};
if (meta != null)
{
body.Add("meta", meta);
}
// check if a secret key to generate token exists or not
if (JwtManager.Enabled)
{

View File

@ -30,8 +30,7 @@ namespace OnlineEditorsExampleMVC.Helpers
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can create files from templates using data from the editor",
"Can see the information about all users"
"Can create files from templates using data from the editor"
};
static List<string> descr_user_2 = new List<string>()
@ -40,8 +39,7 @@ namespace OnlineEditorsExampleMVC.Helpers
"Can review only his own changes or changes made by users with no group",
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
"This file is marked as favorite",
"Can create new files from the editor",
"Can see the information about users from Group2 and users who dont belong to any group"
"Can create new files from the editor"
};
static List<string> descr_user_3 = new List<string>()
@ -53,8 +51,7 @@ namespace OnlineEditorsExampleMVC.Helpers
"Cant copy data from the file to clipboard",
"Cant download the file",
"Cant print the file",
"Can create new files from the editor",
"Can see the information about Group2 users"
"Can create new files from the editor"
};
static List<string> descr_user_0 = new List<string>()
@ -65,11 +62,7 @@ namespace OnlineEditorsExampleMVC.Helpers
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor",
"Cant see anyones information",
"Can't rename files from the editor",
"Can't view chat",
"View file without collaboration",
"Can't create new files from the editor"
};
private static List<User> users = new List<User>() {
@ -77,11 +70,10 @@ namespace OnlineEditorsExampleMVC.Helpers
"uid-1",
"John Smith",
"smith@example.com",
"",
null,
null,
new Dictionary<string, object>(),
null,
null,
new List<string>(),
descr_user_1,
true
@ -98,7 +90,6 @@ namespace OnlineEditorsExampleMVC.Helpers
{ "edit", new List<string>() { "group-2", "" } },
{ "remove", new List<string>() { "group-2" } }
},
new List<string>() { "group-2", "" },
true,
new List<string>(),
descr_user_2,
@ -116,7 +107,6 @@ namespace OnlineEditorsExampleMVC.Helpers
{ "edit", new List<string>() { "group-2" } },
{ "remove", new List<string>() { } }
},
new List<string>() { "group-2" },
false,
new List<string>() { "copy", "download", "print" },
descr_user_3,
@ -126,10 +116,9 @@ namespace OnlineEditorsExampleMVC.Helpers
"uid-0",
null,
null,
"",
null,
null,
new Dictionary<string,object>(),
new List<string>(),
null,
new List<string>(),
descr_user_0,
@ -184,9 +173,8 @@ namespace OnlineEditorsExampleMVC.Helpers
public List<string> deniedPermissions;
public List<string> descriptions;
public bool templates;
public List<string> userInfoGroups;
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates)
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates)
{
this.id = id;
this.name = name;
@ -198,7 +186,6 @@ namespace OnlineEditorsExampleMVC.Helpers
this.deniedPermissions = deniedPermissions;
this.descriptions = descriptions;
this.templates = templates;
this.userInfoGroups = userInfoGroups;
}
}
}

View File

@ -21,7 +21,6 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.Configuration;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using OnlineEditorsExampleMVC.Helpers;
@ -43,7 +42,7 @@ namespace OnlineEditorsExampleMVC.Models
// get file url for user
public string FileUriUser
{
get { return Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ? DownloadUrl + "&dmode=emb" : DocManagerHelper.GetFileUri(FileName, false); }
get { return DocManagerHelper.GetFileUri(FileName, false); }
}
public string FileName { get; set; } // file name
@ -80,16 +79,11 @@ namespace OnlineEditorsExampleMVC.Models
var editorsMode = Mode ?? "edit"; // get editor mode
var canEdit = DocManagerHelper.EditedExts.Contains(ext); // check if the file with such an extension can be edited
var mode = canEdit && editorsMode != "view" ? "edit" : "view"; // set the mode parameter: change it to view if the document can't be edited
var submitForm = canEdit && (editorsMode.Equals("edit") || editorsMode.Equals("fillForms")); // check if the Submit form button is displayed or not
var id = request.Cookies.GetOrDefault("uid", null);
var user = Users.getUser(id); // get the user
if ((!canEdit && editorsMode.Equals("edit") || editorsMode.Equals("fillForms")) && DocManagerHelper.FillFormExts.Contains(ext)) {
editorsMode = "fillForms";
canEdit = true;
}
var submitForm = editorsMode.Equals("fillForms") && id.Equals("uid-1") && false; // check if the Submit form button is displayed or not
var mode = canEdit && editorsMode != "view" ? "edit" : "view"; // set the mode parameter: change it to view if the document can't be edited
// favorite icon state
bool? favorite = user.favorite;
@ -97,7 +91,6 @@ namespace OnlineEditorsExampleMVC.Models
var actionLink = request.GetOrDefault("actionLink", null); // get the action link (comment or bookmark) if it exists
var actionData = string.IsNullOrEmpty(actionLink) ? null : jss.DeserializeObject(actionLink); // get action data for the action link
var directUrl = DocManagerHelper.GetDownloadUrl(FileName, false);
var createUrl = DocManagerHelper.GetCreateUrl(FileUtility.GetFileType(FileName));
var templatesImageUrl = DocManagerHelper.GetTemplateImageUrl(FileUtility.GetFileType(FileName)); // image url for templates
var templates = new List<Dictionary<string, string>>
@ -126,7 +119,6 @@ namespace OnlineEditorsExampleMVC.Models
{
{ "title", FileName },
{ "url", DownloadUrl },
{ "directUrl", directUrl },
{ "fileType", ext.Trim('.') },
{ "key", Key },
{
@ -150,10 +142,8 @@ namespace OnlineEditorsExampleMVC.Models
{ "modifyFilter", editorsMode != "filter" },
{ "modifyContentControl", editorsMode != "blockcontent" },
{ "review", canEdit && (editorsMode == "edit" || editorsMode == "review") },
{ "chat", !user.id.Equals("uid-0") },
{ "reviewGroups", user.reviewGroups },
{ "commentGroups", user.commentGroups },
{ "userInfoGroups", user.userInfoGroups }
{ "commentGroups", user.commentGroups }
}
}
}
@ -165,18 +155,13 @@ namespace OnlineEditorsExampleMVC.Models
{ "mode", mode },
{ "lang", request.Cookies.GetOrDefault("ulang", "en") },
{ "callbackUrl", CallbackUrl }, // absolute URL to the document storage service
{ "coEditing", editorsMode == "view" && user.id.Equals("uid-0") ?
new Dictionary<string, object>{
{"mode", "strict"},
{"change", false}
} : null },
{ "createUrl", !user.id.Equals("uid-0") ? createUrl : null },
{ "templates", user.templates ? templates : null },
{
// the user currently viewing or editing the document
"user", new Dictionary<string, object>
{
{ "id", !user.id.Equals("uid-0") ? user.id : null },
{ "id", user.id },
{ "name", user.name },
{ "group", user.group }
}
@ -185,9 +170,9 @@ namespace OnlineEditorsExampleMVC.Models
// the parameters for the embedded document type
"embedded", new Dictionary<string, object>
{
{ "saveUrl", directUrl }, // the absolute URL that will allow the document to be saved onto the user personal computer
{ "embedUrl", directUrl }, // the absolute URL to the document serving as a source file for the document embedded into the web page
{ "shareUrl", directUrl }, // the absolute URL that will allow other users to share this document
{ "saveUrl", FileUriUser }, // the absolute URL that will allow the document to be saved onto the user personal computer
{ "embedUrl", FileUriUser }, // the absolute URL to the document serving as a source file for the document embedded into the web page
{ "shareUrl", FileUriUser }, // the absolute URL that will allow other users to share this document
{ "toolbarDocked", "top" } // the place for the embedded viewer toolbar (top or bottom)
}
},
@ -196,14 +181,13 @@ namespace OnlineEditorsExampleMVC.Models
"customization", new Dictionary<string, object>
{
{ "about", true }, // the About section display
{ "comments", true },
{ "feedback", true }, // the Feedback & Support menu button display
{ "forcesave", false }, // adds the request for the forced file saving to the callback handler
{ "submitForm", submitForm }, // if the Submit form button is displayed or not
{
"goback", new Dictionary<string, object> // settings for the Open file location menu button and upper right corner button
{
{ "url", DocManagerHelper.GetServerUrl(false) } // the absolute URL to the website address which will be opened when clicking the Open file location menu button
{ "url", url.Action("Index", "Home") } // the absolute URL to the website address which will be opened when clicking the Open file location menu button
}
}
}
@ -225,8 +209,7 @@ namespace OnlineEditorsExampleMVC.Models
// get the document history
public void GetHistory(out string history, out string historyData)
{
var storagePath = WebConfigurationManager.AppSettings["storage-path"];
{
var jss = new JavaScriptSerializer();
var histDir = DocManagerHelper.HistoryDir(DocManagerHelper.StoragePath(FileName, null));
@ -265,28 +248,9 @@ namespace OnlineEditorsExampleMVC.Models
}
}
var ext = Path.GetExtension(FileName).ToLower();
dataObj.Add("fileType", ext.Replace(".", ""));
dataObj.Add("key", key);
// write file url to the data object
string prevFileUrl;
string directPrevFileUrl;
if (Path.IsPathRooted(storagePath) && !string.IsNullOrEmpty(storagePath))
{
prevFileUrl = i == currentVersion ? DocManagerHelper.GetHistoryDownloadUrl(FileName, i.ToString(), "prev" + ext)
: DocManagerHelper.GetDownloadUrl(Directory.GetFiles(verDir, "prev.*")[0].Replace(storagePath + "\\", ""));
directPrevFileUrl = i == currentVersion ? DocManagerHelper.GetHistoryDownloadUrl(FileName, i.ToString(), "prev" + ext, false)
: DocManagerHelper.GetDownloadUrl(Directory.GetFiles(verDir, "prev.*")[0].Replace(storagePath + "\\", ""), false);
}
else {
prevFileUrl = i == currentVersion ? FileUri
: DocManagerHelper.GetHistoryDownloadUrl(FileName, i.ToString(), "prev" + ext);
directPrevFileUrl = i == currentVersion ? DocManagerHelper.GetHistoryDownloadUrl(FileName, i.ToString(), "prev" + ext, false)
: DocManagerHelper.GetDownloadUrl(Directory.GetFiles(verDir, "prev.*")[0].Replace(storagePath + "\\", ""), false);
}
dataObj.Add("url", prevFileUrl);
dataObj.Add("directUrl", directPrevFileUrl);
dataObj.Add("url", i == currentVersion ? FileUri : DocManagerHelper.GetPathUri(Directory.GetFiles(verDir, "prev.*")[0].Substring(HttpRuntime.AppDomainAppPath.Length)));
dataObj.Add("version", i);
if (i > 1) // check if the version number is greater than 1 (the file was modified)
{
@ -305,14 +269,11 @@ namespace OnlineEditorsExampleMVC.Models
var prev = (Dictionary<string, object>)histData[(i - 2).ToString()]; // get the history data from the previous file version
dataObj.Add("previous", new Dictionary<string, object>() { // write information about previous file version to the data object
{ "fileType", prev["fileType"] },
{ "key", prev["key"] }, // write key and url information about previous file version
{ "url", prev["url"] },
{ "directUrl", prev["directUrl"] },
});
// write the path to the diff.zip archive with differences in this file version
var changesUrl = DocManagerHelper.GetHistoryDownloadUrl(FileName, (i - 1).ToString(), "diff.zip");
dataObj.Add("changesUrl", changesUrl);
dataObj.Add("changesUrl", DocManagerHelper.GetPathUri(Path.Combine(DocManagerHelper.VersionDir(histDir, i - 1), "diff.zip").Substring(HttpRuntime.AppDomainAppPath.Length)));
}
if(JwtManager.Enabled)
{
@ -347,20 +308,11 @@ namespace OnlineEditorsExampleMVC.Models
Query = "type=assets&fileName=" + HttpUtility.UrlEncode("sample.docx")
};
var directCompareFileUrl = new UriBuilder(DocManagerHelper.GetServerUrl(false))
{
Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "webeditor.ashx",
Query = "type=assets&fileName=" + HttpUtility.UrlEncode("sample.docx")
};
// create an object with the information about the compared file
var dataCompareFile = new Dictionary<string, object>
{
{ "fileType", "docx" },
{ "url", compareFileUrl.ToString() },
{ "directUrl", directCompareFileUrl.ToString()}
{ "url", compareFileUrl.ToString() }
};
if (JwtManager.Enabled) // if the secret key to generate token exists
@ -385,19 +337,11 @@ namespace OnlineEditorsExampleMVC.Models
+ "Content\\images\\logo.png"
};
var directMailMergeUrl = new UriBuilder(DocManagerHelper.GetServerUrl(false))
{
Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "Content\\images\\logo.png"
};
// create a logo config
var logoConfig = new Dictionary<string, object>
{
{ "fileType", "png"},
{ "url", mailMergeUrl.ToString()},
{ "directUrl", directMailMergeUrl.ToString()}
{ "url", mailMergeUrl.ToString()}
};
if (JwtManager.Enabled) // if the secret key to generate token exists
@ -424,21 +368,11 @@ namespace OnlineEditorsExampleMVC.Models
Query = "type=csv"
};
var directMailMergeUrl = new UriBuilder(DocManagerHelper.GetServerUrl(false))
{
Path =
HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "webeditor.ashx",
Query = "type=csv"
};
// create a mail merge config
var mailMergeConfig = new Dictionary<string, object>
{
{ "fileType", "csv" },
{ "url", mailMergeUrl.ToString()},
{ "directUrl", directMailMergeUrl.ToString()}
{ "url", mailMergeUrl.ToString()}
};
if (JwtManager.Enabled) // if the secret key to generate token exists

View File

@ -49,13 +49,13 @@ namespace OnlineEditorsExampleMVC.Models
".dot", ".dotx", ".dotm",
".odt", ".fodt", ".ott", ".rtf", ".txt",
".html", ".htm", ".mht", ".xml",
".pdf", ".djvu", ".fb2", ".epub", ".xps", ".oxps", ".oform"
".pdf", ".djvu", ".fb2", ".epub", ".xps", ".oxps"
};
// spreadsheet extensions
public static readonly List<string> ExtsSpreadsheet = new List<string>
{
".xls", ".xlsx", ".xlsm", ".xlsb",
".xls", ".xlsx", ".xlsm",
".xlt", ".xltx", ".xltm",
".ods", ".fods", ".ots", ".csv"
};

View File

@ -13,7 +13,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OnlineEditorsExampleMVC</RootNamespace>
<AssemblyName>OnlineEditorsExampleMVC</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<MvcBuildViews>false</MvcBuildViews>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort />
@ -43,9 +43,6 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="JWT, Version=9.0.0.0, Culture=neutral, PublicKeyToken=6f98bca0f40f2ecf, processorArchitecture=MSIL">
<HintPath>packages\JWT.9.0.3\lib\net46\JWT.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
@ -53,49 +50,49 @@
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Services" />
<Reference Include="Antlr3.Runtime, Version=3.5.0.2, Culture=neutral, PublicKeyToken=eb42632606e9261f, processorArchitecture=MSIL">
<Reference Include="Antlr3.Runtime">
<HintPath>packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll</HintPath>
</Reference>
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<Reference Include="EntityFramework">
<HintPath>packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="Microsoft.Web.Infrastructure">
<HintPath>packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json">
<HintPath>packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.Formatting, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Net.Http.Formatting">
<HintPath>packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.Helpers">
<HintPath>packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.Http">
<HintPath>packages\Microsoft.AspNet.WebApi.Core.5.2.7\lib\net45\System.Web.Http.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.WebHost, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.Http.WebHost">
<HintPath>packages\Microsoft.AspNet.WebApi.WebHost.5.2.7\lib\net45\System.Web.Http.WebHost.dll</HintPath>
</Reference>
<Reference Include="System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.Mvc">
<HintPath>packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll</HintPath>
</Reference>
<Reference Include="System.Web.Optimization, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.Optimization">
<HintPath>packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll</HintPath>
</Reference>
<Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.Razor">
<HintPath>packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.WebPages">
<HintPath>packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.WebPages.Deployment">
<HintPath>packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.WebPages.Razor">
<HintPath>packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
</Reference>
<Reference Include="WebGrease, Version=1.6.5135.21930, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="WebGrease">
<HintPath>packages\WebGrease.1.6.0\lib\WebGrease.dll</HintPath>
</Reference>
</ItemGroup>
@ -134,7 +131,6 @@
<Content Include="Content\images\embeded.svg" />
<Content Include="Content\images\error.svg" />
<Content Include="Content\images\file_docx.svg" />
<Content Include="Content\images\file_docxf.svg" />
<Content Include="Content\images\file_pptx.svg" />
<Content Include="Content\images\file_upload.svg" />
<Content Include="Content\images\file_xlsx.svg" />
@ -147,7 +143,6 @@
<Content Include="Content\images\loader16.gif" />
<Content Include="Content\images\logo.png" />
<Content Include="Content\images\logo.svg" />
<Content Include="Content\images\mobile-fill-forms.svg" />
<Content Include="Content\images\mobile.svg" />
<Content Include="Content\images\notdone.svg" />
<Content Include="Content\images\review.svg" />
@ -185,12 +180,10 @@
<Content Include="assets\AUTHORS.md" />
<Content Include="assets\LICENSE" />
<Content Include="assets\new\new.docx" />
<Content Include="assets\new\new.docxf" />
<Content Include="assets\new\new.pptx" />
<Content Include="assets\new\new.xlsx" />
<Content Include="assets\sample\csv.csv" />
<Content Include="assets\sample\sample.docx" />
<Content Include="assets\sample\sample.docxf" />
<Content Include="assets\sample\sample.pptx" />
<Content Include="assets\sample\sample.xlsx" />
<None Include="packages.config" />

View File

@ -2,25 +2,22 @@
This example will help you integrate ONLYOFFICE Docs into your web application written in .Net (C# MVC).
**Please note**: It is intended for testing purposes and demonstrating functionality of the editors. Do NOT use this integration example on your own server without proper code modifications! In case you enabled the test example, disable it before going for production.
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
## Step 1. Install ONLYOFFICE Docs
Download and install ONLYOFFICE Docs (packaged as Document Server).
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx), [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx), or [for Docker](https://helpcenter.onlyoffice.com/server/developer-edition/docker/docker-installation.aspx).
## Step 2. Download the .Net (C# MVC) code for the editors integration
Download the [.Net (C# MVC) example](https://api.onlyoffice.com/editors/demopreview) from our site.
To connect the editors to your website, specify the path to the editors installation and the path to the storage folder in the *settings.config* file:
You need to connnect the editors to your website. Specify path to the editors installation in the *settings.config* file:
```
<add key="storage-path" value=""/>
<add key="files.docservice.url.site" value="https://documentserver/" />
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed and the **storage-path** is the path where files will be created and stored. You can set an absolute path.
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) in the *DocEditor.aspx* file.
## Step 3. Install the prerequisites
@ -28,41 +25,31 @@ If you want to experiment with the editor configuration, modify the [parameters]
* **Microsoft .NET Framework**: version 4.5 (download it from the [official Microsoft website](https://www.microsoft.com/en-US/download/details.aspx?id=30653));
* **Internet Information Services**: version 7 or later.
Configure the IIS components for the server to work correctly:
1. Open Windows features:
**Start** -> **Control Panel** -> **Programs** -> **Programs and Features** -> **Turn Windows features on or off**
2. In the opened window, find **Internet Information Services** and choose all the necessary features. To do this, open the **World Wide Web Services** list and check the following components:
* **Application Development Features**: .NET Extensibility 4.8, ASP.NET 4.8, ISAPI Extensions, ISAPI Filters,
* **Common HTTP Features**: Default Document,
* **Security**: Request Filtering.
## Step 4. Run your website with the editors
1. Run the Internet Information Service (IIS) Manager:
**Start** -> **Control Panel** -> **System and Security** -> **Administrative Tools** -> **Internet Information Services (IIS) Manager**
2. Add your website in the IIS Manager.
On the **Connections** panel right-click the **Sites** node in the tree, then click **Add Website**.
![add](screenshots/add.png)
3. In the **Add Website** dialog box specify the name of the folder with the .Net (C# MVC) project in the **Site name** box.
Specify the path to the folder with your project in the **Physical Path** box.
Specify the unique value used only for this website in the **Port** box.
![sitename](screenshots/sitename.png)
4. Check for the .NET platform version specified in IIS Manager for you website. Choose **v4.0.** version.
**Application Pools** -> right-click the platform name -> **Set application Pool defaults** -> **.NET CLR version**
![platform](screenshots/platform.png)
5. Browse your website with the IIS Manager:
Right-click the site -> **Manage Website** -> **Browse**
![browse](screenshots/browse.png)
## Step 5. Check accessibility
@ -70,12 +57,3 @@ Configure the IIS components for the server to work correctly:
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## Important security info
Please keep in mind the following security aspects when you are using test examples:
* There is no protection of the storage from unauthorized access since there is no need for authorization.
* There are no checks against parameter substitution in links, since the parameters are generated by the code according to the pre-arranged scripts.
* There are no data checks in requests of saving the file after editing, since each test example is intended for requests only from ONLYOFFICE Document Server.
* There are no prohibitions on using test examples from other sites, since they are intended to interact with ONLYOFFICE Document Server from another domain.

View File

@ -168,7 +168,7 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.');
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (EditedExtList.indexOf(posExt) != -1 || FillExtList.indexOf(posExt) != -1) {
if (EditedExtList.indexOf(posExt) != -1) {
jq("#beginEdit").removeClass("disable");
}
};

View File

@ -46,13 +46,10 @@
<script type="text/javascript" language="javascript">
var docEditor;
var config;
var innerAlert = function (message, inEditor) {
var innerAlert = function (message) {
if (console && console.log)
console.log(message);
if (inEditor && docEditor)
docEditor.showMessage(message);
};
// the application is loaded into the browser
@ -108,14 +105,10 @@
// the meta information of the document is changed via the meta command
var onMetaChange = function (event) {
if (event.data.favorite) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite); // change the Favorite icon state
}
innerAlert("onMetaChange: " + JSON.stringify(event.data));
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite); // change the Favorite icon state
};
// the user is trying to insert an image by clicking the Image from Storage button
@ -141,44 +134,8 @@
<% Model.GetMailMergeConfig(out dataMailMergeRecipients); %>
docEditor.setMailMergeRecipients(<%= dataMailMergeRecipients%>); // insert recipient data for mail merge into the file
};
var onRequestSaveAs = function (event) { // the user is trying to save file by clicking Save Copy as... button
var title = event.data.title;
var url = event.data.url;
var data = {
title: title,
url: url
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "webeditor.ashx?type=saveas");
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
innerAlert(JSON.parse(xhr.responseText).file, true);
}
};
var onRequestRename = function(event) { // the user is trying to rename file by clicking Rename... button
innerAlert("onRequestRename: " + JSON.stringify(event.data));
var newfilename = event.data;
var data = {
newfilename: newfilename,
dockey: config.document.key,
ext: config.document.fileType
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "webeditor.ashx?type=rename");
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
}
};
config = <%= Model.GetDocConfig(Request, Url) %>;
var config = <%= Model.GetDocConfig(Request, Url) %>;
config.width = "100%";
config.height = "100%";
@ -198,60 +155,44 @@
<% string hist, histData; %>
<% Model.GetHistory(out hist, out histData); %>
<% if (!string.IsNullOrEmpty(hist) && !string.IsNullOrEmpty(histData))
{ %>
// the user is trying to show the document version history
config.events['onRequestHistory'] = function () {
docEditor.refreshHistory(<%= hist %>); // show the document version history
};
// the user is trying to click the specific document version in the document version history
config.events['onRequestHistoryData'] = function (event) {
var ver = event.data;
var histData = <%= histData %>;
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
};
// the user is trying to go back to the document from viewing the document version history
config.events['onRequestHistoryClose '] = function () {
document.location.reload();
};
<% } %>
<% string usersForMentions; %>
<% Model.GetUsersMentions(Request, out usersForMentions); %>
if (config.editorConfig.user.id) {
<% if (!string.IsNullOrEmpty(hist) && !string.IsNullOrEmpty(histData))
{ %>
// the user is trying to show the document version history
config.events['onRequestHistory'] = function () {
docEditor.refreshHistory(<%= hist %>); // show the document version history
};
// the user is trying to click the specific document version in the document version history
config.events['onRequestHistoryData'] = function (event) {
var ver = event.data;
var histData = <%= histData %>;
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
};
// the user is trying to go back to the document from viewing the document version history
config.events['onRequestHistoryClose '] = function () {
document.location.reload();
};
<% } %>
// add mentions for not anonymous users
<% if (!string.IsNullOrEmpty(usersForMentions))
{ %>
config.events['onRequestUsers'] = function () {
docEditor.setUsers({ // set a list of users to mention in the comments
"users": <%= usersForMentions %>
});
};
<% } %>
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
// prevent file renaming for anonymous users
config.events['onRequestRename'] = onRequestRename;
}
if (config.editorConfig.createUrl) {
config.events.onRequestSaveAs = onRequestSaveAs;
<% if (!string.IsNullOrEmpty(usersForMentions))
// add mentions for not anonymous users
{ %>
config.events['onRequestUsers'] = function () {
docEditor.setUsers({ // set a list of users to mention in the comments
"users": <%= usersForMentions%>
});
};
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
var actionLink = JSON.stringify(event.data.actionLink);
console.log("onRequestSendNotify:");
console.log(event.data);
console.log("Link to comment: " + replaceActionLink(location.href, actionLink));
};
<% } %>
var сonnectEditor = function () {
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
return;
}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -4,7 +4,6 @@
<%@ Import Namespace="System.Web.Configuration" %>
<%@ Import Namespace="OnlineEditorsExampleMVC.Helpers" %>
<%@ Import Namespace="OnlineEditorsExampleMVC.Models" %>
<%@ Import Namespace="System.Collections.Generic" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
@ -66,9 +65,6 @@
<li>
<a class="try-editor slide" data-type="pptx">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">Form template</a>
</li>
</ul>
<label class="create-sample">
<input id="createSample" class="checkbox" type="checkbox" />With sample content
@ -90,7 +86,7 @@
<select class="select-user" id="user">
<% foreach (User user in Users.getAllUsers())
{ %>
<option value="<%= user.id %>"><%= user.name.IsEmpty() ? "Anonymous" : user.name %></option>
<option value=<%= user.id %> ><%= user.name.IsEmpty() ? "Anonymous" : user.name %></option>
<% } %>
</select>
</td>
@ -99,11 +95,37 @@
<td valign="middle">
<span class="select-user">Language editors interface</span>
<select class="select-user" id="language">
<% Dictionary<string, string> languages = DocManagerHelper.GetLanguages();
foreach (var lang in languages)
{ %>
<option value="<%= lang.Key %>"><%= lang.Value %></option>
<% } %>
<option value="en">English</option>
<option value="be">Belarusian</option>
<option value="bg">Bulgarian</option>
<option value="ca">Catalan</option>
<option value="zh">Chinese</option>
<option value="cs">Czech</option>
<option value="da">Danish</option>
<option value="nl">Dutch</option>
<option value="fi">Finnish</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="el">Greek</option>
<option value="hu">Hungarian</option>
<option value="id">Indonesian</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
<option value="ko">Korean</option>
<option value="lv">Latvian</option>
<option value="lo">Lao</option>
<option value="nb">Norwegian</option>
<option value="pl">Polish</option>
<option value="pt">Portuguese</option>
<option value="ro">Romanian</option>
<option value="ru">Russian</option>
<option value="sk">Slovak</option>
<option value="sl">Slovenian</option>
<option value="sv">Swedish</option>
<option value="es">Spanish</option>
<option value="tr">Turkish</option>
<option value="uk">Ukrainian</option>
<option value="vi">Vietnamese</option>
</select>
</td>
</tr>
@ -114,13 +136,12 @@
<td class="section">
<div class="main-panel">
<% var storedFiles = DocManagerHelper.GetStoredFiles(); %>
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "table-cell" %>">
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "block" %>">
<span class="portal-name">ONLYOFFICE Document Editors Welcome!</span>
<span class="portal-descr">
Get started with a demo-sample of ONLYOFFICE Document Editors, the first html5-based editors.
<br /> You may upload your own documents for testing using the "<b>Upload file</b>" button and <b>selecting</b> the necessary files on your PC.
</span>
<span class="portal-descr">Please do NOT use this integration example on your own server without proper code modifications, it is intended for testing purposes only. In case you enabled this test example, disable it before going for production.</span>
<span class="portal-descr">You can open the same document using different users in different Web browser sessions, so you can check out multi-user editing functions.</span>
<% foreach (User user in Users.getAllUsers())
{ %>
@ -157,13 +178,11 @@
<% foreach (var storedFile in storedFiles)
{
var editUrl = "doceditor.aspx?fileID=" + HttpUtility.UrlEncode(storedFile.Name);
var docType = FileUtility.GetFileType(storedFile.Name).ToString().ToLower();
var ext = Path.GetExtension(storedFile.Name).ToLower();
var canEdit = DocManagerHelper.EditedExts.Contains(ext);
var isFillFormDoc = DocManagerHelper.FillFormExts.Contains(ext);
var docType = FileUtility.GetFileType(storedFile.Name).ToString().ToLower();
var canEdit = DocManagerHelper.EditedExts.Contains(Path.GetExtension(storedFile.Name).ToLower());
%>
<tr class="tableRow" title="<%= storedFile.Name %> [<%= DocManagerHelper.GetFileVersion(storedFile.Name, HttpContext.Current.Request.UserHostAddress.Replace(':', '_')) %>]">
<tr class="tableRow" title="<%= storedFile.Name %> [<%= DocManagerHelper.GetFileVersion(storedFile.Name, HttpContext.Current.Request.UserHostAddress) %>]">
<td class="contentCells">
<a class="stored-edit <%= docType %>" href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name }) %>" target="_blank">
<span><%= storedFile.Name %></span>
@ -198,42 +217,30 @@
</a>
</td>
<% } %>
<% if (docType != "word" && docType != "cell") { %>
<td class="contentCells contentCells-icon contentCellsEmpty"></td>
<% } %>
<% if (docType == "word") { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "fillForms" }) %>" target="_blank">
<img src="content/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon"></td>
<% } %>
<% if (docType == "word"){ %>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "blockcontent" }) %>" target="_blank">
<img src="content/images/block-content.svg" alt="Open in editor without content control modification" title="Open in editor without content control modification"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon"></td>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift"></td>
<% } %>
<% if (docType != "word" && docType != "cell") { %>
<td class="contentCells contentCells-icon "></td>
<% } %>
<% if (isFillFormDoc) { %>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "fillForms" }) %>" target="_blank">
<img src="content/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift"></td>
<% } %>
<% } else if (isFillFormDoc) { %>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "mobile", editorsMode = "fillForms" }) %>" target="_blank">
<img src="content/images/mobile-fill-forms.svg" alt="Open in editor for filling in forms for mobile devices" title="Open in editor for filling in forms for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "fillForms" }) %>" target="_blank">
<img src="content/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-shift contentCells-icon contentCellsEmpty" colspan="6"></td>
<% } %>
@ -301,8 +308,10 @@
<span class="step-descr">They are loaded only once, they will be cached on your computer.</span>
<input type="hidden" name="hiddenFileName" id="hiddenFileName" />
<br />
<br />
<span class="progress-descr">Note the speed of all operations depends on your connection quality and server location.</span>
<br />
<br />
<div class="error-message">
<b>Upload error: </b><span></span>
<br />
@ -311,12 +320,10 @@
</div>
<iframe id="embeddedView" src="" height="345px" width="432px" frameborder="0" scrolling="no" allowtransparency></iframe>
<br />
<div class="buttonsMobile">
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
</div>
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
</div>
<span id="loadScripts" data-docs="<%= WebConfigurationManager.AppSettings["files.docservice.url.site"] + WebConfigurationManager.AppSettings["files.docservice.url.preloader"] %>"></span>
@ -344,7 +351,6 @@
<%: Scripts.Render("~/bundles/jquery", "~/bundles/scripts") %>
<script language="javascript" type="text/javascript">
var FillExtList = '<%= string.Join(",", DocManagerHelper.FillFormExts.ToArray()) %>';
var ConverExtList = '<%= string.Join(",", DocManagerHelper.ConvertExts.ToArray()) %>';
var EditedExtList = '<%= string.Join(",", DocManagerHelper.EditedExts.ToArray()) %>';
var UrlConverter = '<%= Url.Content("~/webeditor.ashx?type=convert") %>';

View File

@ -26,11 +26,11 @@
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
@ -39,28 +39,20 @@
</handlers>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="52428800" />
<requestLimits maxAllowedContentLength="52428800"/>
</requestFiltering>
</security>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
@ -71,4 +63,7 @@
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
</entityFramework>
</configuration>

View File

@ -19,7 +19,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using System.Net;
using System.Web;
@ -47,9 +46,6 @@ namespace OnlineEditorsExampleMVC
case "download":
Download(context);
break;
case "downloadhistory":
DownloadHistory(context);
break;
case "convert":
Convert(context);
break;
@ -68,86 +64,6 @@ namespace OnlineEditorsExampleMVC
case "files":
Files(context);
break;
case "saveas":
SaveAs(context);
break;
case "rename":
Rename(context);
break;
}
}
private static void SaveAs(HttpContext context)
{
context.Response.ContentType = "text/plain";
try
{
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\":\"Request stream is empty\"}");
}
}
catch (Exception e)
{
throw new HttpException((int)HttpStatusCode.BadRequest, e.Message);
}
var jss = new JavaScriptSerializer();
var body = jss.Deserialize<Dictionary<string, object>>(fileData);
var fileUrl = (string) body["url"];
var title = (string) body["title"];
var fileName = DocManagerHelper.GetCorrectName(title);
var extension = "." + (Path.GetExtension(fileName).ToLower() ?? "").Trim('.');
var allExt = DocManagerHelper.ConvertExts
.Concat(DocManagerHelper.EditedExts)
.Concat(DocManagerHelper.ViewedExts)
.Concat(DocManagerHelper.FillFormExts)
.ToArray();
if (!allExt.Contains(extension))
{
context.Response.Write("{\"error\":\"File type is not supported\"}");
}
var req = (HttpWebRequest)WebRequest.Create(fileUrl);
DocManagerHelper.VerifySSL();
using (var stream = req.GetResponse().GetResponseStream())
{
if (stream == null || req.GetResponse().ContentLength <= 0 || req.GetResponse().ContentLength > DocManagerHelper.MaxFileSize)
{
context.Response.Write("{\"error\": \"File size is incorrect\"}");
}
const int bufferSize = 4096;
using (var fs = File.Open(DocManagerHelper.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
DocManagerHelper.CreateMeta(fileName, user.id, user.name, null);
context.Response.Write("{ \"file\": \"" + fileName + "\"}");
}
catch (Exception e)
{
context.Response.Write("{ \"error\": \"" + 1 + "\", \"message\": \"" + e.Message + "\"}");
}
}
@ -157,8 +73,6 @@ namespace OnlineEditorsExampleMVC
context.Response.ContentType = "text/plain";
try
{
DocManagerHelper.VerifySSL();
var httpPostedFile = context.Request.Files[0];
string fileName;
@ -258,8 +172,6 @@ namespace OnlineEditorsExampleMVC
var req = (HttpWebRequest)WebRequest.Create(newFileUri);
DocManagerHelper.VerifySSL();
using (var stream = req.GetResponse().GetResponseStream()) // get response stream of the converting file
{
if (stream == null) throw new Exception("Stream is null");
@ -313,7 +225,7 @@ namespace OnlineEditorsExampleMVC
var userAddress = context.Request["userAddress"];
var fileName = Path.GetFileName(context.Request["fileName"]);
var status = (TrackerStatus) (int) fileData["status"]; // get status from the request body
var saved = 0;
var saved = 1; // editing
switch (status)
{
case TrackerStatus.Editing:
@ -370,7 +282,7 @@ namespace OnlineEditorsExampleMVC
return;
}
context.Response.Write("{\"error\":" + saved + "}");
context.Response.Write("{\"error\":0}");
}
// remove a file
@ -456,12 +368,10 @@ namespace OnlineEditorsExampleMVC
{
try
{
var fileName = Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ? context.Request["fileName"]
: Path.GetFileName(context.Request["fileName"]);
var fileName = Path.GetFileName(context.Request["fileName"]);
var userAddress = context.Request["userAddress"];
var isEmbedded = context.Request["dmode"];
if (JwtManager.Enabled && isEmbedded == null)
if (JwtManager.Enabled)
{
string JWTheader = WebConfigurationManager.AppSettings["files.docservice.header"].Equals("") ? "Authorization" : WebConfigurationManager.AppSettings["files.docservice.header"];
@ -507,88 +417,5 @@ namespace OnlineEditorsExampleMVC
{
get { return false; }
}
// download a history file
private static void DownloadHistory(HttpContext context)
{
try
{
var fileName = Path.GetFileName(context.Request["fileName"]);
var userAddress = Path.GetFileName(context.Request["userAddress"]);
var version = System.Convert.ToInt32(context.Request["ver"]);
var file = Path.GetFileName(context.Request["file"]);
if (JwtManager.Enabled)
{
string JWTheader = WebConfigurationManager.AppSettings["files.docservice.header"].Equals("") ? "Authorization" : WebConfigurationManager.AppSettings["files.docservice.header"];
if (context.Request.Headers.AllKeys.Contains(JWTheader, StringComparer.InvariantCultureIgnoreCase))
{
var headerToken = context.Request.Headers.Get(JWTheader).Substring("Bearer ".Length);
string token = JwtManager.Decode(headerToken);
if (token == null || token.Equals(""))
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
context.Response.Write("JWT validation failed");
return;
}
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
context.Response.Write("JWT validation failed");
return;
}
}
var histPath = DocManagerHelper.HistoryDir(DocManagerHelper.StoragePath(fileName, userAddress));
var filePath = Path.Combine(DocManagerHelper.VersionDir(histPath, version), file); // get the path to document version
download(filePath, context);
}
catch (Exception)
{
context.Response.Write("{ \"error\": \"File not found!\"}");
}
}
// rename a file
private static void Rename(HttpContext context)
{
// read request body
context.Response.ContentType = "text/plain";
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\":\"Request stream is empty\"}");
}
}
catch (Exception e)
{
throw new HttpException((int)HttpStatusCode.BadRequest, e.Message);
}
var jss = new JavaScriptSerializer();
var body = jss.Deserialize<Dictionary<string, object>>(fileData);
var newFileName = (string) body["newfilename"];
var docKey = (string) body["dockey"];
var origExt = '.' + (string) body["ext"];
var curExt = Path.GetExtension(newFileName).ToLower();
if (string.Compare(origExt, curExt, true) != 0)
{
newFileName += origExt;
}
var meta = new Dictionary<string, object>() {
{ "title", newFileName }
};
TrackManager.commandRequest("meta", docKey, meta);
context.Response.Write("{ \"result\": \"OK\"}");
}
}
}

View File

@ -24,15 +24,11 @@ jQuery.UI - jQuery UI is an open source library of interface components —
License: MIT
License File: jQuery.UI.license
JWT - JWT (JSON Web Token) Implementation for .NET (Public Domain) (https://github.com/jwt-dotnet/jwt/)
License: MIT
License File: JWT.license
Microsoft.Web.Infrastructure - This package contains the Microsoft.Web.Infrastructure assembly that lets you dynamically register HTTP modules at run time. (https://www.microsoft.com/web/webpi/eula/aspnetmvc3update-eula.htm)
License: MS-EULA License
License File: Microsoft.Web.Infrastructure.license
Newtonsoft.Json - Json.NET is a popular high-performance JSON framework for .NET (https://github.com/JamesNK/Newtonsoft.Json)
Newtonsoft.Json - Json.NET is a popular high-performance JSON framework for .NET (https://licenses.nuget.org/MIT)
License: MIT
License File: Newtonsoft.Json.license

View File

@ -1,21 +0,0 @@
# Public Domain
Written by John Sheehan (http://john-sheehan.com)
This work is public domain.
The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law.
For more information, please visit: http://creativecommons.org/publicdomain/zero/1.0/
# MIT
Copyright (c) 2019 Jwt.Net Maintainers and Contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For more information, please visit: https://opensource.org/licenses/MIT

View File

@ -1,17 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Antlr" version="3.5.0.2" targetFramework="net48" />
<package id="EntityFramework" version="6.4.4" targetFramework="net48" />
<package id="JWT" version="9.0.3" targetFramework="net48" />
<package id="Microsoft.AspNet.Mvc" version="5.2.7" targetFramework="net48" />
<package id="Microsoft.AspNet.Razor" version="3.2.7" targetFramework="net48" />
<package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net48" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.7" targetFramework="net48" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.7" targetFramework="net48" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.7" targetFramework="net48" />
<package id="Microsoft.AspNet.WebPages" version="3.2.7" targetFramework="net48" />
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net48" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net48" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
<package id="WebGrease" version="1.6.0" targetFramework="net48" />
<package id="Antlr" version="3.5.0.2" targetFramework="net45" />
<package id="EntityFramework" version="6.4.4" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc" version="5.2.7" targetFramework="net45" />
<package id="Microsoft.AspNet.Razor" version="3.2.7" targetFramework="net45" />
<package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.7" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.7" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.7" targetFramework="net45" />
<package id="Microsoft.AspNet.WebPages" version="3.2.7" targetFramework="net45" />
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net45" />
<package id="WebGrease" version="1.6.0" targetFramework="net45" />
</packages>

View File

@ -1,23 +1,17 @@
<?xml version="1.0"?>
<?xml version="1.0"?>
<appSettings>
<clear />
<add key="version" value="1.4.0"/>
<add key="version" value="1.0.0"/>
<add key="filesize-max" value="52428800"/>
<add key="storage-path" value=""/>
<add key="files.docservice.fillform-docs" value=".oform|.docx"/>
<add key="files.docservice.viewed-docs" value=".pdf|.djvu|.xps|.oxps"/>
<add key="files.docservice.edited-docs" value=".docx|.xlsx|.csv|.pptx|.txt|.docxf"/>
<add key="files.docservice.convert-docs" value=".docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xlsb|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2"/>
<add key="files.docservice.edited-docs" value=".docx|.xlsx|.csv|.pptx|.txt"/>
<add key="files.docservice.convert-docs" value=".docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2"/>
<add key="files.docservice.timeout" value="120000" />
<add key="files.docservice.secret" value="" />
<add key="files.docservice.header" value="Authorization" />
<add key="files.docservice.verify-peer-off" value="true"/>
<add key="files.docservice.languages" value="en:English|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (People's Republic of China)|zh-TW:Chinese (Traditional, Taiwan)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lv:Latvian|lo:Lao|ms:Malay (Malaysia)|nb:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese"/>
<add key="files.docservice.url.site" value="http://documentserver/"/>
<add key="files.docservice.url.converter" value="ConvertService.ashx"/>

View File

@ -19,11 +19,3 @@ License File: jQuery.iframe-transport.license
jQuery.UI - jQuery UI is an open source library of interface components — interactions, full-featured widgets, and animation effects — based on the stellar jQuery javascript library . Each component is built according to jQuery's event-driven architecture (find something, manipulate it) and is themeable, making it easy for developers of any skill level to integrate and extend into their own code. (https://jquery.org/license/)
License: MIT
License File: jQuery.UI.license
JWT - JWT (JSON Web Token) Implementation for .NET (Public Domain) (https://github.com/jwt-dotnet/jwt/)
License: MIT
License File: JWT.license
Newtonsoft.Json - Json.NET is a popular high-performance JSON framework for .NET (https://github.com/JamesNK/Newtonsoft.Json)
License: MIT
License File: Newtonsoft.Json.license

View File

@ -1,6 +0,0 @@
<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 3C0 1.34315 1.34315 0 3 0H22.9167L30 7.08333V37C30 38.6569 28.6569 40 27 40H3C1.34315 40 0 38.6569 0 37V3Z" fill="#27ABA3"/>
<path d="M22.9165 0L29.9998 7.08333H25.9165C24.2597 7.08333 22.9165 5.74019 22.9165 4.08333V0Z" fill="#008078"/>
<rect x="6.5" y="15.5" width="17" height="5" stroke="white"/>
<rect x="6.5" y="23.5" width="17" height="5" stroke="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 477 B

View File

@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 5C5 3.89543 5.89543 3 7 3H16C17.1046 3 18 3.89543 18 5V8H17V6H6V18H17V16H18V19C18 20.1046 17.1046 21 16 21H7C5.89543 21 5 20.1046 5 19V5ZM13 4H10V5H13V4ZM12 19.5C12 19.7761 11.7761 20 11.5 20C11.2239 20 11 19.7761 11 19.5C11 19.2239 11.2239 19 11.5 19C11.7761 19 12 19.2239 12 19.5Z" fill="#444444"/>
<rect x="7" y="9" width="1" height="6" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 8V9L11 9V15H12V16H9V15H10V9H9V8H12Z" fill="#444444"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 10H18V14H15H14H13V15H14H18C18.5523 15 19 14.5523 19 14V10C19 9.44772 18.5523 9 18 9H14H13V10H14H15Z" fill="#444444"/>
</svg>

Before

Width:  |  Height:  |  Size: 790 B

View File

@ -87,6 +87,10 @@
}
@media (max-width: 1008px) {
#portal-info {
width: 65vw;
}
.left-panel {
margin-left: 0;
}
@ -124,10 +128,6 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.main-panel {
left: 0;
padding: 48px 18px 24px;
@ -312,9 +312,6 @@
.tableRow td:first-child {
max-width: 17%;
}
#portal-info {
max-width: 60vw;
}
}
.downloadContentCellShift:after {
@ -366,10 +363,6 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.copy {
width: 100%;
text-align: center;
@ -443,58 +436,6 @@
display: none;
width: 1%;
}
/* Mobile Upload*/
.blockUI.blockMsg.blockPage.ui-dialog.ui-widget.ui-corner-all.ui-widget-content.ui-draggable {
width: 344px !important;
box-shadow: 0px 7px 15px rgba(85, 85, 85, 0.1);
border-radius: 2px;
top: 10% !important;
margin-left: -172px !important;
}
.ui-dialog .ui-dialog-titlebar {
padding: 0;
}
.ui-dialog .ui-dialog-content {
padding: 0 !important;
}
#mainProgress {
margin: 24px 16px 0 !important;
}
.blockTitle {
padding: 10px 10px 6px 16px !important;
font-size: 14px !important;
}
#mainProgress .describeUpload {
padding: 8px 0 !important;
}
.dialog-close {
margin: 0 !important;
}
.step-descr{
line-height: 150%;
}
.step {
line-height: 160%;
}
.buttonsMobile{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.button.gray{
margin: 0;
}
.button, .button:hover{
display: flex;
justify-content: center;
padding: 0 !important;
width: 144px;
height: 56px;
margin-bottom: 24px !important;
}
}
@media (max-width: 560px) and (min-width: 510px) {

View File

@ -22,7 +22,6 @@ html {
}
body {
display: block;
background: #FFFFFF;
color: #333333;
font-family: Open Sans;
@ -72,7 +71,6 @@ header img {
}
.main {
display: table;
height: calc(100% - 112px);
min-height: 536px;
}
@ -99,10 +97,6 @@ header img {
width: 896px;
}
#portal-info {
max-width: 65vw;
}
.portal-name {
color: #FF6F3D;
font-size: 24px;
@ -163,10 +157,6 @@ label .checkbox {
background-image: url("images/file_pptx.svg");
}
.try-editor.form {
background-image: url("images/file_docxf.svg");
}
.create-sample {
color: #666666;
line-height: 24px;
@ -738,9 +728,12 @@ html {
width: 30vw;
min-width: 200px;
max-width: 400px;
margin-top: 20px;
}
.user-descr > b {
margin-left: 25px;
}
.portal-descr:nth-child(3) {
margin-bottom: 20px;
}

View File

@ -5,14 +5,12 @@
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Web.Configuration" %>
<%@ Import Namespace="OnlineEditorsExample" %>
<%@ Import Namespace="System.Collections.Generic" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width" />
<title>ONLYOFFICE</title>
<!--
*
@ -69,9 +67,6 @@
<li>
<a class="try-editor slide" data-type="slide">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">Form template</a>
</li>
</ul>
<label class="create-sample">
<input id="createSample" class="checkbox" type="checkbox" />With sample content
@ -101,11 +96,37 @@
<td valign="middle">
<span class="select-user">Language editors interface</span>
<select class="select-user" id="language">
<% Dictionary<string, string> languages = GetLanguages();
foreach (var lang in languages)
{ %>
<option value="<%= lang.Key %>"><%= lang.Value %></option>
<% } %>
<option value="en">English</option>
<option value="be">Belarusian</option>
<option value="bg">Bulgarian</option>
<option value="ca">Catalan</option>
<option value="zh">Chinese</option>
<option value="cs">Czech</option>
<option value="da">Danish</option>
<option value="nl">Dutch</option>
<option value="fi">Finnish</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="el">Greek</option>
<option value="hu">Hungarian</option>
<option value="id">Indonesian</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
<option value="ko">Korean</option>
<option value="lv">Latvian</option>
<option value="lo">Lao</option>
<option value="nb">Norwegian</option>
<option value="pl">Polish</option>
<option value="pt">Portuguese</option>
<option value="ro">Romanian</option>
<option value="ru">Russian</option>
<option value="sk">Slovak</option>
<option value="sl">Slovenian</option>
<option value="sv">Swedish</option>
<option value="es">Spanish</option>
<option value="tr">Turkish</option>
<option value="uk">Ukrainian</option>
<option value="vi">Vietnamese</option>
</select>
</td>
</tr>
@ -116,13 +137,12 @@
<td class="section">
<% var storedFiles = GetStoredFiles(); %>
<div class="main-panel">
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "table-cell" %>">
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "block" %>">
<span class="portal-name">ONLYOFFICE Document Editors Welcome!</span>
<span class="portal-descr">
Get started with a demo-sample of ONLYOFFICE Document Editors, the first html5-based editors.
<br /> You may upload your own documents for testing using the "<b>Upload file</b>" button and <b>selecting</b> the necessary files on your PC.
</span>
<span class="portal-descr">Please do NOT use this integration example on your own server without proper code modifications, it is intended for testing purposes only. In case you enabled this test example, disable it before going for production.</span>
<span class="portal-descr">You can open the same document using different users in different Web browser sessions, so you can check out multi-user editing functions.</span>
<% foreach (User user in Users.getAllUsers())
{ %>
@ -159,13 +179,11 @@
<% foreach (var storedFile in storedFiles)
{
var editUrl = "doceditor.aspx?fileID=" + HttpUtility.UrlEncode(storedFile.Name);
var ext = Path.GetExtension(storedFile.Name).ToLower();
var docType = DocumentType(storedFile.Name);
var canEdit = EditedExts.Contains(ext);
var isFillFormDoc = FillFormsExts.Contains(ext);
var canEdit = EditedExts.Contains(Path.GetExtension(storedFile.Name).ToLower());
%>
<tr class="tableRow" title="<%= storedFile.Name %> [<%= GetFileVersion(storedFile.Name, HttpContext.Current.Request.UserHostAddress.Replace(':','_')) %>]">
<tr class="tableRow" title="<%= storedFile.Name %> [<%= GetFileVersion(storedFile.Name, HttpContext.Current.Request.UserHostAddress) %>]">
<td class="contentCells">
<a class="stored-edit <%= docType %>" href="<%= editUrl %>" target="_blank">
<span><%= storedFile.Name %></span>
@ -200,42 +218,30 @@
</a>
</td>
<% } %>
<%if (docType != "word" && docType != "cell") { %>
<td class="contentCells contentCells-icon contentCellsEmpty"></td>
<% } %>
<% if (docType == "word") { %>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=fillForms" %>" target="_blank">
<img src="app_themes/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-icon"></td>
<% } %>
<% if (docType == "word") { %>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=blockcontent" %>" target="_blank">
<img src="app_themes/images/block-content.svg" alt="Open in editor without content control modification" title="Open in editor without content control modification"/>
</a>
</td>
<% } else{%>
<td class="contentCells contentCells-icon"></td>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift"></td>
<%} %>
<%if (docType != "word" && docType != "cell"){%>
<td class="contentCells contentCells-icon "></td>
<% } %>
<% if (isFillFormDoc) { %>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=fillForms" %>" target="_blank">
<img src="app_themes/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift"></td>
<% } %>
<% } else if (isFillFormDoc) { %>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=mobile&editorsMode=fillForms" %>" target="_blank">
<img src="app_themes/images/mobile-fill-forms.svg" alt="Open in editor for filling in forms for mobile devices" title="Open in editor for filling in forms for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-icon "></td>
<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=fillForms" %>" target="_blank">
<img src="app_themes/images/fill-forms.svg" alt="Open in editor for filling in forms" title="Open in editor for filling in forms"/>
</a>
</td>
<% } else { %>
<td class="contentCells contentCells-shift contentCells-icon contentCellsEmpty" colspan="6"></td>
<% } %>
@ -303,8 +309,10 @@
<span class="step-descr">They are loaded only once, they will be cached on your computer.</span>
<input type="hidden" name="hiddenFileName" id="hiddenFileName" />
<br />
<br />
<span class="progress-descr">Note the speed of all operations depends on your connection quality and server location.</span>
<br />
<br />
<div class="error-message">
<b>Upload error: </b><span></span>
<br />
@ -313,12 +321,10 @@
</div>
<iframe id="embeddedView" src="" height="345px" width="432px" frameborder="0" scrolling="no" allowtransparency></iframe>
<br />
<div class="buttonsMobile">
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
</div>
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
</div>
<span id="loadScripts" data-docs="<%= UrlPreloadScripts %>"></span>
@ -352,7 +358,6 @@
<script language="javascript" type="text/javascript" src="script/jquery.dropdownToggle.js"></script>
<script language="javascript" type="text/javascript" src="script/jscript.js"></script>
<script language="javascript" type="text/javascript">
var FillFormExtList = '<%= string.Join(",", FillFormsExts.ToArray()) %>';
var ConverExtList = '<%= string.Join(",", ConvertExts.ToArray()) %>';
var EditedExtList = '<%= string.Join(",", EditedExts.ToArray()) %>';
</script>

View File

@ -35,7 +35,7 @@ namespace OnlineEditorsExample
// the spreadsheet extension list
public static readonly List<string> ExtsSpreadsheet = new List<string>
{
".xls", ".xlsx", ".xlsm", ".xlsb",
".xls", ".xlsx", ".xlsm",
".xlt", ".xltx", ".xltm",
".ods", ".fods", ".ots", ".csv"
};
@ -56,7 +56,7 @@ namespace OnlineEditorsExample
".dot", ".dotx", ".dotm",
".odt", ".fodt", ".ott", ".rtf", ".txt",
".html", ".htm", ".mht", ".xml",
".pdf", ".djvu", ".fb2", ".epub", ".xps", ".oxps", ".oform"
".pdf", ".djvu", ".fb2", ".epub", ".xps", ".oxps"
};
// get an internal file extension
@ -78,9 +78,7 @@ namespace OnlineEditorsExample
{
get
{
return Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ?
WebConfigurationManager.AppSettings["storage-path"] + "/"
:
return
HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ WebConfigurationManager.AppSettings["storage-path"]
@ -109,7 +107,7 @@ namespace OnlineEditorsExample
// get all the supported file extensions
private static List<string> FileExts
{
get { return ViewedExts.Concat(EditedExts).Concat(ConvertExts).Concat(FillFormsExts).ToList(); }
get { return ViewedExts.Concat(EditedExts).Concat(ConvertExts).ToList(); }
}
// file extensions that can be viewed
@ -117,11 +115,6 @@ namespace OnlineEditorsExample
{
get { return (WebConfigurationManager.AppSettings["files.docservice.viewed-docs"] ?? "").Split(new char[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); }
}
public static List<string> FillFormsExts
{
get { return (WebConfigurationManager.AppSettings["files.docservice.fillform-docs"] ?? "").Split(new char[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); }
}
// file extensions that can be edited
public static List<string> EditedExts
@ -146,52 +139,18 @@ namespace OnlineEditorsExample
// 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) + "\\";
}
var 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;
return directory + Path.GetFileName(fileName);
}
// 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) + "\\";
}
var directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\";
if (!Directory.Exists(directory)) // the directory with host address doesn't exist
{
return "";
@ -353,7 +312,11 @@ namespace OnlineEditorsExample
try
{
VerifySSL();
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if (IsMono)
{
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
}
using (var stream = req.GetResponse().GetResponseStream()) // get response stream of the uploading file
{
@ -383,68 +346,6 @@ namespace OnlineEditorsExample
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<Dictionary<string, object>>(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)
{
@ -485,7 +386,7 @@ namespace OnlineEditorsExample
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "webeditor.ashx";
fileUrl.Query = "type=download&fileName=" + HttpUtility.UrlEncode(_fileName)
+ "&userAddress=" + HttpUtility.UrlEncode(CurUserHostAddress(HttpContext.Current.Request.UserHostAddress));
+ "&userAddress=" + HttpUtility.UrlEncode(HttpContext.Current.Request.UserHostAddress);
// get the url to the converted file
string newFileUri;
@ -500,7 +401,11 @@ namespace OnlineEditorsExample
var req = (HttpWebRequest)WebRequest.Create(newFileUri);
VerifySSL();
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if (IsMono)
{
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
}
using (var stream = req.GetResponse().GetResponseStream()) // get response stream of the converting file
{
@ -552,16 +457,7 @@ namespace OnlineEditorsExample
// get all the stored files from the folder
protected static List<FileInfo> 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) + "\\";
}
var directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(null) + "\\";
if (!Directory.Exists(directory)) return new List<FileInfo>();
var directoryInfo = new DirectoryInfo(directory); // read the user host directory contents
@ -604,27 +500,5 @@ namespace OnlineEditorsExample
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<string, string> GetLanguages()
{
var languages = new Dictionary<string, string>();
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;
}
}
}

View File

@ -64,13 +64,10 @@
<script type="text/javascript" language="javascript">
var docEditor;
var config;
var innerAlert = function (message, inEditor) {
var innerAlert = function (message) {
if (console && console.log)
console.log(message);
if (inEditor && docEditor)
docEditor.showMessage(message);
};
// the application is loaded into the browser
@ -126,14 +123,10 @@
// the meta information of the document is changed via the meta command
var onMetaChange = function (event) {
if (event.data.favorite) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite); // change the Favorite icon state
}
innerAlert("onMetaChange: " + JSON.stringify(event.data));
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite); // change the Favorite icon state
};
// the user is trying to insert an image by clicking the Image from Storage button
@ -153,44 +146,8 @@
var onRequestMailMergeRecipients = function (event) {
docEditor.setMailMergeRecipients(<%= DataMailMergeRecipients %>); // insert recipient data for mail merge into the file
};
var onRequestSaveAs = function (event) { // the user is trying to save file by clicking Save Copy as... button
var title = event.data.title;
var url = event.data.url;
var data = {
title: title,
url: url
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "webeditor.ashx?type=saveas");
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
innerAlert(JSON.parse(xhr.responseText).file, true);
}
};
var onRequestRename = function(event) { // the user is trying to rename file by clicking Rename... button
innerAlert("onRequestRename: " + JSON.stringify(event.data));
var newfilename = event.data;
var data = {
newfilename: newfilename,
dockey: config.document.key,
ext: config.document.fileType
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "webeditor.ashx?type=rename");
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
}
};
config = <%= DocConfig %>;
var config = <%= DocConfig %>;
config.width = "100%";
config.height = "100%";
@ -208,53 +165,39 @@
"onRequestMailMergeRecipients": onRequestMailMergeRecipients,
};
if (config.editorConfig.user.id) {
<% if (!string.IsNullOrEmpty(History) && !string.IsNullOrEmpty(HistoryData))
{ %>
config.events['onRequestHistory'] = function () { // the user is trying to show the document version history
docEditor.refreshHistory(<%= History %>); // show the document version history
};
config.events['onRequestHistoryData'] = function (event) { // the user is trying to click the specific document version in the document version history
var ver = event.data;
var histData = <%= HistoryData %>;
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
};
config.events['onRequestHistoryClose '] = function () { // the user is trying to go back to the document from viewing the document version history
document.location.reload();
};
<% } %>
// add mentions for not anonymous users
<% if (!string.IsNullOrEmpty(UsersForMentions))
{ %>
config.events['onRequestUsers'] = function () {
docEditor.setUsers({ // set a list of users to mention in the comments
"users": <%= UsersForMentions %>
});
};
<% } %>
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
// prevent file renaming for anonymous users
config.events['onRequestRename'] = onRequestRename;
}
if (config.editorConfig.createUrl) {
config.events.onRequestSaveAs = onRequestSaveAs;
<% if (!string.IsNullOrEmpty(History) && !string.IsNullOrEmpty(HistoryData))
{ %>
config.events['onRequestHistory'] = function () { // the user is trying to show the document version history
docEditor.refreshHistory(<%= History %>); // show the document version history
};
config.events['onRequestHistoryData'] = function (event) { // the user is trying to click the specific document version in the document version history
var ver = event.data;
var histData = <%= HistoryData %>;
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
};
config.events['onRequestHistoryClose '] = function () { // the user is trying to go back to the document from viewing the document version history
document.location.reload();
};
<% } %>
<% if (!string.IsNullOrEmpty(UsersForMentions))
{ %>
// add mentions for not anonymous users
config.events['onRequestUsers'] = function () {
docEditor.setUsers({ // set a list of users to mention in the comments
"users": <%= UsersForMentions %>
});
};
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
var actionLink = JSON.stringify(event.data.actionLink);
console.log("onRequestSendNotify:");
console.log(event.data);
console.log("Link to comment: " + replaceActionLink(location.href, actionLink));
};
<% } %>
var сonnectEditor = function () {
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
return;
}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

115
web/documentserver-example/csharp/DocEditor.aspx.cs Executable file → Normal file
View File

@ -41,7 +41,7 @@ namespace OnlineEditorsExample
// get url to the original file for Document Server
public static string FileUriUser
{
get { return Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ? getDownloadUrl(FileName) + "&dmode=emb" : _Default.FileUri(FileName, false); }
get { return _Default.FileUri(FileName, false); }
}
protected string Key
@ -81,7 +81,7 @@ namespace OnlineEditorsExample
+ "webeditor.ashx";
callbackUrl.Query = "type=track"
+ "&fileName=" + HttpUtility.UrlEncode(FileName)
+ "&userAddress=" + HttpUtility.UrlEncode(_Default.CurUserHostAddress(HttpContext.Current.Request.UserHostAddress));
+ "&userAddress=" + HttpUtility.UrlEncode(HttpContext.Current.Request.UserHostAddress);
return callbackUrl.ToString();
}
}
@ -100,18 +100,20 @@ namespace OnlineEditorsExample
}
// get url to download a file
public static string getDownloadUrl(string fileName, Boolean isServer = true)
public static string getDownloadUrl
{
var userAddress = isServer ? "&userAddress=" + HttpUtility.UrlEncode(_Default.CurUserHostAddress(HttpContext.Current.Request.UserHostAddress)) : "";
var downloadUrl = new UriBuilder(_Default.GetServerUrl(isServer));
get
{
var downloadUrl = new UriBuilder(_Default.GetServerUrl(true));
downloadUrl.Path =
HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "webeditor.ashx";
downloadUrl.Query = "type=download"
+ "&fileName=" + HttpUtility.UrlEncode(fileName)
+ userAddress;
+ "&fileName=" + HttpUtility.UrlEncode(FileName)
+ "&userAddress=" + HttpUtility.UrlEncode(HttpContext.Current.Request.UserHostAddress);
return downloadUrl.ToString();
}
}
// loading a page
@ -146,17 +148,12 @@ namespace OnlineEditorsExample
var editorsMode = Request.GetOrDefault("editorsMode", "edit");
var canEdit = _Default.EditedExts.Contains(ext); // check if this file can be edited
var mode = canEdit && editorsMode != "view" ? "edit" : "view"; // get the editor opening mode (edit or view)
var submitForm = canEdit && (editorsMode.Equals("edit") || editorsMode.Equals("fillForms")); // check if the Submit form button is displayed or hidden
var editorsType = Request.GetOrDefault("editorsType", "desktop");
var id = Request.Cookies.GetOrDefault("uid", null);
var user = Users.getUser(id); // get the user
if ((!canEdit && editorsMode.Equals("edit") || editorsMode.Equals("fillForms")) && _Default.FillFormsExts.Contains(ext)) {
editorsMode = "fillForms";
canEdit = true;
}
var submitForm = editorsMode.Equals("fillForms") && id.Equals("uid-1") && false; // check if the Submit form button is displayed or hidden
var mode = canEdit && editorsMode != "view" ? "edit" : "view"; // get the editor opening mode (edit or view)
var jss = new JavaScriptSerializer();
@ -166,7 +163,6 @@ namespace OnlineEditorsExample
var actionLink = Request.GetOrDefault("actionLink", null); // get the action link (comment or bookmark) if it exists
var actionData = string.IsNullOrEmpty(actionLink) ? null : jss.DeserializeObject(actionLink); // get action data for the action link
var directUrl = getDownloadUrl(FileName, false);
var createUrl = getCreateUrl(DocumentType, editorsType);
var templatesImageUrl = GetTemplateImageUrl(ext); // image url for templates
var templates = new List<Dictionary<string, string>>
@ -194,8 +190,7 @@ namespace OnlineEditorsExample
"document", new Dictionary<string, object>
{
{ "title", FileName },
{ "url", getDownloadUrl(FileName) },
{ "directUrl", directUrl },
{ "url", getDownloadUrl },
{ "fileType", ext.Trim('.') },
{ "key", Key },
{
@ -219,10 +214,8 @@ namespace OnlineEditorsExample
{ "modifyFilter", editorsMode != "filter" },
{ "modifyContentControl", editorsMode != "blockcontent" },
{ "review", canEdit && (editorsMode == "edit" || editorsMode == "review") },
{ "chat", !user.id.Equals("uid-0") },
{ "reviewGroups", user.reviewGroups },
{ "commentGroups", user.commentGroups },
{ "userInfoGroups", user.userInfoGroups }
{ "commentGroups", user.commentGroups }
}
}
}
@ -234,18 +227,13 @@ namespace OnlineEditorsExample
{ "mode", mode },
{ "lang", Request.Cookies.GetOrDefault("ulang", "en") },
{ "callbackUrl", CallbackUrl }, // absolute URL to the document storage service
{ "coEditing", editorsMode == "view" && user.id.Equals("uid-0") ?
new Dictionary<string, object>{
{"mode", "strict"},
{"change", false}
} : null },
{ "createUrl", !user.id.Equals("uid-0") ? createUrl : null },
{ "templates", user.templates ? templates : null },
{
// the user currently viewing or editing the document
"user", new Dictionary<string, object>
{
{ "id", !user.id.Equals("uid-0") ? user.id : null },
{ "id", user.id },
{ "name", user.name },
{ "group", user.group }
}
@ -254,9 +242,9 @@ namespace OnlineEditorsExample
// the parameters for the embedded document type
"embedded", new Dictionary<string, object>
{
{ "saveUrl", directUrl }, // the absolute URL that will allow the document to be saved onto the user personal computer
{ "embedUrl", directUrl }, // the absolute URL to the document serving as a source file for the document embedded into the web page
{ "shareUrl", directUrl }, // the absolute URL that will allow other users to share this document
{ "saveUrl", FileUriUser }, // the absolute URL that will allow the document to be saved onto the user personal computer
{ "embedUrl", FileUriUser }, // the absolute URL to the document serving as a source file for the document embedded into the web page
{ "shareUrl", FileUriUser }, // the absolute URL that will allow other users to share this document
{ "toolbarDocked", "top" } // the place for the embedded viewer toolbar (top or bottom)
}
},
@ -265,7 +253,6 @@ namespace OnlineEditorsExample
"customization", new Dictionary<string, object>
{
{ "about", true }, // the About section display
{ "comments", true },
{ "feedback", true }, // the Feedback & Support menu button display
{ "forcesave", false }, // adds the request for the forced file saving to the callback handler
{ "submitForm", submitForm }, // if the Submit form button is displayed or not
@ -326,7 +313,6 @@ namespace OnlineEditorsExample
// get the document history
private void GetHistory(out Dictionary<string, object> history, out Dictionary<string, object> historyData)
{
var storagePath = WebConfigurationManager.AppSettings["storage-path"];
var jss = new JavaScriptSerializer();
var histDir = _Default.HistoryDir(_Default.StoragePath(FileName, null));
@ -364,20 +350,8 @@ namespace OnlineEditorsExample
}
}
var ext = Path.GetExtension(FileName).ToLower();
dataObj.Add("fileType", ext.Replace(".", ""));
dataObj.Add("key", key);
// write file url to the data object
var directPrevFileUrl = i == currentVersion ? _Default.FileUri(FileName, false) : MakePublicHistoryUrl(FileName, i.ToString(), "prev" + ext, false);
var prevFileUrl = i == currentVersion ? FileUri : MakePublicHistoryUrl(FileName, i.ToString(), "prev" + ext);
if (Path.IsPathRooted(storagePath))
{
prevFileUrl = i == currentVersion ? getDownloadUrl(FileName) : getDownloadUrl(Directory.GetFiles(verDir, "prev.*")[0].Replace(storagePath + "\\", ""));
directPrevFileUrl = i == currentVersion ? getDownloadUrl(FileName, false) : getDownloadUrl(Directory.GetFiles(verDir, "prev.*")[0].Replace(storagePath + "\\", ""), false);
}
dataObj.Add("url", prevFileUrl); // write file url to the data object
dataObj.Add("directUrl", directPrevFileUrl); // write direct url to the data object
dataObj.Add("url", i == currentVersion ? FileUri : MakePublicUrl(Directory.GetFiles(verDir, "prev.*")[0])); // write file url to the data object
dataObj.Add("version", i);
if (i > 1) // check if the version number is greater than 1 (the file was modified)
{
@ -396,14 +370,11 @@ namespace OnlineEditorsExample
var prev = (Dictionary<string, object>)histData[(i - 2).ToString()]; // get the history data from the previous file version
dataObj.Add("previous", new Dictionary<string, object>() { // write information about previous file version to the data object
{ "fileType", prev["fileType"] },
{ "key", prev["key"] }, // write key and url information about previous file version
{ "url", prev["url"] },
{ "directUrl", prev["directUrl"] },
});
// write the path to the diff.zip archive with differences in this file version
var changesUrl = MakePublicHistoryUrl(FileName, (i - 1).ToString(), "diff.zip");
dataObj.Add("changesUrl", changesUrl);
dataObj.Add("changesUrl", MakePublicUrl(Path.Combine(_Default.VersionDir(histDir, i - 1), "diff.zip")));
}
if (JwtManager.Enabled)
{
@ -433,17 +404,11 @@ namespace OnlineEditorsExample
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "App_Themes\\images\\logo.png";
var DirectImageUrl = new UriBuilder(_Default.GetServerUrl(false));
DirectImageUrl.Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "App_Themes\\images\\logo.png";
// create a logo config
Dictionary<string, object> logoConfig = new Dictionary<string, object>
{
{ "fileType", "png"},
{ "url", InsertImageUrl.ToString()},
{ "directUrl", DirectImageUrl.ToString()}
{ "url", InsertImageUrl.ToString()}
};
if (JwtManager.Enabled) // if the secret key to generate token exists
@ -465,18 +430,11 @@ namespace OnlineEditorsExample
+ "webeditor.ashx";
compareFileUrl.Query = "type=assets&fileName=" + HttpUtility.UrlEncode("sample.docx");
var DirectFileUrl = new UriBuilder(_Default.GetServerUrl(false));
DirectFileUrl.Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "webeditor.ashx";
DirectFileUrl.Query = "type=assets&fileName=" + HttpUtility.UrlEncode("sample.docx");
// create an object with the information about the compared file
Dictionary<string, object> dataCompareFile = new Dictionary<string, object>
{
{ "fileType", "docx" },
{ "url", compareFileUrl.ToString() },
{ "directUrl", DirectFileUrl.ToString() }
{ "url", compareFileUrl.ToString() }
};
if (JwtManager.Enabled) // if the secret key to generate token exists
@ -499,19 +457,11 @@ namespace OnlineEditorsExample
+ "webeditor.ashx";
mailmergeUrl.Query = "type=csv";
var DirectMailMergeUrl = new UriBuilder(_Default.GetServerUrl(false));
DirectMailMergeUrl.Path =
HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "webeditor.ashx";
DirectMailMergeUrl.Query = "type=csv";
// create a mail merge config
Dictionary<string, object> mailMergeConfig = new Dictionary<string, object>
{
{ "fileType", "csv" },
{ "url", mailmergeUrl.ToString() },
{ "directUrl", DirectMailMergeUrl.ToString() }
{ "url", mailmergeUrl.ToString() }
};
if (JwtManager.Enabled) // if the secret key to generate token exists
@ -548,26 +498,10 @@ namespace OnlineEditorsExample
// create the public url
private string MakePublicUrl(string fullPath)
{
var root = Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ? WebConfigurationManager.AppSettings["storage-path"]
: HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"];
var root = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"];
return _Default.GetServerUrl(true) + fullPath.Substring(root.Length).Replace(Path.DirectorySeparatorChar, '/');
}
// create the public history url
private string MakePublicHistoryUrl(string filename, string version, string file, Boolean isServer = true)
{
var userAddress = isServer ? "&userAddress=" + HttpUtility.UrlEncode(_Default.CurUserHostAddress(HttpContext.Current.Request.UserHostAddress)) : "";
var fileUrl = new UriBuilder(_Default.GetServerUrl(isServer));
fileUrl.Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "webeditor.ashx";
fileUrl.Query = "type=downloadhistory&fileName=" + HttpUtility.UrlEncode(filename)
+ "&ver=" + version + "&file=" + file
+ userAddress;
return fileUrl.ToString();
}
// create demo document
private static void Try(string type, string sample, HttpRequest request)
{
@ -583,9 +517,6 @@ namespace OnlineEditorsExample
case "slide":
ext = ".pptx"; // .pptx for slide document type
break;
case "docxf":
ext = ".docxf";
break;
default:
return;
}

View File

@ -145,7 +145,11 @@ namespace ASC.Api.DocumentConverter
requestStream.Write(bytes, 0, bytes.Length); // and write the serialized body object to it
}
_Default.VerifySSL();
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if (_Default.IsMono)
{
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
}
string dataResponse;
using (var response = request.GetResponse())

View File

@ -16,12 +16,12 @@
*
*/
using JWT;
using JWT.Algorithms;
using JWT.Builder;
using JWT.Serializers;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Web.Configuration;
using System.Web.Script.Serialization;
namespace OnlineEditorsExample
{
@ -30,19 +30,31 @@ namespace OnlineEditorsExample
private static readonly string Secret;
public static readonly bool Enabled;
private static readonly JavaScriptSerializer Serializer;
static JwtManager()
{
Secret = WebConfigurationManager.AppSettings["files.docservice.secret"] ?? ""; // get token secret from the config parameters
Enabled = !string.IsNullOrEmpty(Secret); // check if the token is enabled
Serializer = new JavaScriptSerializer(); // define java script serializer
}
// encode a payload object into a token using a secret key
public static string Encode(IDictionary<string, object> payload)
{
var encoder = new JwtEncoder(new HMACSHA256Algorithm(),
new JsonNetSerializer(),
new JwtBase64UrlEncoder());
return encoder.Encode(payload, Secret);
// define the hashing algorithm and the token type
var header = new Dictionary<string, object>
{
{ "alg", "HS256" },
{ "typ", "JWT" }
};
// three parts of token
var encHeader = Base64UrlEncode(Serializer.Serialize(header)); // header
var encPayload = Base64UrlEncode(Serializer.Serialize(payload)); // payload
var hashSum = Base64UrlEncode(CalculateHash(encHeader, encPayload)); // signature
return string.Format("{0}.{1}.{2}", encHeader, encPayload, hashSum);
}
// decode a token into a payload object using a secret key
@ -50,11 +62,52 @@ namespace OnlineEditorsExample
{
if (!Enabled || string.IsNullOrEmpty(token)) return "";
return JwtBuilder.Create()
.WithAlgorithm(new HMACSHA256Algorithm())
.WithSecret(Secret)
.MustVerifySignature()
.Decode(token);
var split = token.Split('.');
if (split.Length != 3) return "";
var hashSum = Base64UrlEncode(CalculateHash(split[0], split[1])); // get signature
if (hashSum != split[2]) return ""; // and check if it is equal to the signature from the token
return Base64UrlDecode(split[1]); // decode payload
}
// generate a hash code based on a key using the HMAC method
private static byte[] CalculateHash(string encHeader, string encPayload)
{
using (var hasher = new HMACSHA256(Encoding.UTF8.GetBytes(Secret)))
{
var bytes = Encoding.UTF8.GetBytes(string.Format("{0}.{1}", encHeader, encPayload));
return hasher.ComputeHash(bytes);
}
}
// encode a string into the base64 value
private static string Base64UrlEncode(string str)
{
return Base64UrlEncode(Encoding.UTF8.GetBytes(str));
}
// encode bytes into the base64 value
private static string Base64UrlEncode(byte[] bytes)
{
return Convert.ToBase64String(bytes)
.TrimEnd('=').Replace('+', '-').Replace('/', '_');
}
// decode a base64 value into the string
private static string Base64UrlDecode(string payload)
{
var b64 = payload.Replace('_', '/').Replace('-', '+');
switch (b64.Length%4)
{
case 2:
b64 += "==";
break;
case 3:
b64 += "=";
break;
}
var bytes = Convert.FromBase64String(b64);
return Encoding.UTF8.GetString(bytes);
}
}
}

View File

@ -11,7 +11,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OnlineEditorsExample</RootNamespace>
<AssemblyName>OnlineEditorsExample</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
@ -23,8 +23,6 @@
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<TargetFrameworkProfile />
<Use64BitIISExpress />
<UseGlobalApplicationHostFile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -46,33 +44,27 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="JWT, Version=9.0.0.0, Culture=neutral, PublicKeyToken=6f98bca0f40f2ecf, processorArchitecture=MSIL">
<HintPath>packages\JWT.9.0.3\lib\net46\JWT.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="Microsoft.Web.Infrastructure">
<HintPath>packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.Helpers">
<HintPath>packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll</HintPath>
</Reference>
<Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.Razor">
<HintPath>packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll</HintPath>
</Reference>
<Reference Include="System.Web.Services" />
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.WebPages">
<HintPath>packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.WebPages.Deployment">
<HintPath>packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Web.WebPages.Razor">
<HintPath>packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
</Reference>
</ItemGroup>
@ -88,7 +80,6 @@
<Content Include="App_Themes\images\embeded.svg" />
<Content Include="App_Themes\images\error.svg" />
<Content Include="App_Themes\images\file_docx.svg" />
<Content Include="App_Themes\images\file_docxf.svg" />
<Content Include="App_Themes\images\file_pptx.svg" />
<Content Include="App_Themes\images\file_upload.svg" />
<Content Include="App_Themes\images\file_xlsx.svg" />
@ -99,7 +90,6 @@
<Content Include="App_Themes\images\icon_xlsx.svg" />
<Content Include="App_Themes\images\info.svg" />
<Content Include="App_Themes\images\logo.svg" />
<Content Include="App_Themes\images\mobile-fill-forms.svg" />
<Content Include="App_Themes\images\mobile.svg" />
<Content Include="App_Themes\images\notdone.svg" />
<Content Include="App_Themes\images\review.svg" />
@ -161,12 +151,10 @@
<Content Include="assets\AUTHORS.md" />
<Content Include="assets\LICENSE" />
<Content Include="assets\new\new.docx" />
<Content Include="assets\new\new.docxf" />
<Content Include="assets\new\new.pptx" />
<Content Include="assets\new\new.xlsx" />
<Content Include="assets\sample\csv.csv" />
<Content Include="assets\sample\sample.docx" />
<Content Include="assets\sample\sample.docxf" />
<Content Include="assets\sample\sample.pptx" />
<Content Include="assets\sample\sample.xlsx" />
<None Include="packages.config" />

View File

@ -2,11 +2,11 @@
This example will help you integrate ONLYOFFICE Docs into your web application written in .Net (C#).
**Please note**: It is intended for testing purposes and demonstrating functionality of the editors. Do NOT use this integration example on your own server without proper code modifications! In case you enabled the test example, disable it before going for production.
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
## Step 1. Install ONLYOFFICE Docs
Download and install ONLYOFFICE Docs (packaged as Document Server).
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx), [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx), or [for Docker](https://helpcenter.onlyoffice.com/server/developer-edition/docker/docker-installation.aspx).
@ -14,12 +14,11 @@ See the detailed guide to learn how to install Document Server [for Windows](htt
Download the [.Net (C#) example](https://api.onlyoffice.com/editors/demopreview) from our site.
To connect the editors to your website, specify the path to the editors installation and the path to the storage folder in the *settings.config* file:
Connect the editors to your website by specifying the path to the editors installation in the *settings.config* file:
```
<add key="storage-path" value=""/>
<add key="files.docservice.url.site" value="https://documentserver/" />
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed and the **storage-path** is the path where files will be created and stored. You can set an absolute path.
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) in the *DocEditor.aspx* file.
@ -29,23 +28,13 @@ Check that your system meets the requirements:
* **Microsoft .NET Framework**: version 4.5 (download it from the [official Microsoft website](https://www.microsoft.com/en-US/download/details.aspx?id=30653));
* **Internet Information Services**: version 7 or later.
Configure the IIS components for the server to work correctly:
1. Open Windows features:
**Start** -> **Control Panel** -> **Programs** -> **Programs and Features** -> **Turn Windows features on or off**
2. In the opened window, find **Internet Information Services** and choose all the necessary features. To do this, open the **World Wide Web Services** list and check the following components:
* **Application Development Features**: .NET Extensibility 4.8, ASP.NET 4.8, ISAPI Extensions, ISAPI Filters,
* **Common HTTP Features**: Default Document,
* **Security**: Request Filtering.
## Step 4. Run your website with the editors
1. Run the Internet Information Service (IIS) Manager:
**Start** -> **Control Panel** -> **System and Security** -> **Administrative Tools** -> **Internet Information Services (IIS) Manager**
2. Add your website in the IIS Manager.
On the **Connections** panel right-click the **Sites** node in the tree, then click **Add Website**.
![add](screenshots/add.png)
@ -57,7 +46,7 @@ Configure the IIS components for the server to work correctly:
![sitename](screenshots/sitename.png)
4. Check for the .NET platform version specified in IIS Manager for you website. Choose **v4.0.** version.
**Application Pools** -> right-click the platform name -> **Set application Pool defaults** -> **.NET CLR version**
![platform](screenshots/platform.png)
@ -72,12 +61,3 @@ Configure the IIS components for the server to work correctly:
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
Make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## Important security info
Please keep in mind the following security aspects when you are using test examples:
* There is no protection of the storage from unauthorized access since there is no need for authorization.
* There are no checks against parameter substitution in links, since the parameters are generated by the code according to the pre-arranged scripts.
* There are no data checks in requests of saving the file after editing, since each test example is intended for requests only from ONLYOFFICE Document Server.
* There are no prohibitions on using test examples from other sites, since they are intended to interact with ONLYOFFICE Document Server from another domain.

View File

@ -78,9 +78,7 @@ namespace OnlineEditorsExample
if (token != null && !token.Equals("")) // invalid signature error
{
fileData = jss.Deserialize<Dictionary<string, object>>(token);
if (fileData.ContainsKey("payload"))
fileData = (Dictionary<string, object>)fileData["payload"];
fileData = (Dictionary<string, object>)jss.Deserialize<Dictionary<string, object>>(token)["payload"];
}
else
{
@ -99,11 +97,7 @@ namespace OnlineEditorsExample
}
var downloadUri = (string)fileData["url"];
var curExt = Path.GetExtension(fileName).ToLower(); // get current file extension
var downloadExt = fileData.ContainsKey("filetype")
? "." + (string)fileData["filetype"]
: Path.GetExtension(downloadUri).ToLower() ?? ""; // TODO: Delete in version 7.0 or higher. Support for versions below 7.0
var downloadExt = Path.GetExtension(downloadUri).ToLower() ?? ""; // 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
@ -130,7 +124,11 @@ namespace OnlineEditorsExample
}
}
_Default.VerifySSL();
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if (_Default.IsMono)
{
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
}
var storagePath = _Default.StoragePath(newFileName, userAddress); // get the file path
var histDir = _Default.HistoryDir(storagePath); // get the path to the history directory
@ -177,11 +175,7 @@ namespace OnlineEditorsExample
var downloadUri = (string)fileData["url"];
string curExt = Path.GetExtension(fileName).ToLower(); // get current file extension
var downloadExt = fileData.ContainsKey("filetype")
? "." + (string)fileData["filetype"]
: Path.GetExtension(downloadUri).ToLower(); // TODO: Delete in version 7.0 or higher. Support for versions below 7.0
string downloadExt = Path.GetExtension(downloadUri).ToLower(); // 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
@ -207,7 +201,11 @@ namespace OnlineEditorsExample
}
}
_Default.VerifySSL();
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if (_Default.IsMono)
{
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
}
string forcesavePath = "";
Boolean isSubmitForm = fileData["forcesavetype"].ToString().Equals("3"); // SubmitForm
@ -252,10 +250,8 @@ namespace OnlineEditorsExample
}
// create a command request
public static void commandRequest(string method, string key, object meta = null)
public static void commandRequest(string method, string key)
{
_Default.VerifySSL();
string documentCommandUrl = WebConfigurationManager.AppSettings["files.docservice.url.site"] + WebConfigurationManager.AppSettings["files.docservice.url.command"];
var request = (HttpWebRequest)WebRequest.Create(documentCommandUrl);
@ -267,18 +263,13 @@ namespace OnlineEditorsExample
{ "key", key }
};
if (meta != null)
{
body.Add("meta", meta);
}
// check if a secret key to generate token exists or not
if (JwtManager.Enabled)
{
var payload = new Dictionary<string, object>
{
{ "payload", body }
};
{
{ "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

View File

@ -29,8 +29,7 @@ namespace OnlineEditorsExample
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can create files from templates using data from the editor",
"Can see the information about all users"
"Can create files from templates using data from the editor"
};
static List<string> descr_user_2 = new List<string>()
@ -39,21 +38,19 @@ namespace OnlineEditorsExample
"Can review only his own changes or changes made by users with no group",
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
"This file is marked as favorite",
"Can create new files from the editor",
"Can see the information about users from Group2 and users who dont belong to any group"
"Can create new files from the editor"
};
static List<string> descr_user_3 = new List<string>()
{
"Belongs to Group3",
"Can review changes made by Group2 users",
"Can view comments left by Group2 and Group3 users. Can edit comments left by the Group2 users",
"Can view comments left by Group2 and Group3 users. Can edit comments left by Group2 users",
"This file isnt marked as favorite",
"Cant copy data from the file to clipboard",
"Cant download the file",
"Cant print the file",
"Can create new files from the editor",
"Can see the information about Group2 users"
"Can create new files from the editor"
};
static List<string> descr_user_0 = new List<string>()
@ -64,11 +61,7 @@ namespace OnlineEditorsExample
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor",
"Cant see anyones information",
"Can't rename files from the editor",
"Can't view chat",
"View file without collaboration",
"Can't create new files from the editor"
};
private static List<User> users = new List<User>() {
@ -76,11 +69,10 @@ namespace OnlineEditorsExample
"uid-1",
"John Smith",
"smith@example.com",
"",
null,
null,
new Dictionary<string, object>(),
null,
null,
new List<string>(),
descr_user_1,
true
@ -97,7 +89,6 @@ namespace OnlineEditorsExample
{ "edit", new List<string>() { "group-2", "" } },
{ "remove", new List<string>() { "group-2" } }
},
new List<string>() { "group-2", "" },
true,
new List<string>(),
descr_user_2,
@ -115,7 +106,6 @@ namespace OnlineEditorsExample
{ "edit", new List<string>() { "group-2" } },
{ "remove", new List<string>() { } }
},
new List<string>() { "group-2" },
false,
new List<string>() { "copy", "download", "print" },
descr_user_3,
@ -125,10 +115,9 @@ namespace OnlineEditorsExample
"uid-0",
null,
null,
"",
null,
null,
new Dictionary<string, object>(),
new List<string>(),
null,
new List<string>(),
descr_user_0,
@ -184,9 +173,8 @@ namespace OnlineEditorsExample
public List<string> deniedPermissions;
public List<string> descriptions;
public bool templates;
public List<string> userInfoGroups;
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates)
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates)
{
this.id = id;
this.name = name;
@ -198,7 +186,6 @@ namespace OnlineEditorsExample
this.deniedPermissions = deniedPermissions;
this.descriptions = descriptions;
this.templates = templates;
this.userInfoGroups = userInfoGroups;
}
}
}

View File

@ -1,44 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appSettings configSource="settings.config" />
<appSettings configSource="settings.config"/>
<system.web>
<httpRuntime maxRequestLength="51200" />
<compilation debug="true" targetFramework="4.5" />
<authentication mode="Windows" />
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID" />
<httpRuntime maxRequestLength="51200"/>
<compilation debug="true" targetFramework="4.5"/>
<authentication mode="Windows"/>
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
</system.web>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="52428800" />
<requestLimits maxAllowedContentLength="52428800"/>
<denyUrlSequences>
<add sequence=".." />
<add sequence=".."/>
</denyUrlSequences>
<hiddenSegments>
<remove segment="App_Data" />
<remove segment="App_Data"/>
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -44,9 +44,6 @@ namespace OnlineEditorsExample
case "download":
Download(context);
break;
case "downloadhistory":
DownloadHistory(context);
break;
case "convert":
Convert(context);
break;
@ -65,26 +62,6 @@ namespace OnlineEditorsExample
case "files":
Files(context);
break;
case "saveas":
SaveAs(context);
break;
case "rename":
Rename(context);
break;
}
}
private static void SaveAs(HttpContext context)
{
context.Response.ContentType = "text/plain";
try
{
var result = _Default.DoSaveAs(context);
context.Response.Write(result);
}
catch (Exception e)
{
context.Response.Write("{ \"error\": \"" + 1 + "\", \"message\": \"" + e.Message + "\"}");
}
}
@ -141,7 +118,7 @@ namespace OnlineEditorsExample
var userAddress = context.Request["userAddress"];
var fileName = Path.GetFileName(context.Request["fileName"]);
var status = (TrackerStatus) (int) fileData["status"]; // get status from the request body
var saved = 0;
var saved = 1; // editing
switch (status)
{
case TrackerStatus.Editing:
@ -197,7 +174,7 @@ namespace OnlineEditorsExample
context.Response.Write("{\"error\":" + saved + "}");
return;
}
context.Response.Write("{\"error\":" + saved + "}");
context.Response.Write("{\"error\":0}");
}
// remove a file
@ -207,7 +184,7 @@ namespace OnlineEditorsExample
try
{
var fileName = Path.GetFileName(context.Request["fileName"]);
var path = _Default.StoragePath(fileName, HttpUtility.UrlEncode(_Default.CurUserHostAddress(HttpContext.Current.Request.UserHostAddress)));
var path = _Default.StoragePath(fileName, HttpUtility.UrlEncode(HttpContext.Current.Request.UserHostAddress));
var histDir = _Default.HistoryDir(path);
if (File.Exists(path)) File.Delete(path); // delete file
@ -277,11 +254,10 @@ namespace OnlineEditorsExample
{
try
{
var fileName = Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ? context.Request["fileName"] : Path.GetFileName(context.Request["fileName"]);
var fileName = Path.GetFileName(context.Request["fileName"]);
var userAddress = Path.GetFileName(context.Request["userAddress"]);
var isEmbedded = context.Request["dmode"];
if (JwtManager.Enabled && isEmbedded == null)
if (JwtManager.Enabled)
{
string JWTheader = WebConfigurationManager.AppSettings["files.docservice.header"].Equals("") ? "Authorization" : WebConfigurationManager.AppSettings["files.docservice.header"];
@ -328,86 +304,5 @@ namespace OnlineEditorsExample
{
get { return false; }
}
private static void DownloadHistory(HttpContext context)
{
try
{
var fileName = Path.GetFileName(context.Request["fileName"]);
var userAddress = Path.GetFileName(context.Request["userAddress"]);
var version = Path.GetFileName(context.Request["ver"]);
var file = Path.GetFileName(context.Request["file"]);
if (JwtManager.Enabled)
{
string JWTheader = WebConfigurationManager.AppSettings["files.docservice.header"].Equals("") ? "Authorization" : WebConfigurationManager.AppSettings["files.docservice.header"];
if (context.Request.Headers.AllKeys.Contains(JWTheader, StringComparer.InvariantCultureIgnoreCase))
{
var headerToken = context.Request.Headers.Get(JWTheader).Substring("Bearer ".Length);
string token = JwtManager.Decode(headerToken);
if (token == null || token.Equals(""))
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
context.Response.Write("JWT validation failed");
return;
}
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
context.Response.Write("JWT validation failed");
return;
}
}
var filePath = _Default.HistoryPath(fileName, userAddress, version, file); // get the path to the force saved document version
download(filePath, context);
}
catch (Exception)
{
context.Response.Write("{ \"error\": \"File not found!\"}");
}
}
// rename a file
private static void Rename(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;
}
}
catch (Exception e)
{
throw new HttpException((int)HttpStatusCode.BadRequest, e.Message);
}
var jss = new JavaScriptSerializer();
var body = jss.Deserialize<Dictionary<string, object>>(fileData);
var newFileName = (string) body["newfilename"];
var docKey = (string) body["dockey"];
var origExt = '.' + (string) body["ext"];
var curExt = Path.GetExtension(newFileName).ToLower();
if (string.Compare(origExt, curExt, true) != 0)
{
newFileName += origExt;
}
var meta = new Dictionary<string, object>() {
{ "title", newFileName }
};
TrackManager.commandRequest("meta", docKey, meta);
context.Response.Write("{ \"result\": \"OK\"}");
}
}
}

View File

@ -19,11 +19,3 @@ License File: jQuery.iframe-transport.license
jQuery.UI - jQuery UI is an open source library of interface components — interactions, full-featured widgets, and animation effects — based on the stellar jQuery javascript library . Each component is built according to jQuery's event-driven architecture (find something, manipulate it) and is themeable, making it easy for developers of any skill level to integrate and extend into their own code. (https://jquery.org/license/)
License: MIT
License File: jQuery.UI.license
JWT - JWT (JSON Web Token) Implementation for .NET (Public Domain) (https://github.com/jwt-dotnet/jwt/)
License: MIT
License File: JWT.license
Newtonsoft.Json - Json.NET is a popular high-performance JSON framework for .NET (https://github.com/JamesNK/Newtonsoft.Json)
License: MIT
License File: Newtonsoft.Json.license

View File

@ -1,21 +0,0 @@
# Public Domain
Written by John Sheehan (http://john-sheehan.com)
This work is public domain.
The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law.
For more information, please visit: http://creativecommons.org/publicdomain/zero/1.0/
# MIT
Copyright (c) 2019 Jwt.Net Maintainers and Contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For more information, please visit: https://opensource.org/licenses/MIT

View File

@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="JWT" version="9.0.3" targetFramework="net48" />
<package id="Microsoft.AspNet.Razor" version="3.2.7" targetFramework="net48" />
<package id="Microsoft.AspNet.WebPages" version="3.2.7" targetFramework="net48" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net48" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
<package id="Microsoft.AspNet.Razor" version="3.2.7" targetFramework="net45" />
<package id="Microsoft.AspNet.WebPages" version="3.2.7" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
</packages>

View File

@ -168,7 +168,7 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.');
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (EditedExtList.indexOf(posExt) != -1 || FillFormExtList.indexOf(posExt) != -1) {
if (EditedExtList.indexOf(posExt) != -1) {
jq("#beginEdit").removeClass("disable");
}
};

View File

@ -1,21 +1,17 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<appSettings>
<clear />
<add key="version" value="1.4.0"/>
<add key="version" value="1.0.0"/>
<add key="filesize-max" value="52428800"/>
<add key="storage-path" value=""/>
<add key="files.docservice.fillform-docs" value=".oform|.docx"/>
<add key="files.docservice.viewed-docs" value=".pdf|.djvu|.xps|.oxps"/>
<add key="files.docservice.edited-docs" value=".docx|.xlsx|.csv|.pptx|.txt|.docxf"/>
<add key="files.docservice.convert-docs" value=".docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xlsb|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2"/>
<add key="files.docservice.edited-docs" value=".docx|.xlsx|.csv|.pptx|.txt"/>
<add key="files.docservice.convert-docs" value=".docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2"/>
<add key="files.docservice.timeout" value="120000" />
<add key="files.docservice.secret" value="" />
<add key="files.docservice.header" value="Authorization" />
<add key="files.docservice.verify-peer-off" value="true"/>
<add key="files.docservice.languages" value="en:English|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (People's Republic of China)|zh-TW:Chinese (Traditional, Taiwan)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lv:Latvian|lo:Lao|ms:Malay (Malaysia)|nb:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese"/>
<add key="files.docservice.url.site" value="http://documentserver/"/>

View File

@ -1,18 +1,17 @@
## Overview
This example will help you integrate ONLYOFFICE Docs into your web application written in Java
with Spring Boot.
with Spring Boot.
Spring Boot has a lot of functionality, but its most significant features are: dependency management,
auto-configuration, and built-in servlet containers.
**Please note**: It is intended for testing purposes and demonstrating functionality of the editors. Do NOT use this integration example on your own server without proper code modifications! In case you enabled the test example, disable it before going for production.
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
## For Windows
### Step 1. Install ONLYOFFICE Docs
Download and install ONLYOFFICE Docs (packaged as Document Server).
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx).
@ -20,15 +19,16 @@ See the detailed guide to learn how to install Document Server [for Windows](htt
Download the [Java-Spring example](https://api.onlyoffice.com/editors/demopreview) from our site.
To connect the editors to your website, specify the path to the editors installation, server port and the path to the storage folder in the *\src\main\resources\application.properties* file:
To connect the editors to your website, specify the path to the editors installation, server address and port in the *\src\main\resources\application.properties* file:
```
files.storage=
server.address=address
server.port=port
files.docservice.url.site=https://documentserver/
```
where the **documentserver** is the name of the server with the ONLYOFFICE Docs installed, **port** is any available port and **files.storage** is the path where files will be created and stored (in the project folder by default). You can set an absolute path. For example, *D:\\\\folder*. Please note that on Windows OS the double backslash must be used as a separator.
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
**address** is the address of the server or comment this line to use localhost, **port** is the any available port.
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) it the *\src\main\resources\editor.html* file.
@ -65,11 +65,11 @@ To run the Java example code, install the Java version 11 appropriate for your O
```
echo %JAVA_HOME%
```
2. Set the **MAVEN_HOME** environment variable:
Unzip the downloaded archive with the maven to any directory, it will be something like this:
```
C:\apache-maven-3.8.1
```
@ -87,7 +87,7 @@ To run the Java example code, install the Java version 11 appropriate for your O
Add C:\apache-maven-3.8.1\bin to the PATH system variable:
In system variables, find PATH, clicks on the Edit... button. In “Edit environment variable” dialog, clicks on the New button and add this C:\apache-maven-3.8.1\bin
Check if the variable created successfully by **echo** command in the **Command Prompt**:
```
@ -112,6 +112,8 @@ To run the Java example code, install the Java version 11 appropriate for your O
```
http://server.address:server.port/
```
### Step 6. Check accessibility
@ -149,8 +151,8 @@ See the detailed guide to learn how to install Document Server [for Linux](https
```
git clone https://github.com/ONLYOFFICE/document-server-integration.git
```
3. Change the current directory for the project directory:
a) from archive
@ -171,13 +173,13 @@ See the detailed guide to learn how to install Document Server [for Linux](https
Edit the following lines:
```
files.storage=
server.address=address
server.port=port
files.docservice.url.site=https://documentserver/
```
where the **documentserver** is the name of the server with the ONLYOFFICE Docs installed, **port** is any available port and **files.storage** is the path where files will be created and stored (in the project folder by default). You can set an absolute path.
Where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
**address** is the address of the server or comment this line to use localhost, **port** is the any available port.
5. Install **Maven**:
@ -190,18 +192,19 @@ See the detailed guide to learn how to install Document Server [for Linux](https
```
mvn package
```
7. Start Java-Spring example:
```
./mvnw spring-boot:run
```
8. Open your browser using **server.address** and **server.port**:
```
http://server.address:server.port/
```
### Step 3. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
@ -219,12 +222,13 @@ Make sure that the Document Server has access to the server with the example ins
2. Edit the following lines:
```
files.storage=
server.address=address
server.port=port
files.docservice.url.site=https://documentserver/
```
where the **documentserver** is the name of the server with the ONLYOFFICE Docs installed, **port** is any available port and **files.storage** is the path where files will be created and stored (in the project folder by default). You can set an absolute path.
Where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
**address** is the address of the server or comment this line to use localhost, **port** is the any available port.
3. Run the next command in the java example directory:
@ -232,16 +236,7 @@ Make sure that the Document Server has access to the server with the example ins
docker-compose up
```
4. Open your browser using **server.address** and **server.port**:
```
http://server.address:server.port/
```
## Important security info
Please keep in mind the following security aspects when you are using test examples:
* There is no protection of the storage from unauthorized access since there is no need for authorization.
* There are no checks against parameter substitution in links, since the parameters are generated by the code according to the pre-arranged scripts.
* There are no data checks in requests of saving the file after editing, since each test example is intended for requests only from ONLYOFFICE Document Server.
* There are no prohibitions on using test examples from other sites, since they are intended to interact with ONLYOFFICE Document Server from another domain.

View File

@ -7,9 +7,7 @@ services:
image: maven:3.8.1
working_dir: /java-spring
volumes:
- .:/java-spring
ports:
- 4000:4000
- .:/java-spring
command: mvn clean spring-boot:run

34
web/documentserver-example/java-spring/pom.xml Normal file → Executable file
View File

@ -48,7 +48,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>com.inversoft</groupId>
@ -61,15 +61,10 @@
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4.2</version>
<version>2.12.2</version>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
@ -83,31 +78,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.17</version>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<configuration>
<configLocation>google_checks.xml</configLocation>
<encoding>UTF-8</encoding>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
<logViolationsToConsole>true</logViolationsToConsole>
<violationSeverity>warning</violationSeverity>
<consoleOutput>true</consoleOutput>
<includeTestSourceDirectory>true
</includeTestSourceDirectory>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -33,39 +33,31 @@ public class ExampleData {
private UserServices userService;
@PostConstruct
public void init(){
List<String> description_user_0=List.of( // the description for user 0
List<String> description_user_0=List.of(
"The name is requested when the editor is opened",
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor",
"Cant see anyones information",
"Can't rename files from the editor",
"Can't view chat",
"View file without collaboration"
"Can't create new files from the editor"
);
List<String> description_user_1 = List.of( // the description for user 1
List<String> description_user_1 = List.of(
"File author by default",
"He doesnt belong to any of the groups",
"He can review all the changes",
"He can do everything with the comments",
"The file favorite state is undefined",
"Can create a file from a template with data from the editor",
"Can see the information about all users",
"Can view chat"
"Can create a file from a template with data from the editor"
);
List<String> description_user_2 = List.of( // the description for user 2
List<String> description_user_2 = List.of(
"He belongs to Group2",
"He can review only his own changes or the changes made by the users who dont belong to any of the groups",
"He can view every comment, edit his comments and the comments left by the users who don't belong to any of the groups and remove only his comments",
"This file is favorite",
"Can create a file from an editor",
"Can see the information about users from Group2 and users who dont belong to any group",
"Can view chat"
"Can create a file from an editor"
);
List<String> description_user_3 = List.of( // the description for user 3
List<String> description_user_3 = List.of(
"He belongs to Group3",
"He can review only the changes made by the users from Group2",
"He can view the comments left by the users from Group2 and Group3 and edit the comments left by the users from Group2",
@ -73,28 +65,21 @@ public class ExampleData {
"He cant copy data from the file into the clipboard",
"He cant download the file",
"He cant print the file",
"Can create a file from an editor",
"Can see the information about Group2 users",
"Can view chat"
"Can create a file from an editor"
);
userService.createUser("John Smith", "smith@example.com", // create user 1 with the specified parameters
description_user_1, "", List.of(FilterState.NULL.toString()),
userService.createUser("John Smith", "smith@example.com",
description_user_1, null, List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()),
null, true);
userService.createUser("Mark Pottato", "pottato@example.com", // create user 2 with the specified parameters
List.of(FilterState.NULL.toString()), null);
userService.createUser("Mark Pottato", "pottato@example.com",
description_user_2, "group-2", List.of("","group-2"), List.of(FilterState.NULL.toString()),
List.of("group-2", ""), List.of("group-2"), List.of("group-2", ""), true,
true);
userService.createUser("Hamish Mitchell", "mitchell@example.com", // create user 3 with the specified parameters
List.of("group-2", ""), List.of("group-2"), true);
userService.createUser("Hamish Mitchell", "mitchell@example.com",
description_user_3, "group-3", List.of("group-2"), List.of("group-2", "group-3"),
List.of("group-2"), new ArrayList<>(), List.of("group-2"), false,
true);
userService.createUser("Anonymous",null, // create user 0 with the specified parameters
description_user_0,"", List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()), new ArrayList<>(),null,
false);
List.of("group-2"), new ArrayList<>(), false);
userService.createUser("Anonymous",null,
description_user_0,null, List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()), null);
}
}

View File

@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class IntegrationApplication {
// run the SpringApplication from the IntagrationApplication with the specified parameters
public static void main(String[] args) {
SpringApplication.run(IntegrationApplication.class, args);
}

View File

@ -30,57 +30,38 @@ import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import com.onlyoffice.integration.documentserver.util.SSLUtils;
@Configuration
public class IntegrationConfiguration {
@Value("${files.storage}")
private String storageAddress;
@Value("${files.docservice.verify-peer-off}")
private String verifyPerrOff;
@Autowired
private FileStoragePathBuilder storagePathBuilder;
@Autowired
private SSLUtils ssl;
@Bean
public ModelMapper mapper(){ // create the model mapper
public ModelMapper mapper(){
ModelMapper mapper = new ModelMapper();
mapper.getConfiguration() // get the mapper configuration and set new parameters to it
.setMatchingStrategy(MatchingStrategies.STRICT) // specify the STRICT matching strategy
.setFieldMatchingEnabled(true) // define if the field matching is enabled or not
.setSkipNullEnabled(true) // define if null value will be skipped or not
.setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE); // specify the PRIVATE field access level
mapper.getConfiguration()
.setMatchingStrategy(MatchingStrategies.STRICT)
.setFieldMatchingEnabled(true)
.setSkipNullEnabled(true)
.setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE);
return mapper;
}
@Bean
public JSONParser jsonParser(){ // create JSON parser
public JSONParser jsonParser(){
return new JSONParser();
}
@PostConstruct
public void init(){ // initialize the storage path builder
public void init(){
storagePathBuilder.configure(storageAddress.isBlank() ? null : storageAddress);
if(!verifyPerrOff.isEmpty()) {
try{
if(verifyPerrOff.equals("true")) {
ssl.turnOffSslChecking(); //the certificate will be ignored
} else {
ssl.turnOnSslChecking(); //the certificate will be verified
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
@Bean
public ObjectMapper objectMapper(){ // create the object mapper
public ObjectMapper objectMapper(){
return new ObjectMapper();
}
}

View File

@ -26,6 +26,7 @@ import com.onlyoffice.integration.documentserver.models.enums.Action;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.integration.entities.User;
import com.onlyoffice.integration.dto.Mentions;
import com.onlyoffice.integration.documentserver.models.enums.Language;
import com.onlyoffice.integration.documentserver.models.enums.Type;
import com.onlyoffice.integration.documentserver.models.filemodel.FileModel;
import com.onlyoffice.integration.services.UserServices;
@ -52,9 +53,6 @@ public class EditorController {
@Value("${files.docservice.url.api}")
private String docserviceApiUrl;
@Value("${files.docservice.languages}")
private String langs;
@Autowired
private FileStoragePathBuilder storagePathBuilder;
@ -74,7 +72,6 @@ public class EditorController {
private FileConfigurer<DefaultFileWrapper> fileConfigurer;
@GetMapping(path = "${url.editor}")
// process request to open the editor page
public String index(@RequestParam("fileName") String fileName,
@RequestParam(value = "action", required = false) String actionParam,
@RequestParam(value = "type", required = false) String typeParam,
@ -84,58 +81,47 @@ public class EditorController {
Model model) throws JsonProcessingException {
Action action = Action.edit;
Type type = Type.desktop;
Locale locale = new Locale("en");
Language language = Language.en;
if(actionParam != null) action = Action.valueOf(actionParam);
if(typeParam != null) type = Type.valueOf(typeParam);
List<String> langsAndKeys = Arrays.asList(langs.split("\\|"));
for (String langAndKey : langsAndKeys) {
String[] couple = langAndKey.split(":");
if (couple[0].equals(lang)) {
String[] langAndCountry = couple[0].split("-");
locale = new Locale(langAndCountry[0], langAndCountry.length > 1 ? langAndCountry[1] : "");
}
}
if(lang != null) language = Language.valueOf(lang);
Optional<User> optionalUser = userService.findUserById(Integer.parseInt(uid));
// if the user is not present, return the ONLYOFFICE start page
if(!optionalUser.isPresent()) return "index.html";
User user = optionalUser.get();
// get file model with the default file parameters
FileModel fileModel = fileConfigurer.getFileModel(
DefaultFileWrapper
.builder()
.fileName(fileName)
.type(type)
.lang(locale.toLanguageTag())
.lang(language)
.action(action)
.user(user)
.actionData(actionLink)
.build()
);
// add attributes to the specified model
model.addAttribute("model", fileModel); // add file model with the default parameters to the original model
model.addAttribute("fileHistory", historyManager.getHistory(fileModel.getDocument())); // get file history and add it to the model
model.addAttribute("docserviceApiUrl",docserviceSite + docserviceApiUrl); // create the document service api URL and add it to the model
model.addAttribute("dataInsertImage", getInsertImage()); // get an image and add it to the model
model.addAttribute("dataCompareFile", getCompareFile()); // get a document for comparison and add it to the model
model.addAttribute("dataMailMergeRecipients", getMailMerge()); // get recipients data for mail merging and add it to the model
model.addAttribute("usersForMentions", getUserMentions(uid)); // get user data for mentions and add it to the model
model.addAttribute("model", fileModel);
model.addAttribute("fileHistory", historyManager.getHistory(fileModel.getDocument()));
model.addAttribute("docserviceApiUrl",docserviceSite + docserviceApiUrl);
model.addAttribute("dataInsertImage", getInsertImage());
model.addAttribute("dataCompareFile", getCompareFile());
model.addAttribute("dataMailMergeRecipients", getMailMerge());
model.addAttribute("usersForMentions", getUserMentions(uid));
return "editor.html";
}
private List<Mentions> getUserMentions(String uid){ // get user data for mentions
private List<Mentions> getUserMentions(String uid){
List<Mentions> usersForMentions=new ArrayList<>();
if(uid!=null && !uid.equals("4")) {
List<User> list = userService.findAll();
for (User u : list) {
if (u.getId()!=Integer.parseInt(uid) && u.getId()!=4) {
usersForMentions.add(new Mentions(u.getName(),u.getEmail())); // user data includes user names and emails
usersForMentions.add(new Mentions(u.getName(),u.getEmail()));
}
}
}
@ -144,30 +130,26 @@ public class EditorController {
}
@SneakyThrows
private String getInsertImage() { // get an image that will be inserted into the document
private String getInsertImage() {
Map<String, Object> dataInsertImage = new HashMap<>();
dataInsertImage.put("fileType", "png");
dataInsertImage.put("url", storagePathBuilder.getServerUrl(true) + "/css/img/logo.png");
dataInsertImage.put("directUrl", storagePathBuilder.getServerUrl(false) + "/css/img/logo.png");
// check if the document token is enabled
if(jwtManager.tokenEnabled()){
dataInsertImage.put("token", jwtManager.createToken(dataInsertImage)); // create token from the dataInsertImage object
dataInsertImage.put("token", jwtManager.createToken(dataInsertImage));
}
return objectMapper.writeValueAsString(dataInsertImage).substring(1, objectMapper.writeValueAsString(dataInsertImage).length()-1);
}
@SneakyThrows
private String getCompareFile(){ // get a document that will be compared with the current document
private String getCompareFile(){
Map<String, Object> dataCompareFile = new HashMap<>();
dataCompareFile.put("fileType", "docx");
dataCompareFile.put("url", storagePathBuilder.getServerUrl(true) + "/assets?name=sample.docx");
dataCompareFile.put("directUrl", storagePathBuilder.getServerUrl(false) + "/assets?name=sample.docx");
// check if the document token is enabled
if(jwtManager.tokenEnabled()){
dataCompareFile.put("token", jwtManager.createToken(dataCompareFile)); // create token from the dataCompareFile object
dataCompareFile.put("token", jwtManager.createToken(dataCompareFile));
}
return objectMapper.writeValueAsString(dataCompareFile);
@ -175,14 +157,12 @@ public class EditorController {
@SneakyThrows
private String getMailMerge(){
Map<String, Object> dataMailMergeRecipients = new HashMap<>(); // get recipients data for mail merging
Map<String, Object> dataMailMergeRecipients = new HashMap<>();
dataMailMergeRecipients.put("fileType", "csv");
dataMailMergeRecipients.put("url", storagePathBuilder.getServerUrl(true) + "/csv");
dataMailMergeRecipients.put("directUrl", storagePathBuilder.getServerUrl(false) + "/csv");
// check if the document token is enabled
if(jwtManager.tokenEnabled()){
dataMailMergeRecipients.put("token", jwtManager.createToken(dataMailMergeRecipients)); // create token from the dataMailMergeRecipients object
dataMailMergeRecipients.put("token", jwtManager.createToken(dataMailMergeRecipients));
}
return objectMapper.writeValueAsString(dataMailMergeRecipients);

View File

@ -31,7 +31,6 @@ import com.onlyoffice.integration.services.UserServices;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -59,15 +58,6 @@ public class FileController {
@Value("${files.docservice.header}")
private String documentJwtHeader;
@Value("${filesize-max}")
private String filesizeMax;
@Value("${files.docservice.url.site}")
private String docserviceUrlSite;
@Value("${files.docservice.url.command}")
private String docserviceUrlCommand;
@Autowired
private FileUtility fileUtility;
@Autowired
@ -86,39 +76,22 @@ public class FileController {
private ObjectMapper objectMapper;
@Autowired
private ServiceConverter serviceConverter;
@Autowired
private CallbackManager callbackManager;
// create user metadata
private String createUserMetadata(String uid, String fullFileName) {
Optional<User> optionalUser = userService.findUserById(Integer.parseInt(uid)); // find a user by their ID
String documentType = fileUtility.getDocumentType(fullFileName).toString().toLowerCase(); // get document type
Optional<User> optionalUser = userService.findUserById(Integer.parseInt(uid));
String documentType = fileUtility.getDocumentType(fullFileName).toString().toLowerCase();
if(optionalUser.isPresent()){
User user = optionalUser.get();
storageMutator.createMeta(fullFileName, // create meta information with the user ID and name specified
storageMutator.createMeta(fullFileName,
String.valueOf(user.getId()), user.getName());
}
return "{ \"filename\": \"" + fullFileName + "\", \"documentType\": \"" + documentType + "\" }";
}
// download data from the specified file
private ResponseEntity<Resource> downloadFile(String fileName){
Resource resource = storageMutator.loadFileAsResource(fileName); // load the specified file as a resource
Resource resource = storageMutator.loadFileAsResource(fileName);
String contentType = "application/octet-stream";
// create a response with the content type, header and body with the file data
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
// download data from the specified history file
private ResponseEntity<Resource> downloadFileHistory(String fileName, String version, String file){
Resource resource = storageMutator.loadFileAsResourceHistory(fileName,version,file); // load the specified file as a resource
String contentType = "application/octet-stream";
// create a response with the content type, header and body with the file data
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
@ -127,159 +100,130 @@ public class FileController {
@PostMapping("/upload")
@ResponseBody
public String upload(@RequestParam("file") MultipartFile file, // upload a file
public String upload(@RequestParam("file") MultipartFile file,
@CookieValue("uid") String uid){
try {
String fullFileName = file.getOriginalFilename(); // get file name
String fileExtension = fileUtility.getFileExtension(fullFileName); // get file extension
long fileSize = file.getSize(); // get file size
byte[] bytes = file.getBytes(); // get file in bytes
String fullFileName = file.getOriginalFilename();
String fileExtension = fileUtility.getFileExtension(fullFileName);
long fileSize = file.getSize();
byte[] bytes = file.getBytes();
// check if the file size exceeds the maximum file size or is less than 0
if(fileUtility.getMaxFileSize() < fileSize || fileSize <= 0){
return "{ \"error\": \"File size is incorrect\"}"; // if so, write an error message to the response
return "{ \"error\": \"File size is incorrect\"}";
}
// check if file extension is supported by the editor
if(!fileUtility.getFileExts().contains(fileExtension)){
return "{ \"error\": \"File type is not supported\"}"; // if not, write an error message to the response
return "{ \"error\": \"File type is not supported\"}";
}
String fileNamePath = storageMutator.updateFile(fullFileName, bytes); // update a file
String fileNamePath = storageMutator.updateFile(fullFileName, bytes);
if (fileNamePath.isBlank()){
throw new IOException("Could not update a file"); // if the file cannot be updated, an error occurs
throw new IOException("Could not update a file");
}
fullFileName = fileUtility.getFileNameWithoutExtension(fileNamePath) + fileExtension; // get full file name
fullFileName = fileUtility.getFileNameWithoutExtension(fileNamePath) + fileExtension;
return createUserMetadata(uid, fullFileName); // create user metadata and return it
return createUserMetadata(uid, fullFileName);
} catch (Exception e) {
e.printStackTrace();
}
return "{ \"error\": \"Something went wrong when uploading the file.\"}"; // if the operation of file uploading is unsuccessful, an error occurs
return "{ \"error\": \"Something went wrong when uploading the file.\"}";
}
@PostMapping(path = "${url.converter}")
@ResponseBody
public String convert(@RequestBody Converter body, // convert a file
public String convert(@RequestBody Converter body,
@CookieValue("uid") String uid, @CookieValue("ulang") String lang){
String fileName = body.getFileName(); // get file name
String fileUri = documentManager.getDownloadUrl(fileName, true); // get URL for downloading a file with the specified name
String filePass = body.getFilePass() != null ? body.getFilePass() : null; // get file password if it exists
String fileExt = fileUtility.getFileExtension(fileName); // get file extension
DocumentType type = fileUtility.getDocumentType(fileName); // get document type (word, cell or slide)
String internalFileExt = fileUtility.getInternalExtension(type); // get an editor internal extension (".docx", ".xlsx" or ".pptx")
String fileName = body.getFileName();
String fileUri = documentManager.getDownloadUrl(fileName);
String filePass = body.getFilePass() != null ? body.getFilePass() : null;
String fileExt = fileUtility.getFileExtension(fileName);
DocumentType type = fileUtility.getDocumentType(fileName);
String internalFileExt = fileUtility.getInternalExtension(type);
try{
if(fileUtility.getConvertExts().contains(fileExt)){ // check if the file with such an extension can be converted
String key = serviceConverter.generateRevisionId(fileUri); // generate document key
String newFileUri = serviceConverter // get the URL to the converted file
if(fileUtility.getConvertExts().contains(fileExt)){
String key = serviceConverter.generateRevisionId(fileUri);
String newFileUri = serviceConverter
.getConvertedUri(fileUri, fileExt, internalFileExt, key, filePass, true, lang);
if(newFileUri.isEmpty()){
return "{ \"step\" : \"0\", \"filename\" : \"" + fileName + "\"}";
}
// get a file name of an internal file extension with an index if the file with such a name already exists
String nameWithInternalExt = fileUtility.getFileNameWithoutExtension(fileName) + internalFileExt;
String correctedName = documentManager.getCorrectName(nameWithInternalExt);
URL url = new URL(newFileUri);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
InputStream stream = connection.getInputStream(); // get input stream of the converted file
InputStream stream = connection.getInputStream();
if (stream == null){
connection.disconnect();
throw new RuntimeException("Input stream is null");
}
// create the converted file with input stream
storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(correctedName)), stream);
fileName = correctedName;
}
// create meta information about the converted file with the user ID and name specified
return createUserMetadata(uid, fileName);
}catch (Exception e) {
e.printStackTrace();
}
return "{ \"error\": \"" + "The file can't be converted.\"}"; // if the operation of file converting is unsuccessful, an error occurs
return "{ \"error\": \"" + "The file can't be converted.\"}";
}
@PostMapping("/delete")
@ResponseBody
public String delete(@RequestBody Converter body){ // delete a file
public String delete(@RequestBody Converter body){
try
{
String fullFileName = fileUtility.getFileName(body.getFileName()); // get full file name
boolean fileSuccess = storageMutator.deleteFile(fullFileName); // delete a file from the storage and return the status of this operation (true or false)
boolean historySuccess = storageMutator.deleteFileHistory(fullFileName); // delete file history and return the status of this operation (true or false)
String fullFileName = fileUtility.getFileName(body.getFileName());
boolean fileSuccess = storageMutator.deleteFile(fullFileName);
boolean historySuccess = storageMutator.deleteFileHistory(fullFileName);
return "{ \"success\": \""+ (fileSuccess && historySuccess) +"\"}";
}
catch (Exception e)
{
return "{ \"error\": \"" + e.getMessage() + "\"}"; // if the operation of file deleting is unsuccessful, an error occurs
}
}
@GetMapping("/downloadhistory")
public ResponseEntity<Resource> downloadHistory(HttpServletRequest request,// download a file
@RequestParam("fileName") String fileName,
@RequestParam("ver") String version,
@RequestParam("file") String file){ // history file
try{
// check if a token is enabled or not
if(jwtManager.tokenEnabled()){
String header = request.getHeader(documentJwtHeader == null // get the document JWT header
|| documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader);
if(header != null && !header.isEmpty()){
String token = header.replace("Bearer ", ""); // token is the header without the Bearer prefix
jwtManager.readToken(token); // read the token
}else {
return null;
}
}
return downloadFileHistory(fileName,version,file); // download data from the specified file
} catch(Exception e){
return null;
return "{ \"error\": \"" + e.getMessage() + "\"}";
}
}
@GetMapping(path = "${url.download}")
public ResponseEntity<Resource> download(HttpServletRequest request, // download a file
public ResponseEntity<Resource> download(HttpServletRequest request,
@RequestParam("fileName") String fileName){
try{
// check if a token is enabled or not
if(jwtManager.tokenEnabled()){
String header = request.getHeader(documentJwtHeader == null // get the document JWT header
String header = request.getHeader(documentJwtHeader == null
|| documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader);
if(header != null && !header.isEmpty()){
String token = header.replace("Bearer ", ""); // token is the header without the Bearer prefix
jwtManager.readToken(token); // read the token
String token = header.replace("Bearer ", "");
jwtManager.readToken(token);
}
}
return downloadFile(fileName); // download data from the specified file
return downloadFile(fileName);
} catch(Exception e){
return null;
}
}
@GetMapping("/create")
public String create(@RequestParam("fileExt") String fileExt, // create a sample file of the specified extension
public String create(@RequestParam("fileExt") String fileExt,
@RequestParam(value = "sample", required = false) Optional<Boolean> isSample,
@CookieValue(value = "uid", required = false) String uid,
Model model){
Boolean sampleData = (isSample.isPresent() && !isSample.isEmpty()) && isSample.get(); // specify if the sample data exists or not
Boolean sampleData = (isSample.isPresent() && !isSample.isEmpty()) && isSample.get();
if(fileExt != null){
try{
Optional<User> user = userService.findUserById(Integer.parseInt(uid)); // find a user by their ID
if (!user.isPresent()) throw new RuntimeException("Could not fine any user with id = "+uid); // if the user with the specified ID doesn't exist, an error occurs
String fileName = documentManager.createDemo(fileExt, sampleData, uid, user.get().getName()); // create a demo document with the sample data
Optional<User> user = userService.findUserById(Integer.parseInt(uid));
if (!user.isPresent()) throw new RuntimeException("Could not fine any user with id = "+uid);
String fileName = documentManager.createDemo(fileExt, sampleData, uid, user.get().getName());
if (fileName.isBlank() || fileName == null) {
throw new RuntimeException("You must have forgotten to add asset files");
}
return "redirect:editor?fileName=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8); // redirect the request
return "redirect:editor?fileName=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8);
}catch (Exception ex){
model.addAttribute("error", ex.getMessage());
return "error.html";
@ -289,14 +233,14 @@ public class FileController {
}
@GetMapping("/assets")
public ResponseEntity<Resource> assets(@RequestParam("name") String name) // get sample files from the assests
public ResponseEntity<Resource> assets(@RequestParam("name") String name)
{
String fileName = Path.of("assets", "sample", fileUtility.getFileName(name)).toString();
return downloadFile(fileName);
}
@GetMapping("/csv")
public ResponseEntity<Resource> csv() // download a csv file
public ResponseEntity<Resource> csv()
{
String fileName = Path.of("assets", "sample", "csv.csv").toString();
return downloadFile(fileName);
@ -304,27 +248,27 @@ public class FileController {
@GetMapping("/files")
@ResponseBody
public ArrayList<Map<String, Object>> files(@RequestParam(value = "fileId", required = false) String fileId){ // get files information
public ArrayList<Map<String, Object>> files(@RequestParam(value = "fileId", required = false) String fileId){
return fileId == null ? documentManager.getFilesInfo() : documentManager.getFilesInfo(fileId);
}
@PostMapping(path = "${url.track}")
@ResponseBody
public String track(HttpServletRequest request, // track file changes
public String track(HttpServletRequest request,
@RequestParam("fileName") String fileName,
@RequestParam("userAddress") String userAddress,
@RequestBody Track body){
try {
String bodyString = objectMapper.writeValueAsString(body); // write the request body to the object mapper as a string
String header = request.getHeader(documentJwtHeader == null // get the request header
String bodyString = objectMapper.writeValueAsString(body);
String header = request.getHeader(documentJwtHeader == null
|| documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader);
if (bodyString.isEmpty()) { // if the request body is empty, an error occurs
if (bodyString.isEmpty()) {
throw new RuntimeException("{\"error\":1,\"message\":\"Request payload is empty\"}");
}
JSONObject bodyCheck = jwtManager.parseBody(bodyString, header); // parse the request body
body = objectMapper.readValue(bodyCheck.toJSONString(), Track.class); // read the request body
JSONObject bodyCheck = jwtManager.parseBody(bodyString, header);
body = objectMapper.readValue(bodyCheck.toJSONString(), Track.class);
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
@ -334,63 +278,4 @@ public class FileController {
return"{\"error\":" + error + "}";
}
@PostMapping("/saveas")
@ResponseBody
public String saveAs(@RequestBody JSONObject body, @CookieValue("uid") String uid) {
String title = (String) body.get("title");
String saveAsFileUrl = (String) body.get("url");
try {
String fileName = documentManager.getCorrectName(title);
String curExt = fileUtility.getFileExtension(fileName);
if (!fileUtility.getFileExts().contains(curExt)) {
return "{\"error\":\"File type is not supported\"}";
}
URL url = new URL(saveAsFileUrl);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
InputStream stream = connection.getInputStream();
if (Integer.parseInt(filesizeMax) < stream.available() || stream.available() <= 0) {
return "{\"error\":\"File size is incorrect\"}";
}
storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(fileName)), stream);
createUserMetadata(uid, fileName);
return "{\"file\": \"" + fileName + "\"}";
} catch (IOException e) {
e.printStackTrace();
return "{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}";
}
}
@PostMapping("/rename")
@ResponseBody
public String rename(@RequestBody JSONObject body) {
String newfilename = (String) body.get("newfilename");
String dockey = (String) body.get("dockey");
String origExt = "." + (String) body.get("ext");
String curExt = newfilename;
if(newfilename.indexOf(".") != -1) {
curExt = (String) fileUtility.getFileExtension(newfilename);
}
if(origExt.compareTo(curExt) != 0) {
newfilename += origExt;
}
HashMap<String, String> meta = new HashMap<>();
meta.put("title", newfilename);
try {
callbackManager.commandRequest("meta", dockey, meta);
return "result ok";
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}
}

View File

@ -64,41 +64,26 @@ public class IndexController {
@Value("${url.editor}")
private String urlEditor;
@Value("${files.docservice.languages}")
private String langs;
@GetMapping("${url.index}")
public String index(Model model){
java.io.File[] files = storageMutator.getStoredFiles(); // get all the stored files from the storage
java.io.File[] files = storageMutator.getStoredFiles();
List<String> docTypes = new ArrayList<>();
List<Boolean> filesEditable = new ArrayList<>();
List<String> versions = new ArrayList<>();
List<Boolean> isFillFormDoc = new ArrayList<>();
List<String> langsAndKeys = Arrays.asList(langs.split("\\|"));
Map<String, String> languages = new LinkedHashMap<>();
List<User> users = userService.findAll();
langsAndKeys.forEach((str) -> {
String[] couple = str.split(":");
languages.put(couple[0], couple[1]);
});
List<User> users = userService.findAll(); // get a list of all the users
String tooltip = users.stream() // get the tooltip with the user descriptions
.map(user -> mistUtility.convertUserDescriptions(user.getName(), user.getDescriptions())) // convert user descriptions to the specified format
String tooltip = users.stream()
.map(user -> mistUtility.convertUserDescriptions(user.getName(), user.getDescriptions()))
.collect(Collectors.joining());
for(java.io.File file:files){ // run through all the files
String fileName = file.getName(); // get file name
docTypes.add(fileUtility.getDocumentType(fileName).toString().toLowerCase()); // add a document type of each file to the list
filesEditable.add(fileUtility.getEditedExts().contains(fileUtility.getFileExtension(fileName))); // specify if a file is editable or not
versions.add(" ["+storagePathBuilder.getFileVersion(fileName, true)+"]"); // add a file version to the list
isFillFormDoc.add(fileUtility.getFillExts().contains(fileUtility.getFileExtension(fileName)));
for(java.io.File file:files){
String fileName = file.getName();
docTypes.add(fileUtility.getDocumentType(fileName).toString().toLowerCase());
filesEditable.add(fileUtility.getEditedExts().contains(fileUtility.getFileExtension(fileName)));
versions.add(" ["+storagePathBuilder.getFileVersion(fileName, true)+"]");
}
// add all the parameters to the model
model.addAttribute("isFillFormDoc", isFillFormDoc);
model.addAttribute("versions",versions);
model.addAttribute("files", files);
model.addAttribute("docTypes", docTypes);
@ -106,19 +91,17 @@ public class IndexController {
model.addAttribute("datadocs", docserviceSite+docservicePreloader);
model.addAttribute("tooltip", tooltip);
model.addAttribute("users", users);
model.addAttribute("languages", languages);
return "index.html";
}
@PostMapping("/config")
@ResponseBody
public HashMap<String, String> configParameters(){ // get configuration parameters
public HashMap<String, String> configParameters(){
HashMap<String, String> configuration = new HashMap<>();
configuration.put("FillExtList", String.join(",", fileUtility.getFillExts())); // put a list of the extensions that can be filled to config
configuration.put("ConverExtList", String.join(",", fileUtility.getConvertExts())); // put a list of the extensions that can be converted to config
configuration.put("EditedExtList", String.join(",", fileUtility.getEditedExts())); // put a list of the extensions that can be edited to config
configuration.put("ConverExtList", String.join(",",fileUtility.getConvertExts()));
configuration.put("EditedExtList", String.join(",",fileUtility.getEditedExts()));
configuration.put("UrlConverter", urlConverter);
configuration.put("UrlEditor", urlEditor);

View File

@ -21,12 +21,11 @@ package com.onlyoffice.integration.documentserver.callbacks;
import com.onlyoffice.integration.dto.Track;
import org.springframework.beans.factory.annotation.Autowired;
// specify the callback handler functions
public interface Callback {
int handle(Track body, String fileName); // handle the callback
int getStatus(); // get document status
int handle(Track body, String fileName);
int getStatus();
@Autowired
default void selfRegistration(CallbackHandler callbackHandler){ // register a callback handler
default void selfRegistration(CallbackHandler callbackHandler){
callbackHandler.register(getStatus(), this);
}
}

View File

@ -33,11 +33,11 @@ public class CallbackHandler {
private Map<Integer, Callback> callbackHandlers = new HashMap<>();
public void register(int code, Callback callback){ // register a callback handler
public void register(int code, Callback callback){
callbackHandlers.put(code, callback);
}
public int handle(Track body, String fileName){ // handle a callback
public int handle(Track body, String fileName){
Callback callback = callbackHandlers.get(body.getStatus());
if (callback == null){
logger.warn("Callback status "+body.getStatus()+" is not supported yet");

View File

@ -18,18 +18,17 @@
package com.onlyoffice.integration.documentserver.callbacks;
// document status
public enum Status {
EDITING(1), // 1 - document is being edited
SAVE(2), // 2 - document is ready for saving
CORRUPTED(3), // 3 - document saving error has occurred
MUST_FORCE_SAVE(6), // 6 - document is being edited, but the current document state is saved
CORRUPTED_FORCE_SAVE(7); // 7 - error has occurred while force saving the document
EDITING(1),
SAVE(2),
CORRUPTED(3),
MUST_FORCE_SAVE(6),
CORRUPTED_FORCE_SAVE(7);
private int code;
Status(int code){
this.code = code;
}
public int getCode(){ // get document status
public int getCode(){
return this.code;
}
}

View File

@ -31,15 +31,15 @@ public class EditCallback implements Callback {
@Autowired
private CallbackManager callbackManager;
@Override
public int handle(Track body, String fileName) { // handle the callback when the document is being edited
public int handle(Track body, String fileName) {
int result = 0;
Action action = body.getActions().get(0); // get the user ID who is editing the document
if (action.getType().equals(com.onlyoffice.integration.documentserver.models.enums.Action.edit)) { // if this value is not equal to the user ID
String user = action.getUserid(); // get user ID
if (!body.getUsers().contains(user)) { // if this user is not specified in the body
String key = body.getKey(); // get document key
Action action = body.getActions().get(0);
if (action.getType().equals(com.onlyoffice.integration.documentserver.models.enums.Action.edit)) {
String user = action.getUserid();
if (!body.getUsers().contains(user)) {
String key = body.getKey();
try {
callbackManager.commandRequest("forcesave", key, null); // create a command request to forcibly save the document being edited without closing it
callbackManager.commandRequest("forcesave", key);
} catch (Exception e) {
e.printStackTrace();
result = 1;
@ -50,7 +50,7 @@ public class EditCallback implements Callback {
}
@Override
public int getStatus() { // get document status
return Status.EDITING.getCode(); // return status 1 - document is being edited
public int getStatus() {
return Status.EDITING.getCode();
}
}

View File

@ -30,10 +30,10 @@ public class ForcesaveCallback implements Callback {
@Autowired
private CallbackManager callbackManager;
@Override
public int handle(Track body, String fileName) { // handle the callback when the force saving request is performed
public int handle(Track body, String fileName) {
int result = 0;
try {
callbackManager.processForceSave(body, fileName); // file force saving process
callbackManager.processForceSave(body, fileName);
} catch (Exception ex) {
ex.printStackTrace();
result = 1;
@ -42,7 +42,7 @@ public class ForcesaveCallback implements Callback {
}
@Override
public int getStatus() { // get document status
return Status.MUST_FORCE_SAVE.getCode(); // return status 6 - document is being edited, but the current document state is saved
public int getStatus() {
return Status.MUST_FORCE_SAVE.getCode();
}
}

View File

@ -30,10 +30,10 @@ public class SaveCallback implements Callback {
@Autowired
private CallbackManager callbackManager;
@Override
public int handle(Track body, String fileName) { // handle the callback when the saving request is performed
public int handle(Track body, String fileName) {
int result = 0;
try {
callbackManager.processSave(body, fileName); // file saving process
callbackManager.processSave(body, fileName);
} catch (Exception ex) {
ex.printStackTrace();
result = 1;
@ -43,7 +43,7 @@ public class SaveCallback implements Callback {
}
@Override
public int getStatus() { // get document status
return Status.SAVE.getCode(); // return status 2 - document is ready for saving
public int getStatus() {
return Status.SAVE.getCode();
}
}

View File

@ -19,10 +19,9 @@
package com.onlyoffice.integration.documentserver.managers.callback;
import com.onlyoffice.integration.dto.Track;
import java.util.HashMap;
public interface CallbackManager { // specify the callback manager functions
void processSave(Track body, String fileName); // file saving process
void commandRequest(String method, String key, HashMap meta); // create a command request
void processForceSave(Track body, String fileName); // file force saving process
public interface CallbackManager {
void processSave(Track body, String fileName);
void commandRequest(String method, String key);
void processForceSave(Track body, String fileName);
}

View File

@ -69,40 +69,36 @@ public class DefaultCallbackManager implements CallbackManager {
@Autowired
private ServiceConverter serviceConverter;
// save file information from the URL to the file specified
private void downloadToFile(String url, Path path) throws Exception {
if (url == null || url.isEmpty()) throw new RuntimeException("Url argument is not specified"); // URL isn't specified
if (path == null) throw new RuntimeException("Path argument is not specified"); // file isn't specified
if (url == null || url.isEmpty()) throw new RuntimeException("Url argument is not specified");
if (path == null) throw new RuntimeException("Path argument is not specified");
URL uri = new URL(url);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) uri.openConnection();
InputStream stream = connection.getInputStream(); // get input stream of the file information from the URL
InputStream stream = connection.getInputStream();
if (stream == null) {
connection.disconnect();
throw new RuntimeException("Input stream is null");
}
storageMutator.createOrUpdateFile(path, stream); // update a file or create a new one
storageMutator.createOrUpdateFile(path, stream);
}
@SneakyThrows
public void processSave(Track body, String fileName) { // file saving process
public void processSave(Track body, String fileName) {
String downloadUri = body.getUrl();
String changesUri = body.getChangesurl();
String key = body.getKey();
String newFileName = fileName;
String curExt = fileUtility.getFileExtension(fileName); // get current file extension
String downloadExt = "." + body.getFiletype(); // get an extension of the downloaded file
// Todo [Delete in version 7.0 or higher]
if (downloadExt != "." + null) downloadExt = fileUtility.getFileExtension(downloadUri); // Support for versions below 7.0
String curExt = fileUtility.getFileExtension(fileName);
String downloadExt = fileUtility.getFileExtension(downloadUri);
//TODO: Refactoring
if (!curExt.equals(downloadExt)) { // convert downloaded file to the file with the current extension if these extensions aren't equal
if (!curExt.equals(downloadExt)) {
try {
String newFileUri = serviceConverter.getConvertedUri(downloadUri, downloadExt, curExt, serviceConverter.generateRevisionId(downloadUri), null, false, null); // convert a file and get URL to a new file
String newFileUri = serviceConverter.getConvertedUri(downloadUri, downloadExt, curExt, serviceConverter.generateRevisionId(downloadUri), null, false, null); // convert file and get url to a new file
if (newFileUri.isEmpty()) {
newFileName = documentManager
.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + downloadExt); // get the correct file name if it already exists
@ -114,28 +110,28 @@ public class DefaultCallbackManager implements CallbackManager {
}
}
String storagePath = storagePathBuilder.getFileLocation(newFileName); // get the path to a new file
Path lastVersion = Paths.get(storagePathBuilder.getFileLocation(fileName)); // get the path to the last file version
String storagePath = storagePathBuilder.getFileLocation(newFileName);
Path lastVersion = Paths.get(storagePathBuilder.getFileLocation(fileName));
if (lastVersion.toFile().exists()) { // if the last file version exists
Path histDir = Paths.get(storagePathBuilder.getHistoryDir(storagePath)); // get the history directory
storageMutator.createDirectory(histDir); // and create it
if (lastVersion.toFile().exists()) {
Path histDir = Paths.get(storagePathBuilder.getHistoryDir(storagePath));
storageMutator.createDirectory(histDir);
String versionDir = documentManager.versionDir(histDir.toAbsolutePath().toString(), // get the file version directory
String versionDir = documentManager.versionDir(histDir.toAbsolutePath().toString(),
storagePathBuilder.getFileVersion(histDir.toAbsolutePath().toString(), false), true);
Path ver = Paths.get(versionDir);
Path toSave = Paths.get(storagePath);
storageMutator.createDirectory(ver); // create the file version directory
storageMutator.moveFile(lastVersion, Paths.get(versionDir + File.separator + "prev" + curExt)); // move the last file version to the file version directory with the "prev" postfix
storageMutator.createDirectory(ver);
storageMutator.moveFile(lastVersion, Paths.get(versionDir + File.separator + "prev" + curExt));
downloadToFile(downloadUri, toSave); // save file to the storage path
downloadToFile(changesUri, Path.of(versionDir + File.separator + "diff.zip")); // save file changes to the diff.zip archive
downloadToFile(downloadUri, toSave);
downloadToFile(changesUri, Path.of(versionDir + File.separator + "diff.zip"));
JSONObject jsonChanges = new JSONObject(); // create a json object for document changes
jsonChanges.put("changes", body.getHistory().getChanges()); // put the changes to the json object
jsonChanges.put("serverVersion", body.getHistory().getServerVersion()); // put the server version to the json object
JSONObject jsonChanges = new JSONObject();
jsonChanges.put("changes", body.getHistory().getChanges());
jsonChanges.put("serverVersion", body.getHistory().getServerVersion());
String history = objectMapper.writeValueAsString(jsonChanges);
if (history == null && body.getHistory() != null) {
@ -143,39 +139,35 @@ public class DefaultCallbackManager implements CallbackManager {
}
if (history != null && !history.isEmpty()) {
storageMutator.writeToFile(versionDir + File.separator + "changes.json", history); // write the history changes to the changes.json file
storageMutator.writeToFile(versionDir + File.separator + "changes.json", history);
}
storageMutator.writeToFile(versionDir + File.separator + "key.txt", key); // write the key value to the key.txt file
storageMutator.deleteFile(storagePathBuilder.getForcesavePath(newFileName, false)); // get the path to the forcesaved file version and remove it
storageMutator.writeToFile(versionDir + File.separator + "key.txt", key);
storageMutator.deleteFile(storagePathBuilder.getForcesavePath(newFileName, false));
}
}
//TODO: Replace (String method) with (Enum method)
@SneakyThrows
public void commandRequest(String method, String key, HashMap meta) { // create a command request
public void commandRequest(String method, String key) {
String DocumentCommandUrl = docserviceUrlSite + docserviceUrlCommand;
URL url = new URL(DocumentCommandUrl);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
HashMap<String, Object> params = new HashMap<String, Object>();
HashMap<String, Object> params = new HashMap<>();
params.put("c", method);
params.put("key", key);
if (meta != null) {
params.put("meta", meta);
}
String headerToken;
if (jwtManager.tokenEnabled()) // check if a secret key to generate token exists or not
if (jwtManager.tokenEnabled())
{
Map<String, Object> payloadMap = new HashMap<>();
payloadMap.put("payload", params);
headerToken = jwtManager.createToken(payloadMap); // encode a payload object into a header token
connection.setRequestProperty(documentJwtHeader.equals("") ? "Authorization" : documentJwtHeader, "Bearer " + headerToken); // add a header Authorization with a header token and Authorization prefix in it
headerToken = jwtManager.createToken(payloadMap);
connection.setRequestProperty(documentJwtHeader.equals("") ? "Authorization" : documentJwtHeader, "Bearer " + headerToken);
String token = jwtManager.createToken(params); // encode a payload object into a body token
String token = jwtManager.createToken(params);
params.put("token", token);
}
@ -183,23 +175,23 @@ public class DefaultCallbackManager implements CallbackManager {
byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8);
connection.setRequestMethod("POST"); // set the request method
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); // set the Content-Type header
connection.setDoOutput(true); // set the doOutput field to true
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setDoOutput(true);
connection.connect();
try (OutputStream os = connection.getOutputStream()) {
os.write(bodyByte); // write bytes to the output stream
os.write(bodyByte);
}
InputStream stream = connection.getInputStream(); // get input stream
InputStream stream = connection.getInputStream();
if (stream == null) throw new RuntimeException("Could not get an answer");
String jsonString = serviceConverter.convertStreamToString(stream); // convert stream to json string
String jsonString = serviceConverter.convertStreamToString(stream);
connection.disconnect();
JSONObject response = serviceConverter.convertStringToJSON(jsonString); // convert json string to json object
JSONObject response = serviceConverter.convertStringToJSON(jsonString);
//TODO: Add errors ENUM
String responseCode = response.get("error").toString();
switch(responseCode) {
@ -214,16 +206,12 @@ public class DefaultCallbackManager implements CallbackManager {
}
@SneakyThrows
public void processForceSave(Track body, String fileName) { // file force saving process
public void processForceSave(Track body, String fileName) {
String downloadUri = body.getUrl();
String curExt = fileUtility.getFileExtension(fileName); // get current file extension
String downloadExt = "."+body.getFiletype(); // get an extension of the downloaded file
// Todo [Delete in version 7.0 or higher]
if (downloadExt != "."+null) downloadExt = fileUtility.getFileExtension(downloadUri); // Support for versions below 7.0
String curExt = fileUtility.getFileExtension(fileName);
String downloadExt = fileUtility.getFileExtension(downloadUri);
Boolean newFileName = false;
// convert downloaded file to the file with the current extension if these extensions aren't equal
@ -231,7 +219,7 @@ public class DefaultCallbackManager implements CallbackManager {
if (!curExt.equals(downloadExt)) {
try {
String newFileUri = serviceConverter.getConvertedUri(downloadUri, downloadExt,
curExt, serviceConverter.generateRevisionId(downloadUri), null, false, null); // convert file and get URL to a new file
curExt, serviceConverter.generateRevisionId(downloadUri), null, false, null); // convert file and get url to a new file
if (newFileUri.isEmpty()) {
newFileName = true;
} else {
@ -249,18 +237,18 @@ public class DefaultCallbackManager implements CallbackManager {
boolean isSubmitForm = body.getForcesavetype().toString().equals("3");
//TODO: Extract function
if (isSubmitForm) { // if the form is submitted
if (isSubmitForm) {
if (newFileName){
fileName = documentManager
.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + "-form" + downloadExt); // get the correct file name if it already exists
} else {
fileName = documentManager.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + "-form" + curExt);
}
forcesavePath = storagePathBuilder.getFileLocation(fileName); // create forcesave path if it doesn't exist
forcesavePath = storagePathBuilder.getFileLocation(fileName);
List<Action> actions = body.getActions();
Action action = actions.get(0);
String user = action.getUserid(); // get the user ID
storageMutator.createMeta(fileName, user, "Filling Form"); // create meta data for the forcesaved file
String user = action.getUserid();
storageMutator.createMeta(fileName, user, "Filling Form");
} else {
if (newFileName){
fileName = documentManager.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + downloadExt);

View File

@ -45,8 +45,6 @@ public class DefaultDocumentManager implements DocumentManager {
@Value("${files.storage.folder}")
private String storageFolder;
@Value("${files.storage}")
private String filesStorage;
@Value("${url.track}")
private String trackUrl;
@Value("${url.download}")
@ -61,43 +59,37 @@ public class DefaultDocumentManager implements DocumentManager {
@Autowired
private ServiceConverter serviceConverter;
// get URL to the created file
public String getCreateUrl(String fileName, Boolean sample){
String fileExt = fileName.substring(fileName.length() - 4);
String url = storagePathBuilder.getServerUrl(true) + "/create?fileExt=" + fileExt + "&sample=" + sample;
return url;
}
// get a file name with an index if the file with such a name already exists
public String getCorrectName(String fileName)
{
String baseName = fileUtility.getFileNameWithoutExtension(fileName); // get file name without extension
String ext = fileUtility.getFileExtension(fileName); // get file extension
String name = baseName + ext; // create a full file name
String baseName = fileUtility.getFileNameWithoutExtension(fileName);
String ext = fileUtility.getFileExtension(fileName);
String name = baseName + ext;
Path path = Paths.get(storagePathBuilder.getFileLocation(name));
for (int i = 1; Files.exists(path); i++) // run through all the files with such a name in the storage directory
for (int i = 1; Files.exists(path); i++)
{
name = baseName + " (" + i + ")" + ext; // and add an index to the base name
name = baseName + " (" + i + ")" + ext;
path = Paths.get(storagePathBuilder.getFileLocation(name));
}
return name;
}
// get file URL
public String getFileUri(String fileName, Boolean forDocumentServer)
{
try
{
String serverPath = storagePathBuilder.getServerUrl(forDocumentServer); // get server URL
String hostAddress = storagePathBuilder.getStorageLocation(); // get the storage directory
String serverPath = storagePathBuilder.getServerUrl(forDocumentServer);
String hostAddress = storagePathBuilder.getStorageLocation();
String filePathDownload = !fileName.contains(InetAddress.getLocalHost().getHostAddress()) ? fileName
: fileName.substring(fileName.indexOf(InetAddress.getLocalHost().getHostAddress()) + InetAddress.getLocalHost().getHostAddress().length() + 1);
if (!filesStorage.isEmpty() && filePathDownload.contains(filesStorage)) {
filePathDownload = filePathDownload.substring(filesStorage.length() + 1);
}
String filePath = serverPath + "/download?fileName=" + URLEncoder.encode(filePathDownload, java.nio.charset.StandardCharsets.UTF_8.toString())
+ "&userAddress" + URLEncoder.encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString());
@ -109,28 +101,6 @@ public class DefaultDocumentManager implements DocumentManager {
}
}
// get file URL
public String getHistoryFileUrl(String fileName, Integer version, String file, Boolean forDocumentServer)
{
try
{
String serverPath = storagePathBuilder.getServerUrl(forDocumentServer); // get server URL
String hostAddress = storagePathBuilder.getStorageLocation(); // get the storage directory
String filePathDownload = !fileName.contains(InetAddress.getLocalHost().getHostAddress()) ? fileName
: fileName.substring(fileName.indexOf(InetAddress.getLocalHost().getHostAddress()) + InetAddress.getLocalHost().getHostAddress().length() + 1);
String userAddress = forDocumentServer ? "&userAddress" + URLEncoder.encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString()) : "";
String filePath = serverPath + "/downloadhistory?fileName=" + URLEncoder.encode(filePathDownload, java.nio.charset.StandardCharsets.UTF_8.toString())
+ "&ver=" + version + "&file="+file
+ userAddress;
return filePath;
}
catch (UnsupportedEncodingException | UnknownHostException e)
{
return "";
}
}
// get the callback URL
public String getCallback(String fileName)
{
String serverPath = storagePathBuilder.getServerUrl(true);
@ -148,16 +118,15 @@ public class DefaultDocumentManager implements DocumentManager {
}
}
// get URL to download a file
public String getDownloadUrl(String fileName, Boolean isServer) {
String serverPath = storagePathBuilder.getServerUrl(isServer);
public String getDownloadUrl(String fileName) {
String serverPath = storagePathBuilder.getServerUrl(true);
String storageAddress = storagePathBuilder.getStorageLocation();
try
{
String userAddress = isServer ? "&userAddress=" + URLEncoder.encode(storageAddress, java.nio.charset.StandardCharsets.UTF_8.toString()) : "";
String query = downloadUrl+"?fileName="
+ URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString())
+ userAddress;
+ "&userAddress="
+ URLEncoder.encode(storageAddress, java.nio.charset.StandardCharsets.UTF_8.toString());
return serverPath + query;
}
@ -167,13 +136,11 @@ public class DefaultDocumentManager implements DocumentManager {
}
}
// get file information
public ArrayList<Map<String, Object>> getFilesInfo(){
ArrayList<Map<String, Object>> files = new ArrayList<>();
// run through all the stored files
for(File file : storageMutator.getStoredFiles()){
Map<String, Object> map = new LinkedHashMap<>(); // write all the parameters to the map
Map<String, Object> map = new LinkedHashMap<>();
map.put("version", storagePathBuilder.getFileVersion(file.getName(), false));
map.put("id", serviceConverter
.generateRevisionId(storagePathBuilder.getStorageLocation() +
@ -192,7 +159,6 @@ public class DefaultDocumentManager implements DocumentManager {
return files;
}
// get file information by its ID
public ArrayList<Map<String, Object>> getFilesInfo(String fileId){
ArrayList<Map<String, Object>> file = new ArrayList<>();
@ -206,7 +172,6 @@ public class DefaultDocumentManager implements DocumentManager {
return file;
}
// get the path to the file version by the history path and file version
public String versionDir(String path, Integer version, boolean historyPath) {
if (!historyPath){
return storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(path)) + version;
@ -214,20 +179,19 @@ public class DefaultDocumentManager implements DocumentManager {
return path + File.separator + version;
}
// create demo document
public String createDemo(String fileExt,Boolean sample,String uid,String uname) {
String demoName = (sample ? "sample." : "new.") + fileExt; // create sample or new template file with the necessary extension
String demoPath = "assets" + File.separator + (sample ? "sample" : "new") + File.separator + demoName; // get the path to the sample document
String fileName = getCorrectName(demoName); // get a file name with an index if the file with such a name already exists
String demoName = (sample ? "sample." : "new.") + fileExt;
String demoPath = "assets" + File.separator + (sample ? "sample" : "new") + File.separator + demoName;
String fileName = getCorrectName(demoName);
InputStream stream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream(demoPath); // get the input file stream
.getResourceAsStream(demoPath);
if (stream == null) return null;
storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(fileName)), stream); // create a file in the specified directory
storageMutator.createMeta(fileName, uid, uname); // create meta information of the demo file
storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(fileName)), stream);
storageMutator.createMeta(fileName, uid, uname);
return fileName;
}

View File

@ -21,16 +21,14 @@ package com.onlyoffice.integration.documentserver.managers.document;
import java.util.ArrayList;
import java.util.Map;
// specify the document manager functions
public interface DocumentManager {
String getCorrectName(String fileName); // get a file name with an index if the file with such a name already exists
String getFileUri(String fileName, Boolean forDocumentServer); // get file URL
String getHistoryFileUrl(String fileName, Integer version, String file, Boolean forDocumentServer); // get file URL
String getCallback(String fileName); // get the callback URL
String getDownloadUrl(String fileName, Boolean forDocumentServer); // get URL to download a file
ArrayList<Map<String, Object>> getFilesInfo(); // get file information
ArrayList<Map<String, Object>> getFilesInfo(String fileId); // get file information by its ID
String versionDir(String path, Integer version, boolean historyPath); // get the path to the file version by the history path and file version
String createDemo(String fileExt,Boolean sample,String uid,String uname) throws Exception; // create demo document
String getCreateUrl(String fileName, Boolean sample); // get URL to the created file
String getCorrectName(String fileName);
String getFileUri(String fileName, Boolean forDocumentServer);
String getCallback(String fileName);
String getDownloadUrl(String fileName);
ArrayList<Map<String, Object>> getFilesInfo();
ArrayList<Map<String, Object>> getFilesInfo(String fileId);
String versionDir(String path, Integer version, boolean historyPath);
String createDemo(String fileExt,Boolean sample,String uid,String uname) throws Exception;
String getCreateUrl(String fileName, Boolean sample);
}

View File

@ -58,28 +58,27 @@ public class DefaultHistoryManager implements HistoryManager {
//TODO: Refactoring
@SneakyThrows
public String[] getHistory(Document document) { // get document history
String histDir = storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(document.getTitle())); // get history directory
Integer curVer = storagePathBuilder.getFileVersion(histDir, false); // get current file version
public String[] getHistory(Document document) {
String histDir = storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(document.getTitle()));
Integer curVer = storagePathBuilder.getFileVersion(histDir, false);
if (curVer > 0) { // check if the current file version is greater than 0
if (curVer > 0) {
List<Object> hist = new ArrayList<>();
Map<String, Object> histData = new HashMap<>();
for (Integer i = 1; i <= curVer; i++) { // run through all the file versions
for (Integer i = 1; i <= curVer; i++) {
Map<String, Object> obj = new HashMap<String, Object>();
Map<String, Object> dataObj = new HashMap<String, Object>();
String verDir = documentManager.versionDir(histDir, i, true); // get the path to the given file version
String verDir = documentManager.versionDir(histDir, i, true);
String key = i == curVer ? document.getKey() : readFileToEnd(new File(verDir + File.separator + "key.txt")); // get document key
String key = i == curVer ? document.getKey() : readFileToEnd(new File(verDir + File.separator + "key.txt"));
obj.put("key", key);
obj.put("version", i);
if (i == 1) { // check if the version number is equal to 1
String createdInfo = readFileToEnd(new File(histDir + File.separator + "createdInfo.json")); // get file with meta data
JSONObject json = (JSONObject) parser.parse(createdInfo); // and turn it into json object
if (i == 1) {
String createdInfo = readFileToEnd(new File(histDir + File.separator + "createdInfo.json"));
JSONObject json = (JSONObject) parser.parse(createdInfo);
// write meta information to the object (user information and creation date)
obj.put("created", json.get("created"));
Map<String, Object> user = new HashMap<String, Object>();
user.put("id", json.get("id"));
@ -87,35 +86,26 @@ public class DefaultHistoryManager implements HistoryManager {
obj.put("user", user);
}
dataObj.put("fileType", fileUtility.getFileExtension(document.getTitle()).replace(".", ""));
dataObj.put("key", key);
dataObj.put("url", i == curVer ? document.getUrl() :
documentManager.getHistoryFileUrl(document.getTitle(), i, "prev" + fileUtility.getFileExtension(document.getTitle()), true));
dataObj.put("directUrl", i == curVer ? document.getDirectUrl() :
documentManager.getHistoryFileUrl(document.getTitle(), i, "prev" + fileUtility.getFileExtension(document.getTitle()), false));
documentManager.getFileUri(documentManager.versionDir(histDir, i, true) + File.separator + "prev" + fileUtility.getFileExtension(document.getTitle()), true));
dataObj.put("version", i);
if (i > 1) { //check if the version number is greater than 1
// if so, get the path to the changes.json file
if (i > 1) {
JSONObject changes = (JSONObject) parser.parse(readFileToEnd(new File(documentManager.versionDir(histDir, i - 1, true) + File.separator + "changes.json")));
JSONObject change = (JSONObject) ((JSONArray) changes.get("changes")).get(0);
// write information about changes to the object
obj.put("changes", changes.get("changes"));
obj.put("serverVersion", changes.get("serverVersion"));
obj.put("created", change.get("created"));
obj.put("user", change.get("user"));
Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(i - 2)); // get the history data from the previous file version
Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(i - 2));
Map<String, Object> prevInfo = new HashMap<String, Object>();
prevInfo.put("fileType", prev.get("fileType"));
prevInfo.put("key", prev.get("key")); // write key and URL information about previous file version
prevInfo.put("key", prev.get("key"));
prevInfo.put("url", prev.get("url"));
prevInfo.put("directUrl", prev.get("directUrl"));
dataObj.put("previous", prevInfo); // write information about previous file version to the data object
// write the path to the diff.zip archive with differences in this file version
Integer verdiff = i - 1;
dataObj.put("changesUrl", documentManager.getHistoryFileUrl(document.getTitle(), verdiff, "diff.zip", true));
dataObj.put("previous", prevInfo);
dataObj.put("changesUrl", documentManager.getFileUri(documentManager.versionDir(histDir, i - 1, true) + File.separator + "diff.zip", true));
}
if (jwtManager.tokenEnabled()) dataObj.put("token", jwtManager.createToken(dataObj));
@ -124,7 +114,6 @@ public class DefaultHistoryManager implements HistoryManager {
histData.put(Integer.toString(i - 1), dataObj);
}
// write history information about the current file version to the history object
Map<String, Object> histObj = new HashMap<String, Object>();
histObj.put("currentVersion", curVer);
histObj.put("history", hist);
@ -138,12 +127,11 @@ public class DefaultHistoryManager implements HistoryManager {
return new String[]{"", ""};
}
// read a file
private String readFileToEnd(File file) {
String output = "";
try {
try (FileInputStream is = new FileInputStream(file)) {
Scanner scanner = new Scanner(is); // read data from the source
Scanner scanner = new Scanner(is);
scanner.useDelimiter("\\A");
while (scanner.hasNext()) {
output += scanner.next();

View File

@ -20,7 +20,6 @@ package com.onlyoffice.integration.documentserver.managers.history;
import com.onlyoffice.integration.documentserver.models.filemodel.Document;
// specify the history manager functions
public interface HistoryManager {
String[] getHistory(Document document); // get document history
String[] getHistory(Document document);
}

View File

@ -42,62 +42,56 @@ public class DefaultJwtManager implements JwtManager {
@Autowired
private JSONParser parser;
// create document token
public String createToken(Map<String, Object> payloadClaims) {
try {
// build a HMAC signer using a SHA-256 hash
Signer signer = HMACSigner.newSHA256Signer(tokenSecret);
JWT jwt = new JWT();
for (String key : payloadClaims.keySet()) { // run through all the keys from the payload
jwt.addClaim(key, payloadClaims.get(key)); // and write each claim to the jwt
for (String key : payloadClaims.keySet()) {
jwt.addClaim(key, payloadClaims.get(key));
}
return JWT.getEncoder().encode(jwt, signer); // sign and encode the JWT to a JSON string representation
return JWT.getEncoder().encode(jwt, signer);
} catch (Exception e) {
return "";
}
}
// check if the token is enabled
public boolean tokenEnabled() {
return tokenSecret != null && !tokenSecret.isEmpty();
}
// read document token
public JWT readToken(String token) {
try {
// build a HMAC verifier using the token secret
Verifier verifier = HMACVerifier.newVerifier(tokenSecret);
return JWT.getDecoder().decode(token, verifier); // verify and decode the encoded string JWT to a rich object
return JWT.getDecoder().decode(token, verifier);
} catch (Exception exception) {
return null;
}
}
// parse the body
public JSONObject parseBody(String payload, String header) {
JSONObject body;
try {
Object obj = parser.parse(payload); // get body parameters by parsing the payload
Object obj = parser.parse(payload);
body = (JSONObject) obj;
} catch (Exception ex) {
throw new RuntimeException("{\"error\":1,\"message\":\"JSON Parsing error\"}");
}
if (tokenEnabled()) { // check if the token is enabled
String token = (String) body.get("token"); // get token from the body
if (token == null) { // if token is empty
if (header != null && !header.isBlank()) { // and the header is defined
token = header.startsWith("Bearer ") ? header.substring(7) : header; // get token from the header (it is placed after the Bearer prefix if it exists)
if (tokenEnabled()) {
String token = (String) body.get("token");
if (token == null) {
if (header != null && !header.isBlank()) {
token = header.startsWith("Bearer ") ? header.substring(7) : header;
}
}
if (token == null || token.isBlank()) {
throw new RuntimeException("{\"error\":1,\"message\":\"JWT expected\"}");
}
JWT jwt = readToken(token); // read token
JWT jwt = readToken(token);
if (jwt == null) {
throw new RuntimeException("{\"error\":1,\"message\":\"JWT validation failed\"}");
}
if (jwt.getObject("payload") != null) { // get payload from the token and check if it is not empty
if (jwt.getObject("payload") != null) {
try {
@SuppressWarnings("unchecked") LinkedHashMap<String, Object> jwtPayload =
(LinkedHashMap<String, Object>)jwt.getObject("payload");

View File

@ -23,10 +23,9 @@ import org.primeframework.jwt.domain.JWT;
import java.util.Map;
// specify the jwt manager functions
public interface JwtManager {
boolean tokenEnabled(); // check if the token is enabled
String createToken(Map<String, Object> payloadClaims); // create document token
JWT readToken(String token); // read document token
JSONObject parseBody(String payload, String header); // parse the body
boolean tokenEnabled();
String createToken(Map<String, Object> payloadClaims);
JWT readToken(String token);
JSONObject parseBody(String payload, String header);
}

View File

@ -41,27 +41,25 @@ public class SampleTemplateManager implements TemplateManager {
@Autowired
private FileUtility fileUtility;
// create a template document with the specified name
public List<Template> createTemplates(String fileName){
List<Template> templates = List.of(
new Template("", "Blank", documentManager.getCreateUrl(fileName, false)), // create a blank template
new Template(getTemplateImageUrl(fileName), "With sample content", documentManager.getCreateUrl(fileName, true)) // create a template with sample content using the template image
new Template("", "Blank", documentManager.getCreateUrl(fileName, false)),
new Template(getTemplateImageUrl(fileName), "With sample content", documentManager.getCreateUrl(fileName, true))
);
return templates;
}
// get the template image URL for the specified file
public String getTemplateImageUrl(String fileName){
DocumentType fileType = fileUtility.getDocumentType(fileName); // get the file type
String path = storagePathBuilder.getServerUrl(true); // get server URL
if(fileType.equals(DocumentType.word)){ // get URL to the template image for the word document type
DocumentType fileType = fileUtility.getDocumentType(fileName);
String path = storagePathBuilder.getServerUrl(true);
if(fileType.equals(DocumentType.word)){
return path + "/css/img/file_docx.svg";
} else if(fileType.equals(DocumentType.slide)){ // get URL to the template image for the slide document type
} else if(fileType.equals(DocumentType.slide)){
return path + "/css/img/file_pptx.svg";
} else if(fileType.equals(DocumentType.cell)){ // get URL to the template image for the cell document type
} else if(fileType.equals(DocumentType.cell)){
return path + "/css/img/file_xlsx.svg";
}
return path + "/css/img/file_docx.svg"; // get URL to the template image for the default document type (word)
return path + "/css/img/file_docx.svg";
}
}

View File

@ -21,8 +21,7 @@ package com.onlyoffice.integration.documentserver.managers.template;
import com.onlyoffice.integration.documentserver.models.filemodel.Template;
import java.util.List;
// specify the template manager functions
public interface TemplateManager {
List<Template> createTemplates(String fileName); // create a template document with the specified name
String getTemplateImageUrl(String fileName); // get the template image URL for the specified file
List<Template> createTemplates(String fileName);
String getTemplateImageUrl(String fileName);
}

View File

@ -28,21 +28,20 @@ import org.springframework.stereotype.Component;
@Scope("prototype")
@Getter
@Setter
public class Customization { // the parameters which allow to customize the editor interface so that it looked like your other products (if there are any) and change the presence or absence of the additional buttons, links, change logos and editor owner details
public class Customization {
@Autowired
private Logo logo; // the image file at the top left corner of the Editor header
private Logo logo;
@Autowired
private Goback goback; // the settings for the Open file location menu button and upper right corner button
private Boolean autosave = true; // if the Autosave menu option is enabled or disabled
private Boolean comments = true; // if the Comments menu button is displayed or hidden
private Boolean compactHeader = false; // if the additional action buttons are displayed in the upper part of the editor window header next to the logo (false) or in the toolbar (true)
private Boolean compactToolbar = false; // if the top toolbar type displayed is full (false) or compact (true)
private Boolean compatibleFeatures = false; // the use of functionality only compatible with the OOXML format
private Boolean forcesave = false; // add the request for the forced file saving to the callback handler when saving the document within the document editing service
private Boolean help = true; // if the Help menu button is displayed or hidden
private Boolean hideRightMenu = false; // if the right menu is displayed or hidden on first loading
private Boolean hideRulers = false; // if the editor rulers are displayed or hidden
private Boolean submitForm = false; // if the Submit form button is displayed or hidden
private Boolean about = true;
private Boolean feedback =true;
private Goback goback;
private Boolean autosave = true;
private Boolean chat = true;
private Boolean comments = true;
private Boolean compactHeader = false;
private Boolean compactToolbar = false;
private Boolean compatibleFeatures = false;
private Boolean forcesave = false;
private Boolean help = true;
private Boolean hideRightMenu = false;
private Boolean hideRulers = false;
private Boolean submitForm = false;
}

View File

@ -28,9 +28,9 @@ import org.springframework.stereotype.Component;
@Scope("prototype")
@Getter
@Setter
public class Embedded { // the parameters which allow to change the settings which define the behavior of the buttons in the embedded mode
private String embedUrl; // the absolute URL to the document serving as a source file for the document embedded into the web page
private String saveUrl; // the absolute URL that will allow the document to be saved onto the user personal computer
private String shareUrl; // the absolute URL that will allow other users to share this document
private ToolbarDocked toolbarDocked; // the place for the embedded viewer toolbar, can be either top or bottom
public class Embedded {
private String embedUrl;
private String saveUrl;
private String shareUrl;
private ToolbarDocked toolbarDocked;
}

View File

@ -20,6 +20,7 @@ package com.onlyoffice.integration.documentserver.models.configurations;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
@ -29,19 +30,19 @@ import javax.annotation.PostConstruct;
@Component
@Scope("prototype")
public class Goback { // the settings for the Open file location menu button and upper right corner button
@Getter
@Setter
public class Goback {
@Autowired
private FileStoragePathBuilder storagePathBuilder;
@Value("${url.index}")
private String indexMapping;
@Getter
private String url; // the absolute URL to the website address which will be opened when clicking the Open file location menu button
private String url;
@PostConstruct
private void init() {
this.url = storagePathBuilder.getServerUrl(false) + indexMapping;
private void init(){
this.url = storagePathBuilder.getServerUrl(false)+indexMapping;
}
}

View File

@ -31,10 +31,10 @@ import java.util.Locale;
@Scope("prototype")
@Getter
@Setter
public class Info { // the additional parameters for the document (document owner, folder where the document is stored, uploading date, sharing settings)
private String owner = "Me"; // the name of the document owner/creator
private Boolean favorite = null; // the highlighting state of the Favorite icon
private String uploaded = getDate(); // the document uploading date
public class Info {
private String owner = "Me";
private Boolean favorite = null;
private String uploaded = getDate();
private String getDate() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE MMM dd yyyy", Locale.US);

View File

@ -28,11 +28,11 @@ import org.springframework.stereotype.Component;
@Scope("prototype")
@Getter
@Setter
public class Logo { // the image file at the top left corner of the Editor header
public class Logo {
@Value("${logo.image}")
private String image; // the path to the image file used to show in common work mode
private String image;
@Value("${logo.imageEmbedded}")
private String imageEmbedded; // the path to the image file used to show in the embedded mode
private String imageEmbedded;
@Value("${logo.url}")
private String url; // the absolute URL which will be used when someone clicks the logo image
private String url;
}

View File

@ -25,7 +25,6 @@ public enum Action {
embedded,
filter,
comment,
chat,
fillForms,
blockcontent
}

View File

@ -0,0 +1,53 @@
/**
*
* (c) Copyright Ascensio System SIA 2021
*
* 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.
*
*/
package com.onlyoffice.integration.documentserver.models.enums;
public enum Language {
en,
de,
ru,
pl,
be,
bg,
ca,
zh,
cs,
da,
nl,
fi,
fr,
el,
hu,
id,
it,
ja,
ko,
lv,
lo,
nb,
pt,
ro,
sk,
sl,
sv,
es,
tr,
uk,
vi
}

View File

@ -33,9 +33,9 @@ import java.util.List;
@AllArgsConstructor
public class CommentGroup {
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
private List<String> view; // define a list of groups whose comments the user can view
private List<String> view;
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
private List<String> edit; // define a list of groups whose comments the user can edit
private List<String> edit;
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
private List<String> remove; // define a list of groups whose comments the user can remove
private List<String> remove;
}

View File

@ -29,15 +29,14 @@ import org.springframework.stereotype.Component;
@Scope("prototype")
@Getter
@Setter
public class Document { // the parameters pertaining to the document (title, url, file type, etc.)
public class Document {
@Autowired
private Info info; // additional parameters for the document (document owner, folder where the document is stored, uploading date, sharing settings)
private Info info;
@Autowired
private Permission permissions; // the permission for the document to be edited and downloaded or not
private String fileType; // the file type for the source viewed or edited document
private String key; // the unique document identifier used by the service to recognize the document
private String urlUser; // the absolute URL that will allow the document to be saved onto the user personal computer
private String title; // the desired file name for the viewed or edited document which will also be used as file name when the document is downloaded
private String url; // the absolute URL where the source viewed or edited document is stored
private String directUrl;
private Permission permissions;
private String fileType;
private String key;
private String urlUser;
private String title;
private String url;
}

View File

@ -20,6 +20,7 @@ package com.onlyoffice.integration.documentserver.models.filemodel;
import com.onlyoffice.integration.documentserver.models.configurations.Customization;
import com.onlyoffice.integration.documentserver.models.configurations.Embedded;
import com.onlyoffice.integration.documentserver.models.enums.Language;
import com.onlyoffice.integration.documentserver.models.enums.Mode;
import lombok.*;
import org.springframework.beans.factory.annotation.Autowired;
@ -34,18 +35,17 @@ import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EditorConfig { // the parameters pertaining to the editor interface: opening mode (viewer or editor), interface language, additional buttons, etc.
private HashMap<String, Object> actionLink = null; // the data which contains the information about the action in the document that will be scrolled to
private String callbackUrl; // the absolute URL to the document storage service
private HashMap<String, Object> coEditing = null;
private String createUrl; // the absolute URL of the document where it will be created and available after creation
public class EditorConfig {
private HashMap<String, Object> actionLink = null;
private String callbackUrl;
private String createUrl;
@Autowired
private Customization customization; // the parameters which allow to customize the editor interface so that it looked like your other products (if there are any) and change the presence or absence of the additional buttons, links, change logos and editor owner details
private Customization customization;
@Autowired
private Embedded embedded; // the parameters which allow to change the settings which define the behavior of the buttons in the embedded mode
private String lang; // the editor interface language
private Mode mode; // the editor opening mode
private Embedded embedded;
private Language lang;
private Mode mode;
@Autowired
private User user; // the user currently viewing or editing the document
private List<Template> templates; // the presence or absence of the templates in the <b>Create New...</b> menu option
private User user;
private List<Template> templates;
}

View File

@ -30,12 +30,12 @@ import org.springframework.stereotype.Component;
@Scope("prototype")
@Getter
@Setter
public class FileModel { // the file base parameters which include the platform type used, document display size (width and height) and type of the document opened
public class FileModel {
@Autowired
private Document document; // the parameters pertaining to the document (title, url, file type, etc.)
private DocumentType documentType; // the document type to be opened
private Document document;
private DocumentType documentType;
@Autowired
private EditorConfig editorConfig; // the parameters pertaining to the editor interface: opening mode (viewer or editor), interface language, additional buttons, etc.
private String token; // the encrypted signature added to the Document Server config
private Type type; // the platform type used to access the document
private EditorConfig editorConfig;
private String token;
private Type type;
}

View File

@ -33,21 +33,18 @@ import java.util.List;
@Scope("prototype")
@Getter
@Setter
public class Permission extends AbstractModel { // the permission for the document to be edited and downloaded or not
private Boolean comment = true; // if the document can be commented or not
private Boolean copy = true; // if the content can be copied to the clipboard or not
private Boolean download = true; // if the document can be downloaded or only viewed or edited online
private Boolean edit = true; // if the document can be edited or only viewed
private Boolean print = true; // if the document can be printed or not
private Boolean fillForms = true; // if the forms can be filled
private Boolean modifyFilter = true; // if the filter can applied globally (true) affecting all the other users, or locally (false)
private Boolean modifyContentControl = true; // if the content control settings can be changed
private Boolean review = true; // if the document can be reviewed or not
private Boolean chat = true; // if a chat can be used
public class Permission extends AbstractModel {
private Boolean comment = true;
private Boolean copy = true;
private Boolean download = true;
private Boolean edit = true;
private Boolean print = true;
private Boolean fillForms = true;
private Boolean modifyFilter = true;
private Boolean modifyContentControl = true;
private Boolean review = true;
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
private List<String> reviewGroups; // the groups whose changes the user can accept/reject
private List<String> reviewGroups;
@Autowired
private CommentGroup commentGroups; // the groups whose comments the user can edit, remove and/or view
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
private List<String> userInfoGroups;
private CommentGroup commentGroups;
}

View File

@ -7,8 +7,8 @@ import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class Template { // the document template parameters
private String image; // the absolute URL to the image for template
private String title; // the template title that will be displayed in the <b>Create New...</b> menu option
private String url; // the absolute URL to the document where it will be created and available after creation
public class Template {
private String image;
private String title;
private String url;
}

View File

@ -33,10 +33,9 @@ public class User extends AbstractModel {
private String name;
private String group;
// the user configuration parameters
public void configure(int id, String name, String group){
this.id = "uid-"+id; // the user id
this.name = name; // the user name
this.group = group; // the group the user belongs to
this.id = "uid-"+id;
this.name = name;
this.group = group;
}
}

View File

@ -6,18 +6,16 @@ import java.io.File;
import java.io.InputStream;
import java.nio.file.Path;
// specify the file storage mutator functions
public interface FileStorageMutator {
void createDirectory(Path path); // create a new directory if it does not exist
boolean createFile(Path path, InputStream stream); // create a new file if it does not exist
boolean deleteFile(String fileName); // delete a file
boolean deleteFileHistory(String fileName); // delete file history
String updateFile(String fileName, byte[] bytes); // update a file
boolean writeToFile(String pathName, String payload); // write the payload to the file
boolean moveFile(Path source, Path destination); // move a file to the specified destination
Resource loadFileAsResource(String fileName); // load file as a resource
Resource loadFileAsResourceHistory(String fileName,String version,String file); // load file as a resource
File[] getStoredFiles(); // get a collection of all the stored files
void createMeta(String fileName, String uid, String uname); // create the file meta information
boolean createOrUpdateFile(Path path, InputStream stream); // create or update a file
void createDirectory(Path path);
boolean createFile(Path path, InputStream stream);
boolean deleteFile(String fileName);
boolean deleteFileHistory(String fileName);
String updateFile(String fileName, byte[] bytes);
boolean writeToFile(String pathName, String payload);
boolean moveFile(Path source, Path destination);
Resource loadFileAsResource(String fileName);
File[] getStoredFiles();
void createMeta(String fileName, String uid, String uname);
boolean createOrUpdateFile(Path path, InputStream stream);
}

View File

@ -1,12 +1,11 @@
package com.onlyoffice.integration.documentserver.storage;
// specify the file storage path builder functions
public interface FileStoragePathBuilder {
void configure(String address); // create a new storage folder
String getStorageLocation(); // get the storage directory
String getFileLocation(String fileName); // get the directory of the specified file
String getServerUrl(Boolean forDocumentServer); // get the server URL
String getHistoryDir(String fileName); // get the history directory
int getFileVersion(String historyPath, Boolean ifIndexPage); // get the file version
String getForcesavePath(String fileName, Boolean create); // get the path where all the forcely saved file versions are saved or create it
void configure(String address);
String getStorageLocation();
String getFileLocation(String fileName);
String getServerUrl(Boolean forDocumentServer);
String getHistoryDir(String fileName);
int getFileVersion(String historyPath, Boolean ifIndexPage);
String getForcesavePath(String fileName, Boolean create);
}

View File

@ -82,26 +82,16 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
createDirectory(Paths.get(getStorageLocation()));
}
// get the storage directory
public String getStorageLocation(){
String serverPath = System.getProperty("user.dir"); // get the path to the server
String directory; // create the storage directory
if (Paths.get(this.storageAddress).isAbsolute()) {
directory = this.storageAddress + File.separator;
} else {
directory = serverPath
+ File.separator + storageFolder
+ File.separator + this.storageAddress
+ File.separator;
}
if (!Files.exists(Paths.get(directory))) {
createDirectory(Paths.get(directory));
}
String serverPath = System.getProperty("user.dir");
String directory = serverPath
+ File.separator + storageFolder
+ File.separator + this.storageAddress
+ File.separator;
return directory;
}
// get the directory of the specified file
public String getFileLocation(String fileName){
if (fileName.contains(File.separator)) {
return getStorageLocation() + fileName;
@ -109,7 +99,6 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
return getStorageLocation() + fileUtility.getFileName(fileName);
}
// create a new directory if it does not exist
public void createDirectory(Path path){
if (Files.exists(path)) return;
try {
@ -119,22 +108,21 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
}
}
// create a new file if it does not exist
public boolean createFile(Path path, InputStream stream){
if (Files.exists(path)){
return true;
}
try {
File file = Files.createFile(path).toFile(); // create a new file in the specified path
File file = Files.createFile(path).toFile();
try (FileOutputStream out = new FileOutputStream(file))
{
int read;
final byte[] bytes = new byte[1024];
while ((read = stream.read(bytes)) != -1)
{
out.write(bytes, 0, read); // write bytes to the output stream
out.write(bytes, 0, read);
}
out.flush(); // force write data to the output stream that can be cached in the current thread
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
@ -142,41 +130,38 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
return false;
}
// delete a file
public boolean deleteFile(String fileName){
fileName = URLDecoder.decode(fileName, StandardCharsets.UTF_8); // decode a x-www-form-urlencoded string
fileName = URLDecoder.decode(fileName, StandardCharsets.UTF_8);
if (fileName.isBlank()) return false;
String filenameWithoutExt = fileUtility.getFileNameWithoutExtension(fileName); // get file name without extension
String filenameWithoutExt = fileUtility.getFileNameWithoutExtension(fileName);
Path filePath = fileName.contains(File.separator) ? Paths.get(fileName) : Paths.get(getFileLocation(fileName)); // get the path to the file
Path filePathWithoutExt = fileName.contains(File.separator) ? Paths.get(filenameWithoutExt) : Paths.get(getStorageLocation() + filenameWithoutExt); // get the path to the file without extension
Path filePath = fileName.contains(File.separator) ? Paths.get(fileName) : Paths.get(getFileLocation(fileName));
Path filePathWithoutExt = fileName.contains(File.separator) ? Paths.get(filenameWithoutExt) : Paths.get(getStorageLocation() + filenameWithoutExt);
boolean fileDeleted = FileSystemUtils.deleteRecursively(filePath.toFile()); // delete the specified file; for directories, recursively delete any nested directories or files as well
boolean fileWithoutExtDeleted = FileSystemUtils.deleteRecursively(filePathWithoutExt.toFile()); // delete the specified file without extension; for directories, recursively delete any nested directories or files as well
boolean fileDeleted = FileSystemUtils.deleteRecursively(filePath.toFile());
boolean fileWithoutExtDeleted = FileSystemUtils.deleteRecursively(filePathWithoutExt.toFile());
return fileDeleted && fileWithoutExtDeleted;
}
// delete file history
public boolean deleteFileHistory(String fileName) {
fileName = URLDecoder.decode(fileName, StandardCharsets.UTF_8); // decode a x-www-form-urlencoded string
fileName = URLDecoder.decode(fileName, StandardCharsets.UTF_8);
if (fileName.isBlank()) return false;
Path fileHistoryPath = Paths.get(getStorageLocation() + getHistoryDir(fileName)); // get the path to the history file
Path fileHistoryPathWithoutExt = Paths.get(getStorageLocation() + getHistoryDir(fileUtility.getFileNameWithoutExtension(fileName))); // get the path to the history file without extension
Path fileHistoryPath = Paths.get(getStorageLocation() + getHistoryDir(fileName));
Path fileHistoryPathWithoutExt = Paths.get(getStorageLocation() + getHistoryDir(fileUtility.getFileNameWithoutExtension(fileName)));
boolean historyDeleted = FileSystemUtils.deleteRecursively(fileHistoryPath.toFile()); // delete the specified history file; for directories, recursively delete any nested directories or files as well
boolean historyWithoutExtDeleted = FileSystemUtils.deleteRecursively(fileHistoryPathWithoutExt.toFile()); // delete the specified history file without extension; for directories, recursively delete any nested directories or files as well
boolean historyDeleted = FileSystemUtils.deleteRecursively(fileHistoryPath.toFile());
boolean historyWithoutExtDeleted = FileSystemUtils.deleteRecursively(fileHistoryPathWithoutExt.toFile());
return historyDeleted || historyWithoutExtDeleted;
}
// update a file
public String updateFile(String fileName, byte[] bytes) {
Path path = fileUtility.generateFilepath(getStorageLocation(), fileName); // generate the path to the specified file
Path path = fileUtility.generateFilepath(getStorageLocation(), fileName);
try {
Files.write(path, bytes); // write new information in the bytes format to the file
Files.write(path, bytes);
return path.getFileName().toString();
} catch (IOException e) {
e.printStackTrace();
@ -184,7 +169,6 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
return "";
}
// move a file to the specified destination
public boolean moveFile(Path source, Path destination){
try {
Files.move(source, destination,
@ -196,7 +180,6 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
return false;
}
// write the payload to the file
public boolean writeToFile(String pathName, String payload){
try (FileWriter fw = new FileWriter(pathName)) {
fw.write(payload);
@ -207,19 +190,18 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
return false;
}
// get the path where all the forcely saved file versions are saved or create it
public String getForcesavePath(String fileName, Boolean create) {
String directory = getStorageLocation();
Path path = Paths.get(directory); // get the storage directory
Path path = Paths.get(directory);
if (!Files.exists(path)) return "";
directory = getFileLocation(fileName) + historyPostfix + File.separator;
path = Paths.get(directory); // get the history file directory
path = Paths.get(directory);
if (!create && !Files.exists(path)) return "";
createDirectory(path); // create a new directory where all the forcely saved file versions will be saved
createDirectory(path);
directory = directory + fileName;
path = Paths.get(directory);
@ -230,15 +212,14 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
return directory;
}
// load file as a resource
public Resource loadFileAsResource(String fileName){
String fileLocation = getForcesavePath(fileName, false); // get the path where all the forcely saved file versions are saved
if (fileLocation.isBlank()){ // if file location is empty
fileLocation = getFileLocation(fileName); // get it by the file name
String fileLocation = getForcesavePath(fileName, false);
if (fileLocation.isBlank()){
fileLocation = getFileLocation(fileName);
}
try {
Path filePath = Paths.get(fileLocation); // get the path to the file location
Resource resource = new UrlResource(filePath.toUri()); // convert the file path to URL
Path filePath = Paths.get(fileLocation);
Resource resource = new UrlResource(filePath.toUri());
if(resource.exists()) return resource;
} catch (MalformedURLException e) {
e.printStackTrace();
@ -246,21 +227,6 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
return null;
}
public Resource loadFileAsResourceHistory(String fileName,String version,String file){
String fileLocation = getStorageLocation() + fileName + "-hist" + File.separator + version + File.separator + file; // get it by the file name
try {
Path filePath = Paths.get(fileLocation); // get the path to the file location
Resource resource = new UrlResource(filePath.toUri()); // convert the file path to URL
if(resource.exists()) return resource;
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
// get a collection of all the stored files
public File[] getStoredFiles()
{
File file = new File(getStorageLocation());
@ -268,19 +234,18 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
}
@SneakyThrows
public void createMeta(String fileName, String uid, String uname) { // create the file meta information
String histDir = getHistoryDir(getFileLocation(fileName)); // get the history directory
public void createMeta(String fileName, String uid, String uname) {
String histDir = getHistoryDir(getFileLocation(fileName));
Path path = Paths.get(histDir); // get the path to the history directory
createDirectory(path); // create the history directory
Path path = Paths.get(histDir);
createDirectory(path);
// create the json object with the file metadata
JSONObject json = new JSONObject();
json.put("created", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); // put the file creation date to the json object
json.put("id", uid); // put the user ID to the json object
json.put("name", uname); // put the user name to the json object
json.put("created", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
json.put("id", uid);
json.put("name", uname);
File meta = new File(histDir + File.separator + "createdInfo.json"); // create the createdInfo.json file with the file meta information
File meta = new File(histDir + File.separator + "createdInfo.json");
try (FileWriter writer = new FileWriter(meta)) {
json.writeJSONString(writer);
} catch (IOException ex){
@ -288,13 +253,12 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
}
}
// create or update a file
public boolean createOrUpdateFile(Path path, InputStream stream) {
if (!Files.exists(path)){ // if the specified file does not exist
return createFile(path, stream); // create it in the specified directory
if (!Files.exists(path)){
return createFile(path, stream);
} else {
try {
Files.write(path, stream.readAllBytes()); // otherwise, write new information in the bytes format to the file
Files.write(path, stream.readAllBytes());
return true;
} catch (IOException e) {
e.printStackTrace();
@ -303,7 +267,6 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
return false;
}
// get the server URL
public String getServerUrl(Boolean forDocumentServer) {
if (forDocumentServer && !docserviceUrlExample.equals("")) {
return docserviceUrlExample;
@ -312,29 +275,27 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
}
}
// get the history directory
public String getHistoryDir(String path)
{
return path + historyPostfix;
}
// get the file version
public int getFileVersion(String historyPath, Boolean ifIndexPage)
{
Path path;
if (ifIndexPage) { // if the start page is opened
path = Paths.get(getStorageLocation() + getHistoryDir(historyPath)); // get the storage directory and add the history directory to it
if (ifIndexPage) {
path = Paths.get(getStorageLocation() + getHistoryDir(historyPath));
} else {
path = Paths.get(historyPath); // otherwise, get the path to the history directory
if (!Files.exists(path)) return 1; // if the history directory does not exist, then the file version is 1
path = Paths.get(historyPath);
if (!Files.exists(path)) return 1;
}
try (Stream<Path> stream = Files.walk(path, 1)) { // run through all the files in the history directory
try (Stream<Path> stream = Files.walk(path, 1)) {
return stream
.filter(file -> Files.isDirectory(file)) // take only directories from the history folder
.map(Path::getFileName) // get file names
.map(Path::toString) // and convert them into strings
.collect(Collectors.toSet()).size(); // convert stream into set and get its size which specifies the file version
.filter(file -> Files.isDirectory(file))
.map(Path::getFileName)
.map(Path::toString)
.collect(Collectors.toSet()).size();
} catch (IOException e) {
e.printStackTrace();
return 0;

View File

@ -7,7 +7,7 @@ import java.util.stream.Collectors;
@Component
public class Misc {
public String convertUserDescriptions(String username, List<String> description){ // cenvert user descriptions to the specified format
public String convertUserDescriptions(String username, List<String> description){
String result = "<div class=\"user-descr\"><b>"+username+"</b><br/><ul>"+description.
stream().map(text -> "<li>"+text+"</li>")
.collect(Collectors.joining()) + "</ul></div>";

View File

@ -1,59 +0,0 @@
package com.onlyoffice.integration.documentserver.util;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.springframework.stereotype.Component;
/**
* Disables and enables certificate and host-name checking in
* HttpsURLConnection, the default JVM implementation of the HTTPS/TLS protocol.
* Has no effect on implementations such as Apache Http Client, Ok Http.
*/
@Component
public final class SSLUtils {
private final HostnameVerifier jvmHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
private final HostnameVerifier trivialHostnameVerifier = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession sslSession) {
return true;
}
};
private final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
public void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
HttpsURLConnection.setDefaultHostnameVerifier(trivialHostnameVerifier);
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, UNQUESTIONING_TRUST_MANAGER, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
public void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
HttpsURLConnection.setDefaultHostnameVerifier(jvmHostnameVerifier);
// Return it to the initial state (discovered by reflection, now hardcoded)
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, null, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
}

Some files were not shown because too many files have changed in this diff Show More