-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FEATURE support Temporary URLs #50
Comments
I agree - my case would be profile pictures. They should be available within my web application for the specific user, but not totally public. |
I needed quick support for this in my Laravel application and resolved it by extending the Adapter and using the code sample from Bunny (https://github.com/BunnyWay/BunnyCDN.TokenAuthentication/blob/master/php/url_signing.php) In 'bunnycdn' => [
'driver' => 'bunnycdn',
'storage_zone' => env('BUNNYCDN_STORAGE_ZONE'),
'api_key' => env('BUNNYCDN_API_KEY'),
'region' => env('BUNNYCDN_REGION'),
'pullzone_url' => env('BUNNYCDN_PULLZONE_URL'),
'security_key' => env('BUNNYCDN_SECURITY_KEY'),
], In public function boot(): void
{
$this->addBunnyStorageAdapter();
}
public function addBunnyStorageAdapter(): void
{
Storage::extend('bunnycdn', function (Application $app, array $config) {
$adapter = new BunnyCdnWithTemporaryUrlAdapter(
new BunnyCDNClient(
$config['storage_zone'],
$config['api_key'],
$config['region']
),
$config['pullzone_url']
);
return new FilesystemAdapter(
new Filesystem($adapter, $config),
$adapter,
$config
);
});
} <?php
namespace App\Support\Flysystem;
use DateTimeInterface;
use League\Flysystem\ChecksumProvider;
use League\Flysystem\FilesystemAdapter;
use League\Flysystem\UnableToGenerateTemporaryUrl;
use League\Flysystem\UrlGeneration\PublicUrlGenerator;
use League\Flysystem\UrlGeneration\TemporaryUrlGenerator;
use PlatformCommunity\Flysystem\BunnyCDN\BunnyCDNAdapter;
use Throwable;
class BunnyCdnWithTemporaryUrlAdapter extends BunnyCDNAdapter implements FilesystemAdapter, PublicUrlGenerator, ChecksumProvider, TemporaryUrlGenerator
{
// Laravel checks if this method exists to determine if temporary URLs can be generated
public function getTemporaryUrl(string $path, DateTimeInterface $expiresAt, $config): string
{
return $this->temporaryUrl($path, $expiresAt, $config);
}
public function temporaryUrl(string $path, DateTimeInterface $expiresAt, $config): string
{
if (config('filesystems.disks.bunnycdn.pullzone_url') === '') {
throw UnableToGenerateTemporaryUrl::dueToError($path, 'In order to get a temporary URL for a BunnyCDN object, you must pass the "pullzone_url" parameter to the BunnyCDNAdapter.');
}
if (config('filesystems.disks.bunnycdn.security_key') === '') {
throw UnableToGenerateTemporaryUrl::dueToError($path, 'In order to get a temporary URL for a BunnyCDN object, you must pass the "security_key" parameter (Url Token Authentication Key) to the BunnyCDNAdapter.');
}
try {
$unsignedUrl = rtrim(config('filesystems.disks.bunnycdn.pullzone_url'), '/') . '/' . ltrim($path, '/');
return $this->sign_bcdn_url($unsignedUrl, config('filesystems.disks.bunnycdn.security_key'), $expiresAt->getTimestamp() - time());
} catch (Throwable $exception) {
throw UnableToGenerateTemporaryUrl::dueToError($path, $exception);
}
}
// BunnyCDN php sample code
// see https://github.com/BunnyWay/BunnyCDN.TokenAuthentication/blob/master/php/url_signing.php
function sign_bcdn_url($url, $securityKey, $expiration_time = 3600, $user_ip = NULL, $is_directory_token = false, $path_allowed = NULL, $countries_allowed = NULL, $countries_blocked = NULL, $referers_allowed = NULL): string
{
if (!is_null($countries_allowed)) {
$url .= (parse_url($url, PHP_URL_QUERY) == "") ? "?" : "&";
$url .= "token_countries={$countries_allowed}";
}
if (!is_null($countries_blocked)) {
$url .= (parse_url($url, PHP_URL_QUERY) == "") ? "?" : "&";
$url .= "token_countries_blocked={$countries_blocked}";
}
if (!is_null($referers_allowed)) {
$url .= (parse_url($url, PHP_URL_QUERY) == "") ? "?" : "&";
$url .= "token_referer={$referers_allowed}";
}
$url_scheme = parse_url($url, PHP_URL_SCHEME);
$url_host = parse_url($url, PHP_URL_HOST);
$url_path = parse_url($url, PHP_URL_PATH);
$url_query = parse_url($url, PHP_URL_QUERY);
$parameters = array();
parse_str($url_query, $parameters);
// Check if the path is specified and ovewrite the default
$signature_path = $url_path;
if (!is_null($path_allowed)) {
$signature_path = $path_allowed;
$parameters["token_path"] = $signature_path;
}
// Expiration time
$expires = time() + $expiration_time;
// Construct the parameter data
ksort($parameters); // Sort alphabetically, very important
$parameter_data = "";
$parameter_data_url = "";
if (sizeof($parameters) > 0) {
foreach ($parameters as $key => $value) {
if (strlen($parameter_data) > 0)
$parameter_data .= "&";
$parameter_data_url .= "&";
$parameter_data .= "{$key}=" . $value;
$parameter_data_url .= "{$key}=" . urlencode($value); // URL encode everything but slashes for the URL data
}
}
// Generate the toke
$hashableBase = $securityKey . $signature_path . $expires;
// If using IP validation
if (!is_null($user_ip)) {
$hashableBase .= $user_ip;
}
$hashableBase .= $parameter_data;
// Generate the token
$token = hash('sha256', $hashableBase, true);
$token = base64_encode($token);
$token = strtr($token, '+/', '-_');
$token = str_replace('=', '', $token);
if ($is_directory_token) {
return "{$url_scheme}://{$url_host}/bcdn_token={$token}&expires={$expires}{$parameter_data_url}{$url_path}";
} else {
return "{$url_scheme}://{$url_host}{$url_path}?token={$token}{$parameter_data_url}&expires={$expires}";
}
}
} In
Security Key can be acquired from the Bunny Dashboard located at Usage$url = Storage::disk('bunnycdn')->temporaryUrl('test.txt', now()->addSeconds(10));
$this->info("test.txt temporary URL valid for 10 seconds: {$url}"); I still would like to see this officially supported, if there is a chance to get a PR reviewed and merged quickly. |
Temporary URLs could be supported by BunnyCDN-Token-Authentications
I have no need for it currently, nor do I see a real case that makes it necessary at the moment. But I think, when flysystem has this feature, there could be really cool needs. :-) Having a look, I thought it could be a feature to implement.
The text was updated successfully, but these errors were encountered: