From a3b811ec9a3f9ecd41eeb3607e89d3508371d158 Mon Sep 17 00:00:00 2001 From: "stephan.kasdorf" Date: Tue, 18 Jun 2024 16:58:02 +0200 Subject: [PATCH] implemented the GitHub calls for the repository --- .env | 8 +- .env-local | 8 +- docker-compose.yml | 14 +- gpt-schema.yml | 57 +++- nibiru-auth-api/src/AuthController.php | 80 ++++++ nibiru-auth-api/src/ValidateToken.php | 1 + nibiru-auth-api/src/composer.json | 27 ++ nibiru-auth-api/src/index.php | 9 + nibiru-webhook-receiver/src/GitHubClient.php | 1 + .../src/WebhookController.php | 261 ++++++++++++++++++ .../src/WebhookReceiver.php | 62 +++++ nibiru-webhook-receiver/src/composer.json | 27 ++ nibiru-webhook-receiver/src/index.php | 6 + src/AuthController.php | 23 -- src/GitHubClient.php | 39 --- src/ValidateToken.php | 9 - src/WebhookController.php | 34 --- src/composer.json | 29 -- src/index.php | 2 - src/webhookReceiver.php | 21 -- 20 files changed, 552 insertions(+), 166 deletions(-) create mode 100644 nibiru-auth-api/src/AuthController.php create mode 100644 nibiru-auth-api/src/ValidateToken.php create mode 100644 nibiru-auth-api/src/composer.json create mode 100644 nibiru-auth-api/src/index.php create mode 100644 nibiru-webhook-receiver/src/GitHubClient.php create mode 100644 nibiru-webhook-receiver/src/WebhookController.php create mode 100644 nibiru-webhook-receiver/src/WebhookReceiver.php create mode 100644 nibiru-webhook-receiver/src/composer.json create mode 100644 nibiru-webhook-receiver/src/index.php delete mode 100644 src/AuthController.php delete mode 100755 src/GitHubClient.php delete mode 100644 src/ValidateToken.php delete mode 100644 src/WebhookController.php delete mode 100755 src/composer.json delete mode 100755 src/index.php delete mode 100755 src/webhookReceiver.php diff --git a/.env b/.env index 2f7af5f..742579d 100644 --- a/.env +++ b/.env @@ -13,4 +13,10 @@ NIBIRU_AUTH_VIRTUAL_HOST=api.agent.auth.nibiru-framework.com NIBIRU_AUTH_LETSENCRYPT_HOST=api.agent.auth.nibiru-framework.com PROXY_NETWORK=nginx-proxy -GITHUB_TOKEN=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 \ No newline at end of file + +GITHUB_REPOSITORY_API_URL=https://api.github.com +GITHUB_REPO_OWNER=alllinux +GITHUB_REPO_NAME=Nibiru +GITHUB_TOKEN=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 + +JWT_SECRET_KEY=fL/S0LGXUVawAj4h45zyyAVQPTeR4oO7upfTMOTVvUc= \ No newline at end of file diff --git a/.env-local b/.env-local index fd4facf..8c0f823 100644 --- a/.env-local +++ b/.env-local @@ -11,4 +11,10 @@ NIBIRU_AUTH_HOST=nibiru-auth-api NIBIRU_AUTH_VIRTUAL_HOST=local.auth.nibiru-framework.com PROXY_NETWORK=nginx-proxy -GITHUB_TOKEN=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 \ No newline at end of file + +GITHUB_REPOSITORY_API_URL=https://api.github.com +GITHUB_REPO_OWNER=alllinux +GITHUB_REPO_NAME=Nibiru + +GITHUB_TOKEN=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 +JWT_SECRET_KEY=fL/S0LGXUVawAj4h45zyyAVQPTeR4oO7upfTMOTVvUc= \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b2bce65..2dc5b70 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,9 +12,12 @@ services: - VIRTUAL_PORT=${FPM_VIRTUAL_PORT} - NIBIRU_AUTH_VIRTUAL_HOST=${NIBIRU_AUTH_VIRTUAL_HOST} - NIBIRU_AUTH_HOST=${NIBIRU_AUTH_HOST} + - GITHUB_REPOSITORY_API_URL=${GITHUB_REPOSITORY_API_URL} + - GITHUB_REPO_OWNER=${GITHUB_REPO_OWNER} + - GITHUB_REPO_NAME=${GITHUB_REPO_NAME} - TZ=${TZ} volumes: - - ./src:/var/www/html + - ./nibiru-auth-api/src:/var/www/html networks: api_internal: restart: always @@ -34,9 +37,12 @@ services: - NIBIRU_AUTH_VIRTUAL_HOST=${NIBIRU_AUTH_VIRTUAL_HOST} - NIBIRU_AUTH_HOST=${NIBIRU_AUTH_HOST} - LETSENCRYPT_HOST=${NIBIRU_AUTH_LETSENCRYPT_HOST} + - GITHUB_REPOSITORY_API_URL=${GITHUB_REPOSITORY_API_URL} + - GITHUB_REPO_OWNER=${GITHUB_REPO_OWNER} + - GITHUB_REPO_NAME=${GITHUB_REPO_NAME} - TZ=${TZ} volumes: - - ./src:/usr/share/nginx/html + - ./nibiru-auth-api/src:/usr/share/nginx/html networks: nginx-proxy: api_internal: @@ -57,7 +63,7 @@ services: - NIBIRU_WEBHOOK_HOST=${NIBIRU_WEBHOOK_HOST} - TZ=${TZ} volumes: - - ./src:/var/www/html + - ./nibiru-webhook-receiver/src:/var/www/html networks: api_internal: restart: always @@ -77,7 +83,7 @@ services: - LETSENCRYPT_HOST=${NIBIRU_WEHOOK_RECEIVER_LETSENCRYPT_HOST} - TZ=${TZ} volumes: - - ./src:/usr/share/nginx/html + - ./nibiru-webhook-receiver/src:/usr/share/nginx/html networks: nginx-proxy: api_internal: diff --git a/gpt-schema.yml b/gpt-schema.yml index 1a9c215..bef532e 100644 --- a/gpt-schema.yml +++ b/gpt-schema.yml @@ -183,7 +183,7 @@ paths: properties: name: type: string - email: + email: type: string date: type: string @@ -195,8 +195,8 @@ paths: properties: sha: type: string - url: - type: string + url: + type: string url: type: string comment_count: @@ -298,5 +298,56 @@ paths: type: string '404': description: Repository not found + + /repos/{owner}/{repo}/branches: + get: + operationId: listBranches + summary: List branches in a repository + description: Retrieve a list of branches in a repository. + parameters: + - name: owner + in: path + required: true + schema: + type: string + description: The owner of the repository. + - name: repo + in: path + required: true + schema: + type: string + description: The name of the repository. + - name: protected + in: query + schema: + type: boolean + description: Set to true to only return protected branches. + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + description: The name of the branch. + commit: + type: object + properties: + sha: + type: string + description: SHA of the commit. + url: + type: string + description: URL of the commit. + protected: + type: boolean + description: Indicates if the branch is protected. + '404': + description: Repository not found components: schemas: {} \ No newline at end of file diff --git a/nibiru-auth-api/src/AuthController.php b/nibiru-auth-api/src/AuthController.php new file mode 100644 index 0000000..b0e5700 --- /dev/null +++ b/nibiru-auth-api/src/AuthController.php @@ -0,0 +1,80 @@ +secretKey = getenv('JWT_SECRET_KEY'); // Use getenv to get the secret key + } + public function handle() + { + $action = $_GET['action'] ?? ''; + + if ($action === 'token') { + $this->generateToken(); + } elseif ($action === 'validate') { + $this->validateToken(); + } else { + echo json_encode(['error' => 'Invalid action']); + } + } + + private function generateToken() + { + $issuedAt = time(); + $expirationTime = $issuedAt + 3600; + $payload = [ + 'iss' => getenv('NIBIRU_AUTH_VIRTUAL_HOST'), + 'aud' => getenv('NIBIRU_AUTH_VIRTUAL_HOST'), + 'iat' => $issuedAt, + 'nbf' => $issuedAt, + 'exp' => $expirationTime, + 'data' => [ + 'userId' => 123, + 'username' => 'example_user' + ] + ]; + + $jwt = $this->encodeJwt($payload, $this->secretKey); + echo json_encode(['token' => $jwt]); + } + + public function validateToken() + { + $headers = getallheaders(); + $authHeader = $headers['Authorization'] ?? ''; + + if (preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) + { + $token = $matches[1]; + + try { + $decoded = JWT::decode($token, new Key($this->secretKey, 'HS256')); + echo json_encode(['valid' => true, 'data' => $decoded]); + } catch (\Exception $e) { + http_response_code(401); + echo json_encode(['error' => 'Invalid token', 'message' => $e->getMessage()]); + } + } else { + http_response_code(401); + echo json_encode(['error' => 'Authorization header missing']); + } + } + + private function encodeJwt($payload, $key) + { + return JWT::encode($payload, $key, 'HS256'); + } + + private function decodeJwt($jwt, $key) + { + return JWT::decode($jwt, new Key($key, 'HS256')); + } +} \ No newline at end of file diff --git a/nibiru-auth-api/src/ValidateToken.php b/nibiru-auth-api/src/ValidateToken.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/nibiru-auth-api/src/ValidateToken.php @@ -0,0 +1 @@ +handle(); \ No newline at end of file diff --git a/nibiru-webhook-receiver/src/GitHubClient.php b/nibiru-webhook-receiver/src/GitHubClient.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/nibiru-webhook-receiver/src/GitHubClient.php @@ -0,0 +1 @@ +secretKey = getenv('JWT_SECRET_KEY'); + $this->authApiUrl = getenv('NIBIRU_AUTH_API_URL'); + $this->githubToken = getenv('GITHUB_TOKEN'); + $this->repoOwner = getenv('GITHUB_REPO_OWNER'); + $this->repoName = getenv('GITHUB_REPO_NAME'); + $this->githubApiUrl = getenv('GITHUB_REPOSITORY_API_URL'); + $this->client = new Client(); + } + + /** + * @desc handle the webhook request and validate the token + * @return void + */ + public function handleWebhook() + { + $token = $this->getBearerToken(); + + // Debug output for token + error_log("Received Token: " . $token); + + if ($token) + { + try { + $decoded = JWT::decode($token, new Key($this->secretKey, 'HS256')); + $payload = (array) $decoded; + + // Token is valid, process the webhook + http_response_code(200); + echo json_encode(['message' => 'Webhook processed', 'data' => $payload]); + } catch (\Exception $e) { + // Invalid token + http_response_code(401); + echo json_encode(['error' => 'Invalid token', 'message' => $e->getMessage()]); + } + } else { + // No token provided + http_response_code(401); + echo json_encode(['error' => 'Authorization header missing']); + } + } + + /** + * @desc get file content from the GitHub repository + * @return void* + * @throws \GuzzleHttp\Exception\GuzzleException + */ + private function listFiles() + { + $token = $this->getBearerToken(); + + if ($token) + { + try { + JWT::decode($token, new Key($this->secretKey, 'HS256')); + + $response = $this->client->get("{$this->githubApiUrl}/repos/{$this->repoOwner}/{$this->repoName}/contents", [ + 'headers' => [ + 'Authorization' => "Bearer {$this->githubToken}", + 'Accept' => 'application/vnd.github.v3+json', + ], + ]); + + $data = json_decode($response->getBody(), true); + http_response_code(200); + echo json_encode($data); + } catch (\Exception $e) { + http_response_code(401); + echo json_encode(['error' => 'Invalid token', 'message' => $e->getMessage()]); + } + } else { + http_response_code(401); + echo json_encode(['error' => 'Authorization header missing']); + } + } + + /** + * @desc get file content from the GitHub repository + * @return void + * @throws \GuzzleHttp\Exception\GuzzleException + */ + private function getFile() + { + $token = $this->getBearerToken(); + $filePath = $_GET['path'] ?? ''; + + if ($token) + { + try { + JWT::decode($token, new Key($this->secretKey, 'HS256')); + + $response = $this->client->get("{$this->githubApiUrl}/repos/{$this->repoOwner}/{$this->repoName}/contents/{$filePath}", [ + 'headers' => [ + 'Authorization' => "Bearer {$this->githubToken}", + 'Accept' => 'application/vnd.github.v3+json', + ], + ]); + + $data = json_decode($response->getBody(), true); + http_response_code(200); + echo json_encode($data); + } catch (\Exception $e) { + http_response_code(401); + echo json_encode(['error' => 'Invalid token', 'message' => $e->getMessage()]); + } + } else { + http_response_code(401); + echo json_encode(['error' => 'Authorization header missing']); + } + } + + /** + * @desc list tags from the GitHub repository + * @return void + * @throws \GuzzleHttp\Exception\GuzzleException + */ + private function listTags() + { + $token = $this->getBearerToken(); + + if ($token) + { + try { + JWT::decode($token, new Key($this->secretKey, 'HS256')); + + $response = $this->client->get("{$this->githubApiUrl}/repos/{$this->repoOwner}/{$this->repoName}/tags", [ + 'headers' => [ + 'Authorization' => "Bearer {$this->githubToken}", + 'Accept' => 'application/vnd.github.v3+json', + ], + ]); + + $data = json_decode($response->getBody(), true); + http_response_code(200); + echo json_encode($data); + } catch (\Exception $e) { + http_response_code(401); + echo json_encode(['error' => 'Invalid token', 'message' => $e->getMessage()]); + } + } else { + http_response_code(401); + echo json_encode(['error' => 'Authorization header missing']); + } + } + + /** + * @desc get authentication header + * @return string|null + */ + private function getAuthorizationHeader() + { + $headers = null; + if (isset($_SERVER['Authorization'])) + { + $headers = trim($_SERVER["Authorization"]); + } elseif (isset($_SERVER['HTTP_AUTHORIZATION'])) { + $headers = trim($_SERVER["HTTP_AUTHORIZATION"]); + } elseif (function_exists('apache_request_headers')) { + $requestHeaders = apache_request_headers(); + $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders)); + if (isset($requestHeaders['Authorization'])) + { + $headers = trim($requestHeaders['Authorization']); + } + } + return $headers; + } + + /** + * @desc Get the Bearer token from the Authorization header + * @return string|null + */ + private function getBearerToken() + { + $headers = $this->getAuthorizationHeader(); + if (!empty($headers)) + { + if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) + { + return $matches[1]; + } + } + return null; + } + + /** + * @desc Split API methods calls in order to handled multiple actions + * @return void + */ + public function handle() + { + $action = $_GET['action'] ?? null; + + switch ($action) { + case 'webhook': + $this->handleWebhook(); + break; + case 'list-files': + $this->listFiles(); + break; + case 'get-file': + $this->getFile(); + break; + case 'list-tags': + $this->listTags(); + break; + default: + http_response_code(404); + echo "Action not found."; + break; + } + } + + private function validateToken($authHeader) + { + $ch = curl_init("{$this->authApiUrl}/index.php?action=validate"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + "Authorization: $authHeader" + ]); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + return $httpCode === 200; + } + + private function processPayload($payload) + { + // Add your payload processing logic here + // For example, you could log the payload or trigger some other action + + $this->response(['message' => 'Webhook received'], 200); + } + + private function response($data, $status) + { + header("Content-Type: application/json", true, $status); + echo json_encode($data); + exit; + } +} \ No newline at end of file diff --git a/nibiru-webhook-receiver/src/WebhookReceiver.php b/nibiru-webhook-receiver/src/WebhookReceiver.php new file mode 100644 index 0000000..8292fb5 --- /dev/null +++ b/nibiru-webhook-receiver/src/WebhookReceiver.php @@ -0,0 +1,62 @@ + 'Webhook processed', 'data' => $payload]); + } catch (Exception $e) { + // Invalid token + http_response_code(401); + echo json_encode(['error' => 'Invalid token', 'message' => $e->getMessage()]); + } +} else { + // No token provided + http_response_code(401); + echo json_encode(['error' => 'Authorization header missing']); +} \ No newline at end of file diff --git a/nibiru-webhook-receiver/src/composer.json b/nibiru-webhook-receiver/src/composer.json new file mode 100644 index 0000000..818f5d8 --- /dev/null +++ b/nibiru-webhook-receiver/src/composer.json @@ -0,0 +1,27 @@ +{ + "name": "nibiru/webhook-receiver", + "description": "Webhook Receiver for Nibiru Framework", + "type": "project", + "require": { + "guzzlehttp/guzzle": "^7.0", + "psr/http-message": "^1.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "symfony/deprecation-contracts": "^2.1", + "firebase/php-jwt": "^6.0" + }, + "autoload": { + "psr-4": { + "NibiruWebhookReceiver\\": "" + } + }, + "config": { + "optimize-autoloader": true, + "sort-packages": true + }, + "scripts": { + "post-update-cmd": [ + "chmod -R 777 storage" + ] + } +} \ No newline at end of file diff --git a/nibiru-webhook-receiver/src/index.php b/nibiru-webhook-receiver/src/index.php new file mode 100644 index 0000000..d7fe250 --- /dev/null +++ b/nibiru-webhook-receiver/src/index.php @@ -0,0 +1,6 @@ +handle(); diff --git a/src/AuthController.php b/src/AuthController.php deleted file mode 100644 index 9a20320..0000000 --- a/src/AuthController.php +++ /dev/null @@ -1,23 +0,0 @@ - $token]); - } else { - http_response_code(401); - echo json_encode(['error' => 'Invalid credentials']); - } - } - - public function validateToken($token) { - // Validate the token (this is a simple example, implement proper token validation) - return strlen($token) === 32; - } -} \ No newline at end of file diff --git a/src/GitHubClient.php b/src/GitHubClient.php deleted file mode 100755 index 45c89e4..0000000 --- a/src/GitHubClient.php +++ /dev/null @@ -1,39 +0,0 @@ -client = new Client([ - 'base_uri' => 'https://api.github.com/', - 'headers' => [ - 'Authorization' => "token $token", - 'Accept' => 'application/vnd.github.v3+json', - ], - ]); - $this->token = $token; - } - - public function getRepositoryContent($owner, $repo, $path, $ref = 'main') - { - $response = $this->client->get("repos/$owner/$repo/contents/$path", [ - 'query' => ['ref' => $ref] - ]); - return json_decode($response->getBody(), true); - } - - public function listCommits($owner, $repo, $params = []) - { - $response = $this->client->get("repos/$owner/$repo/commits", [ - 'query' => $params - ]); - return json_decode($response->getBody(), true); - } -} \ No newline at end of file diff --git a/src/ValidateToken.php b/src/ValidateToken.php deleted file mode 100644 index c4d09d2..0000000 --- a/src/ValidateToken.php +++ /dev/null @@ -1,9 +0,0 @@ -validateToken($token); -echo json_encode(['valid' => $isValid]); \ No newline at end of file diff --git a/src/WebhookController.php b/src/WebhookController.php deleted file mode 100644 index 4e7ac82..0000000 --- a/src/WebhookController.php +++ /dev/null @@ -1,34 +0,0 @@ -authServiceUrl = 'http://nibiru-auth-api:9000/validateToken.php'; - } - - private function validateToken($token) { - // Make a request to the auth service to validate the token - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $this->authServiceUrl); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['token' => $token])); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - $response = curl_exec($ch); - curl_close($ch); - - $result = json_decode($response, true); - return $result && isset($result['valid']) && $result['valid']; - } - - public function handleWebhook() { - $headers = getallheaders(); - $token = $headers['Authorization'] ?? ''; - - if (!$this->validateToken($token)) { - http_response_code(401); - echo json_encode(['error' => 'Unauthorized']); - return; - } - - // Handle the webhook logic here - } -} \ No newline at end of file diff --git a/src/composer.json b/src/composer.json deleted file mode 100755 index ddfe48b..0000000 --- a/src/composer.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "vendor_name/nibiru-framework-agent", - "description": "A project to interact with GitHub API using PHP", - "authors": [ - { - "name": "Stephan Kasdorf", - "email": "stephan.kasdorf@bittomine.com" - } - ], - "require": { - "php": "^8.3", - "guzzlehttp/guzzle": "^7.3" - }, - "autoload": { - "psr-4": { - "": "src/" - } - }, - "scripts": { - "post-install-cmd": [ - "chmod -R 777 storage" - ] - }, - "config": { - "optimize-autoloader": true, - "preferred-install": "dist", - "sort-packages": true - } -} \ No newline at end of file diff --git a/src/index.php b/src/index.php deleted file mode 100755 index bfd863b..0000000 --- a/src/index.php +++ /dev/null @@ -1,2 +0,0 @@ - 'Webhook received']); \ No newline at end of file