github.com/kubeshop/testkube@v1.17.23/internal/app/api/v1/slack_oauth.go (about)

     1  package v1
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  
     9  	"github.com/gofiber/fiber/v2"
    10  
    11  	thttp "github.com/kubeshop/testkube/pkg/http"
    12  )
    13  
    14  const slackAccessUrl = "https://slack.com/api/oauth.v2.access"
    15  
    16  var (
    17  	SlackBotClientID     = ""
    18  	SlackBotClientSecret = ""
    19  )
    20  
    21  type oauthResponse struct {
    22  	Ok         bool   `json:"ok"`
    23  	AppID      string `json:"app_id"`
    24  	AuthedUser struct {
    25  		ID string `json:"id"`
    26  	} `json:"authed_user"`
    27  	Scope       string `json:"scope"`
    28  	TokenType   string `json:"token_type"`
    29  	AccessToken string `json:"access_token"`
    30  	BotUserID   string `json:"bot_user_id"`
    31  	Team        struct {
    32  		ID   string `json:"id"`
    33  		Name string `json:"name"`
    34  	} `json:"team"`
    35  	Enterprise          interface{} `json:"enterprise"`
    36  	IsEnterpriseInstall bool        `json:"is_enterprise_install"`
    37  }
    38  
    39  // OauthHandler creates a handler for slack authentication
    40  func (s TestkubeAPI) OauthHandler() fiber.Handler {
    41  	return func(c *fiber.Ctx) error {
    42  
    43  		errStr := c.Query("error", "")
    44  		if errStr != "" {
    45  			c.Status(http.StatusUnauthorized)
    46  			_, err := c.WriteString(errStr)
    47  			return err
    48  		}
    49  		code := c.Query("code", "")
    50  		if code == "" {
    51  			return s.Error(c, http.StatusBadRequest, fmt.Errorf("Code was not provided"))
    52  		}
    53  
    54  		if SlackBotClientID == "" && SlackBotClientSecret == "" {
    55  			return s.Error(c, http.StatusInternalServerError, fmt.Errorf("\nSlack secrets are not set\n"))
    56  		}
    57  
    58  		var slackClient = thttp.NewClient()
    59  
    60  		req, err := http.NewRequest(http.MethodGet, slackAccessUrl, nil)
    61  		if err != nil {
    62  			return s.Error(c, http.StatusInternalServerError, fmt.Errorf("\nFailed to create request: %+v\n", err))
    63  		}
    64  
    65  		req.SetBasicAuth(SlackBotClientID, SlackBotClientSecret)
    66  		q := req.URL.Query()
    67  		q.Add("code", code)
    68  		req.URL.RawQuery = q.Encode()
    69  		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    70  
    71  		resp, err := slackClient.Do(req)
    72  		if err != nil {
    73  			return s.Error(c, http.StatusInternalServerError, fmt.Errorf("\nFailed to get access token: %+v\n", err))
    74  		}
    75  		defer resp.Body.Close()
    76  
    77  		body, err := io.ReadAll(resp.Body)
    78  
    79  		if err != nil {
    80  			return s.Error(c, http.StatusInternalServerError, fmt.Errorf("\nInvalid format for access token: %+v", err))
    81  		}
    82  
    83  		oResp := oauthResponse{}
    84  		err = json.Unmarshal(body, &oResp)
    85  
    86  		if err != nil {
    87  			return s.Error(c, http.StatusInternalServerError, fmt.Errorf("\nUnable to unmarshal the response: %+v", err))
    88  		}
    89  
    90  		if len(oResp.AccessToken) == 0 {
    91  			return s.Error(c, http.StatusInternalServerError, fmt.Errorf("Unable to get the response from the slack oauth endpoint"))
    92  		}
    93  
    94  		_, err = c.WriteString(fmt.Sprintf("Authentification was succesfull!\nPlease use the following token in the helm values for slackToken : %s", oResp.AccessToken))
    95  		return err
    96  	}
    97  }