2017-02-24 14:50:43 +03:00
|
|
|
<?php
|
2019-12-03 21:57:53 +03:00
|
|
|
|
2018-01-16 22:01:38 +03:00
|
|
|
declare(strict_types=1);
|
2019-12-03 21:57:53 +03:00
|
|
|
|
2017-02-24 14:50:43 +03:00
|
|
|
/**
|
|
|
|
* @copyright Copyright (c) 2017 Bjoern Schiessle <bjoern@schiessle.org>
|
|
|
|
*
|
2017-11-06 17:56:42 +03:00
|
|
|
* @author Bjoern Schiessle <bjoern@schiessle.org>
|
2020-04-29 12:57:22 +03:00
|
|
|
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
2019-12-03 21:57:53 +03:00
|
|
|
* @author Morris Jobke <hey@morrisjobke.de>
|
|
|
|
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
2017-11-06 17:56:42 +03:00
|
|
|
*
|
2017-02-24 14:50:43 +03:00
|
|
|
* @license GNU AGPL version 3 or any later version
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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 Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
2019-12-03 21:57:53 +03:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2017-02-24 14:50:43 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace OC\OCS;
|
|
|
|
|
|
|
|
use OCP\AppFramework\Http;
|
|
|
|
use OCP\Http\Client\IClient;
|
|
|
|
use OCP\Http\Client\IClientService;
|
|
|
|
use OCP\ICache;
|
|
|
|
use OCP\ICacheFactory;
|
|
|
|
use OCP\OCS\IDiscoveryService;
|
|
|
|
|
|
|
|
class DiscoveryService implements IDiscoveryService {
|
|
|
|
|
|
|
|
/** @var ICache */
|
|
|
|
private $cache;
|
|
|
|
|
|
|
|
/** @var IClient */
|
|
|
|
private $client;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param ICacheFactory $cacheFactory
|
|
|
|
* @param IClientService $clientService
|
|
|
|
*/
|
|
|
|
public function __construct(ICacheFactory $cacheFactory,
|
|
|
|
IClientService $clientService
|
|
|
|
) {
|
2017-12-15 13:31:13 +03:00
|
|
|
$this->cache = $cacheFactory->createDistributed('ocs-discovery');
|
2017-02-24 14:50:43 +03:00
|
|
|
$this->client = $clientService->newClient();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Discover OCS end-points
|
|
|
|
*
|
|
|
|
* If no valid discovery data is found the defaults are returned
|
|
|
|
*
|
|
|
|
* @param string $remote
|
|
|
|
* @param string $service the service you want to discover
|
2018-04-06 13:24:41 +03:00
|
|
|
* @param bool $skipCache We won't check if the data is in the cache. This is usefull if a background job is updating the status
|
2017-02-24 14:50:43 +03:00
|
|
|
* @return array
|
|
|
|
*/
|
2018-04-06 13:24:41 +03:00
|
|
|
public function discover(string $remote, string $service, bool $skipCache = false): array {
|
2017-02-24 14:50:43 +03:00
|
|
|
// Check the cache first
|
2018-04-06 13:24:41 +03:00
|
|
|
if ($skipCache === false) {
|
|
|
|
$cacheData = $this->cache->get($remote . '#' . $service);
|
|
|
|
if ($cacheData) {
|
|
|
|
$data = json_decode($cacheData, true);
|
|
|
|
if (\is_array($data)) {
|
|
|
|
return $data;
|
|
|
|
}
|
2018-01-17 00:06:57 +03:00
|
|
|
}
|
2017-02-24 14:50:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
$discoveredServices = [];
|
|
|
|
|
|
|
|
// query the remote server for available services
|
|
|
|
try {
|
|
|
|
$response = $this->client->get($remote . '/ocs-provider/', [
|
|
|
|
'timeout' => 10,
|
|
|
|
'connect_timeout' => 10,
|
|
|
|
]);
|
2020-04-10 15:19:56 +03:00
|
|
|
if ($response->getStatusCode() === Http::STATUS_OK) {
|
2017-02-24 14:50:43 +03:00
|
|
|
$decodedServices = json_decode($response->getBody(), true);
|
2018-01-16 22:01:38 +03:00
|
|
|
if (\is_array($decodedServices)) {
|
|
|
|
$discoveredServices = $this->getEndpoints($decodedServices, $service);
|
|
|
|
}
|
2017-02-24 14:50:43 +03:00
|
|
|
}
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
// if we couldn't discover the service or any end-points we return a empty array
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write into cache
|
2017-12-13 16:51:48 +03:00
|
|
|
$this->cache->set($remote . '#' . $service, json_encode($discoveredServices), 60*60*24);
|
2017-02-24 14:50:43 +03:00
|
|
|
return $discoveredServices;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get requested end-points from the requested service
|
|
|
|
*
|
2018-01-16 22:01:38 +03:00
|
|
|
* @param array $decodedServices
|
|
|
|
* @param string $service
|
2017-02-24 14:50:43 +03:00
|
|
|
* @return array
|
|
|
|
*/
|
2018-01-16 22:01:38 +03:00
|
|
|
protected function getEndpoints(array $decodedServices, string $service): array {
|
2017-02-24 14:50:43 +03:00
|
|
|
$discoveredServices = [];
|
|
|
|
|
2020-04-10 15:19:56 +03:00
|
|
|
if (isset($decodedServices['services'][$service]['endpoints'])) {
|
2017-02-24 14:50:43 +03:00
|
|
|
foreach ($decodedServices['services'][$service]['endpoints'] as $endpoint => $url) {
|
2020-04-10 15:19:56 +03:00
|
|
|
if ($this->isSafeUrl($url)) {
|
2017-02-24 14:50:43 +03:00
|
|
|
$discoveredServices[$endpoint] = $url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $discoveredServices;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether the specified URL includes only safe characters, if not
|
|
|
|
* returns false
|
|
|
|
*
|
|
|
|
* @param string $url
|
|
|
|
* @return bool
|
|
|
|
*/
|
2018-01-16 22:01:38 +03:00
|
|
|
protected function isSafeUrl(string $url): bool {
|
2017-03-09 18:32:13 +03:00
|
|
|
return (bool)preg_match('/^[\/\.\-A-Za-z0-9]+$/', $url);
|
2017-02-24 14:50:43 +03:00
|
|
|
}
|
|
|
|
}
|