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

refactor subdomain processing and add test to it #204

Merged
merged 2 commits into from Sep 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/deployer.yml
Expand Up @@ -6,6 +6,8 @@ on:
- live
- staging
- beta
- alpha
- edge

jobs:
deployer:
Expand Down
90 changes: 20 additions & 70 deletions src/Goteo/Application/EventListener/SessionListener.php
Expand Up @@ -23,6 +23,7 @@
use Goteo\Application\Currency;
use Goteo\Library\Text;
use Goteo\Model\Image;
use Goteo\Util\Parsers\UrlLang;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
Expand All @@ -34,24 +35,6 @@

class SessionListener extends AbstractListener {

/**
* Chechsk if any of the elements in array $prefixes starts with the same chars as $full_str
* @param [type] $full_str full string
* @param [type] $prefixes array of prexixes
* @return boolean found or not
*/
protected function matchPrefix($full_str, $prefixes) {
if(!is_array($prefixes)) {
$prefixes = [$prefixes];
}
foreach($prefixes as $str) {
if(strpos($full_str, $str) === 0) {
return true;
}
}
return false;
}

public function onRequest(GetResponseEvent $event) {

//not need to do anything on sub-requests
Expand All @@ -60,14 +43,15 @@ public function onRequest(GetResponseEvent $event) {
}

$request = $event->getRequest();
$path = $request->getPathInfo();

$parser = new UrlLang($request);

//non cookies for notifyAction on investController
$skip = Config::get('session.skip');
if ($this->matchPrefix($path, $skip)) {
if($parser->skipSessionManagement()) {
return;
}


// clean all caches if requested
// TODO: replace by some controller
if ($request->query->has('cleancache')) {
Expand Down Expand Up @@ -105,66 +89,32 @@ public function onRequest(GetResponseEvent $event) {

// Set lang
$lang = Lang::setFromGlobals($request);
// Cookie
// the stupid cookie EU law
if (!Cookie::exists('goteo_cookies')) {
// print_r($_COOKIE);die('cooki');
Cookie::store('goteo_cookies', 'ok');
// print_r($_COOKIE);die('cooki');
Message::info(Text::get('message-cookies'));
}


$url = $request->getHttpHost();
// Routes to leave as they are
$skip = Config::get('url.redirect.skip');
// Routes to alway reditect to the main url
$fixed = Config::get('url.redirect.fixed');
// Redirect to proper URL if url_lang is defined
if (Config::get('url.url_lang') && !$this->matchPrefix($path, $skip)) {
$parts = explode('.', $url);
$sub_lang = $parts[0];
if($sub_lang == 'www') $sub_lang = Config::get('lang');
if (Lang::exists($sub_lang)) {
// reduce url: ca.goteo.org => goteo.org
array_shift($parts);
$url = implode('.', $parts);
}
// if reduced URL is the main domain, redirect to sub-level lang
if(count($parts) == 2) {
if($request->query->has('lang')) {
$request->query->remove('lang');
}
// Login controller should mantaing always the same URL to help browser
if($this->matchPrefix($path, $fixed)) {
// $url = "$url";
$request->query->set('lang', $lang);
}
else {
$url = preg_replace('!https?://|/$!i', '', Lang::getUrl($lang));
}

}
// print_r($parts);echo "$url [$sub_lang=>$lang] ";die;
}

$host = $parser->getHost($lang);
// Mantain user in secure enviroment if logged and ssl config on
if (Config::get('ssl') && Session::isLogged() && !$request->isSecure()) {
// Force HTTPS redirection
$url = 'https://' . $url;
$host = 'https://' . $host;
} else {
// Conserve the current scheme
$url = $request->getScheme() . '://' . $url;
$host = $request->getScheme() . '://' . $host;
}

// Redirect if needed
if ($url != $request->getScheme() . '://' . $request->getHttpHost()) {
if ($host != $request->getScheme() . '://' . $request->getHttpHost()) {
$query = http_build_query($request->query->all());
// die($url . $request->getPathInfo() . ($query ? "?$query" : ''));
$event->setResponse(new RedirectResponse($url . $request->getPathInfo() . ($query ? "?$query" : '')));
// die($host . $request->getPathInfo() . ($query ? "?$query" : ''));
$event->setResponse(new RedirectResponse($host . $request->getPathInfo() . ($query ? "?$query" : '')));
return;
}
// die("[$url] - " .$request->getScheme() . '://' . $request->getHttpHost());
// die("[$host] - " .$request->getScheme() . '://' . $request->getHttpHost());

// the stupid cookie EU law
if (!Cookie::exists('goteo_cookies')) {
// print_r($_COOKIE);die('cooki');
Cookie::store('goteo_cookies', 'ok');
// print_r($_COOKIE);die('cooki');
Message::info(Text::get('message-cookies'));
}

// set currency
$currency = $request->query->get('currency');
Expand Down
100 changes: 100 additions & 0 deletions src/Goteo/Util/Parsers/UrlLang.php
@@ -0,0 +1,100 @@
<?php
/*
* This file is part of the Goteo Package.
*
* (c) Platoniq y Fundación Goteo <fundacion@goteo.org>
*
* For the full copyright and license information, please view the README.md
* and LICENSE files that was distributed with this source code.
*/

namespace Goteo\Util\Parsers;

use Goteo\Application\Config;
use Goteo\Application\Lang;
use Symfony\Component\HttpFoundation\Request;

class UrlLang {
public $request;
protected $path;
protected $host;

public function __construct(Request $request) {
$this->request = $request;
$this->path = $request->getPathInfo();
$this->host = $request->getHttpHost();
}

/**
* Returns false if the requests is configured to skip any cookie setting
*/
public function skipSessionManagement() {
$skip = Config::get('session.skip');
if ($this->matchPrefix($this->path, $skip)) {
return true;
}
return false;
}

/**
* Returns the proper URL after processing url_lang configurations (adds subdomain lang if needed)
*/
public function getHost($lang) {
$host = $this->host;
if(empty($lang)) {
return $host;
}

// Routes to leave as they are
$skip = Config::get('url.redirect.skip');
// Redirect to proper URL if url_lang is defined
if (!Config::get('url.url_lang') || $this->matchPrefix($this->path, $skip)) {
return $host;
}

// Routes to alway reditect to the main url
$fixed = Config::get('url.redirect.fixed');
$parts = explode('.', $host);
$sub_lang = $parts[0];
if($sub_lang == 'www') $sub_lang = Config::get('lang');
if (Lang::exists($sub_lang)) {
// reduce url: ca.goteo.org => goteo.org
array_shift($parts);
$host = implode('.', $parts);
}
// if reduced URL is the main domain, redirect to sub-level lang
if($host === Config::get("url.url_lang")) {
if($this->request->query->has('lang')) {
$this->request->query->remove('lang');
}
// Login controller should mantaing always the same URL to help browser password management
if($this->matchPrefix($this->path, $fixed)) {
// $host = "$host";
$this->request->query->set('lang', $lang);
}
else {
$host = preg_replace('!https?://|/$!i', '', Lang::getUrl($lang));
}

}
return $host;
}

/**
* Chechsk if any of the elements in array $prefixes starts with the same chars as $full_str
* @param string $full_str full string
* @param array $prefixes array of prexixes
* @return boolean found or not
*/
protected function matchPrefix($full_str, $prefixes) {
if(!is_array($prefixes)) {
$prefixes = [$prefixes];
}
foreach($prefixes as $str) {
if(strpos($full_str, $str) === 0) {
return true;
}
}
return false;
}
}
118 changes: 118 additions & 0 deletions tests/Goteo/Util/Parsers/UrlLangTest.php
@@ -0,0 +1,118 @@
<?php

namespace Goteo\Util\Tests;

use Goteo\Util\Parsers\UrlLang;
use Goteo\Application\Config;
use Symfony\Component\HttpFoundation\Request;

class UrlLangTest extends \PHPUnit\Framework\TestCase {

protected function getParser($url, $host="http://example.com") {
$request = Request::create("$host$url");
return new UrlLang($request);
}

public function testInstance() {
$parser = $this->getParser("/");

$this->assertInstanceOf('\Goteo\Util\Parsers\UrlLang', $parser);

return $parser;
}

/**
* @depends testInstance
* */
public function testSkipSessionManagement($parser) {
$this->assertFalse($parser->skipSessionManagement());

$parser = $this->getParser("/test/something");
$this->assertFalse($parser->skipSessionManagement());

Config::set('session.skip', "/test");
$this->assertTrue($parser->skipSessionManagement());

Config::set('session.skip', ["/test"]);
$this->assertTrue($parser->skipSessionManagement());

}

/**
* @depends testInstance
* */
public function testDomainLang($parser) {
$this->assertEquals("example.com", $parser->getHost(""));

$parser = $this->getParser("/test/something");
$this->assertEquals("example.com", $parser->getHost(""));

Config::set('url.url_lang', "example.com");
$this->assertEquals("example.com", $parser->getHost(""));
$this->assertEquals("en.example.com", $parser->getHost("en"));

Config::set("lang", "es");
$this->assertEquals("www.example.com", $parser->getHost("es"));
$this->assertEquals("en.example.com", $parser->getHost("en"));

$parser = $this->getParser("/", "http://www.example.com");
$this->assertEquals("en.example.com", $parser->getHost("en"));

return $parser;
}

/**
* @depends testDomainLang
* */
public function testRedirectSkip($parser) {
$parser = $this->getParser("/api");
$this->assertEquals("example.com", $parser->getHost("en"));

$parser = $this->getParser("/api", "http://www.example.com");
$this->assertEquals("www.example.com", $parser->getHost("en"));

$parser = $this->getParser("/password-recovery", "http://ca.example.com");
$this->assertEquals("ca.example.com", $parser->getHost("en"));
}

/**
* @depends testDomainLang
* */
public function testFixedRedirection($parser) {
$parser = $this->getParser("/login");
$this->assertEquals("example.com", $parser->getHost("en"));

$parser = $this->getParser("/login", "http://www.example.com");
$this->assertEquals("example.com", $parser->getHost("en"));

$parser = $this->getParser("/password-reset", "http://ca.example.com");
$this->assertEquals("example.com", $parser->getHost("en"));
}

/**
* @depends testDomainLang
* */
public function testSubdomains($parser) {
$parser = $this->getParser("/api", "http://www.sub.example.com");
$this->assertEquals("www.sub.example.com", $parser->getHost("en"));
$parser = $this->getParser("/login", "http://www.sub.example.com");
$this->assertEquals("sub.example.com", $parser->getHost("en"));

$parser = $this->getParser("/", "http://www.sub.example.com");
$this->assertEquals("sub.example.com", $parser->getHost("en"));

Config::set('url.url_lang', "sub.example.com");

$parser = $this->getParser("/api", "http://www.sub.example.com");
$this->assertEquals("www.sub.example.com", $parser->getHost("en"));
$parser = $this->getParser("/login", "http://www.sub.example.com");
$this->assertEquals("sub.example.com", $parser->getHost("en"));

$parser = $this->getParser("/", "http://www.sub.example.com");
$this->assertEquals("en.sub.example.com", $parser->getHost("en"));

$parser = $this->getParser("/test/something", "http://en.sub.example.com");
$this->assertEquals("www.sub.example.com", $parser->getHost("es"));
$this->assertEquals("ca.sub.example.com", $parser->getHost("ca"));
}
}