2015-11-10 04:50:59 -05:00
< ? php
2024-05-28 10:42:42 -04:00
2015-11-10 04:50:59 -05:00
/**
2024-05-28 10:42:42 -04:00
* SPDX - FileCopyrightText : 2017 - 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX - FileCopyrightText : 2016 ownCloud , Inc .
* SPDX - License - Identifier : AGPL - 3.0 - only
2015-11-10 04:50:59 -05:00
*/
namespace OCA\Federation\BackgroundJob ;
2015-11-19 05:48:21 -05:00
use GuzzleHttp\Exception\ClientException ;
2017-12-11 09:07:08 -05:00
use GuzzleHttp\Exception\RequestException ;
2015-11-10 04:50:59 -05:00
use OCA\Federation\TrustedServers ;
use OCP\AppFramework\Http ;
2017-08-01 05:23:40 -04:00
use OCP\AppFramework\Utility\ITimeFactory ;
2015-11-10 04:50:59 -05:00
use OCP\BackgroundJob\IJobList ;
2020-11-24 08:18:47 -05:00
use OCP\BackgroundJob\Job ;
2015-11-10 04:50:59 -05:00
use OCP\Http\Client\IClient ;
2017-07-28 08:54:08 -04:00
use OCP\Http\Client\IClientService ;
2016-03-18 08:22:05 -04:00
use OCP\Http\Client\IResponse ;
2015-11-10 04:50:59 -05:00
use OCP\IURLGenerator ;
2017-02-24 09:33:09 -05:00
use OCP\OCS\IDiscoveryService ;
2022-06-24 09:24:16 -04:00
use Psr\Log\LoggerInterface ;
2015-11-10 04:50:59 -05:00
/**
* Class GetSharedSecret
*
2022-06-24 09:24:16 -04:00
* Request shared secret from remote Nextcloud
2015-11-10 04:50:59 -05:00
*
* @ package OCA\Federation\Backgroundjob
*/
2017-08-01 05:23:40 -04:00
class GetSharedSecret extends Job {
2022-06-24 09:24:16 -04:00
private IClient $httpClient ;
private IJobList $jobList ;
private IURLGenerator $urlGenerator ;
private TrustedServers $trustedServers ;
private IDiscoveryService $ocsDiscoveryService ;
private LoggerInterface $logger ;
protected bool $retainJob = false ;
private string $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret' ;
/** 30 day = 2592000sec */
private int $maxLifespan = 2592000 ;
2015-11-10 04:50:59 -05:00
public function __construct (
2017-07-28 08:54:08 -04:00
IClientService $httpClientService ,
IURLGenerator $urlGenerator ,
IJobList $jobList ,
TrustedServers $trustedServers ,
2022-06-24 09:24:16 -04:00
LoggerInterface $logger ,
2017-08-01 05:23:40 -04:00
IDiscoveryService $ocsDiscoveryService ,
ITimeFactory $timeFactory
2015-11-10 04:50:59 -05:00
) {
2020-12-14 10:35:12 -05:00
parent :: __construct ( $timeFactory );
2017-07-28 08:54:08 -04:00
$this -> logger = $logger ;
$this -> httpClient = $httpClientService -> newClient ();
$this -> jobList = $jobList ;
$this -> urlGenerator = $urlGenerator ;
$this -> ocsDiscoveryService = $ocsDiscoveryService ;
$this -> trustedServers = $trustedServers ;
2015-11-10 04:50:59 -05:00
}
/**
2022-06-28 06:55:26 -04:00
* Run the job , then remove it from the joblist
2015-11-10 04:50:59 -05:00
*/
2022-06-28 06:55:26 -04:00
public function start ( IJobList $jobList ) : void {
2015-11-10 04:50:59 -05:00
$target = $this -> argument [ 'url' ];
// only execute if target is still in the list of trusted domains
if ( $this -> trustedServers -> isTrustedServer ( $target )) {
2022-06-28 06:55:26 -04:00
$this -> parentStart ( $jobList );
2015-11-10 04:50:59 -05:00
}
2016-03-18 08:22:05 -04:00
2017-07-28 08:43:35 -04:00
$jobList -> remove ( $this , $this -> argument );
if ( $this -> retainJob ) {
2017-08-01 05:23:40 -04:00
$this -> reAddJob ( $this -> argument );
2016-03-18 08:22:05 -04:00
}
2015-11-10 04:50:59 -05:00
}
2022-06-28 06:55:26 -04:00
protected function parentStart ( IJobList $jobList ) : void {
parent :: start ( $jobList );
2015-11-19 11:49:43 -05:00
}
2015-11-10 04:50:59 -05:00
protected function run ( $argument ) {
$target = $argument [ 'url' ];
2020-12-14 10:35:12 -05:00
$created = isset ( $argument [ 'created' ]) ? ( int ) $argument [ 'created' ] : $this -> time -> getTime ();
$currentTime = $this -> time -> getTime ();
2015-11-10 04:50:59 -05:00
$source = $this -> urlGenerator -> getAbsoluteURL ( '/' );
$source = rtrim ( $source , '/' );
$token = $argument [ 'token' ];
2017-07-28 08:43:35 -04:00
// kill job after 30 days of trying
$deadline = $currentTime - $this -> maxLifespan ;
if ( $created < $deadline ) {
2024-08-22 04:22:30 -04:00
$this -> logger -> warning ( " The job to get the shared secret job is too old and gets stopped now without retention. Setting server status of ' { $target } ' to failure. " );
2017-07-28 08:43:35 -04:00
$this -> retainJob = false ;
2023-11-23 04:22:34 -05:00
$this -> trustedServers -> setServerStatus ( $target , TrustedServers :: STATUS_FAILURE );
2017-07-28 08:43:35 -04:00
return ;
}
2017-02-24 09:33:09 -05:00
$endPoints = $this -> ocsDiscoveryService -> discover ( $target , 'FEDERATED_SHARING' );
2023-07-07 06:20:21 -04:00
$endPoint = $endPoints [ 'shared-secret' ] ? ? $this -> defaultEndPoint ;
2017-02-24 09:33:09 -05:00
2017-08-01 05:23:40 -04:00
// make sure that we have a well formatted url
2018-04-20 09:53:10 -04:00
$url = rtrim ( $target , '/' ) . '/' . trim ( $endPoint , '/' );
2017-02-24 09:33:09 -05:00
2016-03-18 08:22:05 -04:00
$result = null ;
2015-11-19 05:48:21 -05:00
try {
$result = $this -> httpClient -> get (
2017-02-24 09:33:09 -05:00
$url ,
2015-11-19 05:48:21 -05:00
[
'query' =>
[
'url' => $source ,
2018-04-20 09:53:10 -04:00
'token' => $token ,
'format' => 'json' ,
2015-11-19 05:48:21 -05:00
],
'timeout' => 3 ,
'connect_timeout' => 3 ,
]
);
$status = $result -> getStatusCode ();
} catch ( ClientException $e ) {
$status = $e -> getCode ();
2016-02-15 11:33:06 -05:00
if ( $status === Http :: STATUS_FORBIDDEN ) {
$this -> logger -> info ( $target . ' refused to exchange a shared secret with you.' , [ 'app' => 'federation' ]);
} else {
2017-04-21 05:29:01 -04:00
$this -> logger -> info ( $target . ' responded with a ' . $status . ' containing: ' . $e -> getMessage (), [ 'app' => 'federation' ]);
2016-02-15 11:33:06 -05:00
}
2017-12-11 09:07:08 -05:00
} catch ( RequestException $e ) {
$status = - 1 ; // There is no status code if we could not connect
2022-06-24 09:24:16 -04:00
$this -> logger -> info ( 'Could not connect to ' . $target , [
'exception' => $e ,
2018-01-17 09:21:56 -05:00
]);
2020-12-22 10:29:38 -05:00
} catch ( \Throwable $e ) {
2016-03-18 08:22:05 -04:00
$status = Http :: STATUS_INTERNAL_SERVER_ERROR ;
2022-06-24 09:24:16 -04:00
$this -> logger -> error ( $e -> getMessage (), [
'exception' => $e ,
]);
2015-11-19 05:48:21 -05:00
}
2015-11-10 04:50:59 -05:00
// if we received a unexpected response we try again later
if (
$status !== Http :: STATUS_OK
&& $status !== Http :: STATUS_FORBIDDEN
) {
2016-03-18 08:22:05 -04:00
$this -> retainJob = true ;
2015-11-19 05:48:21 -05:00
}
2016-03-18 08:22:05 -04:00
if ( $status === Http :: STATUS_OK && $result instanceof IResponse ) {
2015-11-10 04:50:59 -05:00
$body = $result -> getBody ();
$result = json_decode ( $body , true );
if ( isset ( $result [ 'ocs' ][ 'data' ][ 'sharedSecret' ])) {
$this -> trustedServers -> addSharedSecret (
2023-11-23 04:22:34 -05:00
$target ,
$result [ 'ocs' ][ 'data' ][ 'sharedSecret' ]
2015-11-10 04:50:59 -05:00
);
} else {
$this -> logger -> error (
2022-06-28 06:55:26 -04:00
'remote server "' . $target . '"" does not return a valid shared secret. Received data: ' . $body ,
[ 'app' => 'federation' ]
2015-11-10 04:50:59 -05:00
);
$this -> trustedServers -> setServerStatus ( $target , TrustedServers :: STATUS_FAILURE );
}
}
}
2017-07-28 08:43:35 -04:00
/**
2022-06-28 06:55:26 -04:00
* Re - add background job
2017-07-28 08:43:35 -04:00
*
* @ param array $argument
*/
2022-06-24 09:24:16 -04:00
protected function reAddJob ( array $argument ) : void {
2017-07-28 08:43:35 -04:00
$url = $argument [ 'url' ];
2022-06-28 06:55:26 -04:00
$created = $argument [ 'created' ] ? ? $this -> time -> getTime ();
2017-07-28 08:43:35 -04:00
$token = $argument [ 'token' ];
$this -> jobList -> add (
GetSharedSecret :: class ,
[
'url' => $url ,
'token' => $token ,
'created' => $created
]
);
}
2015-11-10 04:50:59 -05:00
}