Skip to content
Snippets Groups Projects
Commit e008081b authored by Dominik Hebeler's avatar Dominik Hebeler
Browse files

form submissions working again

parent bb730920
No related branches found
No related tags found
1 merge request!22Resolve "Increase readability of Proxy URLs"
This commit is part of merge request !22. Comments created here will be created in the context of that merge request.
......@@ -15,6 +15,22 @@ abstract class Document
$this->baseUrl = $base;
}
public function proxifyFormAction($url){
$url = trim($url);
if (stripos($url, "javascript:") === 0) {
return "";
}
// Deny Loading internal URLs and check if URL syntax is correct
$host = parse_url($url, PHP_URL_HOST);
$selfHost = \Request::getHttpHost();
if (strpos($url, "http") !== 0 || $host === false || $host === $selfHost) {
return $url;
}
return \App\Http\Controllers\ProxyController::generateFormgetUrl($url);
}
public function proxifyUrl($url, $topLevel)
{
// Only convert valid URLs
......
......@@ -168,7 +168,7 @@ class HtmlDocument extends Document
}
#
# And finally Proxify the Url
$action = $this->proxifyUrl($action, true);
$action = $this->proxifyFormAction($action);
$form->setAttribute("action", $action);
}
......
......@@ -30,6 +30,51 @@ class ProxyController extends Controller
$targetUrl = $request->input("url", "https://metager.de");
$password = $request->input("password", "");
# Check For URL-Parameters that don't belong to the Proxy but to the URL that needs to be proxied
$params = $request->except(['url', 'password']);
if (sizeof($params) > 0) {
# There are Params that need to be passed to the page
# Most of the times this happens due to forms that are submitted on a proxied page
# Let's redirect to the correct URI
$proxyParams = $request->except(array_keys($params));
$redirProxyUrl = $targetUrl;
$redirParams = [];
if (strpos($redirProxyUrl, "?") === false) {
$redirProxyUrl .= "?";
} else {
# There are already Params for this site which need to get updated
$tmpParams = substr($redirProxyUrl, strpos($redirProxyUrl, "?") + 1);
$tmpParams = explode("&", $tmpParams);
foreach ($tmpParams as $param) {
$tmp = explode("=", $param);
if (sizeof($tmp) === 2) {
$redirParams[$tmp[0]] = $tmp[1];
}
}
}
foreach ($params as $key => $value) {
$redirParams[$key] = $value;
}
foreach ($redirParams as $key => $value) {
$redirProxyUrl .= $key . "=" . urlencode($value) . "&";
}
$redirProxyUrl = rtrim($redirProxyUrl, "&");
$pw = md5(env('PROXY_PASSWORD') . $redirProxyUrl);
$redirProxyUrl = base64_encode(str_rot13($redirProxyUrl));
$redirProxyUrl = urlencode(str_replace("/", "<<SLASH>>", $redirProxyUrl));
$proxyParams['url'] = $redirProxyUrl;
$proxyParams['password'] = $pw;
$newLink = action('ProxyController@proxyPage', $proxyParams);
return redirect($newLink);
}
// Check Password
if(!self::checkPassword($targetUrl, null, $password)){
abort(400, "Invalid Request");
......@@ -93,7 +138,6 @@ class ProxyController extends Controller
// Hash Value under which a possible cached file would've been stored
$hash = md5($targetUrl);
$result = [];
$httpcode = 200;
if (!Cache::has($hash) || env("CACHE_ENABLED") === false) {
......@@ -124,10 +168,6 @@ class ProxyController extends Controller
$answer = Cache::get($hash);
}
if(stripos($targetUrl, ".svg") !== FALSE){
$test = "test";
}
if (!empty($answer["error"])) {
if ($answer["error"] === CURLE_ABORTED_BY_CALLBACK) {
// File Downloads aren't working anymore within an IFrame.
......@@ -162,7 +202,7 @@ class ProxyController extends Controller
}
$key = md5($request->ip() . microtime(true));
$headerArray[trim($index)] = $this->proxifyUrl($redLink, null, $key, false);
$headerArray[trim($index)] = self::generateProxyUrl($redLink);
} elseif (strtolower($index) === "content-disposition") {
$headerArray[strtolower(trim($index))] = strtolower(trim($value));
} else {
......@@ -213,8 +253,18 @@ class ProxyController extends Controller
$answer["headers"]["content-disposition"] = "attachment; filename=$name";
}
// no break
case 'image/png': $toggles = "111000A";
case 'image/png':
case 'image/jpeg':
case 'image/gif':
case 'application/font-woff':
case 'application/x-font-woff':
case 'application/x-empty':
case 'font/woff2':
case 'image/svg+xml':
case 'application/octet-stream':
case 'text/plain':
case 'image/x-icon':
case 'font/eot':
case 'image/vnd.microsoft.icon':
case 'application/vnd.ms-fontobject':
case 'application/x-font-ttf':
......@@ -248,6 +298,67 @@ class ProxyController extends Controller
->withHeaders($answer["headers"]);
}
/**
* This function is called if a proxied page submits a form
* It should take the submitted parameters and add them to the url
* After that it should redirect to the correct page with the correct parameters
*/
public function formget(Request $request, $password, $validUntil, $url){
if(empty($password) || empty($validUntil) || empty($url)){
abort(400, "Invalid Request");
}
// Check Password
if(!self::checkPassword($url, $validUntil, $password)){
abort(400, "Invalid Request");
}
try {
$validUntil = Carbon::createFromFormat("d-m-Y H:i:s P", $validUntil);
} catch (InvalidFormatException $e) {
abort(400, "Invalid Request");
}
if ($validUntil->isBefore(Carbon::now()->setTimezone("UTC"))) {
abort(400, "Invalid Request");
}
// Deny Loading internal URLs and check if URL syntax is correct
$host = parse_url($url, PHP_URL_HOST);
$selfHost = $request->getHttpHost();
// The target URL couldn't be parsed. This is probably a malformed URL
// The URL to load itself is a URL to our proxy
if($host === false || $host === $selfHost){
abort(404, "Invalid Request");
}
// All Checks passed we can generate a url where the submitted data is included
$submittedParameters = $request->all();
// The URL itself might contain query parameters
$containedParameters = array();
$parts = parse_url($url);
if(!empty($parts["query"])){
parse_str($parts["query"], $containedParameters);
}
$urlParameters = array_merge($submittedParameters, $containedParameters);
if(empty($parts["scheme"]) || empty($parts["host"])){
abort(400, "Invalid Request");
}
// Build the url
$targetUrl = $parts["scheme"] . "://" .
((!empty($parts["user"]) && !empty($parts["pass"])) ? $parts["user"] . ":" . $parts["pass"] . "@" : "") .
$parts["host"] .
(!empty($parts["port"]) ? ":" . $parts["port"] : "") .
(!empty($parts["path"]) ? $parts["path"] : "") .
(!empty($urlParameters) ? "?" . http_build_query($urlParameters, "", "&", PHP_QUERY_RFC3986) : "") .
(!empty($parts["fragment"]) ? "#" . $parts["fragment"] : "");
return redirect(self::generateProxyWrapperUrl($targetUrl));
}
/**
* This function generates a URL to a proxied page
* including the proxy header.
......@@ -255,7 +366,20 @@ class ProxyController extends Controller
public static function generateProxyWrapperUrl($url){
$password = self::generatePassword($url, null);
$parts = parse_url($url);
$host = null;
$path = null;
if(!empty($parts["host"])){
$host = $parts["host"];
}
if(!empty($parts["path"])){
$path = trim($parts["path"], "/");
}
$parameters = [
"host" => $host,
"path" => $path,
"url" => $url,
"password" => $password,
];
......@@ -272,7 +396,20 @@ class ProxyController extends Controller
$validUntil = self::generateValidUntilDate();
$password = self::generatePassword($url, $validUntil);
$parts = parse_url($url);
$host = null;
$path = null;
if(!empty($parts["host"])){
$host = $parts["host"];
}
if(!empty($parts["path"])){
$path = trim($parts["path"], "/");
}
$parameters = [
"host" => $host,
"path" => $path,
"url" => $url,
"valid-until" => $validUntil,
"password" => $password,
......@@ -281,6 +418,24 @@ class ProxyController extends Controller
return route('proxy', $parameters);
}
/**
* This function generates a URL to a page that takes submitted form data
* excluding the proxy header.
*/
public static function generateFormgetUrl($url){
$validUntil = self::generateValidUntilDate();
$password = self::generatePassword($url, $validUntil);
$parameters = [
"url" => $url,
"validUntil" => $validUntil,
"password" => $password,
];
return route('proxy-formget', $parameters);
}
/**
* This function generates a Date/Time String which is used by our Download Controller
* to check if a download link is valid.
......
......@@ -23,10 +23,17 @@ Route::group(['prefix' => 'download'], function () {
Route::get('/', 'DownloadController@download')->name("download");
});
Route::get('/', 'ProxyController@proxyPage')->name('proxy-wrapper-page');
Route::get('p', 'ProxyController@proxy')->name('proxy');
// Route for form submissions
Route::get('formget/{password}/{validUntil}/{url}', 'ProxyController@formget')
->name('proxy-formget')
->where('password', '[A-Fa-f0-9]{64}')
->where('url', '.*');
// Route without Proxy Header
Route::get('p/{host?}/{path?}', 'ProxyController@proxy')->name('proxy')->where('host', '[^\.]+(\.[^\.]+)+')->where('path', '(.*)');
// Route with Proxy Header
Route::get('{host?}/{path?}', 'ProxyController@proxyPage')->name('proxy-wrapper-page')->where('host', '[^\.]+(\.[^\.]+)+')->where('path', '(.*)');
Route::post('/', function (Request $request) {
Route::post('{host?}/{path?}', function (Request $request) {
if (env("APP_ENV", "") !== "production") {
$validatedData = $request->validate([
'url' => 'required|url|max:255',
......@@ -36,7 +43,7 @@ Route::post('/', function (Request $request) {
}else{
abort(400);
}
});
})->where('host', '[^\.]+(\.[^\.]+)+')->where('path', '(.*)');
/**
* This is our old Proxy route
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment