Skip to content

Commit

Permalink
Authenticate Incoming HTTP Requests (#3)
Browse files Browse the repository at this point in the history
* authenticate incoming HTTP requests

* gofmt

* polish
  • Loading branch information
utkuufuk committed Apr 24, 2022
1 parent 3ec3017 commit 07eaeea
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 49 deletions.
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
PORT=XXXX
# GitHub Config
PERSONAL_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ORG_NAME=Portchain
USER_NAME=utkuufuk
SUBSCRIBED_REPOS=entrello,github-service

# Server Config
PORT=XXXX
SECRET=xxxxxxxxxxxxxxxxxxxx
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ A simple service to query GitHub issues & pull requests.
* See [Server Mode](#server-mode) for using it as an [entrello](https://github.com/utkuufuk/entrello) service.
* See [CLI Mode](#cli-mode) for using it as a CLI tool.

## Configuration
Put your environment variables in a file called `.env`.

See `.env.example` for reference.


## Server Mode
Start the server:
```sh
Expand Down Expand Up @@ -48,6 +42,19 @@ go run ./cmd/cli prlmy
go run ./cmd/cli prlme
```

## Configuration
Put your environment variables in a file called `.env`, based on `.env.example`.

| Environment Variable | Description |
|-|-|
| `PERSONAL_ACCESS_TOKEN` | GitHub personal access token |
| `ORG_NAME` | GitHub organization name (required for `prlo`, `prlmy` and `prlme`) |
| `USER_NAME` | GitHub user name (required for `prlo` and `prlme`) |
| `SUBSCRIBED_REPOS` | Subscribed GitHub repositories (required for `prlo`) |
| `PORT` | HTTP port (server mode only) |
| `SECRET` | API secret (server mode only, optional) |


## Running With Docker
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).

Expand Down
15 changes: 14 additions & 1 deletion cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,24 @@ import (
"os"

"github.com/utkuufuk/entrello/pkg/trello"
"github.com/utkuufuk/github-service/internal/config"
"github.com/utkuufuk/github-service/internal/github"
"github.com/utkuufuk/github-service/internal/logger"
)

var gitHubConfig config.GitHubConfig

func init() {
var err error
gitHubConfig, err = config.ParseGitHubConfig()
if err != nil {
logger.Error("Failed to parse config: %v", err)
os.Exit(1)
}
}

func main() {
client := github.GetClient()
client := github.GetClient(gitHubConfig)

if len(os.Args) == 1 {
displayCards(client.FetchAssignedIssues)
Expand Down
22 changes: 20 additions & 2 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,32 @@ import (
"encoding/json"
"fmt"
"net/http"
"os"

"github.com/utkuufuk/entrello/pkg/trello"
"github.com/utkuufuk/github-service/internal/config"
"github.com/utkuufuk/github-service/internal/github"
"github.com/utkuufuk/github-service/internal/logger"
)

var cfg config.Config

func init() {
var err error
cfg, err = config.ParseServerConfig()
if err != nil {
logger.Error("Failed to parse config: %v", err)
os.Exit(1)
}
}

func main() {
client := github.GetClient()
client := github.GetClient(cfg.GitHub)
http.HandleFunc("/entrello", handleGetRequest(client.FetchAssignedIssues))
http.HandleFunc("/entrello/prlo", handleGetRequest(client.FetchOtherPullRequests))
http.HandleFunc("/entrello/prlme", handleGetRequest(client.FetchOtherPullRequestsAssignedToMe))
http.HandleFunc("/entrello/prlmy", handleGetRequest(client.FetchMyPullRequests))
http.ListenAndServe(fmt.Sprintf(":%d", config.Port), nil)
http.ListenAndServe(fmt.Sprintf(":%d", cfg.Port), nil)
}

func handleGetRequest(
Expand All @@ -29,6 +42,11 @@ func handleGetRequest(
return
}

if cfg.Secret != "" && r.Header.Get("X-Api-Key") != cfg.Secret {
w.WriteHeader(http.StatusUnauthorized)
return
}

cards, err := fetchCards(r.Context())
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
Expand Down
65 changes: 39 additions & 26 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -1,50 +1,63 @@
package config

import (
"fmt"
"os"
"strconv"
"strings"

"github.com/joho/godotenv"
"github.com/utkuufuk/github-service/internal/logger"
)

var (
Port int
PersonalAccessToken string
type GitHubConfig struct {
OrgName string
UserName string
PersonalAccessToken string
SubscribedRepos []string
)
UserName string
}

type Config struct {
// GitHub config
GitHub GitHubConfig

// additional server mode config
Port int
Secret string
}

func init() {
var err error
func ParseGitHubConfig() (cfg GitHubConfig, err error) {
godotenv.Load()

port := os.Getenv("PORT")
Port, err = strconv.Atoi(port)
if err != nil {
logger.Error("PORT not set")
os.Exit(1)
cfg.PersonalAccessToken = os.Getenv("PERSONAL_ACCESS_TOKEN")
if cfg.PersonalAccessToken == "" {
return cfg, fmt.Errorf("PERSONAL_ACCESS_TOKEN not set")
}

PersonalAccessToken = os.Getenv("PERSONAL_ACCESS_TOKEN")
if PersonalAccessToken == "" {
logger.Error("PERSONAL_ACCESS_TOKEN not set")
os.Exit(1)
cfg.OrgName = os.Getenv("ORG_NAME")
if cfg.OrgName == "" {
return cfg, fmt.Errorf("ORG_NAME not set")
}

OrgName = os.Getenv("ORG_NAME")
if OrgName == "" {
logger.Error("ORG_NAME not set")
os.Exit(1)
cfg.UserName = os.Getenv("USER_NAME")
if cfg.UserName == "" {
return cfg, fmt.Errorf("USER_NAME not set")
}

UserName = os.Getenv("USER_NAME")
if UserName == "" {
logger.Error("USER_NAME not set")
os.Exit(1)
cfg.SubscribedRepos = strings.Split(os.Getenv("SUBSCRIBED_REPOS"), ",")

return cfg, nil
}

func ParseServerConfig() (cfg Config, err error) {
ghCfg, err := ParseGitHubConfig()
cfg.GitHub = ghCfg

port := os.Getenv("PORT")
cfg.Port, err = strconv.Atoi(port)
if err != nil {
return cfg, fmt.Errorf("PORT not set")
}

SubscribedRepos = strings.Split(os.Getenv("SUBSCRIBED_REPOS"), ",")
cfg.Secret = os.Getenv("SECRET")
return cfg, nil
}
33 changes: 20 additions & 13 deletions internal/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,21 @@ import (
)

type Client struct {
client *github.Client
client *github.Client
orgName string
subscribedRepos []string
userName string
}

func GetClient() Client {
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: config.PersonalAccessToken})
func GetClient(cfg config.GitHubConfig) Client {
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: cfg.PersonalAccessToken})
tc := oauth2.NewClient(context.Background(), ts)
client := github.NewClient(tc)
return Client{client}
return Client{
github.NewClient(tc),
cfg.OrgName,
cfg.SubscribedRepos,
cfg.UserName,
}
}

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

func (c Client) FetchOtherPullRequests(ctx context.Context) ([]trello.Card, error) {
pullRequests := make([]*github.PullRequest, 0)
for _, repo := range config.SubscribedRepos {
prs, _, err := c.client.PullRequests.List(ctx, config.OrgName, repo, nil)
for _, repo := range c.subscribedRepos {
prs, _, err := c.client.PullRequests.List(ctx, c.orgName, repo, nil)
if err != nil {
return nil, fmt.Errorf("could not retrieve pull requests from %s/%s: %w", config.OrgName, repo, err)
return nil, fmt.Errorf("could not retrieve pull requests from %s/%s: %w", c.orgName, repo, err)
}
pullRequests = append(pullRequests, prs...)
}

otherPullRequests := make([]*github.PullRequest, 0)
for _, i := range pullRequests {
if !*i.Draft && *i.User.Login != config.UserName && (i.Assignee == nil || *i.Assignee.Login != config.UserName) {
if !*i.Draft && *i.User.Login != c.userName && (i.Assignee == nil || *i.Assignee.Login != c.userName) {
otherPullRequests = append(otherPullRequests, i)
}
}
return entrello.CreateCardsFromPullRequests(otherPullRequests)
}

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

assignedPullRequests := make([]*github.Issue, 0)
for _, i := range assignedIssues {
if i.IsPullRequest() && *i.User.Login != config.UserName {
if i.IsPullRequest() && *i.User.Login != c.userName {
assignedPullRequests = append(assignedPullRequests, i)
}
}
return entrello.CreateCardsFromIssues(assignedPullRequests)
}

func (c Client) FetchMyPullRequests(ctx context.Context) ([]trello.Card, error) {
createdIssues, _, err := c.client.Issues.ListByOrg(ctx, config.OrgName, &github.IssueListOptions{
createdIssues, _, err := c.client.Issues.ListByOrg(ctx, c.orgName, &github.IssueListOptions{
Filter: "created",
})
if err != nil {
Expand Down

0 comments on commit 07eaeea

Please sign in to comment.