cloudFederationProvider[$resourceType] = [ 'resourceType' => $resourceType, 'displayName' => $displayName, 'callback' => $callback, ]; } /** * remove cloud federation provider * * @param string $providerId */ public function removeCloudFederationProvider($providerId) { unset($this->cloudFederationProvider[$providerId]); } /** * get a list of all cloudFederationProviders * * @return array [resourceType => ['resourceType' => $resourceType, 'displayName' => $displayName, 'callback' => callback]] */ public function getAllCloudFederationProviders() { return $this->cloudFederationProvider; } /** * get a specific cloud federation provider * * @param string $resourceType * @return ICloudFederationProvider * @throws ProviderDoesNotExistsException */ public function getCloudFederationProvider($resourceType) { if (isset($this->cloudFederationProvider[$resourceType])) { return call_user_func($this->cloudFederationProvider[$resourceType]['callback']); } else { throw new ProviderDoesNotExistsException($resourceType); } } /** * @deprecated 29.0.0 - Use {@see sendCloudShare()} instead and handle errors manually */ public function sendShare(ICloudFederationShare $share) { $cloudID = $this->cloudIdManager->resolveCloudId($share->getShareWith()); try { $ocmProvider = $this->discoveryService->discover($cloudID->getRemote()); } catch (OCMProviderException $e) { return false; } $client = $this->httpClientService->newClient(); try { $response = $client->post($ocmProvider->getEndPoint() . '/shares', array_merge($this->getDefaultRequestOptions(), [ 'body' => json_encode($share->getShare()), ])); if ($response->getStatusCode() === Http::STATUS_CREATED) { $result = json_decode($response->getBody(), true); return (is_array($result)) ? $result : []; } } catch (\Exception $e) { $this->logger->debug($e->getMessage(), ['exception' => $e]); // if flat re-sharing is not supported by the remote server // we re-throw the exception and fall back to the old behaviour. // (flat re-shares has been introduced in Nextcloud 9.1) if ($e->getCode() === Http::STATUS_INTERNAL_SERVER_ERROR) { throw $e; } } return false; } /** * @param ICloudFederationShare $share * @return IResponse * @throws OCMProviderException */ public function sendCloudShare(ICloudFederationShare $share): IResponse { $cloudID = $this->cloudIdManager->resolveCloudId($share->getShareWith()); $ocmProvider = $this->discoveryService->discover($cloudID->getRemote()); $client = $this->httpClientService->newClient(); try { return $client->post($ocmProvider->getEndPoint() . '/shares', array_merge($this->getDefaultRequestOptions(), [ 'body' => json_encode($share->getShare()), ])); } catch (\Throwable $e) { $this->logger->error('Error while sending share to federation server: ' . $e->getMessage(), ['exception' => $e]); try { return $client->getResponseFromThrowable($e); } catch (\Throwable $e) { throw new OCMProviderException($e->getMessage(), $e->getCode(), $e); } } } /** * @param string $url * @param ICloudFederationNotification $notification * @return array|false * @deprecated 29.0.0 - Use {@see sendCloudNotification()} instead and handle errors manually */ public function sendNotification($url, ICloudFederationNotification $notification) { try { $ocmProvider = $this->discoveryService->discover($url); } catch (OCMProviderException $e) { return false; } $client = $this->httpClientService->newClient(); try { $response = $client->post($ocmProvider->getEndPoint() . '/notifications', array_merge($this->getDefaultRequestOptions(), [ 'body' => json_encode($notification->getMessage()), ])); if ($response->getStatusCode() === Http::STATUS_CREATED) { $result = json_decode($response->getBody(), true); return (is_array($result)) ? $result : []; } } catch (\Exception $e) { // log the error and return false $this->logger->error('error while sending notification for federated share: ' . $e->getMessage(), ['exception' => $e]); } return false; } /** * @param string $url * @param ICloudFederationNotification $notification * @return IResponse * @throws OCMProviderException */ public function sendCloudNotification(string $url, ICloudFederationNotification $notification): IResponse { $ocmProvider = $this->discoveryService->discover($url); $client = $this->httpClientService->newClient(); try { return $client->post($ocmProvider->getEndPoint() . '/notifications', array_merge($this->getDefaultRequestOptions(), [ 'body' => json_encode($notification->getMessage()), ])); } catch (\Throwable $e) { $this->logger->error('Error while sending notification to federation server: ' . $e->getMessage(), ['exception' => $e]); try { return $client->getResponseFromThrowable($e); } catch (\Throwable $e) { throw new OCMProviderException($e->getMessage(), $e->getCode(), $e); } } } /** * check if the new cloud federation API is ready to be used * * @return bool */ public function isReady() { return $this->appManager->isEnabledForUser('cloud_federation_api'); } private function getDefaultRequestOptions(): array { $options = [ 'headers' => ['content-type' => 'application/json'], 'timeout' => 10, 'connect_timeout' => 10, ]; if ($this->config->getSystemValueBool('sharing.federation.allowSelfSignedCertificates')) { $options['verify'] = false; } return $options; } }