From 586341b323cc39b1a97dde3b2f2fef549c3306f0 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Wed, 8 Apr 2020 16:38:36 +0300 Subject: [PATCH] Added URL parsing lib --- app/controllers/api/account.php | 13 +++-- app/controllers/api/avatars.php | 42 ++------------- src/Appwrite/URL/URL.php | 78 ++++++++++++++++++++++++++++ tests/unit/URL/URLTest.php | 90 +++++++++++++++++++++++++++++++++ 4 files changed, 181 insertions(+), 42 deletions(-) create mode 100644 src/Appwrite/URL/URL.php create mode 100644 tests/unit/URL/URLTest.php diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index e19f0c919..a87086de1 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -29,6 +29,9 @@ use GeoIp2\Database\Reader; include_once __DIR__ . '/../shared/api.php'; +$oauthDefaultSuccess = Config::getParam('protocol').'://'.Config::getParam('domain').'/auth/oauth2/success'; +$oauthDefaultFailure = Config::getParam('protocol').'://'.Config::getParam('domain').'/auth/oauth2/failure'; + $oauth2Keys = []; $utopia->init(function() use (&$oauth2Keys) { @@ -247,8 +250,8 @@ $utopia->get('/v1/account/sessions/oauth2/:provider') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') ->param('provider', '', function () { return new WhiteList(array_keys(Config::getParam('providers'))); }, 'OAuth2 Provider. Currently, supported providers are: ' . implode(', ', array_keys(array_filter(Config::getParam('providers'), function($node) {return (!$node['mock']);}))).'.') - ->param('success', '', function () use ($clients) { return new Host($clients); }, 'URL to redirect back to your app after a successful login attempt.') - ->param('failure', '', function () use ($clients) { return new Host($clients); }, 'URL to redirect back to your app after a failed login attempt.') + ->param('success', $oauthDefaultSuccess, function () use ($clients) { return new Host($clients); }, 'URL to redirect back to your app after a successful login attempt.', true) + ->param('failure', $oauthDefaultFailure, function () use ($clients) { return new Host($clients); }, 'URL to redirect back to your app after a failed login attempt.', true) ->action( function ($provider, $success, $failure) use ($response, $request, $project) { $protocol = Config::getParam('protocol'); @@ -316,7 +319,7 @@ $utopia->get('/v1/account/sessions/oauth2/:provider/redirect') ->param('code', '', function () { return new Text(1024); }, 'OAuth2 code.') ->param('state', '', function () { return new Text(2048); }, 'OAuth2 state params.', true) ->action( - function ($provider, $code, $state) use ($response, $request, $user, $projectDB, $project, $audit) { + function ($provider, $code, $state) use ($response, $request, $user, $projectDB, $project, $audit, $oauthDefaultSuccess) { $protocol = Config::getParam('protocol'); $callback = $protocol.'://'.$request->getServer('HTTP_HOST').'/v1/account/sessions/oauth2/callback/'.$provider.'/'.$project->getId(); $defaultState = ['success' => $project->getAttribute('url', ''), 'failure' => '']; @@ -476,6 +479,10 @@ $utopia->get('/v1/account/sessions/oauth2/:provider/redirect') ; } + if($state['success'] === $oauthDefaultSuccess) { // Add keys for non-web platforms + $state['success'] = $state['success'].'/?end=true'; + } + $response ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') ->addHeader('Pragma', 'no-cache') diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 6f26f0eea..84689814d 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -10,6 +10,7 @@ use Utopia\Validator\URL; use Utopia\Cache\Cache; use Utopia\Cache\Adapter\Filesystem; use Appwrite\Resize\Resize; +use Appwrite\URL\URL as URLParse; use BaconQrCode\Renderer\ImageRenderer; use BaconQrCode\Renderer\Image\ImagickImageBackEnd; use BaconQrCode\Renderer\RendererStyle\RendererStyle; @@ -265,7 +266,7 @@ $utopia->get('/v1/avatars/favicon') $href = $link->getAttribute('href'); $rel = $link->getAttribute('rel'); $sizes = $link->getAttribute('sizes'); - $absolute = unparse_url(array_merge(parse_url($url), parse_url($href))); + $absolute = URLParse::unparse(array_merge(parse_url($url), parse_url($href))); switch (strtolower($rel)) { case 'icon': @@ -381,41 +382,4 @@ $utopia->get('/v1/avatars/qr') ->send('', $writer->writeString($text)) ; } - ); - -function unparse_url($parsed_url, $ommit = array()) -{ - if (isset($parsed_url['path']) && mb_substr($parsed_url['path'], 0, 1) !== '/') { - $parsed_url['path'] = '/'.$parsed_url['path']; - } - - $p = array(); - - $p['scheme'] = isset($parsed_url['scheme']) ? $parsed_url['scheme'].'://' : ''; - - $p['host'] = isset($parsed_url['host']) ? $parsed_url['host'] : ''; - - $p['port'] = isset($parsed_url['port']) ? ':'.$parsed_url['port'] : ''; - - $p['user'] = isset($parsed_url['user']) ? $parsed_url['user'] : ''; - - $p['pass'] = isset($parsed_url['pass']) ? ':'.$parsed_url['pass'] : ''; - - $p['pass'] = ($p['user'] || $p['pass']) ? $p['pass'].'@' : ''; - - $p['path'] = isset($parsed_url['path']) ? $parsed_url['path'] : ''; - - $p['query'] = isset($parsed_url['query']) ? '?'.$parsed_url['query'] : ''; - - $p['fragment'] = isset($parsed_url['fragment']) ? '#'.$parsed_url['fragment'] : ''; - - if ($ommit) { - foreach ($ommit as $key) { - if (isset($p[ $key ])) { - $p[ $key ] = ''; - } - } - } - - return $p['scheme'].$p['user'].$p['pass'].$p['host'].$p['port'].$p['path'].$p['query'].$p['fragment']; -} + ); \ No newline at end of file diff --git a/src/Appwrite/URL/URL.php b/src/Appwrite/URL/URL.php new file mode 100644 index 000000000..dc29a568a --- /dev/null +++ b/src/Appwrite/URL/URL.php @@ -0,0 +1,78 @@ + '', + 'pass' => '', + 'user' => '', + 'host' => '', + 'port' => null, + 'path' => '', + 'query' => '', + 'fragment' => '', + ]; + + return array_merge($default, parse_url($url)); + } + + /** + * Un-Parse URL + * + * Take URL parts and combine them to a valid string + * + * @param $url array + * @param $ommit array + * + * @return string + */ + static public function unparse(array $url, array $ommit = []):string + { + if (isset($url['path']) && mb_substr($url['path'], 0, 1) !== '/') { + $url['path'] = '/'.$url['path']; + } + + $parts = []; + + $parts['scheme'] = isset($url['scheme']) ? $url['scheme'].'://' : ''; + + $parts['host'] = isset($url['host']) ? $url['host'] : ''; + + $parts['port'] = isset($url['port']) ? ':'.$url['port'] : ''; + + $parts['user'] = isset($url['user']) ? $url['user'] : ''; + + $parts['pass'] = isset($url['pass']) ? ':'.$url['pass'] : ''; + + $parts['pass'] = ($parts['user'] || $parts['pass']) ? $parts['pass'].'@' : ''; + + $parts['path'] = isset($url['path']) ? $url['path'] : ''; + + $parts['query'] = isset($url['query']) && !empty($url['query']) ? '?'.$url['query'] : ''; + + $parts['fragment'] = isset($url['fragment']) ? '#'.$url['fragment'] : ''; + + if ($ommit) { + foreach ($ommit as $key) { + if (isset($parts[ $key ])) { + $parts[ $key ] = ''; + } + } + } + + return $parts['scheme'].$parts['user'].$parts['pass'].$parts['host'].$parts['port'].$parts['path'].$parts['query'].$parts['fragment']; + } +} \ No newline at end of file diff --git a/tests/unit/URL/URLTest.php b/tests/unit/URL/URLTest.php new file mode 100644 index 000000000..c65bcfb43 --- /dev/null +++ b/tests/unit/URL/URLTest.php @@ -0,0 +1,90 @@ +assertIsArray($url); + $this->assertEquals('https', $url['scheme']); + $this->assertEquals('appwrite.io', $url['host']); + $this->assertEquals('8080', $url['port']); + $this->assertEquals('/path', $url['path']); + $this->assertEquals('query=string¶m=value', $url['query']); + + $url = URL::parse('https://appwrite.io'); + + $this->assertIsArray($url); + $this->assertEquals('https', $url['scheme']); + $this->assertEquals('appwrite.io', $url['host']); + $this->assertEquals(null, $url['port']); + $this->assertEquals('', $url['path']); + $this->assertEquals('', $url['query']); + } + + public function testUnparse() + { + $url = URL::unparse([ + 'scheme' => 'https', + 'host' => 'appwrite.io', + 'port' => 8080, + 'path' => '/path', + 'query' => 'query=string¶m=value', + ]); + + $this->assertIsString($url); + $this->assertEquals('https://appwrite.io:8080/path?query=string¶m=value', $url); + + $url = URL::unparse([ + 'scheme' => 'https', + 'host' => 'appwrite.io', + 'port' => null, + 'path' => '/path', + 'query' => 'query=string¶m=value', + ]); + + $this->assertIsString($url); + $this->assertEquals('https://appwrite.io/path?query=string¶m=value', $url); + + $url = URL::unparse([ + 'scheme' => 'https', + 'host' => 'appwrite.io', + 'port' => null, + 'path' => '', + 'query' => '', + ]); + + $this->assertIsString($url); + $this->assertEquals('https://appwrite.io/', $url); + + $url = URL::unparse([ + 'scheme' => 'https', + 'host' => 'appwrite.io', + 'port' => null, + 'path' => '', + 'fragment' => 'bottom', + ]); + + $this->assertIsString($url); + $this->assertEquals('https://appwrite.io/#bottom', $url); + + $url = URL::unparse([ + 'scheme' => 'https', + 'user' => 'eldad', + 'pass' => 'fux', + 'host' => 'appwrite.io', + 'port' => null, + 'path' => '', + 'fragment' => 'bottom', + ]); + + $this->assertIsString($url); + $this->assertEquals('https://eldad:fux@appwrite.io/#bottom', $url); + } +} \ No newline at end of file