1111
1212use GuzzleHttp \Exception \ConnectException ;
1313use JsonException ;
14+ use NCU \Security \Signature \Exceptions \IdentityNotFoundException ;
15+ use NCU \Security \Signature \Exceptions \SignatoryException ;
16+ use OC \Core \AppInfo \ConfigLexicon ;
17+ use OC \OCM \Model \OCMProvider ;
1418use OCP \AppFramework \Http ;
19+ use OCP \EventDispatcher \IEventDispatcher ;
1520use OCP \Http \Client \IClientService ;
21+ use OCP \IAppConfig ;
1622use OCP \ICache ;
1723use OCP \ICacheFactory ;
1824use OCP \IConfig ;
25+ use OCP \IURLGenerator ;
26+ use OCP \OCM \Events \ResourceTypeRegisterEvent ;
1927use OCP \OCM \Exceptions \OCMProviderException ;
2028use OCP \OCM \ICapabilityAwareOCMProvider ;
2129use OCP \OCM \IOCMDiscoveryService ;
2634 */
2735class OCMDiscoveryService implements IOCMDiscoveryService {
2836 private ICache $ cache ;
37+ public const API_VERSION = '1.1.0 ' ;
38+
39+ private ?ICapabilityAwareOCMProvider $ localProvider = null ;
40+ /** @var array<string, ICapabilityAwareOCMProvider> */
41+ private array $ remoteProviders = [];
2942
3043 public function __construct (
3144 ICacheFactory $ cacheFactory ,
3245 private IClientService $ clientService ,
33- private IConfig $ config ,
34- private ICapabilityAwareOCMProvider $ provider ,
46+ private IEventDispatcher $ eventDispatcher ,
47+ protected IConfig $ config ,
48+ private IAppConfig $ appConfig ,
49+ private IURLGenerator $ urlGenerator ,
50+ private OCMSignatoryManager $ ocmSignatoryManager ,
3551 private LoggerInterface $ logger ,
3652 ) {
3753 $ this ->cache = $ cacheFactory ->createDistributed ('ocm-discovery ' );
3854 }
3955
40-
4156 /**
4257 * @param string $remote
4358 * @param bool $skipCache
@@ -56,17 +71,24 @@ public function discover(string $remote, bool $skipCache = false): ICapabilityAw
5671 }
5772 }
5873
74+ if (array_key_exists ($ remote , $ this ->remoteProviders )) {
75+ return $ this ->remoteProviders [$ remote ];
76+ }
77+
78+ $ provider = new OCMProvider ();
79+
5980 if (!$ skipCache ) {
6081 try {
6182 $ cached = $ this ->cache ->get ($ remote );
6283 if ($ cached === false ) {
6384 throw new OCMProviderException ('Previous discovery failed. ' );
6485 }
6586
66- $ this ->provider ->import (json_decode ($ cached ?? '' , true , 8 , JSON_THROW_ON_ERROR ) ?? []);
67- return $ this ->provider ;
87+ $ provider ->import (json_decode ($ cached ?? '' , true , 8 , JSON_THROW_ON_ERROR ) ?? []);
88+ $ this ->remoteProviders [$ remote ] = $ provider ;
89+ return $ provider ;
6890 } catch (JsonException |OCMProviderException $ e ) {
69- // we ignore cache on issues
91+ $ this -> logger -> warning ( ' cache issue on ocm discovery ' , [ ' exception ' => $ e ]);
7092 }
7193 }
7294
@@ -81,15 +103,20 @@ public function discover(string $remote, bool $skipCache = false): ICapabilityAw
81103 }
82104 $ response = $ client ->get ($ remote . '/ocm-provider/ ' , $ options );
83105
106+ $ body = null ;
84107 if ($ response ->getStatusCode () === Http::STATUS_OK ) {
85108 $ body = $ response ->getBody ();
86109 // update provider with data returned by the request
87- $ this -> provider ->import (json_decode ($ body , true , 8 , JSON_THROW_ON_ERROR ) ?? []);
110+ $ provider ->import (json_decode ($ body , true , 8 , JSON_THROW_ON_ERROR ) ?? []);
88111 $ this ->cache ->set ($ remote , $ body , 60 * 60 * 24 );
112+ $ this ->remoteProviders [$ remote ] = $ provider ;
113+ return $ provider ;
89114 }
90- } catch (JsonException |OCMProviderException $ e ) {
115+
116+ throw new OCMProviderException ('invalid remote ocm endpoint ' );
117+ } catch (JsonException |OCMProviderException ) {
91118 $ this ->cache ->set ($ remote , false , 5 * 60 );
92- throw new OCMProviderException ('data returned by remote seems invalid - ' . ($ body ?? '' ));
119+ throw new OCMProviderException ('data returned by remote seems invalid - status: ' . $ response -> getStatusCode () . ' - ' . ($ body ?? '' ));
93120 } catch (\Exception $ e ) {
94121 $ this ->cache ->set ($ remote , false , 5 * 60 );
95122 $ this ->logger ->warning ('error while discovering ocm provider ' , [
@@ -98,7 +125,61 @@ public function discover(string $remote, bool $skipCache = false): ICapabilityAw
98125 ]);
99126 throw new OCMProviderException ('error while requesting remote ocm provider ' );
100127 }
128+ }
101129
102- return $ this ->provider ;
130+ /**
131+ * @return ICapabilityAwareOCMProvider
132+ */
133+ public function getLocalOCMProvider (bool $ fullDetails = true ): ICapabilityAwareOCMProvider {
134+ if ($ this ->localProvider !== null ) {
135+ return $ this ->localProvider ;
136+ }
137+
138+ $ provider = new OCMProvider ('Nextcloud ' . $ this ->config ->getSystemValue ('version ' ));
139+ if (!$ this ->appConfig ->getValueBool ('core ' , ConfigLexicon::OCM_DISCOVERY_ENABLED )) {
140+ return $ provider ;
141+ }
142+
143+ $ url = $ this ->urlGenerator ->linkToRouteAbsolute ('cloud_federation_api.requesthandlercontroller.addShare ' );
144+ $ pos = strrpos ($ url , '/ ' );
145+ if ($ pos === false ) {
146+ $ this ->logger ->debug ('generated route should contain a slash character ' );
147+ return $ provider ;
148+ }
149+
150+ $ provider ->setEnabled (true );
151+ $ provider ->setApiVersion (self ::API_VERSION );
152+ $ provider ->setEndPoint (substr ($ url , 0 , $ pos ));
153+ $ provider ->setCapabilities (['/invite-accepted ' , '/notifications ' , '/shares ' ]);
154+
155+ $ resource = $ provider ->createNewResourceType ();
156+ $ resource ->setName ('file ' )
157+ ->setShareTypes (['user ' , 'group ' ])
158+ ->setProtocols (['webdav ' => '/public.php/webdav/ ' ]);
159+ $ provider ->addResourceType ($ resource );
160+
161+ if ($ fullDetails ) {
162+ // Adding a public key to the ocm discovery
163+ try {
164+ if (!$ this ->appConfig ->getValueBool ('core ' , OCMSignatoryManager::APPCONFIG_SIGN_DISABLED , lazy: true )) {
165+ /**
166+ * @experimental 31.0.0
167+ * @psalm-suppress UndefinedInterfaceMethod
168+ */
169+ $ provider ->setSignatory ($ this ->ocmSignatoryManager ->getLocalSignatory ());
170+ } else {
171+ $ this ->logger ->debug ('ocm public key feature disabled ' );
172+ }
173+ } catch (SignatoryException |IdentityNotFoundException $ e ) {
174+ $ this ->logger ->warning ('cannot generate local signatory ' , ['exception ' => $ e ]);
175+ }
176+ }
177+
178+ $ event = new ResourceTypeRegisterEvent ($ provider );
179+ $ this ->eventDispatcher ->dispatchTyped ($ event );
180+
181+ $ this ->localProvider = $ provider ;
182+ return $ provider ;
103183 }
184+
104185}
0 commit comments