2015-11-10 04:50:59 -05:00
< ? php
2023-06-26 11:20:08 -04:00
declare ( strict_types = 1 );
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 ;
2015-11-10 04:50:59 -05:00
use OCP\IURLGenerator ;
2017-02-24 09:33:09 -05:00
use OCP\OCS\IDiscoveryService ;
2023-06-26 11:20:08 -04:00
use Psr\Log\LoggerInterface ;
2015-11-10 04:50:59 -05:00
/**
* Class RequestSharedSecret
*
2017-04-12 00:16:27 -04:00
* Ask remote Nextcloud to request a sharedSecret from this server
2015-11-10 04:50:59 -05:00
*
* @ package OCA\Federation\Backgroundjob
*/
2016-03-18 08:22:05 -04:00
class RequestSharedSecret extends Job {
2023-06-26 11:20:08 -04:00
private IClient $httpClient ;
2015-11-10 04:50:59 -05:00
2023-06-26 11:20:08 -04:00
protected bool $retainJob = false ;
2015-12-21 09:48:02 -05:00
2023-06-26 11:20:08 -04:00
private string $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/request-shared-secret' ;
2016-03-18 08:22:05 -04:00
2023-06-26 11:20:08 -04:00
/** @var int 30 day = 2592000sec */
private int $maxLifespan = 2592000 ;
2017-02-24 09:33:09 -05:00
2015-11-10 04:50:59 -05:00
public function __construct (
2017-07-28 08:54:08 -04:00
IClientService $httpClientService ,
2023-06-26 11:20:08 -04:00
private IURLGenerator $urlGenerator ,
private IJobList $jobList ,
private TrustedServers $trustedServers ,
private IDiscoveryService $ocsDiscoveryService ,
private LoggerInterface $logger ,
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 -> httpClient = $httpClientService -> newClient ();
2015-11-10 04:50:59 -05:00
}
/**
* run the job , then remove it from the joblist
*/
2023-06-26 11:20:08 -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 )) {
2023-06-26 11:20:08 -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:50:40 -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
}
2015-11-19 11:49:43 -05:00
/**
2023-06-26 11:20:08 -04:00
* Call start () method of parent
* Useful for unit tests
2015-11-19 11:49:43 -05:00
*/
2023-06-26 11:20:08 -04:00
protected function parentStart ( IJobList $jobList ) : void {
parent :: start ( $jobList );
2015-11-19 11:49:43 -05:00
}
2023-06-26 11:20:08 -04:00
/**
* @ param array $argument
* @ return void
*/
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:50:40 -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 request the shared secret job is too old and gets stopped now without retention. Setting server status of ' { $target } ' to failure. " );
2017-07-28 08:50:40 -04:00
$this -> retainJob = false ;
$this -> trustedServers -> setServerStatus ( $target , TrustedServers :: STATUS_FAILURE );
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
2022-07-28 07:11:38 -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
2015-11-19 05:48:21 -05:00
try {
$result = $this -> httpClient -> post (
2017-02-24 09:33:09 -05:00
$url ,
2015-11-19 05:48:21 -05:00
[
'body' => [
'url' => $source ,
'token' => $token ,
2018-04-20 09:53:10 -04:00
'format' => 'json' ,
2015-11-19 05:48:21 -05:00
],
'timeout' => 3 ,
'connect_timeout' => 3 ,
]
);
2015-11-10 04:50:59 -05:00
2015-11-19 05:48:21 -05:00
$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 ask for a shared secret.' , [ '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
$this -> logger -> info ( 'Could not connect to ' . $target , [ 'app' => 'federation' ]);
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 ;
2023-06-26 11:20:08 -04:00
$this -> logger -> error ( $e -> getMessage (), [ 'app' => 'federation' , '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
2024-04-10 15:45:33 -04:00
&& ( $status !== Http :: STATUS_FORBIDDEN || $this -> getAttempt ( $argument ) < 5 )
2015-11-10 04:50:59 -05:00
) {
2016-03-18 08:22:05 -04:00
$this -> retainJob = true ;
2015-11-10 04:50:59 -05:00
}
}
2017-07-28 08:50:40 -04:00
/**
* re - add background job
*/
2023-06-26 11:20:08 -04:00
protected function reAddJob ( array $argument ) : void {
2017-07-28 08:50:40 -04:00
$url = $argument [ 'url' ];
2020-12-14 10:35:12 -05:00
$created = isset ( $argument [ 'created' ]) ? ( int ) $argument [ 'created' ] : $this -> time -> getTime ();
2017-07-28 08:50:40 -04:00
$token = $argument [ 'token' ];
2024-04-10 15:45:33 -04:00
$attempt = $this -> getAttempt ( $argument ) + 1 ;
2017-07-28 08:50:40 -04:00
2017-08-01 05:23:40 -04:00
$this -> jobList -> add (
2017-07-28 08:50:40 -04:00
RequestSharedSecret :: class ,
[
'url' => $url ,
'token' => $token ,
2024-04-10 15:45:33 -04:00
'created' => $created ,
'attempt' => $attempt
2017-07-28 08:50:40 -04:00
]
);
}
2024-04-10 15:45:33 -04:00
protected function getAttempt ( array $argument ) : int {
return $argument [ 'attempt' ] ? ? 0 ;
}
2015-11-10 04:50:59 -05:00
}