88 lines
3.6 KiB
PHP
88 lines
3.6 KiB
PHP
<?php
|
|
|
|
use App\Models\GithubApp;
|
|
use App\Models\GitlabApp;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Str;
|
|
use Lcobucci\JWT\Encoding\ChainedFormatter;
|
|
use Lcobucci\JWT\Encoding\JoseEncoder;
|
|
use Lcobucci\JWT\Signer\Key\InMemory;
|
|
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
|
use Lcobucci\JWT\Token\Builder;
|
|
|
|
function generate_github_installation_token(GithubApp $source)
|
|
{
|
|
$signingKey = InMemory::plainText($source->privateKey->private_key);
|
|
$algorithm = new Sha256();
|
|
$tokenBuilder = (new Builder(new JoseEncoder(), ChainedFormatter::default()));
|
|
$now = new DateTimeImmutable();
|
|
$now = $now->setTime($now->format('H'), $now->format('i'));
|
|
$issuedToken = $tokenBuilder
|
|
->issuedBy($source->app_id)
|
|
->issuedAt($now)
|
|
->expiresAt($now->modify('+10 minutes'))
|
|
->getToken($algorithm, $signingKey)
|
|
->toString();
|
|
$token = Http::withHeaders([
|
|
'Authorization' => "Bearer $issuedToken",
|
|
'Accept' => 'application/vnd.github.machine-man-preview+json'
|
|
])->post("{$source->api_url}/app/installations/{$source->installation_id}/access_tokens");
|
|
if ($token->failed()) {
|
|
throw new \Exception("Failed to get access token for " . $source->name . " with error: " . $token->json()['message']);
|
|
}
|
|
return $token->json()['token'];
|
|
}
|
|
|
|
function generate_github_jwt_token(GithubApp $source)
|
|
{
|
|
$signingKey = InMemory::plainText($source->privateKey->private_key);
|
|
$algorithm = new Sha256();
|
|
$tokenBuilder = (new Builder(new JoseEncoder(), ChainedFormatter::default()));
|
|
$now = new DateTimeImmutable();
|
|
$now = $now->setTime($now->format('H'), $now->format('i'));
|
|
$issuedToken = $tokenBuilder
|
|
->issuedBy($source->app_id)
|
|
->issuedAt($now->modify('-1 minute'))
|
|
->expiresAt($now->modify('+10 minutes'))
|
|
->getToken($algorithm, $signingKey)
|
|
->toString();
|
|
return $issuedToken;
|
|
}
|
|
|
|
function githubApi(GithubApp|GitlabApp|null $source, string $endpoint, string $method = 'get', array|null $data = null, bool $throwError = true)
|
|
{
|
|
if (is_null($source)) {
|
|
throw new \Exception('Not implemented yet.');
|
|
}
|
|
if ($source->getMorphClass() == 'App\Models\GithubApp') {
|
|
if ($source->is_public) {
|
|
$response = Http::github($source->api_url)->$method($endpoint);
|
|
} else {
|
|
$github_access_token = generate_github_installation_token($source);
|
|
if ($data && ($method === 'post' || $method === 'patch' || $method === 'put')) {
|
|
$response = Http::github($source->api_url, $github_access_token)->$method($endpoint, $data);
|
|
} else {
|
|
$response = Http::github($source->api_url, $github_access_token)->$method($endpoint);
|
|
}
|
|
}
|
|
}
|
|
$json = $response->json();
|
|
if ($response->failed() && $throwError) {
|
|
throw new \Exception("Failed to get data from {$source->name} with error:<br><br>" . $json['message'] . "<br><br>Rate Limit resets at: " . Carbon::parse((int)$response->header('X-RateLimit-Reset'))->format('Y-m-d H:i:s') . 'UTC');
|
|
}
|
|
return [
|
|
'rate_limit_remaining' => $response->header('X-RateLimit-Remaining'),
|
|
'rate_limit_reset' => $response->header('X-RateLimit-Reset'),
|
|
'data' => collect($json)
|
|
];
|
|
}
|
|
|
|
function get_installation_path(GithubApp $source)
|
|
{
|
|
$github = GithubApp::where('uuid', $source->uuid)->first();
|
|
$name = Str::of(Str::kebab($github->name));
|
|
$installation_path = $github->html_url === 'https://github.com' ? 'apps' : 'github-apps';
|
|
return "$github->html_url/$installation_path/$name/installations/new";
|
|
}
|