2022-02-20 20:22:07 +00:00
< ? php
namespace Friendica\Addon\s3_storage\src ;
defined ( 'AKEEBAENGINE' ) or define ( 'AKEEBAENGINE' , 1 );
2024-11-27 23:18:20 +00:00
use Akeeba\S3\Configuration ;
use Akeeba\S3\Connector ;
2022-02-20 20:22:07 +00:00
use Friendica\Core\Config\Capability\IManageConfigValues ;
use Friendica\Core\L10n ;
use Friendica\Core\Storage\Capability\ICanConfigureStorage ;
use ParagonIE\HiddenString\HiddenString ;
/**
* The WebDav Backend Storage configuration class
*/
class S3Config implements ICanConfigureStorage
{
const NAME = 'S3Config' ;
const DEFAULT_REGION = 'us-east-1' ;
const DEFAULT_ENDPOINT = 's3.amazonaws.com' ;
const DEFAULT_SIGMETHOD = 'v2' ;
const DEFAULT_BUCKET = 'friendica' ;
/** @var L10n */
private $l10n ;
/** @var IManageConfigValues */
private $config ;
/** @var string */
private $endpoint ;
/** @var HiddenString */
private $accessKey ;
/** @var HiddenString */
private $secretKey ;
/** @var string */
private $signatureMethod ;
/** @var ?string */
private $bucket ;
/** @var ?string */
private $region ;
/** @var bool */
private $legacy ;
/** @var bool */
private $dualStack ;
public function __construct ( L10n $l10n , IManageConfigValues $config )
{
$this -> l10n = $l10n ;
$this -> config = $config ;
$this -> accessKey = new HiddenString ( $this -> config -> get ( 's3' , 'access_key' , '' ));
$this -> secretKey = new HiddenString ( $this -> config -> get ( 's3' , 'secret_key' , '' ));
$this -> signatureMethod = $this -> config -> get ( 's3' , 'signature_method' , self :: DEFAULT_SIGMETHOD );
$this -> bucket = $this -> config -> get ( 's3' , 'bucket' , self :: DEFAULT_BUCKET );
$this -> legacy = ! empty ( $this -> config -> get ( 's3' , 'legacy' ));
$this -> dualStack = ! empty ( $this -> config -> get ( 's3' , 'dual_stack' ));
$this -> region = $this -> config -> get ( 's3' , 'region' );
$this -> endpoint = $this -> config -> get ( 's3' , 'endpoint' );
}
/**
* Returns the whole configuration as a Akeeba compatible configuration instance
*
* @ return Configuration
*/
public function getConfig () : Configuration
{
$config = new Configuration ( $this -> accessKey , $this -> secretKey );
$config -> setUseLegacyPathStyle ( $this -> legacy ? ? false );
$config -> setUseDualstackUrl ( $this -> dualStack ? ? false );
if ( ! empty ( $this -> region )) {
$config -> setRegion ( $this -> region );
}
if ( ! empty ( $this -> endpoint )) {
$config -> setEndpoint ( $this -> endpoint );
}
if ( ! empty ( $this -> signatureMethod ) && empty ( $this -> endpoint )) {
$config -> setSignatureMethod ( $this -> signatureMethod );
}
return $config ;
}
public function getBucket () : string
{
return $this -> bucket ;
}
/**
* @ inheritDoc
*/
public function getOptions () : array
{
$sigMethods = [
'v2' => 'v2' ,
'v4' => 'v4' ,
];
return [
'access_key' => [
'password' ,
$this -> l10n -> t ( 'Access Key' ),
$this -> accessKey ,
$this -> l10n -> t ( 'Set the Access Key of the S3 storage' ),
true ,
],
'secret_key' => [
'password' ,
$this -> l10n -> t ( 'Secret Key' ),
$this -> secretKey ,
$this -> l10n -> t ( 'Set the Secret Key of the S3 storage' ),
true ,
],
'bucket' => [
'input' ,
$this -> l10n -> t ( 'Bucket' ),
$this -> bucket ,
$this -> l10n -> t ( 'The S3 Bucket (name), you want to use with Friendica' ),
true ,
],
'signature_method' => [
'select' ,
$this -> l10n -> t ( 'Signature Method' ),
$this -> signatureMethod ,
$this -> l10n -> t ( 'Set the signature method to use (BEWARE: v4 will be automatically set to v2 in case the endpoint isn\'t amazon)' ),
$sigMethods ,
],
'endpoint' => [
'input' ,
$this -> l10n -> t ( " Amazon S3 compatible endpoint (leave empty for '%s') " , self :: DEFAULT_ENDPOINT ),
$this -> endpoint ,
$this -> l10n -> t ( 'Set the S3 endpoint. Do NOT use a protocol (You can use a custom endpoint with v2 signatures to access third party services which offer S3 compatibility, e.g. OwnCloud, Google Storage etc.)' ),
],
'region' => [
'input' ,
$this -> l10n -> t ( " AWS region (leave empty for '%s') " , self :: DEFAULT_REGION ),
$this -> region ,
$this -> l10n -> t ( 'The AWS region is mandatory for v4 signatures' ),
],
'dualstack_url' => [
'checkbox' ,
$this -> l10n -> t ( 'Use the dualstack URL (which will ship traffic over ipv6 in most cases)' ),
$this -> dualStack ,
$this -> l10n -> t ( 'For more information on these endpoints please read https://docs.aws.amazon.com/AmazonS3/latest/dev/dual-stack-endpoints.html' ),
],
'legacy' => [
'checkbox' ,
$this -> l10n -> t ( 'Use legacy, path-style access to the bucket' ),
$this -> legacy ,
$this -> l10n -> t ( 'When it\'s turned off (default) we use virtual hosting stylepaths which are RECOMMENDED BY AMAZON per http://docs.aws.amazon.com/AmazonS3/latest/API/APIRest.html' ),
],
];
}
/**
* @ inheritDoc
*/
public function saveOptions ( array $data ) : array
{
$feedback = [];
if ( empty ( $data [ 'access_key' ]) || empty ( $data [ 'secret_key' ]) || empty ( $data [ 'bucket' ])) {
return [
'access_key' => $this -> l10n -> t ( 'Invalid input' )
];
}
$s3Config = new Configuration (
$data [ 'access_key' ],
$data [ 'secret_key' ]
);
$bucket = $data [ 'bucket' ];
if ( ! empty ( $data [ 'endpoint' ])) {
try {
$s3Config -> setEndpoint ( $data [ 'endpoint' ]);
} catch ( \Exception $exception ) {
$feedback [ 'endpoint' ] = $exception -> getMessage ();
}
}
if ( ! empty ( $data [ 'region' ])) {
try {
$s3Config -> setRegion ( $data [ 'region' ]);
} catch ( \Exception $exception ) {
$feedback [ 'region' ] = $exception -> getMessage ();
}
}
try {
2022-02-24 22:10:35 +00:00
$s3Config -> setUseLegacyPathStyle (( bool ) $data [ 'legacy' ] ? ? false );
2022-02-20 20:22:07 +00:00
} catch ( \Exception $exception ) {
$feedback [ 'legacy' ] = $exception -> getMessage ();
}
try {
2022-02-24 22:10:35 +00:00
$s3Config -> setUseDualstackUrl (( bool ) $data [ 'dualstack_url' ] ? ? false );
2022-02-20 20:22:07 +00:00
} catch ( \Exception $exception ) {
$feedback [ 'dualstack_url' ] = $exception -> getMessage ();
}
try {
$s3Config -> setSignatureMethod ( $data [ 'signature_method' ] ? ? self :: DEFAULT_SIGMETHOD );
} catch ( \Exception $exception ) {
$feedback [ 'signature_method' ] = $this -> l10n -> t ( " error '%s', message '%s' " , $exception -> getCode (), $exception -> getMessage ());
}
try {
$connector = new Connector ( $s3Config );
$buckets = $connector -> listBuckets ();
if ( ! in_array ( $bucket , $buckets )) {
return [
'bucket' => $this -> l10n -> t ( 'Bucket %s cannot be not found, possible buckets: %s' , $bucket , implode ( ', ' , $buckets ))
];
}
$connector -> getBucket ( $bucket );
} catch ( \Exception $exception ) {
return [
'bucket' => $exception -> getMessage ()
];
}
$this -> config -> set ( 's3' , 'access_key' , ( $this -> accessKey = new HiddenString ( $data [ 'access_key' ])) -> getString ());
$this -> config -> set ( 's3' , 'secret_key' , ( $this -> secretKey = new HiddenString ( $data [ 'secret_key' ])) -> getString ());
$this -> config -> set ( 's3' , 'bucket' , ( $this -> bucket = $bucket ));
2022-02-24 22:10:35 +00:00
if ( $s3Config -> getUseLegacyPathStyle ()) {
$this -> config -> set ( 's3' , 'legacy' , '1' );
} else {
$this -> config -> delete ( 's3' , 'legacy' );
}
if ( $s3Config -> getDualstackUrl ()) {
$this -> config -> set ( 's3' , 'dual_stack' , '1' );
} else {
$this -> config -> delete ( 's3' , 'dual_stack' );
}
2022-02-20 20:22:07 +00:00
$this -> config -> set ( 's3' , 'signature_method' , $s3Config -> getSignatureMethod ());
if ( ! empty ( $data [ 'endpoint' ])) {
$this -> config -> set ( 's3' , 'endpoint' , $s3Config -> getEndpoint ());
} else {
$this -> config -> delete ( 's3' , 'endpoint' );
}
if ( ! empty ( $data [ 'region' ])) {
$this -> config -> set ( 's3' , 'region' , $s3Config -> getRegion ());
} else {
$this -> config -> delete ( 's3' , 'region' );
}
return $feedback ;
}
}