94 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			94 lines
		
	
	
		
			3.8 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 RuntimeException("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) {
 | 
						|
        ray($json);
 | 
						|
        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";
 | 
						|
}
 | 
						|
function get_permissions_path(GithubApp $source) {
 | 
						|
    $github = GithubApp::where('uuid', $source->uuid)->first();
 | 
						|
    $name = Str::of(Str::kebab($github->name));
 | 
						|
    return "$github->html_url/settings/apps/$name/permissions";
 | 
						|
}
 |