Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add redirect capabilities to Invest Controller #627

Merged
merged 8 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Resources/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ url:
- /password-reset
- /signup

# Domains that are allowed by the application to redirect to outside of the platform.
allowed_domains:

# If you want to use a CDN or another web server to serve the cached images
# You can define this constants. All cached images links will point to this
# Url, event if don't exists yet.
Expand Down
10 changes: 10 additions & 0 deletions src/Goteo/Application/Event/FilterInvestFinishEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Contracts\EventDispatcher\Event;
use Goteo\Application\Session;
use Goteo\Library\Domain;
use Goteo\Model\Invest;

class FilterInvestFinishEvent extends Event
Expand Down Expand Up @@ -46,6 +48,13 @@ public function setHttpResponse(Response $response)

public function getHttpResponse() {
if($this->response) return $this->response;

$return_to = Session::get('return_to');
if ($return_to && Domain::isAllowedDomain($return_to)) {
Session::del('return_to');
return new RedirectResponse($return_to);
}

// Default is a redirection
if($this->invest->project) {
return new RedirectResponse('/invest/' . $this->invest->project . '/' . $this->invest->id . '/share');
Expand All @@ -57,4 +66,5 @@ public function getHttpResponse() {
return new RedirectResponse('/donate/' . $this->invest->id . '/share');
}
}

}
33 changes: 24 additions & 9 deletions src/Goteo/Controller/InvestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Goteo\Application\Session;
use Goteo\Application\View;
use Goteo\Core\Controller;
use Goteo\Library\Domain;
use Goteo\Library\Text;
use Goteo\Model\Invest;
use Goteo\Model\Project;
Expand Down Expand Up @@ -73,7 +74,7 @@ protected function getUser(): ?User
* the skip_login variable from project configuration
*/
private function validate(
$project_id, $reward_id = null, &$custom_amount = null, $invest = null, $login_required = true
$project_id, $reward_id = null, &$custom_amount = null, $invest = null, $login_required = true, ?Request $request = null
) {
$project = Project::get($project_id, Lang::current());
// Add analytics to config
Expand All @@ -96,11 +97,23 @@ private function validate(
Config::get('currency')
);

if ($request) {
$return_to = '';

if ($request->query->has('return_to')) {
$return_to = rawurldecode($request->query->get('return_to'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not place the url decoding inside the isAllowedDomain static method? This way we can safely use the functionality without having to worry about the string we are passing to it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, thanks!


if (Domain::isAllowedDomain($return_to))
Session::store('return_to', $return_to);
}
}

$this->page = '/invest/' . $project_id;
$this->query = http_build_query([
'amount' => "$amount_original$currency",
'reward' => $reward_id,
'donate_amount' => "$donate_amount$currency"
'donate_amount' => "$donate_amount$currency",
'return_to' => $return_to
]);

// Some projects may have activated a non-registering investion
Expand Down Expand Up @@ -243,7 +256,7 @@ public function selectRewardAction($project_id, Request $request): Response
{
// TODO: add events
$amount = $request->query->get('amount');
$reward = $this->validate($project_id, $request->query->get('reward'), $amount, null, false);
$reward = $this->validate($project_id, $request->query->get('reward'), $amount, null, false, $request);
if($reward instanceOf Response) return $reward;

// Aqui cambiar por escoger recompensa
Expand All @@ -260,7 +273,7 @@ public function selectRewardAction($project_id, Request $request): Response
public function loginAction($project_id, Request $request)
{
$amount = $request->query->get('amount');
$reward = $this->validate($project_id, $request->query->get('reward'), $amount, null, false);
$reward = $this->validate($project_id, $request->query->get('reward'), $amount, null, false, $request);

if($reward instanceOf Response) return $reward;
if(!$request->query->has('return')) {
Expand All @@ -282,7 +295,7 @@ public function loginAction($project_id, Request $request)
public function signupAction($project_id, Request $request)
{
$amount = $request->query->get('amount');
$reward = $this->validate($project_id, $request->query->get('reward'), $amount, null, false);
$reward = $this->validate($project_id, $request->query->get('reward'), $amount, null, false, $request);

if($reward instanceOf Response) return $reward;
if(!$request->query->has('return')) {
Expand All @@ -307,7 +320,7 @@ public function selectPaymentMethodAction(Request $request, $project_id)
$amount = $request->query->get('amount');
$donate_amount = $request->query->getInt('donate_amount', Config::get('donate.tip_amount'));
$email = $request->query->has('email');
$reward = $this->validate($project_id, $request->query->get('reward'), $amount, null, 'auto');
$reward = $this->validate($project_id, $request->query->get('reward'), $amount, null, 'auto', $request);

if(!($this->skip_login && $email) && !Session::isLogged()) {
return $this->redirect('/invest/' . $project_id . '/signup?' . $this->query);
Expand Down Expand Up @@ -346,7 +359,7 @@ public function paymentFormAction($project_id, Request $request) {
$tip=$request->query->get('tip');
$donate_amount = $tip ? $request->query->get('donate_amount') : 0;
$amount = $amount_original = $request->query->get('amount');
$reward = $this->validate($project_id, $request->query->get('reward'), $amount, null, 'auto');
$reward = $this->validate($project_id, $request->query->get('reward'), $amount, null, 'auto', $request);

if($reward instanceOf Response) return $reward;

Expand Down Expand Up @@ -601,13 +614,15 @@ public function userDataAction($project_id, $invest_id, Request $request)
}
}
$invest->extra_info = $invest_address['extra_info'];
$invest->save();
$invest->save($errors);

if($ok && $invest->setAddress($invest_address)) {
$isAddressValid = $invest->setAddress($invest_address);
if($ok && $isAddressValid) {
return $this->dispatch(AppEvents::INVEST_FINISHED, new FilterInvestFinishEvent($invest, $request))->getHttpResponse();
}
}
Message::error(Text::get('invest-address-fail'));
Message::error(implode(',', $errors));
}

return $this->viewResponse(
Expand Down
35 changes: 35 additions & 0 deletions src/Goteo/Library/Domain.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Goteo\Library;

use Goteo\Application\Config;
use Goteo\Application\Config\ConfigException;

class Domain
{
public static function isAllowedDomain(string $domain): bool
{
try {
$domains = Config::get('url.allowed_domains');
} catch (ConfigException $e) {
return false;
}

if (empty($domains))
return false;

$parse = parse_url($domain, PHP_URL_HOST);
if (!$parse)
return false;

$validDomains = array_filter($domains, function ($domain) use ($parse) {
$parsedDomain = parse_url($domain);
if (!$parsedDomain['scheme'])
return $parsedDomain['path'] == $parse;

return $parsedDomain['host'] == $parse;
});

return !empty($validDomains);
}
}
Loading