Skip to content

Commit

Permalink
feat(Slack): Slack Api Token added
Browse files Browse the repository at this point in the history
  • Loading branch information
Vigneshkna committed Nov 20, 2024
1 parent cb4bb78 commit 7e1e6cc
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/js/how2validate/handler/validator_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { validateNpmAccessToken } from "../validators/npm/npm_access_token.js";
import { validateOpenAIApiKey } from "../validators/openai/openai_api_key.js"; // Import the NPM access token validator
import { validatePagerDutyAPIKey } from "../validators/pagerduty/pagerduty_api_key.js"; // Import the OpenAI API key validator
import { validateSentryAuthToken } from "../validators/sentry/sentry_auth_token.js"; // Import the Sentry Auth Token validator
import { validateSlackApiToken } from "../validators/slack/slack_api_token.js"; // Import the Slack API token validator
import { validateSnykAuthKey } from "../validators/snyk/snyk_auth_key.js"; // Import the Snyk authentication key validator
import { validateSonarcloudToken } from "../validators/sonarcloud/sonarcloud_token.js"; // Import the Sonarcloud token validator

Expand Down Expand Up @@ -55,6 +56,7 @@ const serviceHandlers: Record<string, ValidatorFunction> = {
openai_api_key: validateOpenAIApiKey, // OpenAI API key
pagerduty_api_key: validatePagerDutyAPIKey, // PagerDuty API key
sentry_auth_token: validateSentryAuthToken, // Sentry Auth Token
slack_api_token: validateSlackApiToken, // Slack API token
snyk_auth_key: validateSnykAuthKey, // Snyk auth key validator
sonarcloud_token: validateSonarcloudToken, // Sonarcloud token validator
// Add additional services and their validators here
Expand Down
147 changes: 147 additions & 0 deletions src/js/how2validate/validators/slack/slack_api_token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/**
* @module SlackApiTokenValidator
* @description
* This module provides functionality to validate a Slack API token by making an API call to the Slack service.
* It processes the response from the API, checks if the token is valid, and optionally sends an email report with the validation results.
*
* The module depends on various utilities for handling configuration, logging, and secret statuses.
*
* @requires axios - Used for making HTTP requests to the Slack 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"; // Interface for validation results
import {
handleInactiveStatus,
handleErrors,
getUsernameFromEmail,
handleActiveStatus,
responseValidation
} from "../../utility/tool_utility.js"; // Utility functions for handling statuses and errors
import { EmailResponse } from "../../utility/interface/EmailResponse.js"; // Interface for email response structure
import { SecretStatusMessage } from "../../utility/interface/secretStatusMessage.js"; // Interface for secret status messages
import { sendEmail } from "../../handler/email_handler.js"; // Function to send email using Zoho ZeptoMail
import axios from "axios"; // Axios for making API requests

/**
* @function validateSlackApiToken
* @description
* This function validates a Slack API token by making an API call to the Slack API.
* Based on the response from Slack, it checks the validity of the token, handles errors, and
* returns an appropriate validation result.
*
* If a `report` email is provided, the function also sends an email summarizing the validation results.
*
* @async
* @param {string} provider - The provider name (e.g., "Slack") for which the secret is being validated.
* @param {string} service - The name of the service being validated.
* @param {string} secret - The Slack API token or secret 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 false).
*
* @returns {Promise<ValidationResult>} - A promise that resolves to a `ValidationResult` object containing the validation result.
*
* @throws {Error} - If the validation process encounters an issue, it throws an error.
*
* @example
* const validation = await validateSlackApiToken("Slack", "slack_api_token", "your-slack-token", true, "[email protected]");
* console.log(validation);
*/
export async function validateSlackApiToken(
provider: string,
service: string,
secret: string,
responseFlag: boolean,
report: string,
isBrowser: boolean = true
): Promise<ValidationResult> {
// Initialize the response structure
const validationResponse = {} as SecretStatusMessage;

// Define Slack API endpoint for checking token authentication
const url = "https://slack.com/api/auth.test?pretty=1"; // Slack API endpoint to validate the token
const nocacheHeaders = { "Cache-Control": "no-cache" }; // Avoid cache when making the request
const headers = { Authorization: `Bearer ${secret}` }; // Attach the Slack authentication token in the request headers

try {
// Send a GET request to Slack API to validate the token
const responseData = await axios.get(url, {
headers: { ...nocacheHeaders, ...headers },
});

// If the token is valid (successful response), handle active status
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 the formatted validation result
return responseValidation(activeResponse, responseFlag);
} else {
// Handle inactive token or other statuses
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 the formatted validation result
return responseValidation(inactiveResponse, responseFlag);
}
} catch (error) {
// Handle errors in the validation process
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 the error response as the validation result
return responseValidation(errResponse, responseFlag);
} finally {
// If a report email is provided, send the validation result via email
if (report) {
const emailResponse: EmailResponse = {
provider: provider,
service: service,
state: validationResponse.state,
message: validationResponse.message,
response: validationResponse.response,
};

// Send the email and log success or failure
sendEmail(report, getUsernameFromEmail(report), emailResponse)
.then(() => {
console.info("Validation report sent successfully");
})
.catch((error) => {
console.error("Error sending validation report", error);
});
}
}
}
2 changes: 1 addition & 1 deletion src/js/tokenManager.json
Original file line number Diff line number Diff line change
Expand Up @@ -1521,7 +1521,7 @@
{
"secret_type": "slack_api_token",
"display_name": "Slack Api Token",
"is_enabled": false
"is_enabled": true
},
{
"secret_type": "slack_incoming_webhook_url",
Expand Down
3 changes: 2 additions & 1 deletion src/python/how2validate/handler/validator_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
from how2validate.validators.openai.openai_api_key import validate_openai_api_key
from how2validate.validators.pagerduty.pagerduty_api_key import validate_pagerduty_api_key
from how2validate.validators.sentry.sentry_auth_token import validate_sentry_auth_token
from how2validate.validators.slack.slack_api_token import validate_slack_api_token
from how2validate.validators.snyk.snyk_auth_key import validate_snyk_auth_key
from how2validate.validators.sonarcloud.sonarcloud_token import validate_sonarcloud_token

from how2validate.utility.interface.validationResult import ValidationResult



# Create a dictionary that maps service names to their corresponding validator functions
service_handlers = {
"adafruit_io_key": validate_adafruit_io_key,
Expand All @@ -30,6 +30,7 @@
"openai_api_key": validate_openai_api_key,
"pagerduty_api_key": validate_pagerduty_api_key,
"sentry_auth_token": validate_sentry_auth_token,
"slack_api_token": validate_slack_api_token,
"snyk_auth_key": validate_snyk_auth_key,
"sonarcloud_token": validate_sonarcloud_token,
# Add additional service validators as needed
Expand Down
112 changes: 112 additions & 0 deletions src/python/how2validate/validators/slack/slack_api_token.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
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_slack_api_token(provider: str, service: str, secret: str, response_flag: bool, report: str, is_browser: bool = True) -> ValidationResult:
"""
Validates the Slack API token by making a request to the Slack API.
Parameters:
- provider (str): The provider name (e.g., "Slack").
- service (str): The name of the service being validated.
- secret (str): The Slack API 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=report
)

# Slack API endpoint for testing authentication
url = "https://slack.com/api/auth.test?pretty=1"

# Headers for authorization using the provided Slack API token
headers = {'Authorization': f'Bearer {secret}'}

try:
# Send a GET request to the Slack API with the authorization header
response_data = requests.get(url, headers=headers)
response_data.raise_for_status() # Raise an exception for HTTP error responses

# Check if the request was successful (HTTP 200)
if response_data.status_code == 200:
# Handle active token status
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:
if 400 <= error.response.status_code < 500:
# Handle inactive token or other client errors
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)

elif 500 <= error.response.status_code < 600:
# Handle server errors
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:
# If a report email is provided, send the validation result via email
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)
2 changes: 1 addition & 1 deletion src/python/tokenManager.json
Original file line number Diff line number Diff line change
Expand Up @@ -1521,7 +1521,7 @@
{
"secret_type": "slack_api_token",
"display_name": "Slack Api Token",
"is_enabled": false
"is_enabled": true
},
{
"secret_type": "slack_incoming_webhook_url",
Expand Down

0 comments on commit 7e1e6cc

Please sign in to comment.