Passed
Pull Request — main (#128)
by Yume
01:15
created

oauth.GetGithubAccessToken   B

Complexity

Conditions 7

Size

Total Lines 44
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 26
nop 2
dl 0
loc 44
rs 7.856
c 0
b 0
f 0
1
package oauth
2
3
import (
4
	"bytes"
5
	"context"
6
	"fmt"
7
	"io"
8
	"net/http"
9
10
	"github.com/memnix/memnix-rest/config"
11
	"github.com/memnix/memnix-rest/infrastructures"
12
	"github.com/memnix/memnix-rest/views"
13
	"github.com/pkg/errors"
14
)
15
16
// Represents the response received from Github
17
type githubAccessTokenResponse struct {
18
	AccessToken string `json:"access_token"`
19
	TokenType   string `json:"token_type"`
20
	Scope       string `json:"scope"`
21
}
22
23
const (
24
	githubAccessTokenURL = "https://github.com/login/oauth/access_token"
25
	githubAPIURL         = "https://api.github.com/user"
26
)
27
28
// GetGithubAccessToken gets the access token from Github using the code
29
func GetGithubAccessToken(ctx context.Context, code string) (string, error) {
30
	_, span := infrastructures.GetFiberTracer().Start(ctx, "GetGithubAccessToken")
31
	defer span.End()
32
	// Set us the request body as JSON
33
	requestBodyMap := map[string]string{
34
		"client_id":     infrastructures.GetAppConfig().GithubConfig.ClientID,
35
		"client_secret": infrastructures.GetAppConfig().GithubConfig.ClientSecret,
36
		"code":          code,
37
	}
38
	requestJSON, _ := config.JSONHelper.Marshal(requestBodyMap)
39
40
	// POST request to set URL
41
	req, err := http.NewRequestWithContext(ctx,
42
		http.MethodPost,
43
		githubAccessTokenURL,
44
		bytes.NewBuffer(requestJSON),
45
	)
46
	if err != nil || req == nil || req.Body == nil || req.Header == nil {
47
		return "", errors.Wrap(err, views.RequestFailed)
48
	}
49
	req.Header.Set("Content-Type", "application/json")
50
	req.Header.Set("Accept", "application/json")
51
52
	// Get the response
53
	resp, err := http.DefaultClient.Do(req)
54
	if err != nil {
55
		return "", errors.Wrap(err, views.ResponseFailed)
56
	}
57
58
	defer resp.Body.Close()
59
60
	// Response body converted to stringified JSON
61
	respbody, _ := io.ReadAll(resp.Body)
62
63
	// Convert stringified JSON to a struct object of type githubAccessTokenResponse
64
	var ghresp githubAccessTokenResponse
65
	err = config.JSONHelper.Unmarshal(respbody, &ghresp)
66
	if err != nil {
67
		return "", err
68
	}
69
70
	// Return the access token (as the rest of the
71
	// details are relatively unnecessary for us)
72
	return ghresp.AccessToken, nil
73
}
74
75
// GetGithubData gets the user data from Github using the access token
76
func GetGithubData(ctx context.Context, accessToken string) (string, error) {
77
	_, span := infrastructures.GetFiberTracer().Start(ctx, "GetGithubData")
78
	defer span.End()
79
	// Get request to a set URL
80
	req, err := http.NewRequestWithContext(ctx,
81
		http.MethodGet,
82
		"https://api.github.com/user",
83
		nil,
84
	)
85
	if err != nil {
86
		return "", err
87
	}
88
89
	// Set the Authorization header before sending the request
90
	// Authorization: token XXXXXXXXXXXXXXXXXXXXXXXXXXX
91
	authorizationHeaderValue := fmt.Sprintf("token %s", accessToken)
92
	req.Header.Set("Authorization", authorizationHeaderValue)
93
94
	// Make the request
95
	resp, err := http.DefaultClient.Do(req)
96
	if err != nil {
97
		return "", err
98
	}
99
100
	defer resp.Body.Close()
101
102
	// Read the response as a byte slice
103
	respbody, err := io.ReadAll(resp.Body)
104
	if err != nil {
105
		return "", err
106
	}
107
108
	// Convert byte slice to string and return
109
	return string(respbody), nil
110
}
111