Forráskód Böngészése

wip -- handler for gitrepos endpoint

Alexander Belanger 4 éve
szülő
commit
eae00fe743

+ 1 - 4
api/server/handlers/gitinstallation/get.go

@@ -3,7 +3,6 @@ package gitinstallation
 import (
 	"net/http"
 
-	"github.com/porter-dev/porter/api/server/authz"
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/config"
@@ -13,7 +12,6 @@ import (
 
 type GitInstallationGetHandler struct {
 	handlers.PorterHandlerWriter
-	authz.KubernetesAgentGetter
 }
 
 func NewGitInstallationGetHandler(
@@ -21,8 +19,7 @@ func NewGitInstallationGetHandler(
 	writer shared.ResultWriter,
 ) *GitInstallationGetHandler {
 	return &GitInstallationGetHandler{
-		PorterHandlerWriter:   handlers.NewDefaultPorterHandler(config, nil, writer),
-		KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
+		PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
 	}
 }
 

+ 49 - 0
api/server/handlers/gitinstallation/helpers.go

@@ -0,0 +1,49 @@
+package gitinstallation
+
+import (
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/oauth"
+	"golang.org/x/oauth2"
+)
+
+// GetGithubAppOauthTokenFromRequest gets the GH oauth token from the request based on the currently
+// logged in user
+func GetGithubAppOauthTokenFromRequest(config *config.Config, r *http.Request) (*oauth2.Token, error) {
+	// read the user from context
+	user, _ := r.Context().Value(types.UserScope).(*models.User)
+
+	getOAuthInt := config.Repo.GithubAppOAuthIntegration().ReadGithubAppOauthIntegration
+	oauthInt, err := getOAuthInt(user.GithubAppIntegrationID)
+
+	if err != nil {
+		return nil, err
+	}
+
+	_, _, err = oauth.GetAccessToken(oauthInt.SharedOAuthModel,
+		&config.GithubAppConf.Config,
+		oauth.MakeUpdateGithubAppOauthIntegrationFunction(oauthInt, config.Repo),
+	)
+
+	if err != nil {
+		// try again, in case the token got updated
+		oauthInt2, err := getOAuthInt(user.GithubAppIntegrationID)
+
+		if err != nil || oauthInt2.Expiry == oauthInt.Expiry {
+			return nil, err
+		}
+		oauthInt.AccessToken = oauthInt2.AccessToken
+		oauthInt.RefreshToken = oauthInt2.RefreshToken
+		oauthInt.Expiry = oauthInt2.Expiry
+	}
+
+	return &oauth2.Token{
+		AccessToken:  string(oauthInt.AccessToken),
+		RefreshToken: string(oauthInt.RefreshToken),
+		Expiry:       oauthInt.Expiry,
+		TokenType:    "Bearer",
+	}, nil
+}

+ 97 - 0
api/server/handlers/gitinstallation/list.go

@@ -0,0 +1,97 @@
+package gitinstallation
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+
+	"github.com/google/go-github/github"
+	"github.com/porter-dev/porter/api/server/authz"
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"golang.org/x/oauth2"
+	"gorm.io/gorm"
+)
+
+type GitRepoListHandler struct {
+	handlers.PorterHandlerWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewGitRepoListHandler(
+	config *config.Config,
+	writer shared.ResultWriter,
+) *GitRepoListHandler {
+	return &GitRepoListHandler{
+		PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
+	}
+}
+
+func (c *GitRepoListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	res := types.ListGitInstallationIDsResponse{}
+	tok, err := GetGithubAppOauthTokenFromRequest(c.Config(), r)
+
+	if err != nil {
+		if err == gorm.ErrRecordNotFound {
+			// return empty array, this is not an error
+			c.WriteResult(w, r, res)
+		} else {
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		}
+
+		return
+	}
+
+	client := github.NewClient(c.Config().GithubAppConf.Client(oauth2.NoContext, tok))
+
+	accountIds := make([]int64, 0)
+
+	ghAuthUser, _, err := client.Users.Get(context.Background(), "")
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	accountIds = append(accountIds, *ghAuthUser.ID)
+
+	opts := &github.ListOptions{
+		PerPage: 100,
+		Page:    1,
+	}
+
+	for {
+		orgs, pages, err := client.Organizations.List(context.Background(), "", opts)
+
+		if err != nil {
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+			return
+		}
+
+		for _, org := range orgs {
+			accountIds = append(accountIds, *org.ID)
+		}
+
+		if pages.NextPage == 0 {
+			break
+		}
+	}
+
+	installationData, err := c.Repo().GithubAppInstallation().ReadGithubAppInstallationByAccountIDs(accountIds)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	installationIds := types.ListGitInstallationIDsResponse{}
+
+	for _, v := range installationData {
+		installationIds = append(installationIds, v.InstallationID)
+	}
+
+	json.NewEncoder(w).Encode(installationIds)
+}

+ 7 - 0
api/server/shared/config/config.go

@@ -8,6 +8,7 @@ import (
 	"github.com/porter-dev/porter/internal/auth/token"
 	"github.com/porter-dev/porter/internal/logger"
 	"github.com/porter-dev/porter/internal/notifier"
+	"github.com/porter-dev/porter/internal/oauth"
 	"github.com/porter-dev/porter/internal/repository"
 	"golang.org/x/oauth2"
 )
@@ -42,6 +43,12 @@ type Config struct {
 
 	// DOConf is the configuration for a DigitalOcean OAuth client
 	DOConf *oauth2.Config
+
+	// GithubConf is the configuration for a Github OAuth client
+	GithubConf *oauth2.Config
+
+	// GithubAppConf is the configuration for a Github App OAuth client
+	GithubAppConf *oauth.GithubAppConf
 }
 
 type ConfigLoader interface {

+ 56 - 21
api/server/shared/config/loader/loader.go

@@ -1,6 +1,8 @@
 package loader
 
 import (
+	"strconv"
+
 	"github.com/porter-dev/porter/api/server/shared/apierrors/alerter"
 	"github.com/porter-dev/porter/api/server/shared/config"
 	"github.com/porter-dev/porter/internal/adapter"
@@ -8,6 +10,7 @@ import (
 	"github.com/porter-dev/porter/internal/auth/token"
 	"github.com/porter-dev/porter/internal/notifier"
 	"github.com/porter-dev/porter/internal/notifier/sendgrid"
+	"github.com/porter-dev/porter/internal/oauth"
 	"github.com/porter-dev/porter/internal/repository/gorm"
 
 	lr "github.com/porter-dev/porter/internal/logger"
@@ -19,14 +22,21 @@ func NewEnvLoader() config.ConfigLoader {
 	return &EnvConfigLoader{}
 }
 
-func (e *EnvConfigLoader) LoadConfig() (*config.Config, error) {
+func (e *EnvConfigLoader) LoadConfig() (res *config.Config, err error) {
 	envConf, err := FromEnv()
 
 	if err != nil {
 		return nil, err
 	}
 
-	metadata := config.MetadataFromConf(envConf.ServerConf)
+	sc := envConf.ServerConf
+
+	res = &config.Config{
+		Logger:     lr.NewConsole(sc.Debug),
+		ServerConf: sc,
+	}
+
+	res.Metadata = config.MetadataFromConf(envConf.ServerConf)
 
 	db, err := adapter.New(envConf.DBConf)
 
@@ -46,12 +56,12 @@ func (e *EnvConfigLoader) LoadConfig() (*config.Config, error) {
 		key[i] = b
 	}
 
-	repo := gorm.NewRepository(db, &key)
+	res.Repo = gorm.NewRepository(db, &key)
 
 	// create the session store
-	store, err := sessionstore.NewStore(
+	res.Store, err = sessionstore.NewStore(
 		&sessionstore.NewStoreOpts{
-			SessionRepository: repo.Session(),
+			SessionRepository: res.Repo.Session(),
 			CookieSecrets:     envConf.ServerConf.CookieSecrets,
 		},
 	)
@@ -60,14 +70,14 @@ func (e *EnvConfigLoader) LoadConfig() (*config.Config, error) {
 		return nil, err
 	}
 
-	tokenConf := &token.TokenGeneratorConf{
+	res.TokenConf = &token.TokenGeneratorConf{
 		TokenSecret: envConf.ServerConf.TokenGeneratorSecret,
 	}
 
-	var notif notifier.UserNotifier = &notifier.EmptyUserNotifier{}
+	res.UserNotifier = &notifier.EmptyUserNotifier{}
 
-	if metadata.Email {
-		notif = sendgrid.NewUserNotifier(&sendgrid.Client{
+	if res.Metadata.Email {
+		res.UserNotifier = sendgrid.NewUserNotifier(&sendgrid.Client{
 			APIKey:                  envConf.ServerConf.SendgridAPIKey,
 			PWResetTemplateID:       envConf.ServerConf.SendgridPWResetTemplateID,
 			PWGHTemplateID:          envConf.ServerConf.SendgridPWGHTemplateID,
@@ -77,20 +87,45 @@ func (e *EnvConfigLoader) LoadConfig() (*config.Config, error) {
 		})
 	}
 
-	var errAlerter alerter.Alerter = alerter.NoOpAlerter{}
+	res.Alerter = alerter.NoOpAlerter{}
 
 	if envConf.ServerConf.SentryDSN != "" {
-		errAlerter, err = alerter.NewSentryAlerter(envConf.ServerConf.SentryDSN)
+		res.Alerter, err = alerter.NewSentryAlerter(envConf.ServerConf.SentryDSN)
+	}
+
+	if sc.DOClientID != "" && sc.DOClientSecret != "" {
+		res.DOConf = oauth.NewDigitalOceanClient(&oauth.Config{
+			ClientID:     sc.DOClientID,
+			ClientSecret: sc.DOClientSecret,
+			Scopes:       []string{"read", "write"},
+			BaseURL:      sc.ServerURL,
+		})
+	}
+
+	if sc.GithubClientID != "" && sc.GithubClientSecret != "" {
+		res.GithubConf = oauth.NewGithubClient(&oauth.Config{
+			ClientID:     sc.GithubClientID,
+			ClientSecret: sc.GithubClientSecret,
+			Scopes:       []string{"read:user", "user:email"},
+			BaseURL:      sc.ServerURL,
+		})
+	}
+
+	if sc.GithubAppClientID != "" &&
+		sc.GithubAppClientSecret != "" &&
+		sc.GithubAppName != "" &&
+		sc.GithubAppWebhookSecret != "" &&
+		sc.GithubAppSecretPath != "" &&
+		sc.GithubAppID != "" {
+		if AppID, err := strconv.ParseInt(sc.GithubAppID, 10, 64); err == nil {
+			res.GithubAppConf = oauth.NewGithubAppClient(&oauth.Config{
+				ClientID:     sc.GithubAppClientID,
+				ClientSecret: sc.GithubAppClientSecret,
+				Scopes:       []string{"read:user"},
+				BaseURL:      sc.ServerURL,
+			}, sc.GithubAppName, sc.GithubAppWebhookSecret, sc.GithubAppSecretPath, AppID)
+		}
 	}
 
-	return &config.Config{
-		Alerter:      errAlerter,
-		Logger:       lr.NewConsole(envConf.ServerConf.Debug),
-		Repo:         repo,
-		Metadata:     metadata,
-		Store:        store,
-		ServerConf:   envConf.ServerConf,
-		TokenConf:    tokenConf,
-		UserNotifier: notif,
-	}, nil
+	return res, nil
 }

+ 2 - 0
api/types/git_installation.go

@@ -11,3 +11,5 @@ type GitInstallation struct {
 }
 
 type GetGitInstallationResponse GitInstallation
+
+type ListGitInstallationIDsResponse []int64