diff --git a/src/js/how2validate/handler/validator_handler.ts b/src/js/how2validate/handler/validator_handler.ts index 79dd49d..e649ecf 100644 --- a/src/js/how2validate/handler/validator_handler.ts +++ b/src/js/how2validate/handler/validator_handler.ts @@ -1,6 +1,7 @@ import { validateAdafruitIOKey } from "../validators/adafruit/adafruit_io_key.js"; // Import the Adafruit token validator import { validateAivenAuthToken } from "../validators/aiven/aiven_auth_token.js"; // Import the Aiven API key validator import { validateAnthropicAPIKey } from "../validators/anthropic/anthropic_api_key.js"; // Import the Anthropic API Key validator +import { validateGitHubPersonalAccessToken } from "../validators/github/github_personal_access_token.js"; // Import the GitHub Personal Access Token validator import { validateHFOrgApiKey } from "../validators/hugging_face/hf_org_api_key.js"; // Import the Hugging Face API Key validator import { validateHFUserAccessToken } from "../validators/hugging_face/hf_user_access_token.js"; // Import the Hugging Face API Key validator import { validateNpmAccessToken } from "../validators/npm/npm_access_token.js"; // Import the NPM access token validator @@ -46,6 +47,7 @@ const serviceHandlers: Record = { adafruit_io_key: validateAdafruitIOKey, // Adafruit Io Key validator aiven_auth_token: validateAivenAuthToken, // Aiven Auth token anthropic_api_key: validateAnthropicAPIKey, // Anthropic API Key + github_personal_access_token: validateGitHubPersonalAccessToken, // GitHub Personal Access Token hf_org_api_key: validateHFOrgApiKey, // HuggingFace API Key hf_user_access_token: validateHFUserAccessToken, // HuggingFace API Key npm_access_token: validateNpmAccessToken, // NPM access token validator diff --git a/src/js/how2validate/validators/github/github_personal_access_token.ts b/src/js/how2validate/validators/github/github_personal_access_token.ts new file mode 100644 index 0000000..004a935 --- /dev/null +++ b/src/js/how2validate/validators/github/github_personal_access_token.ts @@ -0,0 +1,121 @@ +/** + * @module GitHubPersonalAccessTokenValidator + * @description + * This module provides functionality to validate a GitHub Personal Access Token by making an API call to the GitHub service. + * It returns a validation status, processes the response from the API, and optionally sends an email report with the results. + * + * @requires axios - Used for making HTTP requests to the GitHub API. + * @requires ../../utility/tool_utility.js - Utility functions for handling status responses and errors. + * @requires ../../handler/email_handler.js - Used for sending email reports on validation results. + */ + +import { ValidationResult } from "../../utility/interface/validationResult.js"; +import { + handleInactiveStatus, + handleErrors, + getUsernameFromEmail, + handleActiveStatus, + responseValidation +} from "../../utility/tool_utility.js"; +import { EmailResponse } from "../../utility/interface/EmailResponse.js"; +import { SecretStatusMessage } from "../../utility/interface/secretStatusMessage.js"; +import { sendEmail } from "../../handler/email_handler.js"; +import axios from "axios"; + +/** + * @function validateGitHubPersonalAccessToken + * @description + * Validates a GitHub Personal Access Token by making an API call to the GitHub API. + * Checks the token's validity, handles errors, and returns a validation result. + * Optionally sends an email summarizing the validation results. + * + * @async + * @param {string} provider - The provider name (e.g., "GitHub"). + * @param {string} service - The name of the service being validated. + * @param {string} secret - The GitHub Personal Access Token to validate. + * @param {boolean} responseFlag - A flag to indicate whether detailed response data should be returned. + * @param {string} [report] - An optional email address to which a validation report should be sent. + * @param {boolean} [isBrowser=true] - Indicates if the function is called from a browser environment (default is true). + * + * @returns {Promise} - A promise that resolves to a `ValidationResult` object containing the validation result. + */ +export async function validateGitHubPersonalAccessToken( + provider: string, + service: string, + secret: string, + responseFlag: boolean, + report: string, + isBrowser: boolean = true +): Promise { + const validationResponse = {} as SecretStatusMessage; + const url = "https://api.github.com/user"; + const nocacheHeaders = { "Cache-Control": "no-cache" }; + const headers = { Authorization: `Bearer ${secret}` }; + + try { + const responseData = await axios.get(url, { + headers: { ...nocacheHeaders, ...headers }, + }); + + if (responseData.status === 200) { + const activeResponse = handleActiveStatus( + provider, + service, + responseData, + responseFlag, + report, + isBrowser + ); + + validationResponse.state = activeResponse.data?.validate.state!; + validationResponse.message = activeResponse.data?.validate.message!; + validationResponse.response = activeResponse.data?.validate.response!; + + return responseValidation(activeResponse, responseFlag); + } else { + const inactiveResponse = handleInactiveStatus( + provider, + service, + responseFlag, + responseData.data, + report, + isBrowser + ); + + validationResponse.state = inactiveResponse.data?.validate.state!; + validationResponse.message = inactiveResponse.data?.validate.message!; + validationResponse.response = inactiveResponse.data?.validate.response!; + + return responseValidation(inactiveResponse, responseFlag); + } + } catch (error) { + const errResponse = handleErrors( + provider, + service, + responseFlag, + report, + error, + isBrowser + ); + + validationResponse.state = errResponse.data?.validate.state!; + validationResponse.message = errResponse.data?.validate.message!; + validationResponse.response = errResponse.data?.validate.response!; + + return responseValidation(errResponse, responseFlag); + } finally { + if (report) { + const emailResponse: EmailResponse = { + provider: provider, + service: service, + state: validationResponse.state, + message: validationResponse.message, + response: validationResponse.response, + }; + + sendEmail(report, getUsernameFromEmail(report), emailResponse) + .then(() => console.info("Validation report sent successfully")) + .catch((error) => console.error("Error sending validation report", error)); + } + } +} diff --git a/src/js/tokenManager.json b/src/js/tokenManager.json index 65a11b9..9db2a63 100644 --- a/src/js/tokenManager.json +++ b/src/js/tokenManager.json @@ -704,7 +704,7 @@ { "secret_type": "github_personal_access_token", "display_name": "Github Personal Access Token", - "is_enabled": false + "is_enabled": true }, { "secret_type": "github_refresh_token", diff --git a/src/python/how2validate/handler/validator_handler.py b/src/python/how2validate/handler/validator_handler.py index 8eaed4e..e9efd87 100644 --- a/src/python/how2validate/handler/validator_handler.py +++ b/src/python/how2validate/handler/validator_handler.py @@ -4,6 +4,7 @@ from how2validate.validators.adafruit.adafruit_io_key import validate_adafruit_io_key from how2validate.validators.aiven.aiven_auth_token import validate_aiven_auth_token from how2validate.validators.anthropic.anthropic_api_key import validate_anthropic_api_key +from how2validate.validators.github.github_personal_access_token import validate_github_personal_access_token from how2validate.validators.hugging_face.hf_org_api_key import validate_hf_org_api_key from how2validate.validators.hugging_face.hf_user_access_token import validate_hf_user_access_token from how2validate.validators.npm.npm_access_token import validate_npm_access_token @@ -20,6 +21,7 @@ "adafruit_io_key": validate_adafruit_io_key, "aiven_auth_token": validate_aiven_auth_token, "anthropic_api_key": validate_anthropic_api_key, + "github_personal_access_token": validate_github_personal_access_token, "hf_org_api_key": validate_hf_org_api_key, "hf_user_access_token": validate_hf_user_access_token, "npm_access_token": validate_npm_access_token, diff --git a/src/python/how2validate/validators/github/github_personal_access_token.py b/src/python/how2validate/validators/github/github_personal_access_token.py new file mode 100644 index 0000000..ede1060 --- /dev/null +++ b/src/python/how2validate/validators/github/github_personal_access_token.py @@ -0,0 +1,119 @@ +import json +import logging +import requests +from how2validate.handler.email_handler import send_email +from how2validate.utility.interface.EmailResponse import EmailResponse +from how2validate.utility.interface.validationResult import ValidationProcess, ValidationResult +from how2validate.utility.tool_utility import handle_active_status, handle_inactive_status, handle_errors, response_validation + +def validate_github_personal_access_token( + provider: str, + service: str, + secret: str, + response_flag: bool, + report: str, + is_browser: bool = True +) -> ValidationResult: + """ + Validates a GitHub personal access token by making a request to the GitHub API. + + Parameters: + - provider (str): The provider name (e.g., "GitHub"). + - service (str): The name of the service being validated. + - secret (str): The GitHub personal access token to validate. + - response_flag (bool): Flag to indicate whether detailed response data should be returned. + - report (str): An optional email address to which a validation report should be sent. + - is_browser (bool): Indicates if the function is called from a browser environment (default is True). + + Returns: + - ValidationResult: A structured response indicating the validation results. + """ + # Initialize the response structure as an instance of the ValidationProcess class + validation_response = ValidationProcess( + state="", + message="", + response=None, + report="email@how2validate.com" + ) + + # GitHub API endpoint for validating a personal access token + url = "https://api.github.com/user" + + # Headers for the API request + nocache_headers = {'Cache-Control': 'no-cache'} + headers = {'Authorization': f'Bearer {secret}'} + + try: + # Send a GET request to the GitHub API + response_data = requests.get(url, headers={**nocache_headers, **headers}) + # Raise an error for unsuccessful HTTP status codes + response_data.raise_for_status() + + # Handle successful response (HTTP 200) + if response_data.status_code == 200: + active_response = handle_active_status( + provider, + service, + response_data, + response_flag, + report, + is_browser + ) + + validation_response.state = active_response.data.validate.state + validation_response.message = active_response.data.validate.message + validation_response.response = json.dumps(active_response.to_dict(), indent=4) + + return response_validation(active_response, response_flag) + + except requests.HTTPError as error: + # Handle 4xx client errors + if 400 <= error.response.status_code < 500: + inactive_response = handle_inactive_status( + provider, + service, + response_flag, + error, + report, + is_browser + ) + + validation_response.state = inactive_response.data.validate.state + validation_response.message = inactive_response.data.validate.message + validation_response.response = json.dumps(inactive_response.to_dict(), indent=4) + + return response_validation(inactive_response, response_flag) + + # Handle 5xx server errors + elif 500 <= error.response.status_code < 600: + error_response = handle_errors( + provider, + service, + response_flag, + report, + error, + is_browser + ) + + validation_response.state = error_response.data.validate.state + validation_response.message = error_response.data.validate.message + validation_response.response = json.dumps(error_response.to_dict(), indent=4) + + return response_validation(error_response, response_flag) + + finally: + # Send the validation result via email if a report email is provided + if report: + email_response = EmailResponse( + email=report, + provider=provider, + service=service, + state=validation_response.state, + message=validation_response.message, + response=validation_response.response, + ) + try: + send_email(email_response) + logging.info('Validation report sent successfully') + except Exception as e: + logging.error('Error sending validation report', exc_info=True) diff --git a/src/python/tokenManager.json b/src/python/tokenManager.json index 65a11b9..9db2a63 100644 --- a/src/python/tokenManager.json +++ b/src/python/tokenManager.json @@ -704,7 +704,7 @@ { "secret_type": "github_personal_access_token", "display_name": "Github Personal Access Token", - "is_enabled": false + "is_enabled": true }, { "secret_type": "github_refresh_token",