Skip to content

Commit

Permalink
[GH-261] Handle revoked token (#308)
Browse files Browse the repository at this point in the history
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Michael Kochell <6913320+mickmister@users.noreply.github.com>
  • Loading branch information
3 people committed May 9, 2023
1 parent c3e7bbc commit 0e8c416
Show file tree
Hide file tree
Showing 13 changed files with 642 additions and 253 deletions.
65 changes: 59 additions & 6 deletions server/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/gorilla/mux"
"github.com/pkg/errors"
gitlabLib "github.com/xanzy/go-gitlab"
"golang.org/x/oauth2"

"github.com/mattermost/mattermost-plugin-api/experimental/bot/logger"
Expand Down Expand Up @@ -354,6 +355,14 @@ func (p *Plugin) completeConnectUserToGitlab(c *Context, w http.ResponseWriter,
return
}

if err = p.storeGitlabUserToken(userInfo.UserID, tok); err != nil {
c.Log.WithError(err).Warnf("Can't store user token")

rErr = errors.Wrap(err, "Unable to connect user to GitLab")
http.Error(w, rErr.Error(), http.StatusInternalServerError)
return
}

if err = p.storeGitlabToUserIDMapping(userInfo.GitlabUsername, userID); err != nil {
c.Log.WithError(err).Warnf("Can't store GitLab to user id mapping")
}
Expand Down Expand Up @@ -491,7 +500,7 @@ func (p *Plugin) getConnected(c *Context, w http.ResponseWriter, r *http.Request
}

info, _ := p.getGitlabUserInfoByMattermostID(c.UserID)
if info != nil && info.Token != nil {
if info != nil {
resp.Connected = true
resp.GitlabUsername = info.GitlabUsername
resp.GitlabClientID = config.GitlabOAuthClientID
Expand Down Expand Up @@ -522,7 +531,16 @@ func (p *Plugin) getConnected(c *Context, w http.ResponseWriter, r *http.Request
}

func (p *Plugin) getUnreads(c *UserContext, w http.ResponseWriter, r *http.Request) {
result, err := p.GitlabClient.GetUnreads(c.Ctx, c.GitlabInfo)
var result []*gitlabLib.Todo
err := p.useGitlabClient(c.GitlabInfo, func(info *gitlab.UserInfo, token *oauth2.Token) error {
resp, err := p.GitlabClient.GetUnreads(c.Ctx, info, token)
if err != nil {
return err
}
result = resp
return nil
})

if err != nil {
c.Log.WithError(err).Warnf("Unable to list unreads in GitLab API")
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: "Unable to list unreads in GitLab API.", StatusCode: http.StatusInternalServerError})
Expand All @@ -533,7 +551,16 @@ func (p *Plugin) getUnreads(c *UserContext, w http.ResponseWriter, r *http.Reque
}

func (p *Plugin) getReviews(c *UserContext, w http.ResponseWriter, r *http.Request) {
result, err := p.GitlabClient.GetReviews(c.Ctx, c.GitlabInfo)
var result []*gitlab.MergeRequest
err := p.useGitlabClient(c.GitlabInfo, func(info *gitlab.UserInfo, token *oauth2.Token) error {
resp, err := p.GitlabClient.GetReviews(c.Ctx, info, token)
if err != nil {
return err
}
result = resp
return nil
})

if err != nil {
c.Log.WithError(err).Warnf("Unable to list merge-request where assignee in GitLab API")
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: "Unable to list merge-request in GitLab API.", StatusCode: http.StatusInternalServerError})
Expand All @@ -544,7 +571,16 @@ func (p *Plugin) getReviews(c *UserContext, w http.ResponseWriter, r *http.Reque
}

func (p *Plugin) getYourPrs(c *UserContext, w http.ResponseWriter, r *http.Request) {
result, err := p.GitlabClient.GetYourPrs(c.Ctx, c.GitlabInfo)
var result []*gitlab.MergeRequest
err := p.useGitlabClient(c.GitlabInfo, func(info *gitlab.UserInfo, token *oauth2.Token) error {
resp, err := p.GitlabClient.GetYourPrs(c.Ctx, info, token)
if err != nil {
return err
}
result = resp
return nil
})

if err != nil {
c.Log.WithError(err).Warnf("Can't list merge-request where author in GitLab API")
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: "Unable to list merge-request in GitLab API.", StatusCode: http.StatusInternalServerError})
Expand All @@ -561,7 +597,15 @@ func (p *Plugin) getPrDetails(c *UserContext, w http.ResponseWriter, r *http.Req
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: fmt.Sprintf("Error decoding PRDetails JSON body. Error: %s", err.Error()), StatusCode: http.StatusBadRequest})
return
}
result, err := p.GitlabClient.GetYourPrDetails(c.Ctx, c.Log, c.GitlabInfo, prList)
var result []*gitlab.PRDetails
err := p.useGitlabClient(c.GitlabInfo, func(info *gitlab.UserInfo, token *oauth2.Token) error {
resp, err := p.GitlabClient.GetYourPrDetails(c.Ctx, c.Log, info, token, prList)
if err != nil {
return err
}
result = resp
return nil
})
if err != nil {
c.Log.WithError(err).Warnf("Can't list merge-request details in GitLab API")
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: fmt.Sprintf("Can't list merge-request details in GitLab API. Error: %s", err.Error()), StatusCode: http.StatusInternalServerError})
Expand All @@ -572,7 +616,16 @@ func (p *Plugin) getPrDetails(c *UserContext, w http.ResponseWriter, r *http.Req
}

func (p *Plugin) getYourAssignments(c *UserContext, w http.ResponseWriter, r *http.Request) {
result, err := p.GitlabClient.GetYourAssignments(c.Ctx, c.GitlabInfo)
var result []*gitlab.Issue
err := p.useGitlabClient(c.GitlabInfo, func(info *gitlab.UserInfo, token *oauth2.Token) error {
resp, err := p.GitlabClient.GetYourAssignments(c.Ctx, info, token)
if err != nil {
return err
}
result = resp
return nil
})

if err != nil {
c.Log.WithError(err).Warnf("Unable to list issue where assignee in GitLab API")
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: "Unable to list issue in GitLab API.", StatusCode: http.StatusInternalServerError})
Expand Down
13 changes: 1 addition & 12 deletions server/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ import (
"net/http"
"net/http/httptest"
"testing"
"time"

pluginapi "github.com/mattermost/mattermost-plugin-api"
"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/plugin/plugintest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/oauth2"

"github.com/mattermost/mattermost-plugin-gitlab/server/gitlab"
)
Expand All @@ -32,20 +30,11 @@ func TestGetChannelSubscriptions(t *testing.T) {
plugin := Plugin{configuration: &config}
plugin.initializeAPI()

token := oauth2.Token{
AccessToken: "access_token",
Expiry: time.Now().Add(1 * time.Hour),
}
info := gitlab.UserInfo{
UserID: "user_id",
Token: &token,
GitlabUsername: "gitlab_username",
GitlabUserID: 0,
}
encryptedToken, err := encrypt([]byte(config.EncryptionKey), info.Token.AccessToken)
require.NoError(t, err)

info.Token.AccessToken = encryptedToken

jsonInfo, err := json.Marshal(info)
require.NoError(t, err)
Expand All @@ -54,7 +43,7 @@ func TestGetChannelSubscriptions(t *testing.T) {
plugin.SetAPI(mock)
plugin.client = pluginapi.NewClient(plugin.API, plugin.Driver)

mock.On("KVGet", "user_id_gitlabtoken").Return(jsonInfo, nil).Once()
mock.On("KVGet", "user_id_userinfo").Return(jsonInfo, nil).Once()

return &plugin, mock
}
Expand Down
97 changes: 77 additions & 20 deletions server/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/plugin"
"github.com/pkg/errors"
gitlabLib "github.com/xanzy/go-gitlab"
"golang.org/x/oauth2"

"github.com/mattermost/mattermost-plugin-gitlab/server/gitlab"
)
Expand Down Expand Up @@ -234,7 +236,16 @@ func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*mo
}
return p.getCommandResponse(args, text), nil
case "me":
gitUser, err := p.GitlabClient.GetUserDetails(ctx, info)
var gitUser *gitlabLib.User
err := p.useGitlabClient(info, func(info *gitlab.UserInfo, token *oauth2.Token) error {
resp, err := p.GitlabClient.GetUserDetails(ctx, info, token)
if err != nil {
return err
}
gitUser = resp
return nil
})

if err != nil {
return p.getCommandResponse(args, "Encountered an error getting your GitLab profile."), nil
}
Expand Down Expand Up @@ -348,22 +359,46 @@ func (p *Plugin) webhookCommand(ctx context.Context, parameters []string, info *
}

namespace := parameters[1]
group, project, err := p.GitlabClient.ResolveNamespaceAndProject(ctx, info, namespace, enablePrivateRepo)
var group, project string
err := p.useGitlabClient(info, func(info *gitlab.UserInfo, token *oauth2.Token) error {
respGroup, respProject, err := p.GitlabClient.ResolveNamespaceAndProject(ctx, info, token, namespace, enablePrivateRepo)
if err != nil {
return err
}
group = respGroup
project = respProject
return nil
})

if err != nil {
return err.Error()
}

var webhookInfo []*gitlab.WebhookInfo
if project != "" {
webhookInfo, err = p.GitlabClient.GetProjectHooks(ctx, info, group, project)
err := p.useGitlabClient(info, func(info *gitlab.UserInfo, token *oauth2.Token) error {
resp, err := p.GitlabClient.GetProjectHooks(ctx, info, token, group, project)
if err != nil {
return err
}
webhookInfo = resp
return nil
})
if err != nil {
if strings.Contains(err.Error(), projectNotFoundError) {
return projectNotFoundMessage + namespace
}
return err.Error()
}
} else {
webhookInfo, err = p.GitlabClient.GetGroupHooks(ctx, info, group)
err := p.useGitlabClient(info, func(info *gitlab.UserInfo, token *oauth2.Token) error {
resp, err := p.GitlabClient.GetGroupHooks(ctx, info, token, group)
if err != nil {
return err
}
webhookInfo = resp
return nil
})
if err != nil {
if strings.Contains(err.Error(), groupNotFoundError) {
return groupNotFoundMessage + group
Expand Down Expand Up @@ -410,12 +445,21 @@ func (p *Plugin) webhookCommand(ctx context.Context, parameters []string, info *
}

namespace := parameters[1]
group, project, namespaceErr := p.GitlabClient.ResolveNamespaceAndProject(ctx, info, namespace, enablePrivateRepo)
var group, project string
namespaceErr := p.useGitlabClient(info, func(info *gitlab.UserInfo, token *oauth2.Token) error {
respGroup, respProject, err := p.GitlabClient.ResolveNamespaceAndProject(ctx, info, token, namespace, enablePrivateRepo)
if err != nil {
return err
}
group = respGroup
project = respProject
return nil
})
if namespaceErr != nil {
return namespaceErr.Error()
}

newWebhook, err := CreateHook(ctx, p.GitlabClient, info, group, project, hookOptions)
newWebhook, err := p.createHook(ctx, p.GitlabClient, info, group, project, hookOptions)
if err != nil {
return err.Error()
}
Expand Down Expand Up @@ -527,10 +571,16 @@ func (p *Plugin) subscriptionsListCommand(channelID string) string {

// subscriptionsAddCommand subscripes to A GitLab Project
func (p *Plugin) subscriptionsAddCommand(ctx context.Context, info *gitlab.UserInfo, config *configuration, fullPath, channelID, features string) string {
var err error
namespace, project, err := p.GitlabClient.ResolveNamespaceAndProject(
ctx, info, fullPath, config.EnablePrivateRepo)

var namespace, project string
err := p.useGitlabClient(info, func(info *gitlab.UserInfo, token *oauth2.Token) error {
respGroup, respProject, err := p.GitlabClient.ResolveNamespaceAndProject(ctx, info, token, fullPath, config.EnablePrivateRepo)
if err != nil {
return err
}
namespace = respGroup
project = respProject
return nil
})
if err != nil {
if errors.Is(err, gitlab.ErrNotFound) {
return "Resource with such path is not found."
Expand Down Expand Up @@ -641,19 +691,26 @@ func (p *Plugin) pipelinesCommand(ctx context.Context, parameters []string, chan

// pipelineRunCommand run a pipeline in a project
func (p *Plugin) pipelineRunCommand(ctx context.Context, namespace, ref, channelID string, info *gitlab.UserInfo) string {
group, projectName, err := p.GitlabClient.ResolveNamespaceAndProject(ctx, info, namespace, true)
if err != nil {
return err.Error()
}
project, err := p.GitlabClient.GetProject(ctx, info, group, projectName)
var pipelineInfo *gitlab.PipelineInfo
err := p.useGitlabClient(info, func(info *gitlab.UserInfo, token *oauth2.Token) error {
groupName, projectName, err := p.GitlabClient.ResolveNamespaceAndProject(ctx, info, token, namespace, true)
if err != nil {
return err
}
project, err := p.GitlabClient.GetProject(ctx, info, token, groupName, projectName)
if err != nil {
return err
}
projectID := fmt.Sprintf("%d", project.ID)
pipelineInfo, err = p.GitlabClient.TriggerProjectPipeline(info, token, projectID, ref)
if err != nil {
return errors.Wrapf(err, "failed to run pipeline for Project: :%s", projectName)
}
return nil
})
if err != nil {
return err.Error()
}
projectID := fmt.Sprintf("%d", project.ID)
pipelineInfo, err := p.GitlabClient.TriggerProjectPipeline(info, projectID, ref)
if err != nil {
return errors.Wrapf(err, "failed to run pipeline for Project: :%s", projectName).Error()
}
var txt string
if pipelineInfo == nil {
txt = "Currently there is no pipeline info"
Expand Down

0 comments on commit 0e8c416

Please sign in to comment.