Skip to content

Commit 07eaeea

Browse files
authored
Authenticate Incoming HTTP Requests (#3)
* authenticate incoming HTTP requests * gofmt * polish
1 parent 3ec3017 commit 07eaeea

File tree

6 files changed

+111
-49
lines changed

6 files changed

+111
-49
lines changed

.env.example

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
PORT=XXXX
1+
# GitHub Config
22
PERSONAL_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
33
ORG_NAME=Portchain
44
USER_NAME=utkuufuk
55
SUBSCRIBED_REPOS=entrello,github-service
6+
7+
# Server Config
8+
PORT=XXXX
9+
SECRET=xxxxxxxxxxxxxxxxxxxx

README.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@ A simple service to query GitHub issues & pull requests.
33
* See [Server Mode](#server-mode) for using it as an [entrello](https://github.com/utkuufuk/entrello) service.
44
* See [CLI Mode](#cli-mode) for using it as a CLI tool.
55

6-
## Configuration
7-
Put your environment variables in a file called `.env`.
8-
9-
See `.env.example` for reference.
10-
11-
126
## Server Mode
137
Start the server:
148
```sh
@@ -48,6 +42,19 @@ go run ./cmd/cli prlmy
4842
go run ./cmd/cli prlme
4943
```
5044

45+
## Configuration
46+
Put your environment variables in a file called `.env`, based on `.env.example`.
47+
48+
| Environment Variable | Description |
49+
|-|-|
50+
| `PERSONAL_ACCESS_TOKEN` | GitHub personal access token |
51+
| `ORG_NAME` | GitHub organization name (required for `prlo`, `prlmy` and `prlme`) |
52+
| `USER_NAME` | GitHub user name (required for `prlo` and `prlme`) |
53+
| `SUBSCRIBED_REPOS` | Subscribed GitHub repositories (required for `prlo`) |
54+
| `PORT` | HTTP port (server mode only) |
55+
| `SECRET` | API secret (server mode only, optional) |
56+
57+
5158
## Running With Docker
5259
A new [Docker image](https://github.com/utkuufuk?tab=packages&repo_name=github-service) will be created upon each [release](https://github.com/utkuufuk/github-service/releases).
5360

cmd/cli/main.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,24 @@ import (
77
"os"
88

99
"github.com/utkuufuk/entrello/pkg/trello"
10+
"github.com/utkuufuk/github-service/internal/config"
1011
"github.com/utkuufuk/github-service/internal/github"
12+
"github.com/utkuufuk/github-service/internal/logger"
1113
)
1214

15+
var gitHubConfig config.GitHubConfig
16+
17+
func init() {
18+
var err error
19+
gitHubConfig, err = config.ParseGitHubConfig()
20+
if err != nil {
21+
logger.Error("Failed to parse config: %v", err)
22+
os.Exit(1)
23+
}
24+
}
25+
1326
func main() {
14-
client := github.GetClient()
27+
client := github.GetClient(gitHubConfig)
1528

1629
if len(os.Args) == 1 {
1730
displayCards(client.FetchAssignedIssues)

cmd/server/main.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,32 @@ import (
55
"encoding/json"
66
"fmt"
77
"net/http"
8+
"os"
89

910
"github.com/utkuufuk/entrello/pkg/trello"
1011
"github.com/utkuufuk/github-service/internal/config"
1112
"github.com/utkuufuk/github-service/internal/github"
13+
"github.com/utkuufuk/github-service/internal/logger"
1214
)
1315

16+
var cfg config.Config
17+
18+
func init() {
19+
var err error
20+
cfg, err = config.ParseServerConfig()
21+
if err != nil {
22+
logger.Error("Failed to parse config: %v", err)
23+
os.Exit(1)
24+
}
25+
}
26+
1427
func main() {
15-
client := github.GetClient()
28+
client := github.GetClient(cfg.GitHub)
1629
http.HandleFunc("/entrello", handleGetRequest(client.FetchAssignedIssues))
1730
http.HandleFunc("/entrello/prlo", handleGetRequest(client.FetchOtherPullRequests))
1831
http.HandleFunc("/entrello/prlme", handleGetRequest(client.FetchOtherPullRequestsAssignedToMe))
1932
http.HandleFunc("/entrello/prlmy", handleGetRequest(client.FetchMyPullRequests))
20-
http.ListenAndServe(fmt.Sprintf(":%d", config.Port), nil)
33+
http.ListenAndServe(fmt.Sprintf(":%d", cfg.Port), nil)
2134
}
2235

2336
func handleGetRequest(
@@ -29,6 +42,11 @@ func handleGetRequest(
2942
return
3043
}
3144

45+
if cfg.Secret != "" && r.Header.Get("X-Api-Key") != cfg.Secret {
46+
w.WriteHeader(http.StatusUnauthorized)
47+
return
48+
}
49+
3250
cards, err := fetchCards(r.Context())
3351
if err != nil {
3452
w.WriteHeader(http.StatusInternalServerError)

internal/config/config.go

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,63 @@
11
package config
22

33
import (
4+
"fmt"
45
"os"
56
"strconv"
67
"strings"
78

89
"github.com/joho/godotenv"
9-
"github.com/utkuufuk/github-service/internal/logger"
1010
)
1111

12-
var (
13-
Port int
14-
PersonalAccessToken string
12+
type GitHubConfig struct {
1513
OrgName string
16-
UserName string
14+
PersonalAccessToken string
1715
SubscribedRepos []string
18-
)
16+
UserName string
17+
}
18+
19+
type Config struct {
20+
// GitHub config
21+
GitHub GitHubConfig
22+
23+
// additional server mode config
24+
Port int
25+
Secret string
26+
}
1927

20-
func init() {
21-
var err error
28+
func ParseGitHubConfig() (cfg GitHubConfig, err error) {
2229
godotenv.Load()
2330

24-
port := os.Getenv("PORT")
25-
Port, err = strconv.Atoi(port)
26-
if err != nil {
27-
logger.Error("PORT not set")
28-
os.Exit(1)
31+
cfg.PersonalAccessToken = os.Getenv("PERSONAL_ACCESS_TOKEN")
32+
if cfg.PersonalAccessToken == "" {
33+
return cfg, fmt.Errorf("PERSONAL_ACCESS_TOKEN not set")
2934
}
3035

31-
PersonalAccessToken = os.Getenv("PERSONAL_ACCESS_TOKEN")
32-
if PersonalAccessToken == "" {
33-
logger.Error("PERSONAL_ACCESS_TOKEN not set")
34-
os.Exit(1)
36+
cfg.OrgName = os.Getenv("ORG_NAME")
37+
if cfg.OrgName == "" {
38+
return cfg, fmt.Errorf("ORG_NAME not set")
3539
}
3640

37-
OrgName = os.Getenv("ORG_NAME")
38-
if OrgName == "" {
39-
logger.Error("ORG_NAME not set")
40-
os.Exit(1)
41+
cfg.UserName = os.Getenv("USER_NAME")
42+
if cfg.UserName == "" {
43+
return cfg, fmt.Errorf("USER_NAME not set")
4144
}
4245

43-
UserName = os.Getenv("USER_NAME")
44-
if UserName == "" {
45-
logger.Error("USER_NAME not set")
46-
os.Exit(1)
46+
cfg.SubscribedRepos = strings.Split(os.Getenv("SUBSCRIBED_REPOS"), ",")
47+
48+
return cfg, nil
49+
}
50+
51+
func ParseServerConfig() (cfg Config, err error) {
52+
ghCfg, err := ParseGitHubConfig()
53+
cfg.GitHub = ghCfg
54+
55+
port := os.Getenv("PORT")
56+
cfg.Port, err = strconv.Atoi(port)
57+
if err != nil {
58+
return cfg, fmt.Errorf("PORT not set")
4759
}
4860

49-
SubscribedRepos = strings.Split(os.Getenv("SUBSCRIBED_REPOS"), ",")
61+
cfg.Secret = os.Getenv("SECRET")
62+
return cfg, nil
5063
}

internal/github/github.go

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,21 @@ import (
1212
)
1313

1414
type Client struct {
15-
client *github.Client
15+
client *github.Client
16+
orgName string
17+
subscribedRepos []string
18+
userName string
1619
}
1720

18-
func GetClient() Client {
19-
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: config.PersonalAccessToken})
21+
func GetClient(cfg config.GitHubConfig) Client {
22+
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: cfg.PersonalAccessToken})
2023
tc := oauth2.NewClient(context.Background(), ts)
21-
client := github.NewClient(tc)
22-
return Client{client}
24+
return Client{
25+
github.NewClient(tc),
26+
cfg.OrgName,
27+
cfg.SubscribedRepos,
28+
cfg.UserName,
29+
}
2330
}
2431

2532
func (c Client) FetchAssignedIssues(ctx context.Context) ([]trello.Card, error) {
@@ -39,42 +46,42 @@ func (c Client) FetchAssignedIssues(ctx context.Context) ([]trello.Card, error)
3946

4047
func (c Client) FetchOtherPullRequests(ctx context.Context) ([]trello.Card, error) {
4148
pullRequests := make([]*github.PullRequest, 0)
42-
for _, repo := range config.SubscribedRepos {
43-
prs, _, err := c.client.PullRequests.List(ctx, config.OrgName, repo, nil)
49+
for _, repo := range c.subscribedRepos {
50+
prs, _, err := c.client.PullRequests.List(ctx, c.orgName, repo, nil)
4451
if err != nil {
45-
return nil, fmt.Errorf("could not retrieve pull requests from %s/%s: %w", config.OrgName, repo, err)
52+
return nil, fmt.Errorf("could not retrieve pull requests from %s/%s: %w", c.orgName, repo, err)
4653
}
4754
pullRequests = append(pullRequests, prs...)
4855
}
4956

5057
otherPullRequests := make([]*github.PullRequest, 0)
5158
for _, i := range pullRequests {
52-
if !*i.Draft && *i.User.Login != config.UserName && (i.Assignee == nil || *i.Assignee.Login != config.UserName) {
59+
if !*i.Draft && *i.User.Login != c.userName && (i.Assignee == nil || *i.Assignee.Login != c.userName) {
5360
otherPullRequests = append(otherPullRequests, i)
5461
}
5562
}
5663
return entrello.CreateCardsFromPullRequests(otherPullRequests)
5764
}
5865

5966
func (c Client) FetchOtherPullRequestsAssignedToMe(ctx context.Context) ([]trello.Card, error) {
60-
assignedIssues, _, err := c.client.Issues.ListByOrg(ctx, config.OrgName, &github.IssueListOptions{
67+
assignedIssues, _, err := c.client.Issues.ListByOrg(ctx, c.orgName, &github.IssueListOptions{
6168
Filter: "assigned",
6269
})
6370
if err != nil {
64-
return nil, fmt.Errorf("could not retrieve assigned %s issues: %w", config.OrgName, err)
71+
return nil, fmt.Errorf("could not retrieve assigned %s issues: %w", c.orgName, err)
6572
}
6673

6774
assignedPullRequests := make([]*github.Issue, 0)
6875
for _, i := range assignedIssues {
69-
if i.IsPullRequest() && *i.User.Login != config.UserName {
76+
if i.IsPullRequest() && *i.User.Login != c.userName {
7077
assignedPullRequests = append(assignedPullRequests, i)
7178
}
7279
}
7380
return entrello.CreateCardsFromIssues(assignedPullRequests)
7481
}
7582

7683
func (c Client) FetchMyPullRequests(ctx context.Context) ([]trello.Card, error) {
77-
createdIssues, _, err := c.client.Issues.ListByOrg(ctx, config.OrgName, &github.IssueListOptions{
84+
createdIssues, _, err := c.client.Issues.ListByOrg(ctx, c.orgName, &github.IssueListOptions{
7885
Filter: "created",
7986
})
8087
if err != nil {

0 commit comments

Comments
 (0)