Skip to content

Instantly share code, notes, and snippets.

@ManukMinasyan
Last active January 30, 2025 16:11
Show Gist options
  • Select an option

  • Save ManukMinasyan/962eece79d07cc7987b29b19f41b49f9 to your computer and use it in GitHub Desktop.

Select an option

Save ManukMinasyan/962eece79d07cc7987b29b19f41b49f9 to your computer and use it in GitHub Desktop.
Composer Satis Authentication with Laravel
<?php
namespace App\Providers;
use App\Actions\LicenseActivate;
use App\Contracts\LicenseActivates;
use App\Models\License;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public array $singletons = [
LicenseActivates::class => LicenseActivate::class,
];
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Model::unguard();
Auth::viaRequest('license-key', function (Request $request) {
$license = License::query()
->where('key', $request->getPassword())
->first();
if (! $license) {
abort(401, 'License key invalid');
}
if ($license->isExpired()) {
abort(401, 'This license is expired');
}
return $license;
});
}
}
<?php
namespace App\Http\Controllers;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class SatisAuthenticationController extends Controller
{
public function __invoke(License $license, Request $request)
{
/*
* Find the package that is being requested.
*/
$package = $this->getRequestedPackage($request);
/*
* Composer can only store one authentication method per repository.
* This means the user is probably going to try to authenticate with a license
* key for the wrong package. We have to check the user's other licenses
* as well.
*/
$license = License::query()
->where('key', $request->getPassword())
->whereHas('product', function (Builder $query) use ($package) {
$query->where('composer_package', $package);
});
abort_unless($license->exists(), 401);
// Increase the download count for the package
StatsWriter::for(
subject: PackageStatsEvent::class,
attributes: [
'product_id' => $license->first()->product_id,
'ip' => $request->ip(),
]
)
->increase();
ActivateLicenseKeyJob::dispatchAfterResponse(
$license->first(),
$this->getRequestedDomain($request)
);
return response('valid');
}
protected function getRequestedPackage(Request $request): string
{
$originalUrl = $request->header('X-Original-URI', '');
preg_match('#^/dist/(?<package>relaticle/[^/]*)/#', $originalUrl, $matches);
if (!key_exists('package', $matches)) {
abort(401, 'Missing X-Original-URI header');
}
return $matches['package'];
}
protected function getRequestedDomain(Request $request): string
{
$password = $request->getPassword();
$parts = explode(':', $password);
if (count($parts) !== 2) {
abort(402, 'Invalid password format');
}
return $parts[1];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment