diff --git a/server/atlassian_connect.go b/server/atlassian_connect.go index 29dbc8dd..e3e63fbc 100644 --- a/server/atlassian_connect.go +++ b/server/atlassian_connect.go @@ -12,9 +12,10 @@ import ( ) var atlassianConnectJSON = &Endpoint{ - Path: "/atlassian-connect.json", - Method: http.MethodGet, - Execute: renderAtlassianConnectJSON, + Path: "/atlassian-connect.json", + Method: http.MethodGet, + Execute: renderAtlassianConnectJSON, + IsAuthenticated: false, } func renderAtlassianConnectJSON(w http.ResponseWriter, r *http.Request, p *Plugin) { diff --git a/server/confluence_cloud.go b/server/confluence_cloud.go index 4a16f4aa..78ac4b05 100644 --- a/server/confluence_cloud.go +++ b/server/confluence_cloud.go @@ -11,9 +11,10 @@ import ( ) var confluenceCloudWebhook = &Endpoint{ - Path: "/cloud/{event:[A-Za-z0-9_]+}", - Method: http.MethodPost, - Execute: handleConfluenceCloudWebhook, + Path: "/cloud/{event:[A-Za-z0-9_]+}", + Method: http.MethodPost, + Execute: handleConfluenceCloudWebhook, + IsAuthenticated: false, } func handleConfluenceCloudWebhook(w http.ResponseWriter, r *http.Request, p *Plugin) { diff --git a/server/confluence_server.go b/server/confluence_server.go index 98bba394..31449c88 100644 --- a/server/confluence_server.go +++ b/server/confluence_server.go @@ -19,9 +19,10 @@ import ( ) var confluenceServerWebhook = &Endpoint{ - Path: "/server/webhook", - Method: http.MethodPost, - Execute: handleConfluenceServerWebhook, + Path: "/server/webhook", + Method: http.MethodPost, + Execute: handleConfluenceServerWebhook, + IsAuthenticated: false, } func handleConfluenceServerWebhook(w http.ResponseWriter, r *http.Request, p *Plugin) { @@ -124,7 +125,13 @@ func handleConfluenceServerWebhook(w http.ResponseWriter, r *http.Request, p *Pl notification.SendConfluenceNotifications(eventData, event.Event, p.BotUserID) } else { - event := serializer.ConfluenceServerEventFromJSON(r.Body) + event, err := serializer.ConfluenceServerEventFromJSON(r.Body) + if err != nil { + p.client.Log.Error("Error occurred while unmarshalling Confluence server webhook payload", "error", err) + http.Error(w, "Failed to unmarshal Confluence server webhook payload", http.StatusInternalServerError) + return + } + go service.SendConfluenceNotifications(event, event.Event) } diff --git a/server/controller.go b/server/controller.go index 56b5230d..dfcef7aa 100644 --- a/server/controller.go +++ b/server/controller.go @@ -17,9 +17,10 @@ import ( ) type Endpoint struct { - Path string - Method string - Execute func(w http.ResponseWriter, r *http.Request, p *Plugin) + Path string + Method string + Execute func(w http.ResponseWriter, r *http.Request, p *Plugin) + IsAuthenticated bool } // Endpoints is a map of endpoint key to endpoint object @@ -50,12 +51,27 @@ func (p *Plugin) InitAPI() *mux.Router { s := r.PathPrefix("/api/v1").Subrouter() for _, endpoint := range Endpoints { handler := endpoint.Execute - s.HandleFunc(endpoint.Path, p.wrapHandler(handler)).Methods(endpoint.Method) + if endpoint.IsAuthenticated { + s.HandleFunc(endpoint.Path, p.checkAuth(p.wrapHandler(handler))).Methods(endpoint.Method) + } else { + s.HandleFunc(endpoint.Path, p.wrapHandler(handler)).Methods(endpoint.Method) + } } return r } +func (p *Plugin) checkAuth(handler http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + userID := r.Header.Get(config.HeaderMattermostUserID) + if userID == "" { + http.Error(w, "Not authorized", http.StatusUnauthorized) + return + } + handler(w, r) + } +} + // wrapHandler ensures the plugin is passed to the handler func (p *Plugin) wrapHandler(handler func(http.ResponseWriter, *http.Request, *Plugin)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { diff --git a/server/edit_subscription.go b/server/edit_subscription.go index cfeccf0d..5580da6e 100644 --- a/server/edit_subscription.go +++ b/server/edit_subscription.go @@ -13,9 +13,10 @@ import ( ) var editChannelSubscription = &Endpoint{ - Path: "/{channelID:[A-Za-z0-9]+}/subscription/{type:[A-Za-z_]+}", - Method: http.MethodPut, - Execute: handleEditChannelSubscription, + Path: "/{channelID:[A-Za-z0-9]+}/subscription/{type:[A-Za-z_]+}", + Method: http.MethodPut, + Execute: handleEditChannelSubscription, + IsAuthenticated: true, } const subscriptionEditSuccess = "Your subscription has been edited successfully." diff --git a/server/get_subscription.go b/server/get_subscription.go index 8215f741..ad05c725 100644 --- a/server/get_subscription.go +++ b/server/get_subscription.go @@ -10,9 +10,10 @@ import ( ) var getChannelSubscription = &Endpoint{ - Path: "/{channelID:[A-Za-z0-9]+}/subscription", - Method: http.MethodGet, - Execute: handleGetChannelSubscription, + Path: "/{channelID:[A-Za-z0-9]+}/subscription", + Method: http.MethodGet, + Execute: handleGetChannelSubscription, + IsAuthenticated: true, } func handleGetChannelSubscription(w http.ResponseWriter, r *http.Request, p *Plugin) { diff --git a/server/get_subscriptions.go b/server/get_subscriptions.go index 2fad688e..832ad5fa 100644 --- a/server/get_subscriptions.go +++ b/server/get_subscriptions.go @@ -5,8 +5,6 @@ import ( "net/http" "strings" - "github.com/pkg/errors" - "github.com/mattermost/mattermost-plugin-confluence/server/config" "github.com/mattermost/mattermost-plugin-confluence/server/service" "github.com/mattermost/mattermost-plugin-confluence/server/store" @@ -15,17 +13,14 @@ import ( ) var autocompleteGetChannelSubscriptions = &Endpoint{ - Path: "/autocomplete/GetChannelSubscriptions", - Method: http.MethodGet, - Execute: handleGetChannelSubscriptions, + Path: "/autocomplete/GetChannelSubscriptions", + Method: http.MethodGet, + Execute: handleGetChannelSubscriptions, + IsAuthenticated: true, } func handleGetChannelSubscriptions(w http.ResponseWriter, r *http.Request, p *Plugin) { - mattermostUserID := r.Header.Get("Mattermost-User-Id") - if mattermostUserID == "" { - _, _ = respondErr(w, http.StatusUnauthorized, errors.New("not authorized")) - return - } + mattermostUserID := r.Header.Get(config.HeaderMattermostUserID) pluginConfig := config.GetConfig() if pluginConfig.ServerVersionGreaterthan9 { diff --git a/server/oauth2.go b/server/oauth2.go index b84d6874..a3fd49d3 100644 --- a/server/oauth2.go +++ b/server/oauth2.go @@ -9,19 +9,22 @@ const ( ) var userConnect = &Endpoint{ - Path: routeUserConnect, - Method: http.MethodGet, - Execute: httpOAuth2Connect, + Path: routeUserConnect, + Method: http.MethodGet, + Execute: httpOAuth2Connect, + IsAuthenticated: true, } var userConnectComplete = &Endpoint{ - Path: routeUserComplete, - Method: http.MethodGet, - Execute: httpOAuth2Complete, + Path: routeUserComplete, + Method: http.MethodGet, + Execute: httpOAuth2Complete, + IsAuthenticated: true, } var userConnectionInfo = &Endpoint{ - Path: routeUserConnectionInfo, - Method: http.MethodGet, - Execute: httpGetUserInfo, + Path: routeUserConnectionInfo, + Method: http.MethodGet, + Execute: httpGetUserInfo, + IsAuthenticated: true, } diff --git a/server/save_subscription.go b/server/save_subscription.go index be4cd236..281e58c5 100644 --- a/server/save_subscription.go +++ b/server/save_subscription.go @@ -15,9 +15,10 @@ import ( const subscriptionSaveSuccess = "Your subscription has been saved." var saveChannelSubscription = &Endpoint{ - Path: "/{channelID:[A-Za-z0-9]+}/subscription/{type:[A-Za-z_]+}", - Method: http.MethodPost, - Execute: handleSaveSubscription, + Path: "/{channelID:[A-Za-z0-9]+}/subscription/{type:[A-Za-z_]+}", + Method: http.MethodPost, + Execute: handleSaveSubscription, + IsAuthenticated: true, } func handleSaveSubscription(w http.ResponseWriter, r *http.Request, _ *Plugin) { diff --git a/server/serializer/confluence_server.go b/server/serializer/confluence_server.go index 1ac3db0c..fb03c24c 100644 --- a/server/serializer/confluence_server.go +++ b/server/serializer/confluence_server.go @@ -174,12 +174,14 @@ type ConfluenceServerWebhookPayload struct { Space SpacePayload `json:"space"` } -func ConfluenceServerEventFromJSON(data io.Reader) *ConfluenceServerEvent { +func ConfluenceServerEventFromJSON(data io.Reader) (*ConfluenceServerEvent, error) { var confluenceServerEvent ConfluenceServerEvent if err := json.NewDecoder(data).Decode(&confluenceServerEvent); err != nil { config.Mattermost.LogError("Unable to decode JSON for ConfluenceServerEvent.", "Error", err.Error()) + return nil, err } - return &confluenceServerEvent + + return &confluenceServerEvent, nil } func (e *ConfluenceServerEvent) GetUserDisplayName(withLink bool) string { diff --git a/server/user.go b/server/user.go index 4d0475fb..d2335481 100644 --- a/server/user.go +++ b/server/user.go @@ -31,13 +31,7 @@ func httpOAuth2Connect(w http.ResponseWriter, r *http.Request, p *Plugin) { } isAdmin := IsAdmin(w, r) - - mattermostUserID := r.Header.Get("Mattermost-User-Id") - if mattermostUserID == "" { - _, _ = respondErr(w, http.StatusUnauthorized, - errors.New("not authorized")) - return - } + mattermostUserID := r.Header.Get(config.HeaderMattermostUserID) instanceURL := config.GetConfig().GetConfluenceBaseURL() if instanceURL == "" { @@ -99,12 +93,6 @@ func httpOAuth2Complete(w http.ResponseWriter, r *http.Request, p *Plugin) { return } - mattermostUserID := r.Header.Get(config.HeaderMattermostUserID) - if mattermostUserID == "" { - http.Error(w, "not authorized", http.StatusUnauthorized) - return - } - instanceURL := config.GetConfig().GetConfluenceBaseURL() if instanceURL == "" { http.Error(w, "missing Confluence base url", http.StatusInternalServerError) @@ -113,7 +101,7 @@ func httpOAuth2Complete(w http.ResponseWriter, r *http.Request, p *Plugin) { isAdmin := IsAdmin(w, r) - cuser, mmuser, err := p.CompleteOAuth2(mattermostUserID, code, state, instanceURL, isAdmin) + cuser, mmuser, err := p.CompleteOAuth2(r.Header.Get(config.HeaderMattermostUserID), code, state, instanceURL, isAdmin) if err != nil { http.Error(w, "Failed to complete OAuth2 connection", http.StatusInternalServerError) return @@ -339,13 +327,7 @@ func httpGetUserInfo(w http.ResponseWriter, r *http.Request, p *Plugin) { return } - mattermostUserID := r.Header.Get("Mattermost-User-Id") - if mattermostUserID == "" { - _, _ = respondErr(w, http.StatusUnauthorized, - errors.New("not authorized")) - return - } - + mattermostUserID := r.Header.Get(config.HeaderMattermostUserID) serverVersionGreaterThan9 := config.GetConfig().ServerVersionGreaterthan9 if !serverVersionGreaterThan9 {