@@ -29,40 +29,40 @@ |
||
| 29 | 29 | |
| 30 | 30 | class FedAuth extends AbstractBasic { |
| 31 | 31 | |
| 32 | - /** @var DbHandler */ |
|
| 33 | - private $db; |
|
| 32 | + /** @var DbHandler */ |
|
| 33 | + private $db; |
|
| 34 | 34 | |
| 35 | - /** |
|
| 36 | - * FedAuth constructor. |
|
| 37 | - * |
|
| 38 | - * @param DbHandler $db |
|
| 39 | - */ |
|
| 40 | - public function __construct(DbHandler $db) { |
|
| 41 | - $this->db = $db; |
|
| 42 | - $this->principalPrefix = 'principals/system/'; |
|
| 35 | + /** |
|
| 36 | + * FedAuth constructor. |
|
| 37 | + * |
|
| 38 | + * @param DbHandler $db |
|
| 39 | + */ |
|
| 40 | + public function __construct(DbHandler $db) { |
|
| 41 | + $this->db = $db; |
|
| 42 | + $this->principalPrefix = 'principals/system/'; |
|
| 43 | 43 | |
| 44 | - // setup realm |
|
| 45 | - $defaults = new \OCP\Defaults(); |
|
| 46 | - $this->realm = $defaults->getName(); |
|
| 47 | - } |
|
| 44 | + // setup realm |
|
| 45 | + $defaults = new \OCP\Defaults(); |
|
| 46 | + $this->realm = $defaults->getName(); |
|
| 47 | + } |
|
| 48 | 48 | |
| 49 | - /** |
|
| 50 | - * Validates a username and password |
|
| 51 | - * |
|
| 52 | - * This method should return true or false depending on if login |
|
| 53 | - * succeeded. |
|
| 54 | - * |
|
| 55 | - * @param string $username |
|
| 56 | - * @param string $password |
|
| 57 | - * @return bool |
|
| 58 | - */ |
|
| 59 | - protected function validateUserPass($username, $password) { |
|
| 60 | - return $this->db->auth($username, $password); |
|
| 61 | - } |
|
| 49 | + /** |
|
| 50 | + * Validates a username and password |
|
| 51 | + * |
|
| 52 | + * This method should return true or false depending on if login |
|
| 53 | + * succeeded. |
|
| 54 | + * |
|
| 55 | + * @param string $username |
|
| 56 | + * @param string $password |
|
| 57 | + * @return bool |
|
| 58 | + */ |
|
| 59 | + protected function validateUserPass($username, $password) { |
|
| 60 | + return $this->db->auth($username, $password); |
|
| 61 | + } |
|
| 62 | 62 | |
| 63 | - /** |
|
| 64 | - * @inheritdoc |
|
| 65 | - */ |
|
| 66 | - public function challenge(RequestInterface $request, ResponseInterface $response) { |
|
| 67 | - } |
|
| 63 | + /** |
|
| 64 | + * @inheritdoc |
|
| 65 | + */ |
|
| 66 | + public function challenge(RequestInterface $request, ResponseInterface $response) { |
|
| 67 | + } |
|
| 68 | 68 | } |
@@ -50,185 +50,185 @@ |
||
| 50 | 50 | */ |
| 51 | 51 | class RequestSharedSecret extends Job { |
| 52 | 52 | |
| 53 | - /** @var IClient */ |
|
| 54 | - private $httpClient; |
|
| 55 | - |
|
| 56 | - /** @var IJobList */ |
|
| 57 | - private $jobList; |
|
| 58 | - |
|
| 59 | - /** @var IURLGenerator */ |
|
| 60 | - private $urlGenerator; |
|
| 61 | - |
|
| 62 | - /** @var DbHandler */ |
|
| 63 | - private $dbHandler; |
|
| 64 | - |
|
| 65 | - /** @var TrustedServers */ |
|
| 66 | - private $trustedServers; |
|
| 67 | - |
|
| 68 | - /** @var IDiscoveryService */ |
|
| 69 | - private $ocsDiscoveryService; |
|
| 70 | - |
|
| 71 | - /** @var ILogger */ |
|
| 72 | - private $logger; |
|
| 73 | - |
|
| 74 | - /** @var ITimeFactory */ |
|
| 75 | - private $timeFactory; |
|
| 76 | - |
|
| 77 | - /** @var bool */ |
|
| 78 | - protected $retainJob = false; |
|
| 79 | - |
|
| 80 | - private $format = '?format=json'; |
|
| 81 | - |
|
| 82 | - private $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/request-shared-secret'; |
|
| 83 | - |
|
| 84 | - /** @var int 30 day = 2592000sec */ |
|
| 85 | - private $maxLifespan = 2592000; |
|
| 86 | - |
|
| 87 | - /** |
|
| 88 | - * RequestSharedSecret constructor. |
|
| 89 | - * |
|
| 90 | - * @param IClientService $httpClientService |
|
| 91 | - * @param IURLGenerator $urlGenerator |
|
| 92 | - * @param IJobList $jobList |
|
| 93 | - * @param TrustedServers $trustedServers |
|
| 94 | - * @param DbHandler $dbHandler |
|
| 95 | - * @param IDiscoveryService $ocsDiscoveryService |
|
| 96 | - * @param ILogger $logger |
|
| 97 | - * @param ITimeFactory $timeFactory |
|
| 98 | - */ |
|
| 99 | - public function __construct( |
|
| 100 | - IClientService $httpClientService, |
|
| 101 | - IURLGenerator $urlGenerator, |
|
| 102 | - IJobList $jobList, |
|
| 103 | - TrustedServers $trustedServers, |
|
| 104 | - DbHandler $dbHandler, |
|
| 105 | - IDiscoveryService $ocsDiscoveryService, |
|
| 106 | - ILogger $logger, |
|
| 107 | - ITimeFactory $timeFactory |
|
| 108 | - ) { |
|
| 109 | - $this->httpClient = $httpClientService->newClient(); |
|
| 110 | - $this->jobList = $jobList; |
|
| 111 | - $this->urlGenerator = $urlGenerator; |
|
| 112 | - $this->dbHandler = $dbHandler; |
|
| 113 | - $this->logger = $logger; |
|
| 114 | - $this->ocsDiscoveryService = $ocsDiscoveryService; |
|
| 115 | - $this->trustedServers = $trustedServers; |
|
| 116 | - $this->timeFactory = $timeFactory; |
|
| 117 | - } |
|
| 118 | - |
|
| 119 | - |
|
| 120 | - /** |
|
| 121 | - * run the job, then remove it from the joblist |
|
| 122 | - * |
|
| 123 | - * @param JobList $jobList |
|
| 124 | - * @param ILogger|null $logger |
|
| 125 | - */ |
|
| 126 | - public function execute($jobList, ILogger $logger = null) { |
|
| 127 | - $target = $this->argument['url']; |
|
| 128 | - // only execute if target is still in the list of trusted domains |
|
| 129 | - if ($this->trustedServers->isTrustedServer($target)) { |
|
| 130 | - $this->parentExecute($jobList, $logger); |
|
| 131 | - } |
|
| 132 | - |
|
| 133 | - $jobList->remove($this, $this->argument); |
|
| 134 | - |
|
| 135 | - if ($this->retainJob) { |
|
| 136 | - $this->reAddJob($this->argument); |
|
| 137 | - } |
|
| 138 | - } |
|
| 139 | - |
|
| 140 | - /** |
|
| 141 | - * call execute() method of parent |
|
| 142 | - * |
|
| 143 | - * @param JobList $jobList |
|
| 144 | - * @param ILogger $logger |
|
| 145 | - */ |
|
| 146 | - protected function parentExecute($jobList, $logger) { |
|
| 147 | - parent::execute($jobList, $logger); |
|
| 148 | - } |
|
| 149 | - |
|
| 150 | - protected function run($argument) { |
|
| 151 | - |
|
| 152 | - $target = $argument['url']; |
|
| 153 | - $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 154 | - $currentTime = $this->timeFactory->getTime(); |
|
| 155 | - $source = $this->urlGenerator->getAbsoluteURL('/'); |
|
| 156 | - $source = rtrim($source, '/'); |
|
| 157 | - $token = $argument['token']; |
|
| 158 | - |
|
| 159 | - // kill job after 30 days of trying |
|
| 160 | - $deadline = $currentTime - $this->maxLifespan; |
|
| 161 | - if ($created < $deadline) { |
|
| 162 | - $this->retainJob = false; |
|
| 163 | - $this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE); |
|
| 164 | - return; |
|
| 165 | - } |
|
| 166 | - |
|
| 167 | - $endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING'); |
|
| 168 | - $endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint; |
|
| 169 | - |
|
| 170 | - // make sure that we have a well formated url |
|
| 171 | - $url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format; |
|
| 172 | - |
|
| 173 | - try { |
|
| 174 | - $result = $this->httpClient->post( |
|
| 175 | - $url, |
|
| 176 | - [ |
|
| 177 | - 'body' => [ |
|
| 178 | - 'url' => $source, |
|
| 179 | - 'token' => $token, |
|
| 180 | - ], |
|
| 181 | - 'timeout' => 3, |
|
| 182 | - 'connect_timeout' => 3, |
|
| 183 | - ] |
|
| 184 | - ); |
|
| 185 | - |
|
| 186 | - $status = $result->getStatusCode(); |
|
| 187 | - |
|
| 188 | - } catch (ClientException $e) { |
|
| 189 | - $status = $e->getCode(); |
|
| 190 | - if ($status === Http::STATUS_FORBIDDEN) { |
|
| 191 | - $this->logger->info($target . ' refused to ask for a shared secret.', ['app' => 'federation']); |
|
| 192 | - } else { |
|
| 193 | - $this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']); |
|
| 194 | - } |
|
| 195 | - } catch (\Exception $e) { |
|
| 196 | - $status = Http::STATUS_INTERNAL_SERVER_ERROR; |
|
| 197 | - $this->logger->logException($e, ['app' => 'federation']); |
|
| 198 | - } |
|
| 199 | - |
|
| 200 | - // if we received a unexpected response we try again later |
|
| 201 | - if ( |
|
| 202 | - $status !== Http::STATUS_OK |
|
| 203 | - && $status !== Http::STATUS_FORBIDDEN |
|
| 204 | - ) { |
|
| 205 | - $this->retainJob = true; |
|
| 206 | - } |
|
| 207 | - |
|
| 208 | - if ($status === Http::STATUS_FORBIDDEN) { |
|
| 209 | - // clear token if remote server refuses to ask for shared secret |
|
| 210 | - $this->dbHandler->addToken($target, ''); |
|
| 211 | - } |
|
| 212 | - |
|
| 213 | - } |
|
| 214 | - |
|
| 215 | - /** |
|
| 216 | - * re-add background job |
|
| 217 | - * |
|
| 218 | - * @param array $argument |
|
| 219 | - */ |
|
| 220 | - protected function reAddJob(array $argument) { |
|
| 221 | - $url = $argument['url']; |
|
| 222 | - $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 223 | - $token = $argument['token']; |
|
| 224 | - |
|
| 225 | - $this->jobList->add( |
|
| 226 | - RequestSharedSecret::class, |
|
| 227 | - [ |
|
| 228 | - 'url' => $url, |
|
| 229 | - 'token' => $token, |
|
| 230 | - 'created' => $created |
|
| 231 | - ] |
|
| 232 | - ); |
|
| 233 | - } |
|
| 53 | + /** @var IClient */ |
|
| 54 | + private $httpClient; |
|
| 55 | + |
|
| 56 | + /** @var IJobList */ |
|
| 57 | + private $jobList; |
|
| 58 | + |
|
| 59 | + /** @var IURLGenerator */ |
|
| 60 | + private $urlGenerator; |
|
| 61 | + |
|
| 62 | + /** @var DbHandler */ |
|
| 63 | + private $dbHandler; |
|
| 64 | + |
|
| 65 | + /** @var TrustedServers */ |
|
| 66 | + private $trustedServers; |
|
| 67 | + |
|
| 68 | + /** @var IDiscoveryService */ |
|
| 69 | + private $ocsDiscoveryService; |
|
| 70 | + |
|
| 71 | + /** @var ILogger */ |
|
| 72 | + private $logger; |
|
| 73 | + |
|
| 74 | + /** @var ITimeFactory */ |
|
| 75 | + private $timeFactory; |
|
| 76 | + |
|
| 77 | + /** @var bool */ |
|
| 78 | + protected $retainJob = false; |
|
| 79 | + |
|
| 80 | + private $format = '?format=json'; |
|
| 81 | + |
|
| 82 | + private $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/request-shared-secret'; |
|
| 83 | + |
|
| 84 | + /** @var int 30 day = 2592000sec */ |
|
| 85 | + private $maxLifespan = 2592000; |
|
| 86 | + |
|
| 87 | + /** |
|
| 88 | + * RequestSharedSecret constructor. |
|
| 89 | + * |
|
| 90 | + * @param IClientService $httpClientService |
|
| 91 | + * @param IURLGenerator $urlGenerator |
|
| 92 | + * @param IJobList $jobList |
|
| 93 | + * @param TrustedServers $trustedServers |
|
| 94 | + * @param DbHandler $dbHandler |
|
| 95 | + * @param IDiscoveryService $ocsDiscoveryService |
|
| 96 | + * @param ILogger $logger |
|
| 97 | + * @param ITimeFactory $timeFactory |
|
| 98 | + */ |
|
| 99 | + public function __construct( |
|
| 100 | + IClientService $httpClientService, |
|
| 101 | + IURLGenerator $urlGenerator, |
|
| 102 | + IJobList $jobList, |
|
| 103 | + TrustedServers $trustedServers, |
|
| 104 | + DbHandler $dbHandler, |
|
| 105 | + IDiscoveryService $ocsDiscoveryService, |
|
| 106 | + ILogger $logger, |
|
| 107 | + ITimeFactory $timeFactory |
|
| 108 | + ) { |
|
| 109 | + $this->httpClient = $httpClientService->newClient(); |
|
| 110 | + $this->jobList = $jobList; |
|
| 111 | + $this->urlGenerator = $urlGenerator; |
|
| 112 | + $this->dbHandler = $dbHandler; |
|
| 113 | + $this->logger = $logger; |
|
| 114 | + $this->ocsDiscoveryService = $ocsDiscoveryService; |
|
| 115 | + $this->trustedServers = $trustedServers; |
|
| 116 | + $this->timeFactory = $timeFactory; |
|
| 117 | + } |
|
| 118 | + |
|
| 119 | + |
|
| 120 | + /** |
|
| 121 | + * run the job, then remove it from the joblist |
|
| 122 | + * |
|
| 123 | + * @param JobList $jobList |
|
| 124 | + * @param ILogger|null $logger |
|
| 125 | + */ |
|
| 126 | + public function execute($jobList, ILogger $logger = null) { |
|
| 127 | + $target = $this->argument['url']; |
|
| 128 | + // only execute if target is still in the list of trusted domains |
|
| 129 | + if ($this->trustedServers->isTrustedServer($target)) { |
|
| 130 | + $this->parentExecute($jobList, $logger); |
|
| 131 | + } |
|
| 132 | + |
|
| 133 | + $jobList->remove($this, $this->argument); |
|
| 134 | + |
|
| 135 | + if ($this->retainJob) { |
|
| 136 | + $this->reAddJob($this->argument); |
|
| 137 | + } |
|
| 138 | + } |
|
| 139 | + |
|
| 140 | + /** |
|
| 141 | + * call execute() method of parent |
|
| 142 | + * |
|
| 143 | + * @param JobList $jobList |
|
| 144 | + * @param ILogger $logger |
|
| 145 | + */ |
|
| 146 | + protected function parentExecute($jobList, $logger) { |
|
| 147 | + parent::execute($jobList, $logger); |
|
| 148 | + } |
|
| 149 | + |
|
| 150 | + protected function run($argument) { |
|
| 151 | + |
|
| 152 | + $target = $argument['url']; |
|
| 153 | + $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 154 | + $currentTime = $this->timeFactory->getTime(); |
|
| 155 | + $source = $this->urlGenerator->getAbsoluteURL('/'); |
|
| 156 | + $source = rtrim($source, '/'); |
|
| 157 | + $token = $argument['token']; |
|
| 158 | + |
|
| 159 | + // kill job after 30 days of trying |
|
| 160 | + $deadline = $currentTime - $this->maxLifespan; |
|
| 161 | + if ($created < $deadline) { |
|
| 162 | + $this->retainJob = false; |
|
| 163 | + $this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE); |
|
| 164 | + return; |
|
| 165 | + } |
|
| 166 | + |
|
| 167 | + $endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING'); |
|
| 168 | + $endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint; |
|
| 169 | + |
|
| 170 | + // make sure that we have a well formated url |
|
| 171 | + $url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format; |
|
| 172 | + |
|
| 173 | + try { |
|
| 174 | + $result = $this->httpClient->post( |
|
| 175 | + $url, |
|
| 176 | + [ |
|
| 177 | + 'body' => [ |
|
| 178 | + 'url' => $source, |
|
| 179 | + 'token' => $token, |
|
| 180 | + ], |
|
| 181 | + 'timeout' => 3, |
|
| 182 | + 'connect_timeout' => 3, |
|
| 183 | + ] |
|
| 184 | + ); |
|
| 185 | + |
|
| 186 | + $status = $result->getStatusCode(); |
|
| 187 | + |
|
| 188 | + } catch (ClientException $e) { |
|
| 189 | + $status = $e->getCode(); |
|
| 190 | + if ($status === Http::STATUS_FORBIDDEN) { |
|
| 191 | + $this->logger->info($target . ' refused to ask for a shared secret.', ['app' => 'federation']); |
|
| 192 | + } else { |
|
| 193 | + $this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']); |
|
| 194 | + } |
|
| 195 | + } catch (\Exception $e) { |
|
| 196 | + $status = Http::STATUS_INTERNAL_SERVER_ERROR; |
|
| 197 | + $this->logger->logException($e, ['app' => 'federation']); |
|
| 198 | + } |
|
| 199 | + |
|
| 200 | + // if we received a unexpected response we try again later |
|
| 201 | + if ( |
|
| 202 | + $status !== Http::STATUS_OK |
|
| 203 | + && $status !== Http::STATUS_FORBIDDEN |
|
| 204 | + ) { |
|
| 205 | + $this->retainJob = true; |
|
| 206 | + } |
|
| 207 | + |
|
| 208 | + if ($status === Http::STATUS_FORBIDDEN) { |
|
| 209 | + // clear token if remote server refuses to ask for shared secret |
|
| 210 | + $this->dbHandler->addToken($target, ''); |
|
| 211 | + } |
|
| 212 | + |
|
| 213 | + } |
|
| 214 | + |
|
| 215 | + /** |
|
| 216 | + * re-add background job |
|
| 217 | + * |
|
| 218 | + * @param array $argument |
|
| 219 | + */ |
|
| 220 | + protected function reAddJob(array $argument) { |
|
| 221 | + $url = $argument['url']; |
|
| 222 | + $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 223 | + $token = $argument['token']; |
|
| 224 | + |
|
| 225 | + $this->jobList->add( |
|
| 226 | + RequestSharedSecret::class, |
|
| 227 | + [ |
|
| 228 | + 'url' => $url, |
|
| 229 | + 'token' => $token, |
|
| 230 | + 'created' => $created |
|
| 231 | + ] |
|
| 232 | + ); |
|
| 233 | + } |
|
| 234 | 234 | } |
@@ -150,7 +150,7 @@ discard block |
||
| 150 | 150 | protected function run($argument) { |
| 151 | 151 | |
| 152 | 152 | $target = $argument['url']; |
| 153 | - $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 153 | + $created = isset($argument['created']) ? (int) $argument['created'] : $this->timeFactory->getTime(); |
|
| 154 | 154 | $currentTime = $this->timeFactory->getTime(); |
| 155 | 155 | $source = $this->urlGenerator->getAbsoluteURL('/'); |
| 156 | 156 | $source = rtrim($source, '/'); |
@@ -168,7 +168,7 @@ discard block |
||
| 168 | 168 | $endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint; |
| 169 | 169 | |
| 170 | 170 | // make sure that we have a well formated url |
| 171 | - $url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format; |
|
| 171 | + $url = rtrim($target, '/').'/'.trim($endPoint, '/').$this->format; |
|
| 172 | 172 | |
| 173 | 173 | try { |
| 174 | 174 | $result = $this->httpClient->post( |
@@ -188,9 +188,9 @@ discard block |
||
| 188 | 188 | } catch (ClientException $e) { |
| 189 | 189 | $status = $e->getCode(); |
| 190 | 190 | if ($status === Http::STATUS_FORBIDDEN) { |
| 191 | - $this->logger->info($target . ' refused to ask for a shared secret.', ['app' => 'federation']); |
|
| 191 | + $this->logger->info($target.' refused to ask for a shared secret.', ['app' => 'federation']); |
|
| 192 | 192 | } else { |
| 193 | - $this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']); |
|
| 193 | + $this->logger->info($target.' responded with a '.$status.' containing: '.$e->getMessage(), ['app' => 'federation']); |
|
| 194 | 194 | } |
| 195 | 195 | } catch (\Exception $e) { |
| 196 | 196 | $status = Http::STATUS_INTERNAL_SERVER_ERROR; |
@@ -219,7 +219,7 @@ discard block |
||
| 219 | 219 | */ |
| 220 | 220 | protected function reAddJob(array $argument) { |
| 221 | 221 | $url = $argument['url']; |
| 222 | - $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 222 | + $created = isset($argument['created']) ? (int) $argument['created'] : $this->timeFactory->getTime(); |
|
| 223 | 223 | $token = $argument['token']; |
| 224 | 224 | |
| 225 | 225 | $this->jobList->add( |
@@ -50,199 +50,199 @@ |
||
| 50 | 50 | */ |
| 51 | 51 | class GetSharedSecret extends Job { |
| 52 | 52 | |
| 53 | - /** @var IClient */ |
|
| 54 | - private $httpClient; |
|
| 55 | - |
|
| 56 | - /** @var IJobList */ |
|
| 57 | - private $jobList; |
|
| 58 | - |
|
| 59 | - /** @var IURLGenerator */ |
|
| 60 | - private $urlGenerator; |
|
| 61 | - |
|
| 62 | - /** @var TrustedServers */ |
|
| 63 | - private $trustedServers; |
|
| 64 | - |
|
| 65 | - /** @var DbHandler */ |
|
| 66 | - private $dbHandler; |
|
| 67 | - |
|
| 68 | - /** @var IDiscoveryService */ |
|
| 69 | - private $ocsDiscoveryService; |
|
| 70 | - |
|
| 71 | - /** @var ILogger */ |
|
| 72 | - private $logger; |
|
| 73 | - |
|
| 74 | - /** @var ITimeFactory */ |
|
| 75 | - private $timeFactory; |
|
| 76 | - |
|
| 77 | - /** @var bool */ |
|
| 78 | - protected $retainJob = false; |
|
| 79 | - |
|
| 80 | - private $format = '?format=json'; |
|
| 81 | - |
|
| 82 | - private $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret'; |
|
| 83 | - |
|
| 84 | - /** @var int 30 day = 2592000sec */ |
|
| 85 | - private $maxLifespan = 2592000; |
|
| 86 | - |
|
| 87 | - /** |
|
| 88 | - * RequestSharedSecret constructor. |
|
| 89 | - * |
|
| 90 | - * @param IClientService $httpClientService |
|
| 91 | - * @param IURLGenerator $urlGenerator |
|
| 92 | - * @param IJobList $jobList |
|
| 93 | - * @param TrustedServers $trustedServers |
|
| 94 | - * @param ILogger $logger |
|
| 95 | - * @param DbHandler $dbHandler |
|
| 96 | - * @param IDiscoveryService $ocsDiscoveryService |
|
| 97 | - * @param ITimeFactory $timeFactory |
|
| 98 | - */ |
|
| 99 | - public function __construct( |
|
| 100 | - IClientService $httpClientService, |
|
| 101 | - IURLGenerator $urlGenerator, |
|
| 102 | - IJobList $jobList, |
|
| 103 | - TrustedServers $trustedServers, |
|
| 104 | - ILogger $logger, |
|
| 105 | - DbHandler $dbHandler, |
|
| 106 | - IDiscoveryService $ocsDiscoveryService, |
|
| 107 | - ITimeFactory $timeFactory |
|
| 108 | - ) { |
|
| 109 | - $this->logger = $logger; |
|
| 110 | - $this->httpClient = $httpClientService->newClient(); |
|
| 111 | - $this->jobList = $jobList; |
|
| 112 | - $this->urlGenerator = $urlGenerator; |
|
| 113 | - $this->dbHandler = $dbHandler; |
|
| 114 | - $this->ocsDiscoveryService = $ocsDiscoveryService; |
|
| 115 | - $this->trustedServers = $trustedServers; |
|
| 116 | - $this->timeFactory = $timeFactory; |
|
| 117 | - } |
|
| 118 | - |
|
| 119 | - /** |
|
| 120 | - * run the job, then remove it from the joblist |
|
| 121 | - * |
|
| 122 | - * @param JobList $jobList |
|
| 123 | - * @param ILogger|null $logger |
|
| 124 | - */ |
|
| 125 | - public function execute($jobList, ILogger $logger = null) { |
|
| 126 | - $target = $this->argument['url']; |
|
| 127 | - // only execute if target is still in the list of trusted domains |
|
| 128 | - if ($this->trustedServers->isTrustedServer($target)) { |
|
| 129 | - $this->parentExecute($jobList, $logger); |
|
| 130 | - } |
|
| 131 | - |
|
| 132 | - $jobList->remove($this, $this->argument); |
|
| 133 | - |
|
| 134 | - if ($this->retainJob) { |
|
| 135 | - $this->reAddJob($this->argument); |
|
| 136 | - } |
|
| 137 | - } |
|
| 138 | - |
|
| 139 | - /** |
|
| 140 | - * call execute() method of parent |
|
| 141 | - * |
|
| 142 | - * @param JobList $jobList |
|
| 143 | - * @param ILogger $logger |
|
| 144 | - */ |
|
| 145 | - protected function parentExecute($jobList, $logger = null) { |
|
| 146 | - parent::execute($jobList, $logger); |
|
| 147 | - } |
|
| 148 | - |
|
| 149 | - protected function run($argument) { |
|
| 150 | - $target = $argument['url']; |
|
| 151 | - $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 152 | - $currentTime = $this->timeFactory->getTime(); |
|
| 153 | - $source = $this->urlGenerator->getAbsoluteURL('/'); |
|
| 154 | - $source = rtrim($source, '/'); |
|
| 155 | - $token = $argument['token']; |
|
| 156 | - |
|
| 157 | - // kill job after 30 days of trying |
|
| 158 | - $deadline = $currentTime - $this->maxLifespan; |
|
| 159 | - if ($created < $deadline) { |
|
| 160 | - $this->retainJob = false; |
|
| 161 | - $this->trustedServers->setServerStatus($target,TrustedServers::STATUS_FAILURE); |
|
| 162 | - return; |
|
| 163 | - } |
|
| 164 | - |
|
| 165 | - $endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING'); |
|
| 166 | - $endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint; |
|
| 167 | - |
|
| 168 | - // make sure that we have a well formatted url |
|
| 169 | - $url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format; |
|
| 170 | - |
|
| 171 | - $result = null; |
|
| 172 | - try { |
|
| 173 | - $result = $this->httpClient->get( |
|
| 174 | - $url, |
|
| 175 | - [ |
|
| 176 | - 'query' => |
|
| 177 | - [ |
|
| 178 | - 'url' => $source, |
|
| 179 | - 'token' => $token |
|
| 180 | - ], |
|
| 181 | - 'timeout' => 3, |
|
| 182 | - 'connect_timeout' => 3, |
|
| 183 | - ] |
|
| 184 | - ); |
|
| 185 | - |
|
| 186 | - $status = $result->getStatusCode(); |
|
| 187 | - |
|
| 188 | - } catch (ClientException $e) { |
|
| 189 | - $status = $e->getCode(); |
|
| 190 | - if ($status === Http::STATUS_FORBIDDEN) { |
|
| 191 | - $this->logger->info($target . ' refused to exchange a shared secret with you.', ['app' => 'federation']); |
|
| 192 | - } else { |
|
| 193 | - $this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']); |
|
| 194 | - } |
|
| 195 | - } catch (\Exception $e) { |
|
| 196 | - $status = Http::STATUS_INTERNAL_SERVER_ERROR; |
|
| 197 | - $this->logger->logException($e, ['app' => 'federation']); |
|
| 198 | - } |
|
| 199 | - |
|
| 200 | - // if we received a unexpected response we try again later |
|
| 201 | - if ( |
|
| 202 | - $status !== Http::STATUS_OK |
|
| 203 | - && $status !== Http::STATUS_FORBIDDEN |
|
| 204 | - ) { |
|
| 205 | - $this->retainJob = true; |
|
| 206 | - } else { |
|
| 207 | - // reset token if we received a valid response |
|
| 208 | - $this->dbHandler->addToken($target, ''); |
|
| 209 | - } |
|
| 210 | - |
|
| 211 | - if ($status === Http::STATUS_OK && $result instanceof IResponse) { |
|
| 212 | - $body = $result->getBody(); |
|
| 213 | - $result = json_decode($body, true); |
|
| 214 | - if (isset($result['ocs']['data']['sharedSecret'])) { |
|
| 215 | - $this->trustedServers->addSharedSecret( |
|
| 216 | - $target, |
|
| 217 | - $result['ocs']['data']['sharedSecret'] |
|
| 218 | - ); |
|
| 219 | - } else { |
|
| 220 | - $this->logger->error( |
|
| 221 | - 'remote server "' . $target . '"" does not return a valid shared secret', |
|
| 222 | - ['app' => 'federation'] |
|
| 223 | - ); |
|
| 224 | - $this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE); |
|
| 225 | - } |
|
| 226 | - } |
|
| 227 | - |
|
| 228 | - } |
|
| 229 | - |
|
| 230 | - /** |
|
| 231 | - * re-add background job |
|
| 232 | - * |
|
| 233 | - * @param array $argument |
|
| 234 | - */ |
|
| 235 | - protected function reAddJob(array $argument) { |
|
| 236 | - $url = $argument['url']; |
|
| 237 | - $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 238 | - $token = $argument['token']; |
|
| 239 | - $this->jobList->add( |
|
| 240 | - GetSharedSecret::class, |
|
| 241 | - [ |
|
| 242 | - 'url' => $url, |
|
| 243 | - 'token' => $token, |
|
| 244 | - 'created' => $created |
|
| 245 | - ] |
|
| 246 | - ); |
|
| 247 | - } |
|
| 53 | + /** @var IClient */ |
|
| 54 | + private $httpClient; |
|
| 55 | + |
|
| 56 | + /** @var IJobList */ |
|
| 57 | + private $jobList; |
|
| 58 | + |
|
| 59 | + /** @var IURLGenerator */ |
|
| 60 | + private $urlGenerator; |
|
| 61 | + |
|
| 62 | + /** @var TrustedServers */ |
|
| 63 | + private $trustedServers; |
|
| 64 | + |
|
| 65 | + /** @var DbHandler */ |
|
| 66 | + private $dbHandler; |
|
| 67 | + |
|
| 68 | + /** @var IDiscoveryService */ |
|
| 69 | + private $ocsDiscoveryService; |
|
| 70 | + |
|
| 71 | + /** @var ILogger */ |
|
| 72 | + private $logger; |
|
| 73 | + |
|
| 74 | + /** @var ITimeFactory */ |
|
| 75 | + private $timeFactory; |
|
| 76 | + |
|
| 77 | + /** @var bool */ |
|
| 78 | + protected $retainJob = false; |
|
| 79 | + |
|
| 80 | + private $format = '?format=json'; |
|
| 81 | + |
|
| 82 | + private $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret'; |
|
| 83 | + |
|
| 84 | + /** @var int 30 day = 2592000sec */ |
|
| 85 | + private $maxLifespan = 2592000; |
|
| 86 | + |
|
| 87 | + /** |
|
| 88 | + * RequestSharedSecret constructor. |
|
| 89 | + * |
|
| 90 | + * @param IClientService $httpClientService |
|
| 91 | + * @param IURLGenerator $urlGenerator |
|
| 92 | + * @param IJobList $jobList |
|
| 93 | + * @param TrustedServers $trustedServers |
|
| 94 | + * @param ILogger $logger |
|
| 95 | + * @param DbHandler $dbHandler |
|
| 96 | + * @param IDiscoveryService $ocsDiscoveryService |
|
| 97 | + * @param ITimeFactory $timeFactory |
|
| 98 | + */ |
|
| 99 | + public function __construct( |
|
| 100 | + IClientService $httpClientService, |
|
| 101 | + IURLGenerator $urlGenerator, |
|
| 102 | + IJobList $jobList, |
|
| 103 | + TrustedServers $trustedServers, |
|
| 104 | + ILogger $logger, |
|
| 105 | + DbHandler $dbHandler, |
|
| 106 | + IDiscoveryService $ocsDiscoveryService, |
|
| 107 | + ITimeFactory $timeFactory |
|
| 108 | + ) { |
|
| 109 | + $this->logger = $logger; |
|
| 110 | + $this->httpClient = $httpClientService->newClient(); |
|
| 111 | + $this->jobList = $jobList; |
|
| 112 | + $this->urlGenerator = $urlGenerator; |
|
| 113 | + $this->dbHandler = $dbHandler; |
|
| 114 | + $this->ocsDiscoveryService = $ocsDiscoveryService; |
|
| 115 | + $this->trustedServers = $trustedServers; |
|
| 116 | + $this->timeFactory = $timeFactory; |
|
| 117 | + } |
|
| 118 | + |
|
| 119 | + /** |
|
| 120 | + * run the job, then remove it from the joblist |
|
| 121 | + * |
|
| 122 | + * @param JobList $jobList |
|
| 123 | + * @param ILogger|null $logger |
|
| 124 | + */ |
|
| 125 | + public function execute($jobList, ILogger $logger = null) { |
|
| 126 | + $target = $this->argument['url']; |
|
| 127 | + // only execute if target is still in the list of trusted domains |
|
| 128 | + if ($this->trustedServers->isTrustedServer($target)) { |
|
| 129 | + $this->parentExecute($jobList, $logger); |
|
| 130 | + } |
|
| 131 | + |
|
| 132 | + $jobList->remove($this, $this->argument); |
|
| 133 | + |
|
| 134 | + if ($this->retainJob) { |
|
| 135 | + $this->reAddJob($this->argument); |
|
| 136 | + } |
|
| 137 | + } |
|
| 138 | + |
|
| 139 | + /** |
|
| 140 | + * call execute() method of parent |
|
| 141 | + * |
|
| 142 | + * @param JobList $jobList |
|
| 143 | + * @param ILogger $logger |
|
| 144 | + */ |
|
| 145 | + protected function parentExecute($jobList, $logger = null) { |
|
| 146 | + parent::execute($jobList, $logger); |
|
| 147 | + } |
|
| 148 | + |
|
| 149 | + protected function run($argument) { |
|
| 150 | + $target = $argument['url']; |
|
| 151 | + $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 152 | + $currentTime = $this->timeFactory->getTime(); |
|
| 153 | + $source = $this->urlGenerator->getAbsoluteURL('/'); |
|
| 154 | + $source = rtrim($source, '/'); |
|
| 155 | + $token = $argument['token']; |
|
| 156 | + |
|
| 157 | + // kill job after 30 days of trying |
|
| 158 | + $deadline = $currentTime - $this->maxLifespan; |
|
| 159 | + if ($created < $deadline) { |
|
| 160 | + $this->retainJob = false; |
|
| 161 | + $this->trustedServers->setServerStatus($target,TrustedServers::STATUS_FAILURE); |
|
| 162 | + return; |
|
| 163 | + } |
|
| 164 | + |
|
| 165 | + $endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING'); |
|
| 166 | + $endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint; |
|
| 167 | + |
|
| 168 | + // make sure that we have a well formatted url |
|
| 169 | + $url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format; |
|
| 170 | + |
|
| 171 | + $result = null; |
|
| 172 | + try { |
|
| 173 | + $result = $this->httpClient->get( |
|
| 174 | + $url, |
|
| 175 | + [ |
|
| 176 | + 'query' => |
|
| 177 | + [ |
|
| 178 | + 'url' => $source, |
|
| 179 | + 'token' => $token |
|
| 180 | + ], |
|
| 181 | + 'timeout' => 3, |
|
| 182 | + 'connect_timeout' => 3, |
|
| 183 | + ] |
|
| 184 | + ); |
|
| 185 | + |
|
| 186 | + $status = $result->getStatusCode(); |
|
| 187 | + |
|
| 188 | + } catch (ClientException $e) { |
|
| 189 | + $status = $e->getCode(); |
|
| 190 | + if ($status === Http::STATUS_FORBIDDEN) { |
|
| 191 | + $this->logger->info($target . ' refused to exchange a shared secret with you.', ['app' => 'federation']); |
|
| 192 | + } else { |
|
| 193 | + $this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']); |
|
| 194 | + } |
|
| 195 | + } catch (\Exception $e) { |
|
| 196 | + $status = Http::STATUS_INTERNAL_SERVER_ERROR; |
|
| 197 | + $this->logger->logException($e, ['app' => 'federation']); |
|
| 198 | + } |
|
| 199 | + |
|
| 200 | + // if we received a unexpected response we try again later |
|
| 201 | + if ( |
|
| 202 | + $status !== Http::STATUS_OK |
|
| 203 | + && $status !== Http::STATUS_FORBIDDEN |
|
| 204 | + ) { |
|
| 205 | + $this->retainJob = true; |
|
| 206 | + } else { |
|
| 207 | + // reset token if we received a valid response |
|
| 208 | + $this->dbHandler->addToken($target, ''); |
|
| 209 | + } |
|
| 210 | + |
|
| 211 | + if ($status === Http::STATUS_OK && $result instanceof IResponse) { |
|
| 212 | + $body = $result->getBody(); |
|
| 213 | + $result = json_decode($body, true); |
|
| 214 | + if (isset($result['ocs']['data']['sharedSecret'])) { |
|
| 215 | + $this->trustedServers->addSharedSecret( |
|
| 216 | + $target, |
|
| 217 | + $result['ocs']['data']['sharedSecret'] |
|
| 218 | + ); |
|
| 219 | + } else { |
|
| 220 | + $this->logger->error( |
|
| 221 | + 'remote server "' . $target . '"" does not return a valid shared secret', |
|
| 222 | + ['app' => 'federation'] |
|
| 223 | + ); |
|
| 224 | + $this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE); |
|
| 225 | + } |
|
| 226 | + } |
|
| 227 | + |
|
| 228 | + } |
|
| 229 | + |
|
| 230 | + /** |
|
| 231 | + * re-add background job |
|
| 232 | + * |
|
| 233 | + * @param array $argument |
|
| 234 | + */ |
|
| 235 | + protected function reAddJob(array $argument) { |
|
| 236 | + $url = $argument['url']; |
|
| 237 | + $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 238 | + $token = $argument['token']; |
|
| 239 | + $this->jobList->add( |
|
| 240 | + GetSharedSecret::class, |
|
| 241 | + [ |
|
| 242 | + 'url' => $url, |
|
| 243 | + 'token' => $token, |
|
| 244 | + 'created' => $created |
|
| 245 | + ] |
|
| 246 | + ); |
|
| 247 | + } |
|
| 248 | 248 | } |
@@ -148,7 +148,7 @@ discard block |
||
| 148 | 148 | |
| 149 | 149 | protected function run($argument) { |
| 150 | 150 | $target = $argument['url']; |
| 151 | - $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 151 | + $created = isset($argument['created']) ? (int) $argument['created'] : $this->timeFactory->getTime(); |
|
| 152 | 152 | $currentTime = $this->timeFactory->getTime(); |
| 153 | 153 | $source = $this->urlGenerator->getAbsoluteURL('/'); |
| 154 | 154 | $source = rtrim($source, '/'); |
@@ -158,7 +158,7 @@ discard block |
||
| 158 | 158 | $deadline = $currentTime - $this->maxLifespan; |
| 159 | 159 | if ($created < $deadline) { |
| 160 | 160 | $this->retainJob = false; |
| 161 | - $this->trustedServers->setServerStatus($target,TrustedServers::STATUS_FAILURE); |
|
| 161 | + $this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE); |
|
| 162 | 162 | return; |
| 163 | 163 | } |
| 164 | 164 | |
@@ -166,7 +166,7 @@ discard block |
||
| 166 | 166 | $endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint; |
| 167 | 167 | |
| 168 | 168 | // make sure that we have a well formatted url |
| 169 | - $url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format; |
|
| 169 | + $url = rtrim($target, '/').'/'.trim($endPoint, '/').$this->format; |
|
| 170 | 170 | |
| 171 | 171 | $result = null; |
| 172 | 172 | try { |
@@ -188,9 +188,9 @@ discard block |
||
| 188 | 188 | } catch (ClientException $e) { |
| 189 | 189 | $status = $e->getCode(); |
| 190 | 190 | if ($status === Http::STATUS_FORBIDDEN) { |
| 191 | - $this->logger->info($target . ' refused to exchange a shared secret with you.', ['app' => 'federation']); |
|
| 191 | + $this->logger->info($target.' refused to exchange a shared secret with you.', ['app' => 'federation']); |
|
| 192 | 192 | } else { |
| 193 | - $this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']); |
|
| 193 | + $this->logger->info($target.' responded with a '.$status.' containing: '.$e->getMessage(), ['app' => 'federation']); |
|
| 194 | 194 | } |
| 195 | 195 | } catch (\Exception $e) { |
| 196 | 196 | $status = Http::STATUS_INTERNAL_SERVER_ERROR; |
@@ -203,7 +203,7 @@ discard block |
||
| 203 | 203 | && $status !== Http::STATUS_FORBIDDEN |
| 204 | 204 | ) { |
| 205 | 205 | $this->retainJob = true; |
| 206 | - } else { |
|
| 206 | + } else { |
|
| 207 | 207 | // reset token if we received a valid response |
| 208 | 208 | $this->dbHandler->addToken($target, ''); |
| 209 | 209 | } |
@@ -218,7 +218,7 @@ discard block |
||
| 218 | 218 | ); |
| 219 | 219 | } else { |
| 220 | 220 | $this->logger->error( |
| 221 | - 'remote server "' . $target . '"" does not return a valid shared secret', |
|
| 221 | + 'remote server "'.$target.'"" does not return a valid shared secret', |
|
| 222 | 222 | ['app' => 'federation'] |
| 223 | 223 | ); |
| 224 | 224 | $this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE); |
@@ -234,7 +234,7 @@ discard block |
||
| 234 | 234 | */ |
| 235 | 235 | protected function reAddJob(array $argument) { |
| 236 | 236 | $url = $argument['url']; |
| 237 | - $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime(); |
|
| 237 | + $created = isset($argument['created']) ? (int) $argument['created'] : $this->timeFactory->getTime(); |
|
| 238 | 238 | $token = $argument['token']; |
| 239 | 239 | $this->jobList->add( |
| 240 | 240 | GetSharedSecret::class, |
@@ -47,166 +47,166 @@ |
||
| 47 | 47 | */ |
| 48 | 48 | class OCSAuthAPIController extends OCSController{ |
| 49 | 49 | |
| 50 | - /** @var ISecureRandom */ |
|
| 51 | - private $secureRandom; |
|
| 52 | - |
|
| 53 | - /** @var IJobList */ |
|
| 54 | - private $jobList; |
|
| 55 | - |
|
| 56 | - /** @var TrustedServers */ |
|
| 57 | - private $trustedServers; |
|
| 58 | - |
|
| 59 | - /** @var DbHandler */ |
|
| 60 | - private $dbHandler; |
|
| 61 | - |
|
| 62 | - /** @var ILogger */ |
|
| 63 | - private $logger; |
|
| 64 | - |
|
| 65 | - /** @var ITimeFactory */ |
|
| 66 | - private $timeFactory; |
|
| 67 | - |
|
| 68 | - /** |
|
| 69 | - * OCSAuthAPI constructor. |
|
| 70 | - * |
|
| 71 | - * @param string $appName |
|
| 72 | - * @param IRequest $request |
|
| 73 | - * @param ISecureRandom $secureRandom |
|
| 74 | - * @param IJobList $jobList |
|
| 75 | - * @param TrustedServers $trustedServers |
|
| 76 | - * @param DbHandler $dbHandler |
|
| 77 | - * @param ILogger $logger |
|
| 78 | - * @param ITimeFactory $timeFactory |
|
| 79 | - */ |
|
| 80 | - public function __construct( |
|
| 81 | - $appName, |
|
| 82 | - IRequest $request, |
|
| 83 | - ISecureRandom $secureRandom, |
|
| 84 | - IJobList $jobList, |
|
| 85 | - TrustedServers $trustedServers, |
|
| 86 | - DbHandler $dbHandler, |
|
| 87 | - ILogger $logger, |
|
| 88 | - ITimeFactory $timeFactory |
|
| 89 | - ) { |
|
| 90 | - parent::__construct($appName, $request); |
|
| 91 | - |
|
| 92 | - $this->secureRandom = $secureRandom; |
|
| 93 | - $this->jobList = $jobList; |
|
| 94 | - $this->trustedServers = $trustedServers; |
|
| 95 | - $this->dbHandler = $dbHandler; |
|
| 96 | - $this->logger = $logger; |
|
| 97 | - $this->timeFactory = $timeFactory; |
|
| 98 | - } |
|
| 99 | - |
|
| 100 | - /** |
|
| 101 | - * @NoCSRFRequired |
|
| 102 | - * @PublicPage |
|
| 103 | - * |
|
| 104 | - * request received to ask remote server for a shared secret, for legacy end-points |
|
| 105 | - * |
|
| 106 | - * @param string $url |
|
| 107 | - * @param string $token |
|
| 108 | - * @return Http\DataResponse |
|
| 109 | - * @throws OCSForbiddenException |
|
| 110 | - */ |
|
| 111 | - public function requestSharedSecretLegacy($url, $token) { |
|
| 112 | - return $this->requestSharedSecret($url, $token); |
|
| 113 | - } |
|
| 114 | - |
|
| 115 | - |
|
| 116 | - /** |
|
| 117 | - * @NoCSRFRequired |
|
| 118 | - * @PublicPage |
|
| 119 | - * |
|
| 120 | - * create shared secret and return it, for legacy end-points |
|
| 121 | - * |
|
| 122 | - * @param string $url |
|
| 123 | - * @param string $token |
|
| 124 | - * @return Http\DataResponse |
|
| 125 | - * @throws OCSForbiddenException |
|
| 126 | - */ |
|
| 127 | - public function getSharedSecretLegacy($url, $token) { |
|
| 128 | - return $this->getSharedSecret($url, $token); |
|
| 129 | - } |
|
| 130 | - |
|
| 131 | - /** |
|
| 132 | - * @NoCSRFRequired |
|
| 133 | - * @PublicPage |
|
| 134 | - * |
|
| 135 | - * request received to ask remote server for a shared secret |
|
| 136 | - * |
|
| 137 | - * @param string $url |
|
| 138 | - * @param string $token |
|
| 139 | - * @return Http\DataResponse |
|
| 140 | - * @throws OCSForbiddenException |
|
| 141 | - */ |
|
| 142 | - public function requestSharedSecret($url, $token) { |
|
| 143 | - if ($this->trustedServers->isTrustedServer($url) === false) { |
|
| 144 | - $this->logger->error('remote server not trusted (' . $url . ') while requesting shared secret', ['app' => 'federation']); |
|
| 145 | - throw new OCSForbiddenException(); |
|
| 146 | - } |
|
| 147 | - |
|
| 148 | - // if both server initiated the exchange of the shared secret the greater |
|
| 149 | - // token wins |
|
| 150 | - $localToken = $this->dbHandler->getToken($url); |
|
| 151 | - if (strcmp($localToken, $token) > 0) { |
|
| 152 | - $this->logger->info( |
|
| 153 | - 'remote server (' . $url . ') presented lower token. We will initiate the exchange of the shared secret.', |
|
| 154 | - ['app' => 'federation'] |
|
| 155 | - ); |
|
| 156 | - throw new OCSForbiddenException(); |
|
| 157 | - } |
|
| 158 | - |
|
| 159 | - $this->jobList->add( |
|
| 160 | - 'OCA\Federation\BackgroundJob\GetSharedSecret', |
|
| 161 | - [ |
|
| 162 | - 'url' => $url, |
|
| 163 | - 'token' => $token, |
|
| 164 | - 'created' => $this->timeFactory->getTime() |
|
| 165 | - ] |
|
| 166 | - ); |
|
| 167 | - |
|
| 168 | - return new Http\DataResponse(); |
|
| 169 | - } |
|
| 170 | - |
|
| 171 | - /** |
|
| 172 | - * @NoCSRFRequired |
|
| 173 | - * @PublicPage |
|
| 174 | - * |
|
| 175 | - * create shared secret and return it |
|
| 176 | - * |
|
| 177 | - * @param string $url |
|
| 178 | - * @param string $token |
|
| 179 | - * @return Http\DataResponse |
|
| 180 | - * @throws OCSForbiddenException |
|
| 181 | - */ |
|
| 182 | - public function getSharedSecret($url, $token) { |
|
| 183 | - if ($this->trustedServers->isTrustedServer($url) === false) { |
|
| 184 | - $this->logger->error('remote server not trusted (' . $url . ') while getting shared secret', ['app' => 'federation']); |
|
| 185 | - throw new OCSForbiddenException(); |
|
| 186 | - } |
|
| 187 | - |
|
| 188 | - if ($this->isValidToken($url, $token) === false) { |
|
| 189 | - $expectedToken = $this->dbHandler->getToken($url); |
|
| 190 | - $this->logger->error( |
|
| 191 | - 'remote server (' . $url . ') didn\'t send a valid token (got "' . $token . '" but expected "'. $expectedToken . '") while getting shared secret', |
|
| 192 | - ['app' => 'federation'] |
|
| 193 | - ); |
|
| 194 | - throw new OCSForbiddenException(); |
|
| 195 | - } |
|
| 196 | - |
|
| 197 | - $sharedSecret = $this->secureRandom->generate(32); |
|
| 198 | - |
|
| 199 | - $this->trustedServers->addSharedSecret($url, $sharedSecret); |
|
| 200 | - // reset token after the exchange of the shared secret was successful |
|
| 201 | - $this->dbHandler->addToken($url, ''); |
|
| 202 | - |
|
| 203 | - return new Http\DataResponse([ |
|
| 204 | - 'sharedSecret' => $sharedSecret |
|
| 205 | - ]); |
|
| 206 | - } |
|
| 207 | - |
|
| 208 | - protected function isValidToken($url, $token) { |
|
| 209 | - $storedToken = $this->dbHandler->getToken($url); |
|
| 210 | - return hash_equals($storedToken, $token); |
|
| 211 | - } |
|
| 50 | + /** @var ISecureRandom */ |
|
| 51 | + private $secureRandom; |
|
| 52 | + |
|
| 53 | + /** @var IJobList */ |
|
| 54 | + private $jobList; |
|
| 55 | + |
|
| 56 | + /** @var TrustedServers */ |
|
| 57 | + private $trustedServers; |
|
| 58 | + |
|
| 59 | + /** @var DbHandler */ |
|
| 60 | + private $dbHandler; |
|
| 61 | + |
|
| 62 | + /** @var ILogger */ |
|
| 63 | + private $logger; |
|
| 64 | + |
|
| 65 | + /** @var ITimeFactory */ |
|
| 66 | + private $timeFactory; |
|
| 67 | + |
|
| 68 | + /** |
|
| 69 | + * OCSAuthAPI constructor. |
|
| 70 | + * |
|
| 71 | + * @param string $appName |
|
| 72 | + * @param IRequest $request |
|
| 73 | + * @param ISecureRandom $secureRandom |
|
| 74 | + * @param IJobList $jobList |
|
| 75 | + * @param TrustedServers $trustedServers |
|
| 76 | + * @param DbHandler $dbHandler |
|
| 77 | + * @param ILogger $logger |
|
| 78 | + * @param ITimeFactory $timeFactory |
|
| 79 | + */ |
|
| 80 | + public function __construct( |
|
| 81 | + $appName, |
|
| 82 | + IRequest $request, |
|
| 83 | + ISecureRandom $secureRandom, |
|
| 84 | + IJobList $jobList, |
|
| 85 | + TrustedServers $trustedServers, |
|
| 86 | + DbHandler $dbHandler, |
|
| 87 | + ILogger $logger, |
|
| 88 | + ITimeFactory $timeFactory |
|
| 89 | + ) { |
|
| 90 | + parent::__construct($appName, $request); |
|
| 91 | + |
|
| 92 | + $this->secureRandom = $secureRandom; |
|
| 93 | + $this->jobList = $jobList; |
|
| 94 | + $this->trustedServers = $trustedServers; |
|
| 95 | + $this->dbHandler = $dbHandler; |
|
| 96 | + $this->logger = $logger; |
|
| 97 | + $this->timeFactory = $timeFactory; |
|
| 98 | + } |
|
| 99 | + |
|
| 100 | + /** |
|
| 101 | + * @NoCSRFRequired |
|
| 102 | + * @PublicPage |
|
| 103 | + * |
|
| 104 | + * request received to ask remote server for a shared secret, for legacy end-points |
|
| 105 | + * |
|
| 106 | + * @param string $url |
|
| 107 | + * @param string $token |
|
| 108 | + * @return Http\DataResponse |
|
| 109 | + * @throws OCSForbiddenException |
|
| 110 | + */ |
|
| 111 | + public function requestSharedSecretLegacy($url, $token) { |
|
| 112 | + return $this->requestSharedSecret($url, $token); |
|
| 113 | + } |
|
| 114 | + |
|
| 115 | + |
|
| 116 | + /** |
|
| 117 | + * @NoCSRFRequired |
|
| 118 | + * @PublicPage |
|
| 119 | + * |
|
| 120 | + * create shared secret and return it, for legacy end-points |
|
| 121 | + * |
|
| 122 | + * @param string $url |
|
| 123 | + * @param string $token |
|
| 124 | + * @return Http\DataResponse |
|
| 125 | + * @throws OCSForbiddenException |
|
| 126 | + */ |
|
| 127 | + public function getSharedSecretLegacy($url, $token) { |
|
| 128 | + return $this->getSharedSecret($url, $token); |
|
| 129 | + } |
|
| 130 | + |
|
| 131 | + /** |
|
| 132 | + * @NoCSRFRequired |
|
| 133 | + * @PublicPage |
|
| 134 | + * |
|
| 135 | + * request received to ask remote server for a shared secret |
|
| 136 | + * |
|
| 137 | + * @param string $url |
|
| 138 | + * @param string $token |
|
| 139 | + * @return Http\DataResponse |
|
| 140 | + * @throws OCSForbiddenException |
|
| 141 | + */ |
|
| 142 | + public function requestSharedSecret($url, $token) { |
|
| 143 | + if ($this->trustedServers->isTrustedServer($url) === false) { |
|
| 144 | + $this->logger->error('remote server not trusted (' . $url . ') while requesting shared secret', ['app' => 'federation']); |
|
| 145 | + throw new OCSForbiddenException(); |
|
| 146 | + } |
|
| 147 | + |
|
| 148 | + // if both server initiated the exchange of the shared secret the greater |
|
| 149 | + // token wins |
|
| 150 | + $localToken = $this->dbHandler->getToken($url); |
|
| 151 | + if (strcmp($localToken, $token) > 0) { |
|
| 152 | + $this->logger->info( |
|
| 153 | + 'remote server (' . $url . ') presented lower token. We will initiate the exchange of the shared secret.', |
|
| 154 | + ['app' => 'federation'] |
|
| 155 | + ); |
|
| 156 | + throw new OCSForbiddenException(); |
|
| 157 | + } |
|
| 158 | + |
|
| 159 | + $this->jobList->add( |
|
| 160 | + 'OCA\Federation\BackgroundJob\GetSharedSecret', |
|
| 161 | + [ |
|
| 162 | + 'url' => $url, |
|
| 163 | + 'token' => $token, |
|
| 164 | + 'created' => $this->timeFactory->getTime() |
|
| 165 | + ] |
|
| 166 | + ); |
|
| 167 | + |
|
| 168 | + return new Http\DataResponse(); |
|
| 169 | + } |
|
| 170 | + |
|
| 171 | + /** |
|
| 172 | + * @NoCSRFRequired |
|
| 173 | + * @PublicPage |
|
| 174 | + * |
|
| 175 | + * create shared secret and return it |
|
| 176 | + * |
|
| 177 | + * @param string $url |
|
| 178 | + * @param string $token |
|
| 179 | + * @return Http\DataResponse |
|
| 180 | + * @throws OCSForbiddenException |
|
| 181 | + */ |
|
| 182 | + public function getSharedSecret($url, $token) { |
|
| 183 | + if ($this->trustedServers->isTrustedServer($url) === false) { |
|
| 184 | + $this->logger->error('remote server not trusted (' . $url . ') while getting shared secret', ['app' => 'federation']); |
|
| 185 | + throw new OCSForbiddenException(); |
|
| 186 | + } |
|
| 187 | + |
|
| 188 | + if ($this->isValidToken($url, $token) === false) { |
|
| 189 | + $expectedToken = $this->dbHandler->getToken($url); |
|
| 190 | + $this->logger->error( |
|
| 191 | + 'remote server (' . $url . ') didn\'t send a valid token (got "' . $token . '" but expected "'. $expectedToken . '") while getting shared secret', |
|
| 192 | + ['app' => 'federation'] |
|
| 193 | + ); |
|
| 194 | + throw new OCSForbiddenException(); |
|
| 195 | + } |
|
| 196 | + |
|
| 197 | + $sharedSecret = $this->secureRandom->generate(32); |
|
| 198 | + |
|
| 199 | + $this->trustedServers->addSharedSecret($url, $sharedSecret); |
|
| 200 | + // reset token after the exchange of the shared secret was successful |
|
| 201 | + $this->dbHandler->addToken($url, ''); |
|
| 202 | + |
|
| 203 | + return new Http\DataResponse([ |
|
| 204 | + 'sharedSecret' => $sharedSecret |
|
| 205 | + ]); |
|
| 206 | + } |
|
| 207 | + |
|
| 208 | + protected function isValidToken($url, $token) { |
|
| 209 | + $storedToken = $this->dbHandler->getToken($url); |
|
| 210 | + return hash_equals($storedToken, $token); |
|
| 211 | + } |
|
| 212 | 212 | } |
@@ -39,248 +39,248 @@ |
||
| 39 | 39 | |
| 40 | 40 | class TrustedServers { |
| 41 | 41 | |
| 42 | - /** after a user list was exchanged at least once successfully */ |
|
| 43 | - const STATUS_OK = 1; |
|
| 44 | - /** waiting for shared secret or initial user list exchange */ |
|
| 45 | - const STATUS_PENDING = 2; |
|
| 46 | - /** something went wrong, misconfigured server, software bug,... user interaction needed */ |
|
| 47 | - const STATUS_FAILURE = 3; |
|
| 48 | - /** remote server revoked access */ |
|
| 49 | - const STATUS_ACCESS_REVOKED = 4; |
|
| 50 | - |
|
| 51 | - /** @var dbHandler */ |
|
| 52 | - private $dbHandler; |
|
| 53 | - |
|
| 54 | - /** @var IClientService */ |
|
| 55 | - private $httpClientService; |
|
| 56 | - |
|
| 57 | - /** @var ILogger */ |
|
| 58 | - private $logger; |
|
| 59 | - |
|
| 60 | - /** @var IJobList */ |
|
| 61 | - private $jobList; |
|
| 62 | - |
|
| 63 | - /** @var ISecureRandom */ |
|
| 64 | - private $secureRandom; |
|
| 65 | - |
|
| 66 | - /** @var IConfig */ |
|
| 67 | - private $config; |
|
| 68 | - |
|
| 69 | - /** @var EventDispatcherInterface */ |
|
| 70 | - private $dispatcher; |
|
| 71 | - |
|
| 72 | - /** @var ITimeFactory */ |
|
| 73 | - private $timeFactory; |
|
| 74 | - |
|
| 75 | - /** |
|
| 76 | - * @param DbHandler $dbHandler |
|
| 77 | - * @param IClientService $httpClientService |
|
| 78 | - * @param ILogger $logger |
|
| 79 | - * @param IJobList $jobList |
|
| 80 | - * @param ISecureRandom $secureRandom |
|
| 81 | - * @param IConfig $config |
|
| 82 | - * @param EventDispatcherInterface $dispatcher |
|
| 83 | - * @param ITimeFactory $timeFactory |
|
| 84 | - */ |
|
| 85 | - public function __construct( |
|
| 86 | - DbHandler $dbHandler, |
|
| 87 | - IClientService $httpClientService, |
|
| 88 | - ILogger $logger, |
|
| 89 | - IJobList $jobList, |
|
| 90 | - ISecureRandom $secureRandom, |
|
| 91 | - IConfig $config, |
|
| 92 | - EventDispatcherInterface $dispatcher, |
|
| 93 | - ITimeFactory $timeFactory |
|
| 94 | - ) { |
|
| 95 | - $this->dbHandler = $dbHandler; |
|
| 96 | - $this->httpClientService = $httpClientService; |
|
| 97 | - $this->logger = $logger; |
|
| 98 | - $this->jobList = $jobList; |
|
| 99 | - $this->secureRandom = $secureRandom; |
|
| 100 | - $this->config = $config; |
|
| 101 | - $this->dispatcher = $dispatcher; |
|
| 102 | - $this->timeFactory = $timeFactory; |
|
| 103 | - } |
|
| 104 | - |
|
| 105 | - /** |
|
| 106 | - * add server to the list of trusted servers |
|
| 107 | - * |
|
| 108 | - * @param $url |
|
| 109 | - * @return int server id |
|
| 110 | - */ |
|
| 111 | - public function addServer($url) { |
|
| 112 | - $url = $this->updateProtocol($url); |
|
| 113 | - $result = $this->dbHandler->addServer($url); |
|
| 114 | - if ($result) { |
|
| 115 | - $token = $this->secureRandom->generate(16); |
|
| 116 | - $this->dbHandler->addToken($url, $token); |
|
| 117 | - $this->jobList->add( |
|
| 118 | - 'OCA\Federation\BackgroundJob\RequestSharedSecret', |
|
| 119 | - [ |
|
| 120 | - 'url' => $url, |
|
| 121 | - 'token' => $token, |
|
| 122 | - 'created' => $this->timeFactory->getTime() |
|
| 123 | - ] |
|
| 124 | - ); |
|
| 125 | - } |
|
| 126 | - |
|
| 127 | - return $result; |
|
| 128 | - } |
|
| 129 | - |
|
| 130 | - /** |
|
| 131 | - * enable/disable to automatically add servers to the list of trusted servers |
|
| 132 | - * once a federated share was created and accepted successfully |
|
| 133 | - * |
|
| 134 | - * @param bool $status |
|
| 135 | - */ |
|
| 136 | - public function setAutoAddServers($status) { |
|
| 137 | - $value = $status ? '1' : '0'; |
|
| 138 | - $this->config->setAppValue('federation', 'autoAddServers', $value); |
|
| 139 | - } |
|
| 140 | - |
|
| 141 | - /** |
|
| 142 | - * return if we automatically add servers to the list of trusted servers |
|
| 143 | - * once a federated share was created and accepted successfully |
|
| 144 | - * |
|
| 145 | - * @return bool |
|
| 146 | - */ |
|
| 147 | - public function getAutoAddServers() { |
|
| 148 | - $value = $this->config->getAppValue('federation', 'autoAddServers', '0'); |
|
| 149 | - return $value === '1'; |
|
| 150 | - } |
|
| 151 | - |
|
| 152 | - /** |
|
| 153 | - * get shared secret for the given server |
|
| 154 | - * |
|
| 155 | - * @param string $url |
|
| 156 | - * @return string |
|
| 157 | - */ |
|
| 158 | - public function getSharedSecret($url) { |
|
| 159 | - return $this->dbHandler->getSharedSecret($url); |
|
| 160 | - } |
|
| 161 | - |
|
| 162 | - /** |
|
| 163 | - * add shared secret for the given server |
|
| 164 | - * |
|
| 165 | - * @param string $url |
|
| 166 | - * @param $sharedSecret |
|
| 167 | - */ |
|
| 168 | - public function addSharedSecret($url, $sharedSecret) { |
|
| 169 | - $this->dbHandler->addSharedSecret($url, $sharedSecret); |
|
| 170 | - } |
|
| 171 | - |
|
| 172 | - /** |
|
| 173 | - * remove server from the list of trusted servers |
|
| 174 | - * |
|
| 175 | - * @param int $id |
|
| 176 | - */ |
|
| 177 | - public function removeServer($id) { |
|
| 178 | - $server = $this->dbHandler->getServerById($id); |
|
| 179 | - $this->dbHandler->removeServer($id); |
|
| 180 | - $event = new GenericEvent($server['url_hash']); |
|
| 181 | - $this->dispatcher->dispatch('OCP\Federation\TrustedServerEvent::remove', $event); |
|
| 182 | - } |
|
| 183 | - |
|
| 184 | - /** |
|
| 185 | - * get all trusted servers |
|
| 186 | - * |
|
| 187 | - * @return array |
|
| 188 | - */ |
|
| 189 | - public function getServers() { |
|
| 190 | - return $this->dbHandler->getAllServer(); |
|
| 191 | - } |
|
| 192 | - |
|
| 193 | - /** |
|
| 194 | - * check if given server is a trusted Nextcloud server |
|
| 195 | - * |
|
| 196 | - * @param string $url |
|
| 197 | - * @return bool |
|
| 198 | - */ |
|
| 199 | - public function isTrustedServer($url) { |
|
| 200 | - return $this->dbHandler->serverExists($url); |
|
| 201 | - } |
|
| 202 | - |
|
| 203 | - /** |
|
| 204 | - * set server status |
|
| 205 | - * |
|
| 206 | - * @param string $url |
|
| 207 | - * @param int $status |
|
| 208 | - */ |
|
| 209 | - public function setServerStatus($url, $status) { |
|
| 210 | - $this->dbHandler->setServerStatus($url, $status); |
|
| 211 | - } |
|
| 212 | - |
|
| 213 | - /** |
|
| 214 | - * @param string $url |
|
| 215 | - * @return int |
|
| 216 | - */ |
|
| 217 | - public function getServerStatus($url) { |
|
| 218 | - return $this->dbHandler->getServerStatus($url); |
|
| 219 | - } |
|
| 220 | - |
|
| 221 | - /** |
|
| 222 | - * check if URL point to a ownCloud/Nextcloud server |
|
| 223 | - * |
|
| 224 | - * @param string $url |
|
| 225 | - * @return bool |
|
| 226 | - */ |
|
| 227 | - public function isOwnCloudServer($url) { |
|
| 228 | - $isValidOwnCloud = false; |
|
| 229 | - $client = $this->httpClientService->newClient(); |
|
| 230 | - try { |
|
| 231 | - $result = $client->get( |
|
| 232 | - $url . '/status.php', |
|
| 233 | - [ |
|
| 234 | - 'timeout' => 3, |
|
| 235 | - 'connect_timeout' => 3, |
|
| 236 | - ] |
|
| 237 | - ); |
|
| 238 | - if ($result->getStatusCode() === Http::STATUS_OK) { |
|
| 239 | - $isValidOwnCloud = $this->checkOwnCloudVersion($result->getBody()); |
|
| 240 | - |
|
| 241 | - } |
|
| 242 | - } catch (\Exception $e) { |
|
| 243 | - $this->logger->debug('No Nextcloud server: ' . $e->getMessage()); |
|
| 244 | - return false; |
|
| 245 | - } |
|
| 246 | - |
|
| 247 | - return $isValidOwnCloud; |
|
| 248 | - } |
|
| 249 | - |
|
| 250 | - /** |
|
| 251 | - * check if ownCloud version is >= 9.0 |
|
| 252 | - * |
|
| 253 | - * @param $status |
|
| 254 | - * @return bool |
|
| 255 | - * @throws HintException |
|
| 256 | - */ |
|
| 257 | - protected function checkOwnCloudVersion($status) { |
|
| 258 | - $decoded = json_decode($status, true); |
|
| 259 | - if (!empty($decoded) && isset($decoded['version'])) { |
|
| 260 | - if (!version_compare($decoded['version'], '9.0.0', '>=')) { |
|
| 261 | - throw new HintException('Remote server version is too low. 9.0 is required.'); |
|
| 262 | - } |
|
| 263 | - return true; |
|
| 264 | - } |
|
| 265 | - return false; |
|
| 266 | - } |
|
| 267 | - |
|
| 268 | - /** |
|
| 269 | - * check if the URL contain a protocol, if not add https |
|
| 270 | - * |
|
| 271 | - * @param string $url |
|
| 272 | - * @return string |
|
| 273 | - */ |
|
| 274 | - protected function updateProtocol($url) { |
|
| 275 | - if ( |
|
| 276 | - strpos($url, 'https://') === 0 |
|
| 277 | - || strpos($url, 'http://') === 0 |
|
| 278 | - ) { |
|
| 279 | - |
|
| 280 | - return $url; |
|
| 281 | - |
|
| 282 | - } |
|
| 283 | - |
|
| 284 | - return 'https://' . $url; |
|
| 285 | - } |
|
| 42 | + /** after a user list was exchanged at least once successfully */ |
|
| 43 | + const STATUS_OK = 1; |
|
| 44 | + /** waiting for shared secret or initial user list exchange */ |
|
| 45 | + const STATUS_PENDING = 2; |
|
| 46 | + /** something went wrong, misconfigured server, software bug,... user interaction needed */ |
|
| 47 | + const STATUS_FAILURE = 3; |
|
| 48 | + /** remote server revoked access */ |
|
| 49 | + const STATUS_ACCESS_REVOKED = 4; |
|
| 50 | + |
|
| 51 | + /** @var dbHandler */ |
|
| 52 | + private $dbHandler; |
|
| 53 | + |
|
| 54 | + /** @var IClientService */ |
|
| 55 | + private $httpClientService; |
|
| 56 | + |
|
| 57 | + /** @var ILogger */ |
|
| 58 | + private $logger; |
|
| 59 | + |
|
| 60 | + /** @var IJobList */ |
|
| 61 | + private $jobList; |
|
| 62 | + |
|
| 63 | + /** @var ISecureRandom */ |
|
| 64 | + private $secureRandom; |
|
| 65 | + |
|
| 66 | + /** @var IConfig */ |
|
| 67 | + private $config; |
|
| 68 | + |
|
| 69 | + /** @var EventDispatcherInterface */ |
|
| 70 | + private $dispatcher; |
|
| 71 | + |
|
| 72 | + /** @var ITimeFactory */ |
|
| 73 | + private $timeFactory; |
|
| 74 | + |
|
| 75 | + /** |
|
| 76 | + * @param DbHandler $dbHandler |
|
| 77 | + * @param IClientService $httpClientService |
|
| 78 | + * @param ILogger $logger |
|
| 79 | + * @param IJobList $jobList |
|
| 80 | + * @param ISecureRandom $secureRandom |
|
| 81 | + * @param IConfig $config |
|
| 82 | + * @param EventDispatcherInterface $dispatcher |
|
| 83 | + * @param ITimeFactory $timeFactory |
|
| 84 | + */ |
|
| 85 | + public function __construct( |
|
| 86 | + DbHandler $dbHandler, |
|
| 87 | + IClientService $httpClientService, |
|
| 88 | + ILogger $logger, |
|
| 89 | + IJobList $jobList, |
|
| 90 | + ISecureRandom $secureRandom, |
|
| 91 | + IConfig $config, |
|
| 92 | + EventDispatcherInterface $dispatcher, |
|
| 93 | + ITimeFactory $timeFactory |
|
| 94 | + ) { |
|
| 95 | + $this->dbHandler = $dbHandler; |
|
| 96 | + $this->httpClientService = $httpClientService; |
|
| 97 | + $this->logger = $logger; |
|
| 98 | + $this->jobList = $jobList; |
|
| 99 | + $this->secureRandom = $secureRandom; |
|
| 100 | + $this->config = $config; |
|
| 101 | + $this->dispatcher = $dispatcher; |
|
| 102 | + $this->timeFactory = $timeFactory; |
|
| 103 | + } |
|
| 104 | + |
|
| 105 | + /** |
|
| 106 | + * add server to the list of trusted servers |
|
| 107 | + * |
|
| 108 | + * @param $url |
|
| 109 | + * @return int server id |
|
| 110 | + */ |
|
| 111 | + public function addServer($url) { |
|
| 112 | + $url = $this->updateProtocol($url); |
|
| 113 | + $result = $this->dbHandler->addServer($url); |
|
| 114 | + if ($result) { |
|
| 115 | + $token = $this->secureRandom->generate(16); |
|
| 116 | + $this->dbHandler->addToken($url, $token); |
|
| 117 | + $this->jobList->add( |
|
| 118 | + 'OCA\Federation\BackgroundJob\RequestSharedSecret', |
|
| 119 | + [ |
|
| 120 | + 'url' => $url, |
|
| 121 | + 'token' => $token, |
|
| 122 | + 'created' => $this->timeFactory->getTime() |
|
| 123 | + ] |
|
| 124 | + ); |
|
| 125 | + } |
|
| 126 | + |
|
| 127 | + return $result; |
|
| 128 | + } |
|
| 129 | + |
|
| 130 | + /** |
|
| 131 | + * enable/disable to automatically add servers to the list of trusted servers |
|
| 132 | + * once a federated share was created and accepted successfully |
|
| 133 | + * |
|
| 134 | + * @param bool $status |
|
| 135 | + */ |
|
| 136 | + public function setAutoAddServers($status) { |
|
| 137 | + $value = $status ? '1' : '0'; |
|
| 138 | + $this->config->setAppValue('federation', 'autoAddServers', $value); |
|
| 139 | + } |
|
| 140 | + |
|
| 141 | + /** |
|
| 142 | + * return if we automatically add servers to the list of trusted servers |
|
| 143 | + * once a federated share was created and accepted successfully |
|
| 144 | + * |
|
| 145 | + * @return bool |
|
| 146 | + */ |
|
| 147 | + public function getAutoAddServers() { |
|
| 148 | + $value = $this->config->getAppValue('federation', 'autoAddServers', '0'); |
|
| 149 | + return $value === '1'; |
|
| 150 | + } |
|
| 151 | + |
|
| 152 | + /** |
|
| 153 | + * get shared secret for the given server |
|
| 154 | + * |
|
| 155 | + * @param string $url |
|
| 156 | + * @return string |
|
| 157 | + */ |
|
| 158 | + public function getSharedSecret($url) { |
|
| 159 | + return $this->dbHandler->getSharedSecret($url); |
|
| 160 | + } |
|
| 161 | + |
|
| 162 | + /** |
|
| 163 | + * add shared secret for the given server |
|
| 164 | + * |
|
| 165 | + * @param string $url |
|
| 166 | + * @param $sharedSecret |
|
| 167 | + */ |
|
| 168 | + public function addSharedSecret($url, $sharedSecret) { |
|
| 169 | + $this->dbHandler->addSharedSecret($url, $sharedSecret); |
|
| 170 | + } |
|
| 171 | + |
|
| 172 | + /** |
|
| 173 | + * remove server from the list of trusted servers |
|
| 174 | + * |
|
| 175 | + * @param int $id |
|
| 176 | + */ |
|
| 177 | + public function removeServer($id) { |
|
| 178 | + $server = $this->dbHandler->getServerById($id); |
|
| 179 | + $this->dbHandler->removeServer($id); |
|
| 180 | + $event = new GenericEvent($server['url_hash']); |
|
| 181 | + $this->dispatcher->dispatch('OCP\Federation\TrustedServerEvent::remove', $event); |
|
| 182 | + } |
|
| 183 | + |
|
| 184 | + /** |
|
| 185 | + * get all trusted servers |
|
| 186 | + * |
|
| 187 | + * @return array |
|
| 188 | + */ |
|
| 189 | + public function getServers() { |
|
| 190 | + return $this->dbHandler->getAllServer(); |
|
| 191 | + } |
|
| 192 | + |
|
| 193 | + /** |
|
| 194 | + * check if given server is a trusted Nextcloud server |
|
| 195 | + * |
|
| 196 | + * @param string $url |
|
| 197 | + * @return bool |
|
| 198 | + */ |
|
| 199 | + public function isTrustedServer($url) { |
|
| 200 | + return $this->dbHandler->serverExists($url); |
|
| 201 | + } |
|
| 202 | + |
|
| 203 | + /** |
|
| 204 | + * set server status |
|
| 205 | + * |
|
| 206 | + * @param string $url |
|
| 207 | + * @param int $status |
|
| 208 | + */ |
|
| 209 | + public function setServerStatus($url, $status) { |
|
| 210 | + $this->dbHandler->setServerStatus($url, $status); |
|
| 211 | + } |
|
| 212 | + |
|
| 213 | + /** |
|
| 214 | + * @param string $url |
|
| 215 | + * @return int |
|
| 216 | + */ |
|
| 217 | + public function getServerStatus($url) { |
|
| 218 | + return $this->dbHandler->getServerStatus($url); |
|
| 219 | + } |
|
| 220 | + |
|
| 221 | + /** |
|
| 222 | + * check if URL point to a ownCloud/Nextcloud server |
|
| 223 | + * |
|
| 224 | + * @param string $url |
|
| 225 | + * @return bool |
|
| 226 | + */ |
|
| 227 | + public function isOwnCloudServer($url) { |
|
| 228 | + $isValidOwnCloud = false; |
|
| 229 | + $client = $this->httpClientService->newClient(); |
|
| 230 | + try { |
|
| 231 | + $result = $client->get( |
|
| 232 | + $url . '/status.php', |
|
| 233 | + [ |
|
| 234 | + 'timeout' => 3, |
|
| 235 | + 'connect_timeout' => 3, |
|
| 236 | + ] |
|
| 237 | + ); |
|
| 238 | + if ($result->getStatusCode() === Http::STATUS_OK) { |
|
| 239 | + $isValidOwnCloud = $this->checkOwnCloudVersion($result->getBody()); |
|
| 240 | + |
|
| 241 | + } |
|
| 242 | + } catch (\Exception $e) { |
|
| 243 | + $this->logger->debug('No Nextcloud server: ' . $e->getMessage()); |
|
| 244 | + return false; |
|
| 245 | + } |
|
| 246 | + |
|
| 247 | + return $isValidOwnCloud; |
|
| 248 | + } |
|
| 249 | + |
|
| 250 | + /** |
|
| 251 | + * check if ownCloud version is >= 9.0 |
|
| 252 | + * |
|
| 253 | + * @param $status |
|
| 254 | + * @return bool |
|
| 255 | + * @throws HintException |
|
| 256 | + */ |
|
| 257 | + protected function checkOwnCloudVersion($status) { |
|
| 258 | + $decoded = json_decode($status, true); |
|
| 259 | + if (!empty($decoded) && isset($decoded['version'])) { |
|
| 260 | + if (!version_compare($decoded['version'], '9.0.0', '>=')) { |
|
| 261 | + throw new HintException('Remote server version is too low. 9.0 is required.'); |
|
| 262 | + } |
|
| 263 | + return true; |
|
| 264 | + } |
|
| 265 | + return false; |
|
| 266 | + } |
|
| 267 | + |
|
| 268 | + /** |
|
| 269 | + * check if the URL contain a protocol, if not add https |
|
| 270 | + * |
|
| 271 | + * @param string $url |
|
| 272 | + * @return string |
|
| 273 | + */ |
|
| 274 | + protected function updateProtocol($url) { |
|
| 275 | + if ( |
|
| 276 | + strpos($url, 'https://') === 0 |
|
| 277 | + || strpos($url, 'http://') === 0 |
|
| 278 | + ) { |
|
| 279 | + |
|
| 280 | + return $url; |
|
| 281 | + |
|
| 282 | + } |
|
| 283 | + |
|
| 284 | + return 'https://' . $url; |
|
| 285 | + } |
|
| 286 | 286 | } |
@@ -35,51 +35,51 @@ |
||
| 35 | 35 | |
| 36 | 36 | class AddServerMiddleware extends Middleware { |
| 37 | 37 | |
| 38 | - /** @var string */ |
|
| 39 | - protected $appName; |
|
| 38 | + /** @var string */ |
|
| 39 | + protected $appName; |
|
| 40 | 40 | |
| 41 | - /** @var IL10N */ |
|
| 42 | - protected $l; |
|
| 41 | + /** @var IL10N */ |
|
| 42 | + protected $l; |
|
| 43 | 43 | |
| 44 | - /** @var ILogger */ |
|
| 45 | - protected $logger; |
|
| 44 | + /** @var ILogger */ |
|
| 45 | + protected $logger; |
|
| 46 | 46 | |
| 47 | - /** |
|
| 48 | - * @param string $appName |
|
| 49 | - * @param IL10N $l |
|
| 50 | - * @param ILogger $logger |
|
| 51 | - */ |
|
| 52 | - public function __construct($appName, IL10N $l, ILogger $logger) { |
|
| 53 | - $this->appName = $appName; |
|
| 54 | - $this->l = $l; |
|
| 55 | - $this->logger = $logger; |
|
| 56 | - } |
|
| 47 | + /** |
|
| 48 | + * @param string $appName |
|
| 49 | + * @param IL10N $l |
|
| 50 | + * @param ILogger $logger |
|
| 51 | + */ |
|
| 52 | + public function __construct($appName, IL10N $l, ILogger $logger) { |
|
| 53 | + $this->appName = $appName; |
|
| 54 | + $this->l = $l; |
|
| 55 | + $this->logger = $logger; |
|
| 56 | + } |
|
| 57 | 57 | |
| 58 | - /** |
|
| 59 | - * Log error message and return a response which can be displayed to the user |
|
| 60 | - * |
|
| 61 | - * @param Controller $controller |
|
| 62 | - * @param string $methodName |
|
| 63 | - * @param \Exception $exception |
|
| 64 | - * @return JSONResponse |
|
| 65 | - * @throws \Exception |
|
| 66 | - */ |
|
| 67 | - public function afterException($controller, $methodName, \Exception $exception) { |
|
| 68 | - if (($controller instanceof SettingsController) === false) { |
|
| 69 | - throw $exception; |
|
| 70 | - } |
|
| 71 | - $this->logger->error($exception->getMessage(), ['app' => $this->appName]); |
|
| 72 | - if ($exception instanceof HintException) { |
|
| 73 | - $message = $exception->getHint(); |
|
| 74 | - } else { |
|
| 75 | - $message = $exception->getMessage(); |
|
| 76 | - } |
|
| 58 | + /** |
|
| 59 | + * Log error message and return a response which can be displayed to the user |
|
| 60 | + * |
|
| 61 | + * @param Controller $controller |
|
| 62 | + * @param string $methodName |
|
| 63 | + * @param \Exception $exception |
|
| 64 | + * @return JSONResponse |
|
| 65 | + * @throws \Exception |
|
| 66 | + */ |
|
| 67 | + public function afterException($controller, $methodName, \Exception $exception) { |
|
| 68 | + if (($controller instanceof SettingsController) === false) { |
|
| 69 | + throw $exception; |
|
| 70 | + } |
|
| 71 | + $this->logger->error($exception->getMessage(), ['app' => $this->appName]); |
|
| 72 | + if ($exception instanceof HintException) { |
|
| 73 | + $message = $exception->getHint(); |
|
| 74 | + } else { |
|
| 75 | + $message = $exception->getMessage(); |
|
| 76 | + } |
|
| 77 | 77 | |
| 78 | - return new JSONResponse( |
|
| 79 | - ['message' => $message], |
|
| 80 | - Http::STATUS_BAD_REQUEST |
|
| 81 | - ); |
|
| 78 | + return new JSONResponse( |
|
| 79 | + ['message' => $message], |
|
| 80 | + Http::STATUS_BAD_REQUEST |
|
| 81 | + ); |
|
| 82 | 82 | |
| 83 | - } |
|
| 83 | + } |
|
| 84 | 84 | |
| 85 | 85 | } |
@@ -42,294 +42,294 @@ |
||
| 42 | 42 | */ |
| 43 | 43 | class DbHandler { |
| 44 | 44 | |
| 45 | - /** @var IDBConnection */ |
|
| 46 | - private $connection; |
|
| 47 | - |
|
| 48 | - /** @var IL10N */ |
|
| 49 | - private $IL10N; |
|
| 50 | - |
|
| 51 | - /** @var string */ |
|
| 52 | - private $dbTable = 'trusted_servers'; |
|
| 53 | - |
|
| 54 | - /** |
|
| 55 | - * @param IDBConnection $connection |
|
| 56 | - * @param IL10N $il10n |
|
| 57 | - */ |
|
| 58 | - public function __construct( |
|
| 59 | - IDBConnection $connection, |
|
| 60 | - IL10N $il10n |
|
| 61 | - ) { |
|
| 62 | - $this->connection = $connection; |
|
| 63 | - $this->IL10N = $il10n; |
|
| 64 | - } |
|
| 65 | - |
|
| 66 | - /** |
|
| 67 | - * add server to the list of trusted servers |
|
| 68 | - * |
|
| 69 | - * @param string $url |
|
| 70 | - * @return int |
|
| 71 | - * @throws HintException |
|
| 72 | - */ |
|
| 73 | - public function addServer($url) { |
|
| 74 | - $hash = $this->hash($url); |
|
| 75 | - $url = rtrim($url, '/'); |
|
| 76 | - $query = $this->connection->getQueryBuilder(); |
|
| 77 | - $query->insert($this->dbTable) |
|
| 78 | - ->values( |
|
| 79 | - [ |
|
| 80 | - 'url' => $query->createParameter('url'), |
|
| 81 | - 'url_hash' => $query->createParameter('url_hash'), |
|
| 82 | - ] |
|
| 83 | - ) |
|
| 84 | - ->setParameter('url', $url) |
|
| 85 | - ->setParameter('url_hash', $hash); |
|
| 86 | - |
|
| 87 | - $result = $query->execute(); |
|
| 88 | - |
|
| 89 | - if ($result) { |
|
| 90 | - return (int)$this->connection->lastInsertId('*PREFIX*'.$this->dbTable); |
|
| 91 | - } |
|
| 92 | - |
|
| 93 | - $message = 'Internal failure, Could not add trusted server: ' . $url; |
|
| 94 | - $message_t = $this->IL10N->t('Could not add server'); |
|
| 95 | - throw new HintException($message, $message_t); |
|
| 96 | - } |
|
| 97 | - |
|
| 98 | - /** |
|
| 99 | - * remove server from the list of trusted servers |
|
| 100 | - * |
|
| 101 | - * @param int $id |
|
| 102 | - */ |
|
| 103 | - public function removeServer($id) { |
|
| 104 | - $query = $this->connection->getQueryBuilder(); |
|
| 105 | - $query->delete($this->dbTable) |
|
| 106 | - ->where($query->expr()->eq('id', $query->createParameter('id'))) |
|
| 107 | - ->setParameter('id', $id); |
|
| 108 | - $query->execute(); |
|
| 109 | - } |
|
| 110 | - |
|
| 111 | - /** |
|
| 112 | - * get trusted server with given ID |
|
| 113 | - * |
|
| 114 | - * @param int $id |
|
| 115 | - * @return array |
|
| 116 | - * @throws \Exception |
|
| 117 | - */ |
|
| 118 | - public function getServerById($id) { |
|
| 119 | - $query = $this->connection->getQueryBuilder(); |
|
| 120 | - $query->select('*')->from($this->dbTable) |
|
| 121 | - ->where($query->expr()->eq('id', $query->createParameter('id'))) |
|
| 122 | - ->setParameter('id', $id); |
|
| 123 | - $query->execute(); |
|
| 124 | - $result = $query->execute()->fetchAll(); |
|
| 125 | - |
|
| 126 | - if (empty($result)) { |
|
| 127 | - throw new \Exception('No Server found with ID: ' . $id); |
|
| 128 | - } |
|
| 129 | - |
|
| 130 | - return $result[0]; |
|
| 131 | - } |
|
| 132 | - |
|
| 133 | - /** |
|
| 134 | - * get all trusted servers |
|
| 135 | - * |
|
| 136 | - * @return array |
|
| 137 | - */ |
|
| 138 | - public function getAllServer() { |
|
| 139 | - $query = $this->connection->getQueryBuilder(); |
|
| 140 | - $query->select(['url', 'url_hash', 'id', 'status', 'shared_secret', 'sync_token']) |
|
| 141 | - ->from($this->dbTable); |
|
| 142 | - $statement = $query->execute(); |
|
| 143 | - $result = $statement->fetchAll(); |
|
| 144 | - $statement->closeCursor(); |
|
| 145 | - return $result; |
|
| 146 | - } |
|
| 147 | - |
|
| 148 | - /** |
|
| 149 | - * check if server already exists in the database table |
|
| 150 | - * |
|
| 151 | - * @param string $url |
|
| 152 | - * @return bool |
|
| 153 | - */ |
|
| 154 | - public function serverExists($url) { |
|
| 155 | - $hash = $this->hash($url); |
|
| 156 | - $query = $this->connection->getQueryBuilder(); |
|
| 157 | - $query->select('url') |
|
| 158 | - ->from($this->dbTable) |
|
| 159 | - ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 160 | - ->setParameter('url_hash', $hash); |
|
| 161 | - $statement = $query->execute(); |
|
| 162 | - $result = $statement->fetchAll(); |
|
| 163 | - $statement->closeCursor(); |
|
| 164 | - |
|
| 165 | - return !empty($result); |
|
| 166 | - } |
|
| 167 | - |
|
| 168 | - /** |
|
| 169 | - * write token to database. Token is used to exchange the secret |
|
| 170 | - * |
|
| 171 | - * @param string $url |
|
| 172 | - * @param string $token |
|
| 173 | - */ |
|
| 174 | - public function addToken($url, $token) { |
|
| 175 | - $hash = $this->hash($url); |
|
| 176 | - $query = $this->connection->getQueryBuilder(); |
|
| 177 | - $query->update($this->dbTable) |
|
| 178 | - ->set('token', $query->createParameter('token')) |
|
| 179 | - ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 180 | - ->setParameter('url_hash', $hash) |
|
| 181 | - ->setParameter('token', $token); |
|
| 182 | - $query->execute(); |
|
| 183 | - } |
|
| 184 | - |
|
| 185 | - /** |
|
| 186 | - * get token stored in database |
|
| 187 | - * |
|
| 188 | - * @param string $url |
|
| 189 | - * @return string |
|
| 190 | - * @throws \Exception |
|
| 191 | - */ |
|
| 192 | - public function getToken($url) { |
|
| 193 | - $hash = $this->hash($url); |
|
| 194 | - $query = $this->connection->getQueryBuilder(); |
|
| 195 | - $query->select('token')->from($this->dbTable) |
|
| 196 | - ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 197 | - ->setParameter('url_hash', $hash); |
|
| 198 | - |
|
| 199 | - $statement = $query->execute(); |
|
| 200 | - $result = $statement->fetch(); |
|
| 201 | - $statement->closeCursor(); |
|
| 202 | - |
|
| 203 | - if (!isset($result['token'])) { |
|
| 204 | - throw new \Exception('No token found for: ' . $url); |
|
| 205 | - } |
|
| 206 | - |
|
| 207 | - return $result['token']; |
|
| 208 | - } |
|
| 209 | - |
|
| 210 | - /** |
|
| 211 | - * add shared Secret to database |
|
| 212 | - * |
|
| 213 | - * @param string $url |
|
| 214 | - * @param string $sharedSecret |
|
| 215 | - */ |
|
| 216 | - public function addSharedSecret($url, $sharedSecret) { |
|
| 217 | - $hash = $this->hash($url); |
|
| 218 | - $query = $this->connection->getQueryBuilder(); |
|
| 219 | - $query->update($this->dbTable) |
|
| 220 | - ->set('shared_secret', $query->createParameter('sharedSecret')) |
|
| 221 | - ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 222 | - ->setParameter('url_hash', $hash) |
|
| 223 | - ->setParameter('sharedSecret', $sharedSecret); |
|
| 224 | - $query->execute(); |
|
| 225 | - } |
|
| 226 | - |
|
| 227 | - /** |
|
| 228 | - * get shared secret from database |
|
| 229 | - * |
|
| 230 | - * @param string $url |
|
| 231 | - * @return string |
|
| 232 | - */ |
|
| 233 | - public function getSharedSecret($url) { |
|
| 234 | - $hash = $this->hash($url); |
|
| 235 | - $query = $this->connection->getQueryBuilder(); |
|
| 236 | - $query->select('shared_secret')->from($this->dbTable) |
|
| 237 | - ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 238 | - ->setParameter('url_hash', $hash); |
|
| 239 | - |
|
| 240 | - $statement = $query->execute(); |
|
| 241 | - $result = $statement->fetch(); |
|
| 242 | - $statement->closeCursor(); |
|
| 243 | - return $result['shared_secret']; |
|
| 244 | - } |
|
| 245 | - |
|
| 246 | - /** |
|
| 247 | - * set server status |
|
| 248 | - * |
|
| 249 | - * @param string $url |
|
| 250 | - * @param int $status |
|
| 251 | - * @param string|null $token |
|
| 252 | - */ |
|
| 253 | - public function setServerStatus($url, $status, $token = null) { |
|
| 254 | - $hash = $this->hash($url); |
|
| 255 | - $query = $this->connection->getQueryBuilder(); |
|
| 256 | - $query->update($this->dbTable) |
|
| 257 | - ->set('status', $query->createNamedParameter($status)) |
|
| 258 | - ->where($query->expr()->eq('url_hash', $query->createNamedParameter($hash))); |
|
| 259 | - if (!is_null($token)) { |
|
| 260 | - $query->set('sync_token', $query->createNamedParameter($token)); |
|
| 261 | - } |
|
| 262 | - $query->execute(); |
|
| 263 | - } |
|
| 264 | - |
|
| 265 | - /** |
|
| 266 | - * get server status |
|
| 267 | - * |
|
| 268 | - * @param string $url |
|
| 269 | - * @return int |
|
| 270 | - */ |
|
| 271 | - public function getServerStatus($url) { |
|
| 272 | - $hash = $this->hash($url); |
|
| 273 | - $query = $this->connection->getQueryBuilder(); |
|
| 274 | - $query->select('status')->from($this->dbTable) |
|
| 275 | - ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 276 | - ->setParameter('url_hash', $hash); |
|
| 277 | - |
|
| 278 | - $statement = $query->execute(); |
|
| 279 | - $result = $statement->fetch(); |
|
| 280 | - $statement->closeCursor(); |
|
| 281 | - return (int)$result['status']; |
|
| 282 | - } |
|
| 283 | - |
|
| 284 | - /** |
|
| 285 | - * create hash from URL |
|
| 286 | - * |
|
| 287 | - * @param string $url |
|
| 288 | - * @return string |
|
| 289 | - */ |
|
| 290 | - protected function hash($url) { |
|
| 291 | - $normalized = $this->normalizeUrl($url); |
|
| 292 | - return sha1($normalized); |
|
| 293 | - } |
|
| 294 | - |
|
| 295 | - /** |
|
| 296 | - * normalize URL, used to create the sha1 hash |
|
| 297 | - * |
|
| 298 | - * @param string $url |
|
| 299 | - * @return string |
|
| 300 | - */ |
|
| 301 | - protected function normalizeUrl($url) { |
|
| 302 | - $normalized = $url; |
|
| 303 | - |
|
| 304 | - if (strpos($url, 'https://') === 0) { |
|
| 305 | - $normalized = substr($url, strlen('https://')); |
|
| 306 | - } else if (strpos($url, 'http://') === 0) { |
|
| 307 | - $normalized = substr($url, strlen('http://')); |
|
| 308 | - } |
|
| 309 | - |
|
| 310 | - $normalized = Filesystem::normalizePath($normalized); |
|
| 311 | - $normalized = trim($normalized, '/'); |
|
| 312 | - |
|
| 313 | - return $normalized; |
|
| 314 | - } |
|
| 315 | - |
|
| 316 | - /** |
|
| 317 | - * @param $username |
|
| 318 | - * @param $password |
|
| 319 | - * @return bool |
|
| 320 | - */ |
|
| 321 | - public function auth($username, $password) { |
|
| 322 | - if ($username !== 'system') { |
|
| 323 | - return false; |
|
| 324 | - } |
|
| 325 | - $query = $this->connection->getQueryBuilder(); |
|
| 326 | - $query->select('url')->from($this->dbTable) |
|
| 327 | - ->where($query->expr()->eq('shared_secret', $query->createNamedParameter($password))); |
|
| 328 | - |
|
| 329 | - $statement = $query->execute(); |
|
| 330 | - $result = $statement->fetch(); |
|
| 331 | - $statement->closeCursor(); |
|
| 332 | - return !empty($result); |
|
| 333 | - } |
|
| 45 | + /** @var IDBConnection */ |
|
| 46 | + private $connection; |
|
| 47 | + |
|
| 48 | + /** @var IL10N */ |
|
| 49 | + private $IL10N; |
|
| 50 | + |
|
| 51 | + /** @var string */ |
|
| 52 | + private $dbTable = 'trusted_servers'; |
|
| 53 | + |
|
| 54 | + /** |
|
| 55 | + * @param IDBConnection $connection |
|
| 56 | + * @param IL10N $il10n |
|
| 57 | + */ |
|
| 58 | + public function __construct( |
|
| 59 | + IDBConnection $connection, |
|
| 60 | + IL10N $il10n |
|
| 61 | + ) { |
|
| 62 | + $this->connection = $connection; |
|
| 63 | + $this->IL10N = $il10n; |
|
| 64 | + } |
|
| 65 | + |
|
| 66 | + /** |
|
| 67 | + * add server to the list of trusted servers |
|
| 68 | + * |
|
| 69 | + * @param string $url |
|
| 70 | + * @return int |
|
| 71 | + * @throws HintException |
|
| 72 | + */ |
|
| 73 | + public function addServer($url) { |
|
| 74 | + $hash = $this->hash($url); |
|
| 75 | + $url = rtrim($url, '/'); |
|
| 76 | + $query = $this->connection->getQueryBuilder(); |
|
| 77 | + $query->insert($this->dbTable) |
|
| 78 | + ->values( |
|
| 79 | + [ |
|
| 80 | + 'url' => $query->createParameter('url'), |
|
| 81 | + 'url_hash' => $query->createParameter('url_hash'), |
|
| 82 | + ] |
|
| 83 | + ) |
|
| 84 | + ->setParameter('url', $url) |
|
| 85 | + ->setParameter('url_hash', $hash); |
|
| 86 | + |
|
| 87 | + $result = $query->execute(); |
|
| 88 | + |
|
| 89 | + if ($result) { |
|
| 90 | + return (int)$this->connection->lastInsertId('*PREFIX*'.$this->dbTable); |
|
| 91 | + } |
|
| 92 | + |
|
| 93 | + $message = 'Internal failure, Could not add trusted server: ' . $url; |
|
| 94 | + $message_t = $this->IL10N->t('Could not add server'); |
|
| 95 | + throw new HintException($message, $message_t); |
|
| 96 | + } |
|
| 97 | + |
|
| 98 | + /** |
|
| 99 | + * remove server from the list of trusted servers |
|
| 100 | + * |
|
| 101 | + * @param int $id |
|
| 102 | + */ |
|
| 103 | + public function removeServer($id) { |
|
| 104 | + $query = $this->connection->getQueryBuilder(); |
|
| 105 | + $query->delete($this->dbTable) |
|
| 106 | + ->where($query->expr()->eq('id', $query->createParameter('id'))) |
|
| 107 | + ->setParameter('id', $id); |
|
| 108 | + $query->execute(); |
|
| 109 | + } |
|
| 110 | + |
|
| 111 | + /** |
|
| 112 | + * get trusted server with given ID |
|
| 113 | + * |
|
| 114 | + * @param int $id |
|
| 115 | + * @return array |
|
| 116 | + * @throws \Exception |
|
| 117 | + */ |
|
| 118 | + public function getServerById($id) { |
|
| 119 | + $query = $this->connection->getQueryBuilder(); |
|
| 120 | + $query->select('*')->from($this->dbTable) |
|
| 121 | + ->where($query->expr()->eq('id', $query->createParameter('id'))) |
|
| 122 | + ->setParameter('id', $id); |
|
| 123 | + $query->execute(); |
|
| 124 | + $result = $query->execute()->fetchAll(); |
|
| 125 | + |
|
| 126 | + if (empty($result)) { |
|
| 127 | + throw new \Exception('No Server found with ID: ' . $id); |
|
| 128 | + } |
|
| 129 | + |
|
| 130 | + return $result[0]; |
|
| 131 | + } |
|
| 132 | + |
|
| 133 | + /** |
|
| 134 | + * get all trusted servers |
|
| 135 | + * |
|
| 136 | + * @return array |
|
| 137 | + */ |
|
| 138 | + public function getAllServer() { |
|
| 139 | + $query = $this->connection->getQueryBuilder(); |
|
| 140 | + $query->select(['url', 'url_hash', 'id', 'status', 'shared_secret', 'sync_token']) |
|
| 141 | + ->from($this->dbTable); |
|
| 142 | + $statement = $query->execute(); |
|
| 143 | + $result = $statement->fetchAll(); |
|
| 144 | + $statement->closeCursor(); |
|
| 145 | + return $result; |
|
| 146 | + } |
|
| 147 | + |
|
| 148 | + /** |
|
| 149 | + * check if server already exists in the database table |
|
| 150 | + * |
|
| 151 | + * @param string $url |
|
| 152 | + * @return bool |
|
| 153 | + */ |
|
| 154 | + public function serverExists($url) { |
|
| 155 | + $hash = $this->hash($url); |
|
| 156 | + $query = $this->connection->getQueryBuilder(); |
|
| 157 | + $query->select('url') |
|
| 158 | + ->from($this->dbTable) |
|
| 159 | + ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 160 | + ->setParameter('url_hash', $hash); |
|
| 161 | + $statement = $query->execute(); |
|
| 162 | + $result = $statement->fetchAll(); |
|
| 163 | + $statement->closeCursor(); |
|
| 164 | + |
|
| 165 | + return !empty($result); |
|
| 166 | + } |
|
| 167 | + |
|
| 168 | + /** |
|
| 169 | + * write token to database. Token is used to exchange the secret |
|
| 170 | + * |
|
| 171 | + * @param string $url |
|
| 172 | + * @param string $token |
|
| 173 | + */ |
|
| 174 | + public function addToken($url, $token) { |
|
| 175 | + $hash = $this->hash($url); |
|
| 176 | + $query = $this->connection->getQueryBuilder(); |
|
| 177 | + $query->update($this->dbTable) |
|
| 178 | + ->set('token', $query->createParameter('token')) |
|
| 179 | + ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 180 | + ->setParameter('url_hash', $hash) |
|
| 181 | + ->setParameter('token', $token); |
|
| 182 | + $query->execute(); |
|
| 183 | + } |
|
| 184 | + |
|
| 185 | + /** |
|
| 186 | + * get token stored in database |
|
| 187 | + * |
|
| 188 | + * @param string $url |
|
| 189 | + * @return string |
|
| 190 | + * @throws \Exception |
|
| 191 | + */ |
|
| 192 | + public function getToken($url) { |
|
| 193 | + $hash = $this->hash($url); |
|
| 194 | + $query = $this->connection->getQueryBuilder(); |
|
| 195 | + $query->select('token')->from($this->dbTable) |
|
| 196 | + ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 197 | + ->setParameter('url_hash', $hash); |
|
| 198 | + |
|
| 199 | + $statement = $query->execute(); |
|
| 200 | + $result = $statement->fetch(); |
|
| 201 | + $statement->closeCursor(); |
|
| 202 | + |
|
| 203 | + if (!isset($result['token'])) { |
|
| 204 | + throw new \Exception('No token found for: ' . $url); |
|
| 205 | + } |
|
| 206 | + |
|
| 207 | + return $result['token']; |
|
| 208 | + } |
|
| 209 | + |
|
| 210 | + /** |
|
| 211 | + * add shared Secret to database |
|
| 212 | + * |
|
| 213 | + * @param string $url |
|
| 214 | + * @param string $sharedSecret |
|
| 215 | + */ |
|
| 216 | + public function addSharedSecret($url, $sharedSecret) { |
|
| 217 | + $hash = $this->hash($url); |
|
| 218 | + $query = $this->connection->getQueryBuilder(); |
|
| 219 | + $query->update($this->dbTable) |
|
| 220 | + ->set('shared_secret', $query->createParameter('sharedSecret')) |
|
| 221 | + ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 222 | + ->setParameter('url_hash', $hash) |
|
| 223 | + ->setParameter('sharedSecret', $sharedSecret); |
|
| 224 | + $query->execute(); |
|
| 225 | + } |
|
| 226 | + |
|
| 227 | + /** |
|
| 228 | + * get shared secret from database |
|
| 229 | + * |
|
| 230 | + * @param string $url |
|
| 231 | + * @return string |
|
| 232 | + */ |
|
| 233 | + public function getSharedSecret($url) { |
|
| 234 | + $hash = $this->hash($url); |
|
| 235 | + $query = $this->connection->getQueryBuilder(); |
|
| 236 | + $query->select('shared_secret')->from($this->dbTable) |
|
| 237 | + ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 238 | + ->setParameter('url_hash', $hash); |
|
| 239 | + |
|
| 240 | + $statement = $query->execute(); |
|
| 241 | + $result = $statement->fetch(); |
|
| 242 | + $statement->closeCursor(); |
|
| 243 | + return $result['shared_secret']; |
|
| 244 | + } |
|
| 245 | + |
|
| 246 | + /** |
|
| 247 | + * set server status |
|
| 248 | + * |
|
| 249 | + * @param string $url |
|
| 250 | + * @param int $status |
|
| 251 | + * @param string|null $token |
|
| 252 | + */ |
|
| 253 | + public function setServerStatus($url, $status, $token = null) { |
|
| 254 | + $hash = $this->hash($url); |
|
| 255 | + $query = $this->connection->getQueryBuilder(); |
|
| 256 | + $query->update($this->dbTable) |
|
| 257 | + ->set('status', $query->createNamedParameter($status)) |
|
| 258 | + ->where($query->expr()->eq('url_hash', $query->createNamedParameter($hash))); |
|
| 259 | + if (!is_null($token)) { |
|
| 260 | + $query->set('sync_token', $query->createNamedParameter($token)); |
|
| 261 | + } |
|
| 262 | + $query->execute(); |
|
| 263 | + } |
|
| 264 | + |
|
| 265 | + /** |
|
| 266 | + * get server status |
|
| 267 | + * |
|
| 268 | + * @param string $url |
|
| 269 | + * @return int |
|
| 270 | + */ |
|
| 271 | + public function getServerStatus($url) { |
|
| 272 | + $hash = $this->hash($url); |
|
| 273 | + $query = $this->connection->getQueryBuilder(); |
|
| 274 | + $query->select('status')->from($this->dbTable) |
|
| 275 | + ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) |
|
| 276 | + ->setParameter('url_hash', $hash); |
|
| 277 | + |
|
| 278 | + $statement = $query->execute(); |
|
| 279 | + $result = $statement->fetch(); |
|
| 280 | + $statement->closeCursor(); |
|
| 281 | + return (int)$result['status']; |
|
| 282 | + } |
|
| 283 | + |
|
| 284 | + /** |
|
| 285 | + * create hash from URL |
|
| 286 | + * |
|
| 287 | + * @param string $url |
|
| 288 | + * @return string |
|
| 289 | + */ |
|
| 290 | + protected function hash($url) { |
|
| 291 | + $normalized = $this->normalizeUrl($url); |
|
| 292 | + return sha1($normalized); |
|
| 293 | + } |
|
| 294 | + |
|
| 295 | + /** |
|
| 296 | + * normalize URL, used to create the sha1 hash |
|
| 297 | + * |
|
| 298 | + * @param string $url |
|
| 299 | + * @return string |
|
| 300 | + */ |
|
| 301 | + protected function normalizeUrl($url) { |
|
| 302 | + $normalized = $url; |
|
| 303 | + |
|
| 304 | + if (strpos($url, 'https://') === 0) { |
|
| 305 | + $normalized = substr($url, strlen('https://')); |
|
| 306 | + } else if (strpos($url, 'http://') === 0) { |
|
| 307 | + $normalized = substr($url, strlen('http://')); |
|
| 308 | + } |
|
| 309 | + |
|
| 310 | + $normalized = Filesystem::normalizePath($normalized); |
|
| 311 | + $normalized = trim($normalized, '/'); |
|
| 312 | + |
|
| 313 | + return $normalized; |
|
| 314 | + } |
|
| 315 | + |
|
| 316 | + /** |
|
| 317 | + * @param $username |
|
| 318 | + * @param $password |
|
| 319 | + * @return bool |
|
| 320 | + */ |
|
| 321 | + public function auth($username, $password) { |
|
| 322 | + if ($username !== 'system') { |
|
| 323 | + return false; |
|
| 324 | + } |
|
| 325 | + $query = $this->connection->getQueryBuilder(); |
|
| 326 | + $query->select('url')->from($this->dbTable) |
|
| 327 | + ->where($query->expr()->eq('shared_secret', $query->createNamedParameter($password))); |
|
| 328 | + |
|
| 329 | + $statement = $query->execute(); |
|
| 330 | + $result = $statement->fetch(); |
|
| 331 | + $statement->closeCursor(); |
|
| 332 | + return !empty($result); |
|
| 333 | + } |
|
| 334 | 334 | |
| 335 | 335 | } |
@@ -87,10 +87,10 @@ discard block |
||
| 87 | 87 | $result = $query->execute(); |
| 88 | 88 | |
| 89 | 89 | if ($result) { |
| 90 | - return (int)$this->connection->lastInsertId('*PREFIX*'.$this->dbTable); |
|
| 90 | + return (int) $this->connection->lastInsertId('*PREFIX*'.$this->dbTable); |
|
| 91 | 91 | } |
| 92 | 92 | |
| 93 | - $message = 'Internal failure, Could not add trusted server: ' . $url; |
|
| 93 | + $message = 'Internal failure, Could not add trusted server: '.$url; |
|
| 94 | 94 | $message_t = $this->IL10N->t('Could not add server'); |
| 95 | 95 | throw new HintException($message, $message_t); |
| 96 | 96 | } |
@@ -124,7 +124,7 @@ discard block |
||
| 124 | 124 | $result = $query->execute()->fetchAll(); |
| 125 | 125 | |
| 126 | 126 | if (empty($result)) { |
| 127 | - throw new \Exception('No Server found with ID: ' . $id); |
|
| 127 | + throw new \Exception('No Server found with ID: '.$id); |
|
| 128 | 128 | } |
| 129 | 129 | |
| 130 | 130 | return $result[0]; |
@@ -201,7 +201,7 @@ discard block |
||
| 201 | 201 | $statement->closeCursor(); |
| 202 | 202 | |
| 203 | 203 | if (!isset($result['token'])) { |
| 204 | - throw new \Exception('No token found for: ' . $url); |
|
| 204 | + throw new \Exception('No token found for: '.$url); |
|
| 205 | 205 | } |
| 206 | 206 | |
| 207 | 207 | return $result['token']; |
@@ -278,7 +278,7 @@ discard block |
||
| 278 | 278 | $statement = $query->execute(); |
| 279 | 279 | $result = $statement->fetch(); |
| 280 | 280 | $statement->closeCursor(); |
| 281 | - return (int)$result['status']; |
|
| 281 | + return (int) $result['status']; |
|
| 282 | 282 | } |
| 283 | 283 | |
| 284 | 284 | /** |
@@ -35,48 +35,48 @@ |
||
| 35 | 35 | |
| 36 | 36 | class Application extends App { |
| 37 | 37 | |
| 38 | - /** |
|
| 39 | - * @param array $urlParams |
|
| 40 | - */ |
|
| 41 | - public function __construct($urlParams = []) { |
|
| 42 | - parent::__construct('federation', $urlParams); |
|
| 43 | - $this->registerMiddleware(); |
|
| 44 | - } |
|
| 38 | + /** |
|
| 39 | + * @param array $urlParams |
|
| 40 | + */ |
|
| 41 | + public function __construct($urlParams = []) { |
|
| 42 | + parent::__construct('federation', $urlParams); |
|
| 43 | + $this->registerMiddleware(); |
|
| 44 | + } |
|
| 45 | 45 | |
| 46 | - private function registerMiddleware() { |
|
| 47 | - $container = $this->getContainer(); |
|
| 48 | - $container->registerAlias('AddServerMiddleware', AddServerMiddleware::class); |
|
| 49 | - $container->registerMiddleWare('AddServerMiddleware'); |
|
| 50 | - } |
|
| 46 | + private function registerMiddleware() { |
|
| 47 | + $container = $this->getContainer(); |
|
| 48 | + $container->registerAlias('AddServerMiddleware', AddServerMiddleware::class); |
|
| 49 | + $container->registerMiddleWare('AddServerMiddleware'); |
|
| 50 | + } |
|
| 51 | 51 | |
| 52 | - /** |
|
| 53 | - * listen to federated_share_added hooks to auto-add new servers to the |
|
| 54 | - * list of trusted servers. |
|
| 55 | - */ |
|
| 56 | - public function registerHooks() { |
|
| 52 | + /** |
|
| 53 | + * listen to federated_share_added hooks to auto-add new servers to the |
|
| 54 | + * list of trusted servers. |
|
| 55 | + */ |
|
| 56 | + public function registerHooks() { |
|
| 57 | 57 | |
| 58 | - $container = $this->getContainer(); |
|
| 59 | - $hooksManager = $container->query(Hooks::class); |
|
| 58 | + $container = $this->getContainer(); |
|
| 59 | + $hooksManager = $container->query(Hooks::class); |
|
| 60 | 60 | |
| 61 | - Util::connectHook( |
|
| 62 | - 'OCP\Share', |
|
| 63 | - 'federated_share_added', |
|
| 64 | - $hooksManager, |
|
| 65 | - 'addServerHook' |
|
| 66 | - ); |
|
| 61 | + Util::connectHook( |
|
| 62 | + 'OCP\Share', |
|
| 63 | + 'federated_share_added', |
|
| 64 | + $hooksManager, |
|
| 65 | + 'addServerHook' |
|
| 66 | + ); |
|
| 67 | 67 | |
| 68 | - $dispatcher = $container->getServer()->getEventDispatcher(); |
|
| 69 | - $dispatcher->addListener('OCA\DAV\Connector\Sabre::authInit', function($event) use($container) { |
|
| 70 | - if ($event instanceof SabrePluginEvent) { |
|
| 71 | - $server = $event->getServer(); |
|
| 72 | - if ($server instanceof Server) { |
|
| 73 | - $authPlugin = $server->getPlugin('auth'); |
|
| 74 | - if ($authPlugin instanceof Plugin) { |
|
| 75 | - $authPlugin->addBackend($container->query(FedAuth::class)); |
|
| 76 | - } |
|
| 77 | - } |
|
| 78 | - } |
|
| 79 | - }); |
|
| 80 | - } |
|
| 68 | + $dispatcher = $container->getServer()->getEventDispatcher(); |
|
| 69 | + $dispatcher->addListener('OCA\DAV\Connector\Sabre::authInit', function($event) use($container) { |
|
| 70 | + if ($event instanceof SabrePluginEvent) { |
|
| 71 | + $server = $event->getServer(); |
|
| 72 | + if ($server instanceof Server) { |
|
| 73 | + $authPlugin = $server->getPlugin('auth'); |
|
| 74 | + if ($authPlugin instanceof Plugin) { |
|
| 75 | + $authPlugin->addBackend($container->query(FedAuth::class)); |
|
| 76 | + } |
|
| 77 | + } |
|
| 78 | + } |
|
| 79 | + }); |
|
| 80 | + } |
|
| 81 | 81 | |
| 82 | 82 | } |
@@ -30,45 +30,45 @@ |
||
| 30 | 30 | |
| 31 | 31 | class SyncFederationAddressBooks extends Command { |
| 32 | 32 | |
| 33 | - /** @var \OCA\Federation\SyncFederationAddressBooks */ |
|
| 34 | - private $syncService; |
|
| 33 | + /** @var \OCA\Federation\SyncFederationAddressBooks */ |
|
| 34 | + private $syncService; |
|
| 35 | 35 | |
| 36 | - /** |
|
| 37 | - * @param \OCA\Federation\SyncFederationAddressBooks $syncService |
|
| 38 | - */ |
|
| 39 | - public function __construct(\OCA\Federation\SyncFederationAddressBooks $syncService) { |
|
| 40 | - parent::__construct(); |
|
| 36 | + /** |
|
| 37 | + * @param \OCA\Federation\SyncFederationAddressBooks $syncService |
|
| 38 | + */ |
|
| 39 | + public function __construct(\OCA\Federation\SyncFederationAddressBooks $syncService) { |
|
| 40 | + parent::__construct(); |
|
| 41 | 41 | |
| 42 | - $this->syncService = $syncService; |
|
| 43 | - } |
|
| 42 | + $this->syncService = $syncService; |
|
| 43 | + } |
|
| 44 | 44 | |
| 45 | - protected function configure() { |
|
| 46 | - $this |
|
| 47 | - ->setName('federation:sync-addressbooks') |
|
| 48 | - ->setDescription('Synchronizes addressbooks of all federated clouds'); |
|
| 49 | - } |
|
| 45 | + protected function configure() { |
|
| 46 | + $this |
|
| 47 | + ->setName('federation:sync-addressbooks') |
|
| 48 | + ->setDescription('Synchronizes addressbooks of all federated clouds'); |
|
| 49 | + } |
|
| 50 | 50 | |
| 51 | - /** |
|
| 52 | - * @param InputInterface $input |
|
| 53 | - * @param OutputInterface $output |
|
| 54 | - * @return int |
|
| 55 | - */ |
|
| 56 | - protected function execute(InputInterface $input, OutputInterface $output) { |
|
| 51 | + /** |
|
| 52 | + * @param InputInterface $input |
|
| 53 | + * @param OutputInterface $output |
|
| 54 | + * @return int |
|
| 55 | + */ |
|
| 56 | + protected function execute(InputInterface $input, OutputInterface $output) { |
|
| 57 | 57 | |
| 58 | - $progress = new ProgressBar($output); |
|
| 59 | - $progress->start(); |
|
| 60 | - $this->syncService->syncThemAll(function($url, $ex) use ($progress, $output) { |
|
| 61 | - if ($ex instanceof \Exception) { |
|
| 62 | - $output->writeln("Error while syncing $url : " . $ex->getMessage()); |
|
| 58 | + $progress = new ProgressBar($output); |
|
| 59 | + $progress->start(); |
|
| 60 | + $this->syncService->syncThemAll(function($url, $ex) use ($progress, $output) { |
|
| 61 | + if ($ex instanceof \Exception) { |
|
| 62 | + $output->writeln("Error while syncing $url : " . $ex->getMessage()); |
|
| 63 | 63 | |
| 64 | - } else { |
|
| 65 | - $progress->advance(); |
|
| 66 | - } |
|
| 67 | - }); |
|
| 64 | + } else { |
|
| 65 | + $progress->advance(); |
|
| 66 | + } |
|
| 67 | + }); |
|
| 68 | 68 | |
| 69 | - $progress->finish(); |
|
| 70 | - $output->writeln(''); |
|
| 69 | + $progress->finish(); |
|
| 70 | + $output->writeln(''); |
|
| 71 | 71 | |
| 72 | - return 0; |
|
| 73 | - } |
|
| 72 | + return 0; |
|
| 73 | + } |
|
| 74 | 74 | } |