Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/duplicati/duplicati.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Skovhede <kenneth@hexad.dk>2017-07-04 00:23:39 +0300
committerKenneth Skovhede <kenneth@hexad.dk>2017-07-04 00:23:39 +0300
commit36cccd9776c7a554008a94c01e941c9bcb136185 (patch)
tree4bc59c9dd8cee153eeda76a8325484d3e51c4542
parent9394e7e3b7f6d72019a2fb647f1668505faa5fdf (diff)
parent396ea160dbb969dc8fbadd666fa45775939eb119 (diff)
Merge branch 'feature/synology_ngix_proxy'
-rw-r--r--Duplicati/Server/Duplicati.Server.csproj1
-rw-r--r--Duplicati/Server/WebServer/Server.cs3
-rw-r--r--Duplicati/Server/WebServer/SynologyAuthenticationHandler.cs288
-rw-r--r--Duplicati/Server/webroot/login/login.js4
-rw-r--r--Duplicati/Server/webroot/ngax/scripts/services/AppService.js2
-rwxr-xr-xInstaller/Synology/CGIProxyHandler.exebin20992 -> 0 bytes
-rwxr-xr-xInstaller/Synology/INFO3
-rw-r--r--Installer/Synology/dsm.duplicati.conf12
-rw-r--r--Installer/Synology/make-binary-package.sh72
-rwxr-xr-xInstaller/Synology/scripts/postinst2
-rwxr-xr-xInstaller/Synology/scripts/start-stop-status28
-rw-r--r--Installer/Synology/web-extra/nph-proxy.cgi37
-rw-r--r--Installer/Synology/web-extra/package/ngax/package.js7
-rw-r--r--Tools/CGIProxyHandler/CGIProxyHandler.csproj33
-rw-r--r--Tools/CGIProxyHandler/CGIProxyHandler.sln17
-rw-r--r--Tools/CGIProxyHandler/Program.cs427
-rw-r--r--Tools/CGIProxyHandler/Properties/AssemblyInfo.cs27
17 files changed, 404 insertions, 559 deletions
diff --git a/Duplicati/Server/Duplicati.Server.csproj b/Duplicati/Server/Duplicati.Server.csproj
index 55651e573..08f901e9d 100644
--- a/Duplicati/Server/Duplicati.Server.csproj
+++ b/Duplicati/Server/Duplicati.Server.csproj
@@ -124,6 +124,7 @@
<Compile Include="WebServer\CaptchaUtil.cs" />
<Compile Include="WebServer\RESTMethods\Captcha.cs" />
<Compile Include="WebServer\RESTMethods\CommandLine.cs" />
+ <Compile Include="WebServer\SynologyAuthenticationHandler.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
diff --git a/Duplicati/Server/WebServer/Server.cs b/Duplicati/Server/WebServer/Server.cs
index 283bc4b22..49cd201fd 100644
--- a/Duplicati/Server/WebServer/Server.cs
+++ b/Duplicati/Server/WebServer/Server.cs
@@ -212,6 +212,9 @@ namespace Duplicati.Server.WebServer
{
HttpServer.HttpServer server = new HttpServer.HttpServer();
+ if (string.Equals(Environment.GetEnvironmentVariable("SYNO_DSM_AUTH") ?? string.Empty, "1"))
+ server.Add(new SynologyAuthenticationHandler());
+
server.Add(new AuthenticationHandler());
server.Add(new RESTHandler());
diff --git a/Duplicati/Server/WebServer/SynologyAuthenticationHandler.cs b/Duplicati/Server/WebServer/SynologyAuthenticationHandler.cs
new file mode 100644
index 000000000..f85f3cd75
--- /dev/null
+++ b/Duplicati/Server/WebServer/SynologyAuthenticationHandler.cs
@@ -0,0 +1,288 @@
+// Copyright (C) 2017, The Duplicati Team
+// http://www.duplicati.com, info@duplicati.com
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using HttpServer.HttpModules;
+
+namespace Duplicati.Server.WebServer
+{
+ /// <summary>
+ /// Helper class for enforcing the built-in authentication on Synology DSM
+ /// </summary>
+ public class SynologyAuthenticationHandler : HttpModule
+ {
+ /// <summary>
+ /// The path to the login.cgi script
+ /// </summary>
+ private readonly string LOGIN_CGI = GetEnvArg("SYNO_LOGIN_CGI", "/usr/syno/synoman/webman/login.cgi");
+ /// <summary>
+ /// The path to the authenticate.cgi script
+ /// </summary>
+ private readonly string AUTH_CGI = GetEnvArg("SYNO_AUTHENTICATE_CGI", "/usr/syno/synoman/webman/modules/authenticate.cgi");
+ /// <summary>
+ /// A flag indicating if only admins are allowed
+ /// </summary>
+ private readonly bool ADMIN_ONLY = !(GetEnvArg("SYNO_ALL_USERS", "0") == "1");
+ /// <summary>
+ /// A flag indicating if the XSRF token should be fetched automatically
+ /// </summary>
+ private readonly bool AUTO_XSRF = GetEnvArg("SYNO_AUTO_XSRF", "1") == "1";
+
+ /// <summary>
+ /// A flag indicating that the auth-module is fully disabled
+ /// </summary>
+ private readonly bool FULLY_DISABLED;
+
+ /// <summary>
+ /// Re-evealuate the logins periodically to ensure it is still valid
+ /// </summary>
+ private readonly TimeSpan CACHE_TIMEOUT = TimeSpan.FromMinutes(3);
+
+ /// <summary>
+ /// A cache of previously authenticated logins
+ /// </summary>
+ private readonly Dictionary<string, DateTime> m_logincache = new Dictionary<string, DateTime>();
+
+ /// <summary>
+ /// The loca guarding the login cache
+ /// </summary>
+ private object m_lock = new object();
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="T:Duplicati.Server.WebServer.SynologyAuthenticationHandler"/> class.
+ /// </summary>
+ public SynologyAuthenticationHandler()
+ {
+ Console.WriteLine("Enabling Synology integrated authentication handler");
+ var disable = false;
+ if (!File.Exists(LOGIN_CGI))
+ {
+ Console.WriteLine("Disabling webserver as the login script is not found: {0}", LOGIN_CGI);
+ disable = true;
+ }
+ if (!File.Exists(AUTH_CGI))
+ {
+ Console.WriteLine("Disabling webserver as the auth script is not found: {0}", AUTH_CGI);
+ disable = true;
+ }
+
+ FULLY_DISABLED = disable;
+ }
+
+ /// <summary>
+ /// Processes the request
+ /// </summary>
+ /// <returns><c>true</c> if the request is handled <c>false</c> otherwise.</returns>
+ /// <param name="request">The request.</param>
+ /// <param name="response">The response.</param>
+ /// <param name="session">The session.</param>
+ public override bool Process(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session)
+ {
+ if (FULLY_DISABLED)
+ {
+ response.Status = System.Net.HttpStatusCode.ServiceUnavailable;
+ response.Reason = "The system is incorrectly configured";
+ return true;
+ }
+
+ var limitedAccess =
+ request.Uri.AbsolutePath.StartsWith(RESTHandler.API_URI_PATH, StringComparison.InvariantCultureIgnoreCase)
+ ||
+ request.Uri.AbsolutePath.StartsWith(AuthenticationHandler.LOGIN_SCRIPT_URI, StringComparison.InvariantCultureIgnoreCase)
+ ||
+ request.Uri.AbsolutePath.StartsWith(AuthenticationHandler.LOGOUT_SCRIPT_URI, StringComparison.InvariantCultureIgnoreCase);
+
+ if (!limitedAccess)
+ return false;
+
+ var tmpenv = new Dictionary<string, string>();
+
+ tmpenv["REMOTE_ADDR"] = request.RemoteEndPoint.Address.ToString();
+ tmpenv["REMOTE_PORT"] = request.RemoteEndPoint.Port.ToString();
+
+ if (!string.IsNullOrWhiteSpace(request.Headers["X-Real-IP"]))
+ tmpenv["REMOTE_ADDR"] = request.Headers["X-Real-IP"];
+ if (!string.IsNullOrWhiteSpace(request.Headers["X-Real-IP"]))
+ tmpenv["REMOTE_PORT"] = request.Headers["X-Real-Port"];
+
+ var loginid = request.Cookies["id"]?.Value;
+ if (!string.IsNullOrWhiteSpace(loginid))
+ tmpenv["HTTP_COOKIE"] = "id=" + loginid;
+
+ var xsrftoken = request.Headers["X-Syno-Token"];
+ if (string.IsNullOrWhiteSpace(xsrftoken))
+ xsrftoken = request.QueryString["SynoToken"]?.Value;
+
+ var cachestring = BuildCacheKey(tmpenv, xsrftoken);
+
+ DateTime cacheExpires;
+ if (m_logincache.TryGetValue(cachestring, out cacheExpires) && cacheExpires > DateTime.Now)
+ {
+ // We do not refresh the cache, as we need to ask the synology auth system periodically
+ return false;
+ }
+
+ if (string.IsNullOrWhiteSpace(xsrftoken) && AUTO_XSRF)
+ {
+ var authre = new Regex(@"""SynoToken""\s?\:\s?""(?<token>[^""]+)""");
+ try
+ {
+ var resp = ShellExec(LOGIN_CGI, env: tmpenv).Result;
+
+ var m = authre.Match(resp);
+ if (m.Success)
+ xsrftoken = m.Groups["token"].Value;
+ else
+ throw new Exception("Unable to get XSRF token");
+ }
+ catch (Exception ex)
+ {
+ response.Status = System.Net.HttpStatusCode.InternalServerError;
+ response.Reason = "The system is incorrectly configured";
+ return true;
+
+ }
+ }
+
+ if (!string.IsNullOrWhiteSpace(xsrftoken))
+ tmpenv["HTTP_X_SYNO_TOKEN"] = xsrftoken;
+
+ cachestring = BuildCacheKey(tmpenv, xsrftoken);
+
+ var username = GetEnvArg("SYNO_USERNAME");
+ if (string.IsNullOrWhiteSpace(username))
+ {
+ try
+ {
+ username = ShellExec(AUTH_CGI, shell: false, exitcode: 0, env: tmpenv).Result;
+ }
+ catch (Exception ex)
+ {
+ response.Status = System.Net.HttpStatusCode.InternalServerError;
+ response.Reason = "The system is incorrectly configured";
+ return true;
+ }
+ }
+
+ if (string.IsNullOrWhiteSpace(username))
+ {
+ response.Status = System.Net.HttpStatusCode.Forbidden;
+ response.Reason = "Permission denied, not logged in";
+ return true;
+ }
+
+ username = username.Trim();
+
+ if (ADMIN_ONLY)
+ {
+ var groups = GetEnvArg("SYNO_GROUP_IDS");
+
+ if (string.IsNullOrWhiteSpace(groups))
+ groups = ShellExec("id", "-G '" + username.Trim().Replace("'", "\\'") + "'", exitcode: 0).Result ?? string.Empty;
+ if (!groups.Split(new char[] { ' ' }).Contains("101"))
+ {
+ response.Status = System.Net.HttpStatusCode.Forbidden;
+ response.Reason = "Administrator login required";
+ return true;
+ }
+ }
+
+ // We are now authenticated, add to cache
+ m_logincache[cachestring] = DateTime.Now + CACHE_TIMEOUT;
+ return false;
+ }
+
+ /// <summary>
+ /// Builds a cache key from the environment data
+ /// </summary>
+ /// <returns>The cache key.</returns>
+ /// <param name="values">The environment.</param>
+ /// <param name="xsrftoken">The XSRF token.</param>
+ private static string BuildCacheKey(Dictionary<string, string> values, string xsrftoken)
+ {
+ if (!values.ContainsKey("REMOTE_ADDR") || !values.ContainsKey("REMOTE_PORT") || !values.ContainsKey("HTTP_COOKIE"))
+ return null;
+
+ return string.Format("{0}:{1}/{2}?{3}", values["REMOTE_ADDR"], values["REMOTE_PORT"], values["HTTP_COOKIE"], xsrftoken);
+ }
+
+ /// <summary>
+ /// Runs an external command
+ /// </summary>
+ /// <returns>The stdout data.</returns>
+ /// <param name="command">The executable</param>
+ /// <param name="args">The executable and the arguments.</param>
+ /// <param name="shell">If set to <c>true</c> use the shell context for execution.</param>
+ /// <param name="exitcode">Set the value to check for a particular exitcode.</param>
+ private static async Task<string> ShellExec(string command, string args = null, bool shell = false, int exitcode = -1, Dictionary<string, string> env = null)
+ {
+ var psi = new ProcessStartInfo()
+ {
+ FileName = command,
+ Arguments = shell ? null : args,
+ UseShellExecute = false,
+ RedirectStandardInput = shell,
+ RedirectStandardOutput = true
+ };
+
+ if (env != null)
+ foreach (var pk in env)
+ psi.EnvironmentVariables[pk.Key] = pk.Value;
+
+ using (var p = System.Diagnostics.Process.Start(psi))
+ {
+ if (shell && args != null)
+ await p.StandardInput.WriteLineAsync(args);
+
+ var res = p.StandardOutput.ReadToEndAsync();
+
+ var tries = 10;
+ var ms = (int)TimeSpan.FromSeconds(0.5).TotalMilliseconds;
+ while (tries > 0 && !p.HasExited)
+ {
+ tries--;
+ p.WaitForExit(ms);
+ }
+
+ if (!p.HasExited)
+ try { p.Kill(); }
+ catch { }
+
+ if (!p.HasExited || (p.ExitCode != exitcode && exitcode != -1))
+ throw new Exception(string.Format("Exit code was: {0}, stdout: {1}", p.ExitCode, res));
+ return await res;
+ }
+ }
+
+ /// <summary>
+ /// Gets the environment variable argument.
+ /// </summary>
+ /// <returns>The environment variable.</returns>
+ /// <param name="key">The name of the environment variable.</param>
+ /// <param name="default">The default value.</param>
+ private static string GetEnvArg(string key, string @default = null)
+ {
+ var res = Environment.GetEnvironmentVariable(key);
+ return string.IsNullOrWhiteSpace(res) ? @default : res.Trim();
+ }
+ }
+}
diff --git a/Duplicati/Server/webroot/login/login.js b/Duplicati/Server/webroot/login/login.js
index 1f22ce68e..e2c2de461 100644
--- a/Duplicati/Server/webroot/login/login.js
+++ b/Duplicati/Server/webroot/login/login.js
@@ -10,7 +10,7 @@ $(document).ready(function() {
// First we grab the nonce and salt
$.ajax({
- url: '/login.cgi',
+ url: './login.cgi',
type: 'POST',
dataType: 'json',
data: {'get-nonce': 1}
@@ -21,7 +21,7 @@ $(document).ready(function() {
var noncedpwd = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(CryptoJS.enc.Base64.parse(data.Nonce) + saltedpwd)).toString(CryptoJS.enc.Base64);
$.ajax({
- url: '/login.cgi',
+ url: './login.cgi',
type: 'POST',
dataType: 'json',
data: {'password': noncedpwd }
diff --git a/Duplicati/Server/webroot/ngax/scripts/services/AppService.js b/Duplicati/Server/webroot/ngax/scripts/services/AppService.js
index 5127094f3..54ffbd112 100644
--- a/Duplicati/Server/webroot/ngax/scripts/services/AppService.js
+++ b/Duplicati/Server/webroot/ngax/scripts/services/AppService.js
@@ -1,5 +1,5 @@
backupApp.service('AppService', function($http, $cookies, $q, $cookies, DialogService, appConfig) {
- this.apiurl = '/api/v1';
+ this.apiurl = '../api/v1';
this.proxy_url = null;
var self = this;
diff --git a/Installer/Synology/CGIProxyHandler.exe b/Installer/Synology/CGIProxyHandler.exe
deleted file mode 100755
index 7fba2766a..000000000
--- a/Installer/Synology/CGIProxyHandler.exe
+++ /dev/null
Binary files differ
diff --git a/Installer/Synology/INFO b/Installer/Synology/INFO
index 9ed7439ff..1af1ba15a 100755
--- a/Installer/Synology/INFO
+++ b/Installer/Synology/INFO
@@ -14,4 +14,5 @@ start_dep_services="mono"
thirdparty="yes"
support_conf_folder="yes"
description="Duplicati is a free, open source, backup client that securely stores encrypted, incremental, compressed backups on cloud storage services and remote file servers."
-firmware="5.0-4418"
+firmware="6.0-7300"
+startstop_restart_services="nginx"
diff --git a/Installer/Synology/dsm.duplicati.conf b/Installer/Synology/dsm.duplicati.conf
new file mode 100644
index 000000000..f6971d22b
--- /dev/null
+++ b/Installer/Synology/dsm.duplicati.conf
@@ -0,0 +1,12 @@
+location ~ ^/webman/3rdparty/Duplicati/((.*)\.cgi|api/(.*))$ {
+ proxy_set_header X-Server-IP $server_addr;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Real-HTTPS $https;
+ proxy_set_header X-Server-Port $server_port;
+ proxy_set_header X-Real-Port $remote_port;
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Forwarded-Host $http_host;
+
+ proxy_http_version 1.1;
+ proxy_pass http://127.0.0.1:8200/$1$is_args$args;
+} \ No newline at end of file
diff --git a/Installer/Synology/make-binary-package.sh b/Installer/Synology/make-binary-package.sh
index 342ce48ae..8d9994a0a 100644
--- a/Installer/Synology/make-binary-package.sh
+++ b/Installer/Synology/make-binary-package.sh
@@ -10,11 +10,22 @@ DIRNAME=`echo "${FILENAME}" | cut -d "_" -f 1`
VERSION=`echo "${DIRNAME}" | cut -d "-" -f 2`
DATE_STAMP=`LANG=C date -R`
BASE_FILE_NAME="${FILENAME%.*}"
+TMPDIRNAME="${BASE_FILE_NAME}-extract"
+MONO=/Library/Frameworks/Mono.framework/Commands/mono
+GPG_KEYFILE="${HOME}/.config/signkeys/Duplicati/updater-gpgkey.key"
+
+# Sort on macOS does not have -V / --version-sort
+# https://stackoverflow.com/questions/4493205/unix-sort-of-version-numbers
+SORT_OPTIONS="-t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n"
if [ -d "${DIRNAME}" ]; then
rm -rf "${DIRNAME}"
fi
+if [ -d "${TMPDIRNAME}" ]; then
+ rm -rf "${TMPDIRNAME}"
+fi
+
if [ -f "package.tgz" ]; then
rm -rf "package.tgz"
fi
@@ -23,7 +34,17 @@ if [ -f "${BASE_FILE_NAME}.spk" ]; then
rm -rf "${BASE_FILE_NAME}.spk"
fi
-unzip -d "${DIRNAME}" "$1"
+if [ -f "${BASE_FILE_NAME}.spk.tmp" ]; then
+ rm -rf "${BASE_FILE_NAME}.spk.tmp"
+fi
+
+if [ -f "${BASE_FILE_NAME}.signature" ]; then
+ rm -rf "${BASE_FILE_NAME}.spk.signature"
+fi
+
+TIMESERVER="http://timestamp.synology.com/timestamp.php"
+
+unzip -q -d "${DIRNAME}" "$1"
for n in "../oem" "../../oem" "../../../oem"
do
@@ -60,27 +81,68 @@ rm -rf ./licenses/alphavss
rm -rf ./licenses/MonoMac
rm -rf ./licenses/gpg
-# Install extra control items for Synology
+# Install extra items for Synology
cp -R ../web-extra/* webroot/
-cp ../CGIProxyHandler.exe .
+cp ../dsm.duplicati.conf .
DIRSIZE_KB=`BLOCKSIZE=1024 du -s | cut -d '.' -f 1`
let "DIRSIZE=DIRSIZE_KB*1024"
-tar cvf ../package.tgz ./*
+tar cf ../package.tgz ./*
cd ..
rm -rf "${DIRNAME}"
+ICON_72=$(openssl base64 -A -in PACKAGE_ICON.PNG)
+ICON_256=$(openssl base64 -A -in PACKAGE_ICON_256.PNG)
+
git checkout INFO
echo "version=\"${VERSION}\"" >> "INFO"
MD5=`md5 "package.tgz" | awk -F ' ' '{print $NF}'`
echo "checksum=\"${MD5}\"" >> "INFO"
echo "extractsize=\"${DIRSIZE}\"" >> "INFO"
+echo "package_icon=\"${ICON_72}\"" >> "INFO"
+echo "package_icon_256=\"${ICON_256}\"" >> "INFO"
chmod +x scripts/*
tar cf "${BASE_FILE_NAME}.spk" INFO LICENSE *.PNG package.tgz scripts conf WIZARD_UIFILES
+
git checkout INFO
+rm package.tgz
+
+if [ -f "${GPG_KEYFILE}" ]; then
+ if [ "z${KEYFILE_PASSWORD}" == "z" ]; then
+ echo -n "Enter keyfile password: "
+ read -s KEYFILE_PASSWORD
+ echo
+ fi
+
+ GPGDATA=`"${MONO}" "../../BuildTools/AutoUpdateBuilder/bin/Debug/SharpAESCrypt.exe" d "${KEYFILE_PASSWORD}" "${GPG_KEYFILE}"`
+ if [ ! $? -eq 0 ]; then
+ echo "Decrypting GPG keyfile failed"
+ exit 1
+ fi
+ GPGID=`echo "${GPGDATA}" | head -n 1`
+ GPGKEY=`echo "${GPGDATA}" | head -n 2 | tail -n 1`
+else
+ echo "No GPG keyfile found, skipping gpg signing"
+fi
+
+if [ "z${GPGID}" != "z" ]; then
+ # Now codesign the spk file
+ mkdir "${TMPDIRNAME}"
+ tar xf "${BASE_FILE_NAME}.spk" -C "${TMPDIRNAME}"
+ cat $(find ${TMPDIRNAME} -type f | sort ${SORT_OPTIONS}) > "${BASE_FILE_NAME}.spk.tmp"
+
+ gpg2 --ignore-time-conflict --ignore-valid-from --yes --batch --armor --detach-sign --default-key="${GPGID}" --output "${BASE_FILE_NAME}.signature" "${BASE_FILE_NAME}.spk.tmp"
+ rm "${BASE_FILE_NAME}.spk.tmp"
+
+ curl --silent --form "file=@${BASE_FILE_NAME}.signature" "${TIMESERVER}" > "${TMPDIRNAME}/syno_signature.asc"
+ rm "${BASE_FILE_NAME}.signature"
+
+ rm "${BASE_FILE_NAME}.spk"
+ tar cf "${BASE_FILE_NAME}.spk" -C "${TMPDIRNAME}" `ls -1 ${TMPDIRNAME}`
-rm package.tgz \ No newline at end of file
+ rm -rf "${TMPDIRNAME}"
+fi \ No newline at end of file
diff --git a/Installer/Synology/scripts/postinst b/Installer/Synology/scripts/postinst
index ef6208fb9..bda2ac6af 100755
--- a/Installer/Synology/scripts/postinst
+++ b/Installer/Synology/scripts/postinst
@@ -1,4 +1,6 @@
#!/bin/sh
+mkdir -p /usr/local/bin
+
echo "mono ${SYNOPKG_PKGDEST}/Duplicati.CommandLine.exe $@" > "/usr/local/bin/duplicati-cli"
chmod +x "/usr/local/bin/duplicati-cli"
diff --git a/Installer/Synology/scripts/start-stop-status b/Installer/Synology/scripts/start-stop-status
index 929a5aa0a..d23961e96 100755
--- a/Installer/Synology/scripts/start-stop-status
+++ b/Installer/Synology/scripts/start-stop-status
@@ -6,6 +6,23 @@ PACKAGE_NAME_SIMPLE="$(echo "$SYNOPKG_PKGNAME" | awk '{print tolower($0)}' | sed
PACKAGE_DIR="${SYNOPKG_PKGDEST}"
PACKAGE_UPGRADE_FLAG="/tmp/${PACKAGE_NAME_SIMPLE}.upgrade"
+# We need more space than what /tmp holds
+PACKAGE_TEMP_DIR="${PACKAGE_DIR}/temp"
+
+# These control how the authentication is integrated
+SYNO_LOGIN_CGI=/usr/syno/synoman/webman/login.cgi
+SYNO_AUTHENTICATE_CGI=/usr/syno/synoman/webman/modules/authenticate.cgi
+
+# If all users should have access, set to "1"
+SYNO_ALL_USERS=0
+
+# If we should disable verification of Synology's XSRF tokens, set to "1"
+SYNO_SKIP_XSRF=0
+
+# If we should disable Synology auth completely, set to "0"
+SYNO_DSM_AUTH=1
+
+
# Start & Stop Varables
PID_FILE="/var/run/${PACKAGE_NAME_SIMPLE}.pid"
@@ -13,9 +30,14 @@ DaemonStart() {
DaemonStatus
if [ $? == 0 ]; then
echo "Starting ${PACKAGE_NAME_SIMPLE}."
-
- mono "${PACKAGE_DIR}/Duplicati.Server.exe" &
+
+ mkdir -p "${PACKAGE_TEMP_DIR}"
+
+ TMP_DIR="${PACKAGE_TEMP_DIR}" TEMP="${PACKAGE_TEMP_DIR}" mono "${PACKAGE_DIR}/Duplicati.Server.exe" &
echo $! > "$PID_FILE"
+
+ cp -f ${PACKAGE_DIR}/dsm.duplicati.conf /usr/local/etc/nginx/conf.d/
+
else
echo "${PACKAGE_NAME_SIMPLE} already running."
fi
@@ -32,6 +54,8 @@ DaemonStop() {
kill $(cat "$PID_FILE");
rm -f "$PID_FILE"
+ rm -f /usr/local/etc/nginx/conf.d/dsm.duplicati.conf
+
sleep 3
else
echo "Nothing to stop for ${PACKAGE_NAME_SIMPLE}."
diff --git a/Installer/Synology/web-extra/nph-proxy.cgi b/Installer/Synology/web-extra/nph-proxy.cgi
deleted file mode 100644
index f57ca3b8b..000000000
--- a/Installer/Synology/web-extra/nph-proxy.cgi
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-
-# Basic configuration for the proxy handler
-export SYNO_LOGIN_CGI=/usr/syno/synoman/webman/login.cgi
-export SYNO_AUTHENTICATE_CGI=/usr/syno/synoman/webman/modules/authenticate.cgi
-export SYNO_ALL_USERS=0
-export SYNO_AUTO_XSRF=1
-export SYNO_SKIP_AUTH=0
-export PROXY_HOST=localhost
-export PROXY_PORT=8200
-export PROXY_DEBUG=0
-export PROXY_LOGFILE=/var/log/duplicati-proxy.log
-
-# It seems it is faster to set this up in the script,
-# instead of letting the CGIProxyHandler do it
-if [ "z$SYNO_SKIP_AUTH" != "z1" ]; then
-
- if [ "z$HTTP_X_SYNO_TOKEN" == "z" ]; then
- if [ "z$SYNO_AUTO_XSRF" == "z1" ]; then
- TOKEN=`$SYNO_LOGIN_CGI < /dev/null | grep SynoToken | cut -d '"' -f 4`
- export HTTP_X_SYNO_TOKEN="$TOKEN"
- fi
- fi
-
- if [ "z$HTTP_X_SYNO_TOKEN" != "z" ]; then
- USERNAME=`QUERY_STRING=SynoToken=$HTTP_X_SYNO_TOKEN $SYNO_AUTHENTICATE_CGI < /dev/null`
- export SYNO_USERNAME="$USERNAME"
- fi
-
- if [ "z$USERNAME" != "z" ]; then
- GROUP_IDS=`id -G "$USERNAME" < /dev/null`
- export SYNO_GROUP_IDS="$GROUP_IDS"
- fi
-fi
-
-# This line is injected by the postinst script
-#mono /var/packages/Duplicati/target/CGIProxyHandler.exe \ No newline at end of file
diff --git a/Installer/Synology/web-extra/package/ngax/package.js b/Installer/Synology/web-extra/package/ngax/package.js
index 72b2fad25..027f067e7 100644
--- a/Installer/Synology/web-extra/package/ngax/package.js
+++ b/Installer/Synology/web-extra/package/ngax/package.js
@@ -1,6 +1,4 @@
backupApp.service('ProxyService', function(AppService, $http) {
- AppService.proxy_url = "../nph-proxy.cgi";
-
var origconfig = AppService.proxy_config;
var synotoken = null;
var is_grabbing = false;
@@ -39,14 +37,9 @@ backupApp.service('ProxyService', function(AppService, $http) {
AppService.proxy_config = function(method, options, data, targeturl) {
grab_syno_token();
- options.headers['X-Proxy-Path'] = targeturl;
-
if (synotoken != null)
options.headers['X-Syno-Token'] = synotoken;
- if (options.timeout == null || options.timeout < 30000)
- options.timeout = 30000;
-
if (origconfig != null)
origconfig(method, options, data, targeturl);
};
diff --git a/Tools/CGIProxyHandler/CGIProxyHandler.csproj b/Tools/CGIProxyHandler/CGIProxyHandler.csproj
deleted file mode 100644
index 1939f37ec..000000000
--- a/Tools/CGIProxyHandler/CGIProxyHandler.csproj
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{EA4505A7-3BDE-4057-BD90-94808D649570}</ProjectGuid>
- <OutputType>Exe</OutputType>
- <Prefer32Bit>False</Prefer32Bit>
- <RootNamespace>CGIProxyHandler</RootNamespace>
- <AssemblyName>CGIProxyHandler</AssemblyName>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug</OutputPath>
- <WarningLevel>4</WarningLevel>
- <DebugSymbols>true</DebugSymbols>
- <DefineConstants>DEBUG</DefineConstants>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <Optimize>true</Optimize>
- <OutputPath>bin\Release</OutputPath>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="Program.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- </ItemGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-</Project> \ No newline at end of file
diff --git a/Tools/CGIProxyHandler/CGIProxyHandler.sln b/Tools/CGIProxyHandler/CGIProxyHandler.sln
deleted file mode 100644
index dec62370f..000000000
--- a/Tools/CGIProxyHandler/CGIProxyHandler.sln
+++ /dev/null
@@ -1,17 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CGIProxyHandler", "CGIProxyHandler.csproj", "{EA4505A7-3BDE-4057-BD90-94808D649570}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {EA4505A7-3BDE-4057-BD90-94808D649570}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EA4505A7-3BDE-4057-BD90-94808D649570}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EA4505A7-3BDE-4057-BD90-94808D649570}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EA4505A7-3BDE-4057-BD90-94808D649570}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
-EndGlobal
diff --git a/Tools/CGIProxyHandler/Program.cs b/Tools/CGIProxyHandler/Program.cs
deleted file mode 100644
index dc423699b..000000000
--- a/Tools/CGIProxyHandler/Program.cs
+++ /dev/null
@@ -1,427 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.Threading.Tasks;
-using System.Text.RegularExpressions;
-using System.Linq;
-using System.IO;
-using System.Collections.Generic;
-using System.Threading;
-using System.Runtime.InteropServices;
-
-namespace CGIProxyHandler
-{
- class MainClass
- {
- private class LogHandler
- {
- private object m_lock = new object();
- private StreamWriter m_stream;
- private bool m_debug;
-
- public LogHandler(StreamWriter writer, bool debug)
- {
- m_stream = writer;
- m_debug = debug;
- }
-
- public void WriteMessage(string msg)
- {
- if (m_stream != null)
- lock(m_lock)
- m_stream.WriteLine(msg);
- }
-
- public void WriteDebugMessage(string msg)
- {
- if (m_stream != null && m_debug)
- lock(m_lock)
- m_stream.WriteLine(msg);
- }
-
- }
-
- /// <summary>
- /// Runs an external command
- /// </summary>
- /// <returns>The stdout data.</returns>
- /// <param name="command">The executable</param>
- /// <param name="args">The executable and the arguments.</param>
- /// <param name="shell">If set to <c>true</c> use the shell context for execution.</param>
- /// <param name="exitcode">Set the value to check for a particular exitcode.</param>
- private static async Task<string> ShellExec(string command, string args = null, bool shell = false, int exitcode = -1, Dictionary<string, string> env = null)
- {
- var psi = new ProcessStartInfo() {
- FileName = command,
- Arguments = shell ? null : args,
- UseShellExecute = false,
- RedirectStandardInput = shell,
- RedirectStandardOutput = true
- };
-
- if (env != null)
- foreach (var pk in env)
- psi.EnvironmentVariables[pk.Key] = pk.Value;
-
- using (var p = Process.Start(psi))
- {
- if (shell && args != null)
- await p.StandardInput.WriteLineAsync(args);
-
- var res = await p.StandardOutput.ReadToEndAsync();
-
- p.WaitForExit((int)TimeSpan.FromSeconds(5).TotalMilliseconds);
-
- if (p.ExitCode != exitcode && exitcode != -1)
- throw new Exception(string.Format("Exit code was: {0}, stdout: {1}", p.ExitCode, res));
- return res;
- }
- }
-
- private static string GetEnvArg(string key, string @default = null)
- {
- var res = Environment.GetEnvironmentVariable(key);
- return string.IsNullOrWhiteSpace(res) ? @default : res.Trim();
- }
-
- private const string CRLF = "\r\n";
- private static readonly byte[] ERROR_MESSAGE = System.Text.Encoding.ASCII.GetBytes("Status: 500 Server error" + CRLF + CRLF);
-
- public static void Main(string[] args)
- {
- var debug = GetEnvArg("PROXY_DEBUG", "0") == "1";
- var logfile = GetEnvArg("PROXY_LOGFILE", "/var/log/duplicat-proxy.log");
-
- using (var logout = new StreamWriter(File.Open(logfile, System.IO.FileMode.Append, FileAccess.Write, FileShare.ReadWrite)))
- using(var stdout = Console.OpenStandardOutput())
- {
- if (logout != null)
- logout.AutoFlush = true;
-
-
- var logger = new LogHandler(logout, debug);
-
- try
- {
- //stdout.WriteTimeout = (int)ACTIVITY_TIMEOUT.TotalMilliseconds;
- logger.WriteDebugMessage("Started!");
- logger.WriteDebugMessage(string.Format("Processing request for target url: {0}", GetEnvArg("HTTP_X_PROXY_PATH")));
-
- logger.WriteDebugMessage(string.Format("Redirects: {0},{1},{2}", Console.IsInputRedirected, Console.IsOutputRedirected, Console.IsErrorRedirected));
-
- if (args == null)
- args = new string[0];
-
- foreach(var a in args)
- logger.WriteDebugMessage(string.Format("arg: {0}", a));
-
- Run(args, logger, stdout).Wait();
- }
- catch (Exception ex)
- {
- var rex = ex;
- if (rex is AggregateException && (rex as AggregateException).Flatten().InnerExceptions.Count == 1)
- rex = (rex as AggregateException).Flatten().InnerExceptions.First();
-
- if (debug)
- logger.WriteMessage(string.Format("Failed: {0}", rex));
- else
- logger.WriteMessage(string.Format("Failed: {0}", rex.Message));
-
- try
- {
- stdout.Write(ERROR_MESSAGE, 0, ERROR_MESSAGE.Length);
- }
- catch (Exception ex2)
- {
- logger.WriteDebugMessage(string.Format("Failed to set error status: {0}", ex2));
- }
- }
- }
- }
-
-
- private static async Task Run(string[] args, LogHandler logger, Stream stdout)
- {
- var login_cgi = GetEnvArg("SYNO_LOGIN_CGI", "/usr/syno/synoman/webman/login.cgi");
- var auth_cgi = GetEnvArg("SYNO_AUTHENTICATE_CGI", "/usr/syno/synoman/webman/modules/authenticate.cgi");
- var admin_only = !(GetEnvArg("SYNO_ALL_USERS", "0") == "1");
- var auto_xsrf = GetEnvArg("SYNO_AUTO_XSRF", "1") == "1";
- var skip_auth = GetEnvArg("SYNO_SKIP_AUTH", "0") == "1";
- var query_string = GetEnvArg("QUERY_STRING", "");
- var proxy_host = GetEnvArg("PROXY_HOST", "localhost");
- var proxy_port = GetEnvArg("PROXY_PORT", "8200");
-
- var xsrftoken = GetEnvArg("HTTP_X_SYNO_TOKEN");
- if (string.IsNullOrWhiteSpace(xsrftoken) && !string.IsNullOrWhiteSpace(query_string))
- {
- // Avoid loading a library just for parsing the token
- var tkre = new Regex(@"SynoToken=(<?token>[^&+])");
- var m = tkre.Match(query_string);
- if (m.Success)
- xsrftoken = m.Groups["token"].Value;
- }
-
- if (!skip_auth)
- {
- if (string.IsNullOrWhiteSpace(xsrftoken) && auto_xsrf)
- {
- var authre = new Regex(@"""SynoToken""\s?\:\s?""(?<token>[^""]+)""");
- var resp = await ShellExec(login_cgi);
-
- logger.WriteDebugMessage(string.Format("xsrf response is: {0}", resp));
-
- var m = authre.Match(resp);
- if (m.Success)
- xsrftoken = m.Groups["token"].Value;
- else
- throw new Exception("Unable to get XSRF token");
- }
-
- var tmpenv = new Dictionary<string, string>();
- tmpenv["QUERY_STRING"] = "SynoToken=" + xsrftoken;
-
- var username = GetEnvArg("SYNO_USERNAME");
-
- if (string.IsNullOrWhiteSpace(username))
- {
- username = await ShellExec(auth_cgi, shell: false, exitcode: 0, env: tmpenv);
- logger.WriteDebugMessage(string.Format("Username: {0}", username));
- }
-
- if (string.IsNullOrWhiteSpace(username))
- throw new Exception("Not logged in");
-
- username = username.Trim();
-
- if (admin_only)
- {
- var groups = GetEnvArg("SYNO_GROUP_IDS");
-
- if (string.IsNullOrWhiteSpace(groups))
- groups = await ShellExec("id", "-G '" + username.Trim().Replace("'", "\\'") + "'", exitcode: 0) ?? "";
- if (!groups.Split(new char[] { ' ' }).Contains("101"))
- throw new Exception(string.Format("User {0} is not an admin", username));
-
- logger.WriteDebugMessage("User is admin");
- }
- }
-
- var path = GetEnvArg("HTTP_X_PROXY_PATH");
- if (string.IsNullOrWhiteSpace(path))
- {
- var xpre = new Regex(@"x-proxy-path=(<?url>[^&+])");
- var m = xpre.Match(query_string);
- if (m.Success)
- path = Uri.UnescapeDataString(m.Groups["url"].Value);
- }
-
- logger.WriteDebugMessage(string.Format("Path is {0} and query string is {1}", path, query_string));
-
- if (string.IsNullOrWhiteSpace(path) || !path.StartsWith("/"))
- throw new Exception("Invalid path requested");
-
- if (!string.IsNullOrWhiteSpace(query_string))
- path += (query_string.StartsWith("?") ? "" : "?") + Uri.EscapeUriString(query_string);
-
- int port;
- if (!int.TryParse(proxy_port, out port))
- port = 8200;
-
- logger.WriteDebugMessage(string.Format("About to connect to {0}:{1}", proxy_host, port));
-
- using (var client = new System.Net.Sockets.TcpClient())
- {
- logger.WriteDebugMessage(string.Format("Connecting to {0}:{1}", proxy_host, port));
- client.Connect(proxy_host, port);
- logger.WriteDebugMessage("Connected");
-
- using (var ns = client.GetStream())
- {
- logger.WriteDebugMessage("Opened TCP stream");
-
- using (var sw = new StreamWriter(ns))
- {
- logger.WriteDebugMessage("Created StreamWriter");
-
- //await ForwardRequest(sw, path, logout);
- //await ForwardResponse(ns, stdout, logout);
-
- await Task.WhenAll(
- ForwardRequest(sw, path, logger),
- ForwardResponse(ns, stdout, logger)
- );
-
- logger.WriteDebugMessage("Done processing");
- }
- }
- }
- }
-
- private static readonly byte[] STATUS_PREFIX = System.Text.Encoding.ASCII.GetBytes("Status: ");
- private static readonly int HTTP_HEAD_LEN = "HTTP/1.1 ".Length;
-
-
- private static async Task ForwardResponse(Stream source, Stream target, LogHandler logger)
- {
- var buf = new byte[8 * 1024];
- int r = 0;
- int offset = 0;
- var lastmatch = 0;
- var status = false;
- long contentlength = -1;
- var canceltoken = new CancellationTokenSource();
-
- logger.WriteDebugMessage("Forward response");
-
- while ((r = await source.ReadAsync(buf, offset, buf.Length - offset, canceltoken.Token)) != 0)
- {
- logger.WriteDebugMessage(string.Format("Read {0} bytes", r));
-
- offset += r;
- var ix = Array.IndexOf(buf, (byte)13, 0, offset);
-
- while (ix >= 0 && ix < offset - 1)
- {
- if (buf[ix + 1] == 10)
- {
- if (!status)
- {
- status = true;
- logger.WriteDebugMessage("Writing: Status: " + System.Text.Encoding.ASCII.GetString(buf, lastmatch + HTTP_HEAD_LEN, ix - lastmatch - HTTP_HEAD_LEN));
-
- await target.WriteAsync(STATUS_PREFIX, 0, STATUS_PREFIX.Length, canceltoken.Token);
- await target.WriteAsync(buf, lastmatch + HTTP_HEAD_LEN, (ix - lastmatch - HTTP_HEAD_LEN) + 2, canceltoken.Token);
-
- logger.WriteDebugMessage("Wrote status line");
- }
- else
- {
- // Blank line and we are done
- if (ix - lastmatch == 0)
- {
- logger.WriteDebugMessage(string.Format("Completed header, writing remaining {0} bytes", offset - lastmatch));
-
- await target.WriteAsync(buf, lastmatch, offset - lastmatch, canceltoken.Token);
-
- // Adjust remaining data length
- if (contentlength > 0)
- contentlength -= offset - lastmatch - 2;
-
-
- logger.WriteDebugMessage(string.Format("Body has remaining {0} bytes", contentlength));
-
- while(contentlength > 0)
- {
- r = await source.ReadAsync(buf, 0, (int)Math.Min(buf.Length, contentlength), canceltoken.Token);
- if (r == 0)
- break;
-
- contentlength -= r;
-
-
- await target.WriteAsync(buf, 0, r, canceltoken.Token);
-
- logger.WriteDebugMessage(string.Format("Body has remaining {0} bytes", contentlength));
- }
-
- await target.FlushAsync(canceltoken.Token);
-
- //await logout.WriteDebugMessageAsync(string.Format("Last body chunck: {0}", System.Text.Encoding.ASCII.GetString(buf, 0, r)));
- logger.WriteDebugMessage(string.Format("Completed response forward"));
-
- target.Close();
-
- return;
- }
- else
- {
-
- var header = System.Text.Encoding.ASCII.GetString(buf, lastmatch, ix - lastmatch) ?? string.Empty;
- if (header.StartsWith("Content-Length: ", StringComparison.OrdinalIgnoreCase))
- if (!long.TryParse(header.Substring("Content-Length: ".Length), out contentlength))
- contentlength = -1;
-
- logger.WriteDebugMessage("Writing: " + header);
-
- await target.WriteAsync(buf, lastmatch, (ix - lastmatch) + 2, canceltoken.Token);
- }
-
- }
-
- lastmatch = ix + 2;
- }
-
- //await logger.WriteDebugMessageAsync(string.Format("Buf stats: {0},{1},{2},{3}", buf.Length, ix, offset, lastmatch));
-
- ix = Array.IndexOf(buf, (byte)13, ix + 1, offset - ix - 1);
- }
- }
-
- }
-
- private static async Task ForwardRequest(StreamWriter sw, string path, LogHandler logger)
- {
- var canceltoken = new CancellationTokenSource();
- var env = Environment.GetEnvironmentVariables();
-
- /*foreach (var k in env.Keys)
- logger.WriteDebugMessage(string.Format("{0}: {1}", k, env[k]));*/
-
- await sw.WriteAsync(string.Format("{0} {1} HTTP/1.1{2}", GetEnvArg("REQUEST_METHOD", "").Trim(), path, CRLF));
-
- logger.WriteDebugMessage("Wrote request header line");
-
- foreach (var key in env.Keys.Cast<string>().Where<string>(x => x.StartsWith("HTTP_")))
- await sw.WriteAsync(string.Format("{0}: {1}{2}", key.Substring("HTTP_".Length).Replace("_", "-"), env[key], CRLF));
-
- if (!string.IsNullOrWhiteSpace(GetEnvArg("CONTENT_TYPE")))
- await sw.WriteAsync(string.Format("{0}: {1}{2}", "Content-Type", GetEnvArg("CONTENT_TYPE"), CRLF));
- if (!string.IsNullOrWhiteSpace(GetEnvArg("CONTENT_LENGTH")))
- await sw.WriteAsync(string.Format("{0}: {1}{2}", "Content-Length", GetEnvArg("CONTENT_LENGTH"), CRLF));
-
- await sw.WriteAsync(string.Format("{0}: {1}{2}", "Connection", "close", CRLF));
-
- await sw.WriteAsync(CRLF);
- await sw.FlushAsync();
-
- logger.WriteDebugMessage("Wrote all header lines");
-
- if (new string[] { "POST", "PUT", "PATCH" }.Contains(GetEnvArg("REQUEST_METHOD", "").Trim().ToUpper()))
- {
- logger.WriteDebugMessage(string.Format("Copying StdIn"));
-
- using(var stdin = Console.OpenStandardInput())
- {
- logger.WriteDebugMessage("Opened StdIn");
-
- long reqsize;
- if (!long.TryParse(GetEnvArg("CONTENT_LENGTH"), out reqsize))
- reqsize = long.MaxValue;
-
- var buf = new byte[4 * 1024 * 1024];
- var r = 0;
- while(reqsize > 0)
- {
- logger.WriteDebugMessage(string.Format("Remaining {0} bytes from stdin", reqsize));
-
- r = await stdin.ReadAsync(buf, 0, buf.Length, canceltoken.Token);
- logger.WriteDebugMessage(string.Format("Got {0} bytes from stdin", r));
-
- if (r == 0)
- break;
-
- reqsize -= r;
- await sw.BaseStream.WriteAsync(buf, 0, r, canceltoken.Token);
- }
- }
-
- logger.WriteDebugMessage("Copy stdin done");
-
- }
-
- logger.WriteDebugMessage("Completed writing request");
-
- }
-
- }
-}
diff --git a/Tools/CGIProxyHandler/Properties/AssemblyInfo.cs b/Tools/CGIProxyHandler/Properties/AssemblyInfo.cs
deleted file mode 100644
index 4cb3fd3f2..000000000
--- a/Tools/CGIProxyHandler/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
-
-[assembly: AssemblyTitle("CGIProxyHandler")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("kenneth")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
-
-[assembly: AssemblyVersion("2.0.0.7")]
-
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-
-//[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("")]
-