From fa1948f92d67ec71753fc0005a13e24f38f9cb08 Mon Sep 17 00:00:00 2001 From: grzegorz Date: Wed, 11 Mar 2020 23:53:30 +0100 Subject: [PATCH 1/7] Migrate logging to use RPC Logging methods + improve log messages --- server/plugin.go | 163 +++++++++++++++++++++++++----------------- server/plugin_test.go | 2 + 2 files changed, 99 insertions(+), 66 deletions(-) diff --git a/server/plugin.go b/server/plugin.go index 82f49fc52..b81caca9d 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -16,8 +16,6 @@ import ( "strings" "sync" - "github.com/mattermost/mattermost-server/v5/mlog" - "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/plugin" ) @@ -96,36 +94,36 @@ func (p *Plugin) handleAuthorizeInADD(w http.ResponseWriter, r *http.Request) { userID := r.URL.Query().Get("mattermost_user_id") if userID == "" { - fmt.Println("Not authorized") - http.Error(w, "Not authorized", http.StatusUnauthorized) + p.API.LogError("Cannot authorize in ADD. Missing 'mattermost_user_id' param") + http.Error(w, "Cannot authorize in ADD. Missing 'mattermost_user_id' param.", http.StatusUnauthorized) return } encodedAuthURL := r.URL.Query().Get("navigateTo") if encodedAuthURL == "" { - fmt.Println("Url Param 'navigateTo' is missing") - http.Error(w, "Url Param 'navigateTo' is missing", http.StatusBadRequest) + p.API.LogError("Cannot authorize in ADD. Missing 'navigateTo' param") + http.Error(w, "Cannot authorize in ADD. Missing 'navigateTo' param.", http.StatusBadRequest) return } authURL, err := url.QueryUnescape(encodedAuthURL) if err != nil { - fmt.Println(err.Error()) - http.Error(w, "cannot decode url", http.StatusBadRequest) + p.API.LogError("Cannot authorize in ADD. An error occured while decoding URL", "err", err) + http.Error(w, "Cannot authorize in ADD. An error occured while decoding URL.", http.StatusBadRequest) return } authURLValues, err := url.ParseQuery(authURL) if err != nil { - fmt.Println("cannot parse url") - http.Error(w, "cannot parse url", http.StatusBadRequest) + p.API.LogError("Cannot authorize in ADD. An error occured while parsing URL", "err", err) + http.Error(w, "Cannot authorize in ADD. An error occured while parsing URL.", http.StatusBadRequest) return } state := authURLValues.Get("state") if state == "" { - fmt.Println("Url Param 'state' is missing") - http.Error(w, "Url Param 'state' is missing", http.StatusBadRequest) + p.API.LogError("Cannot authorize in ADD. Missing state' param") + http.Error(w, "Cannot authorize in ADD. Missing state' param.", http.StatusBadRequest) return } @@ -139,33 +137,39 @@ func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) idToken := r.FormValue("id_token") if idToken == "" { - http.Error(w, "missing id_token", http.StatusBadRequest) + p.API.LogError("Cannot complete authorization in ADD. Missing 'id_token' param") + http.Error(w, "Cannot complete authorization in ADD. Missing 'id_token' param.", http.StatusBadRequest) return } state := r.FormValue("state") if state == "" { - http.Error(w, "missing state", http.StatusBadRequest) + p.API.LogError("Cannot complete authorization in ADD. Missing 'state' param") + http.Error(w, "Cannot complete authorization in ADD. Missing 'state' param.", http.StatusBadRequest) return } userID, err := p.API.KVGet(state) if err != nil { - fmt.Println(err.Message) - http.Error(w, "cannot get stored state", http.StatusBadRequest) + p.API.LogError("Cannot complete authorization in ADD. An error occured while fetching stored state", + "err", err) + http.Error(w, "Cannot complete authorization in ADD. An error occured while fetching stored state.", + http.StatusBadRequest) return } if userID == nil { - http.Error(w, "missing stored state", http.StatusBadRequest) + p.API.LogError("Cannot complete authorization in ADD. There is no stored state") + http.Error(w, "Cannot complete authorization in ADD. There is no stored state.", http.StatusBadRequest) return } err = p.API.KVDelete(state) if err != nil { - fmt.Println("cannot delete stored state", err) + p.API.LogWarn("An error occured while completing authorization in ADD. Cannot delete stored state", + "err", err) } p.API.PublishWebSocketEvent(WsEventAuthenticated, map[string]interface{}{ @@ -202,7 +206,8 @@ func (p *Plugin) handleClientID(w http.ResponseWriter, r *http.Request) { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - http.Error(w, "Not authorized", http.StatusUnauthorized) + p.API.LogError("Cannot fetch Client ID. Missing 'Mattermost-User-Id' header") + http.Error(w, "Cannot fetch Client ID. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) return } @@ -222,13 +227,15 @@ func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - http.Error(w, "Not authorized", http.StatusUnauthorized) + p.API.LogError("Cannot fetch Product Type. Missing 'Mattermost-User-Id' header") + http.Error(w, "Cannot fetch Product Type. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) return } config := p.getConfiguration() if config == nil { - http.Error(w, "Cannot fetch configuration", http.StatusUnauthorized) + p.API.LogError("Cannot fetch Product Type. Fetched configuration is empty") + http.Error(w, "Cannot fetch Product Type. Fetched configuration is empty.", http.StatusUnauthorized) return } @@ -237,8 +244,10 @@ func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) { if err := json.NewEncoder(w).Encode(ProductTypeResponse{ ProductType: p.getConfiguration().ProductType, }); err != nil { - fmt.Println(err.Error()) - http.Error(w, err.Error(), http.StatusInternalServerError) + p.API.LogError("Cannot fetch Product Type. An error occured while encoding the product type response", + "err", err) + http.Error(w, "Cannot fetch Product Type. An error occured while encoding the product type response.", + http.StatusInternalServerError) } return @@ -248,48 +257,52 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - fmt.Println("Request doesn't have Mattermost-User-Id header") - http.Error(w, "Not authorized", http.StatusUnauthorized) + p.API.LogError("Cannot register meeting. Missing 'Mattermost-User-Id' header") + http.Error(w, "Cannot register meeting. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) return } user, appErr := p.API.GetUser(userID) if appErr != nil { - fmt.Println(appErr.Error()) - http.Error(w, appErr.Error(), appErr.StatusCode) + p.API.LogError("Cannot register meeting. An error occured while fetching user", + "err", appErr) + http.Error(w, "Cannot register meeting. An error occured while fetching user.", appErr.StatusCode) return } if user == nil { - fmt.Println("User is nil") - http.Error(w, "User is nil", http.StatusUnauthorized) + p.API.LogError("Cannot register meeting. User with that ID doesn't exist", "userID", userID) + http.Error(w, "Cannot register meeting. User with that ID doesn't exist.", http.StatusUnauthorized) return } config := p.getConfiguration() if config == nil { - fmt.Println("Cannot fetch configuration") - http.Error(w, "Forbidden", http.StatusForbidden) + p.API.LogError("Cannot register meeting. Fetched configuration is empty") + http.Error(w, "Cannot register meeting. Fetched configuration is empty.", http.StatusForbidden) return } if config.ProductType == productTypeServer { - fmt.Println("Server version is set") - http.Error(w, "Forbidden", http.StatusForbidden) + p.API.LogError("Cannot register meeting. Product Type is not set as 'online'") + http.Error(w, "Cannot register meeting. Product Type is not set as 'online'.", http.StatusForbidden) return } var req StartMeetingRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - fmt.Println(err.Error()) - http.Error(w, err.Error(), http.StatusBadRequest) + p.API.LogError("Cannot register meeting. An error occured while decoding JSON body:", + "err", err) + http.Error(w, "Cannot register meeting. An error occured while decoding JSON body.", http.StatusBadRequest) return } if _, appErr = p.API.GetChannelMember(req.ChannelID, user.Id); appErr != nil { - fmt.Println(appErr.Error()) - http.Error(w, "Forbidden", http.StatusForbidden) + p.API.LogError("Cannot register meeting. An error occured while fetching channel membership", + "err", appErr.Error()) + http.Error(w, "Cannot register meeting. An error occured while fetching channel membership.", + http.StatusForbidden) return } @@ -314,14 +327,18 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r post, appErr = p.API.CreatePost(post) if appErr != nil { - fmt.Println(appErr.Error()) - http.Error(w, appErr.Error(), appErr.StatusCode) + p.API.LogError("Cannot register meeting. An error occured while creating a post with the meeting", + "err", appErr) + http.Error(w, "Cannot register meeting. An error occured while creating a post with the meeting.", + appErr.StatusCode) return } if appErr = p.API.KVSet(fmt.Sprintf("%v%v", PostMeetingKey, req.MeetingID), []byte(post.Id)); appErr != nil { - fmt.Println(appErr.Error()) - http.Error(w, appErr.Error(), appErr.StatusCode) + p.API.LogError("Cannot register meeting. An error occured while saving the meeting ID in the database", + "err", appErr) + http.Error(w, "Cannot register meeting. An error occured while saving the meeting ID in the database.", + appErr.StatusCode) return } @@ -331,15 +348,15 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *http.Request) { config := p.getConfiguration() if config.ProductType == productTypeOnline { - mlog.Error("Cannot create meeting in the server version when the online is set") - http.Error(w, "Forbidden", http.StatusForbidden) + p.API.LogError("Cannot create meeting. Product Type is not set as 'server'") + http.Error(w, "Cannot create meeting. Product Type is not set as 'server'.", http.StatusForbidden) return } userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - mlog.Error("Request doesn't have Mattermost-User-Id header") - http.Error(w, "Not authorized", http.StatusUnauthorized) + p.API.LogError("Cannot create meeting. Missing 'Mattermost-User-Id' header") + http.Error(w, "Cannot create meeting. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) return } @@ -347,34 +364,39 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht var appError *model.AppError user, appError = p.API.GetUser(userID) if appError != nil { - mlog.Error("Error getting user: " + appError.Error()) - http.Error(w, appError.Error(), appError.StatusCode) + p.API.LogError("Cannot create meeting. An error occured while fetching user", + "err", appError) + http.Error(w, "Cannot create meeting. An error occured while fetching user.", appError.StatusCode) return } if user == nil { - mlog.Error("User with that id doesn't exist: " + userID) - http.Error(w, "User is nil", http.StatusUnauthorized) + p.API.LogError("Cannot create meeting. User with that id doesn't exist", "userID", userID) + http.Error(w, "Cannot create meeting. User with that id doesn't exist.", http.StatusUnauthorized) return } var req StartServerMeetingRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - mlog.Error("Error decoding JSON body: " + err.Error()) - http.Error(w, err.Error(), http.StatusBadRequest) + p.API.LogError("Cannot create meeting. An error occured while decoding JSON body", "err", err) + http.Error(w, "Cannot create meeting. An error occured while decoding JSON body.", http.StatusBadRequest) return } if _, err := p.API.GetChannelMember(req.ChannelID, user.Id); err != nil { - mlog.Error("Error getting channel member: " + err.Error()) - http.Error(w, "Forbidden", http.StatusForbidden) + p.API.LogError("Cannot create meeting. An error occured while fetching channel membership", + "err", err) + http.Error(w, "Cannot create meeting. An error occured while fetching channel membership.", + http.StatusForbidden) return } applicationState, apiErr := p.fetchOnlineMeetingsURL() if apiErr != nil { - mlog.Error("Error fetching meetings resource url: " + apiErr.Message) - http.Error(w, apiErr.Message, http.StatusInternalServerError) + p.API.LogError("Cannot create meeting. An error occured while fetching meetings resource URL", + "err", apiErr.Message) + http.Error(w, "Cannot create meeting. An error occured while fetching meetings resource URL.", + http.StatusInternalServerError) return } @@ -387,8 +409,10 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht applicationState.Token, ) if err != nil { - mlog.Error("Error creating a new meeting: " + err.Error()) - http.Error(w, err.Error(), http.StatusInternalServerError) + p.API.LogError("Cannot create meeting. An error occured while creating a new meeting in UCWA", + "err", err) + http.Error(w, "Cannot create meeting. An error occured while creating a new meeting in UCWA.", + http.StatusInternalServerError) return } @@ -413,21 +437,27 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht post, appErr := p.API.CreatePost(post) if appErr != nil { - mlog.Error("Error creating a new post with the new meeting: " + appErr.Error()) - http.Error(w, appErr.Error(), http.StatusInternalServerError) + p.API.LogError("Cannot create meeting. An error occured while creating a post with a meeting", + "err", appErr) + http.Error(w, "Cannot create meeting. An error occured while creating a post with a meeting.", + http.StatusInternalServerError) return } appErr = p.API.KVSet(fmt.Sprintf("%v%v", PostMeetingKey, newMeetingResponse.MeetingID), []byte(post.Id)) if appErr != nil { - mlog.Error("Error writing meeting id to the database: " + appErr.Error()) - http.Error(w, appErr.Error(), http.StatusInternalServerError) + p.API.LogError("Cannot create meeting. An error occured while saving the meeting ID in the database", + "err", appErr) + http.Error(w, "Cannot create meeting. An error occured while saving the meeting ID in the database.", + http.StatusInternalServerError) return } if err := json.NewEncoder(w).Encode(&newMeetingResponse); err != nil { - mlog.Error("Error encoding the new meeting response: " + err.Error()) - http.Error(w, err.Error(), http.StatusInternalServerError) + p.API.LogError("Cannot create meeting. An error occured while encoding the new meeting response", + "err", err) + http.Error(w, "Cannot create meeting. An error occured while encoding the new meeting response.", + http.StatusInternalServerError) } return @@ -441,8 +471,8 @@ func (p *Plugin) handleProfileImage(w http.ResponseWriter, r *http.Request) { } img, err := os.Open(filepath.Join(bundlePath, "assets", "profile.png")) if err != nil { + p.API.LogError("Cannot read Skype 4 Business plugin profile image", "err", err) http.NotFound(w, r) - mlog.Error("Unable to read Skype 4 Business plugin profile image, err=" + err.Error()) return } defer img.Close() @@ -515,7 +545,7 @@ func (p *Plugin) getApplicationState(discoveryURL string) (*ApplicationState, *A applicationsResourceName := p.extractResourceNameFromApplicationsURL(applicationsURL) if applicationsResourceName != resourceName { - mlog.Warn("Resource from applications url is not the same as resource name from user url") + p.API.LogWarn("Resource from applications URL is not the same as resource name from user URL") authHeader, err := p.client.performRequestAndGetAuthHeader(applicationsURL) if err != nil { @@ -599,7 +629,8 @@ func (p *Plugin) determineRootURL(domain string) (*string, *APIError) { return &o.url, nil } - mlog.Warn("Error performing autodiscovery with " + o.name + " root URL: " + err.Error()) + p.API.LogWarn("An error occued while performing autodiscovery with "+o.name+" root URL", + "err", err) } return nil, &APIError{ diff --git a/server/plugin_test.go b/server/plugin_test.go index 369bee5ed..f132ee0c2 100644 --- a/server/plugin_test.go +++ b/server/plugin_test.go @@ -132,6 +132,7 @@ func TestPlugin(t *testing.T) { api.On("KVGet", "123").Return([]byte("theuserid"), (*model.AppError)(nil)) api.On("KVDelete", "123").Return((*model.AppError)(nil)) api.On("PublishWebSocketEvent", "authenticated", mock.Anything, mock.Anything).Return() + api.On("LogError", mock.AnythingOfTypeArgument("string"), mock.AnythingOfTypeArgument("string")).Return() p := Plugin{} p.setConfiguration(&configuration{ @@ -239,6 +240,7 @@ func makeMocks(mmChannelID string, mmUser model.User, splitDomain bool) Mocks { Return(&model.Post{}, (*model.AppError)(nil)).Times(1) api.On("KVSet", expectedPostMeetingID, mock.AnythingOfType("[]uint8")). Return((*model.AppError)(nil)).Times(1) + api.On("LogWarn", mock.AnythingOfType("string")).Return() clientMock := ClientMock{} clientMock.On("performDiscovery", "https://lyncdiscover."+firstDomain). From bff973698ced80d303b3c5a06d2f4bac52e6d81f Mon Sep 17 00:00:00 2001 From: grzegorz Date: Fri, 13 Mar 2020 04:01:22 +0100 Subject: [PATCH 2/7] * change LogError to LogWarn in most cases * change handleAuthorizeInADD function to return error --- server/plugin.go | 85 +++++++++++++++++++++---------------------- server/plugin_test.go | 4 +- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/server/plugin.go b/server/plugin.go index d6d809087..fc9c49c1b 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -5,6 +5,7 @@ package main import ( "encoding/json" + "errors" "fmt" "io" "net/http" @@ -91,7 +92,12 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req case "/api/v1/client_id": p.handleClientID(w, r) case "/api/v1/auth": - p.handleAuthorizeInADD(w, r) + err := p.handleAuthorizeInADD(w, r) + if err != nil { + p.API.LogWarn(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + } + case "/api/v1/auth_redirect": p.completeAuthorizeInADD(w, r) case "/api/v1/register_meeting_from_online_version": @@ -103,47 +109,38 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req } } -func (p *Plugin) handleAuthorizeInADD(w http.ResponseWriter, r *http.Request) { +func (p *Plugin) handleAuthorizeInADD(w http.ResponseWriter, r *http.Request) error { userID := r.URL.Query().Get("mattermost_user_id") if userID == "" { - p.API.LogError("Cannot authorize in ADD. Missing 'mattermost_user_id' param") - http.Error(w, "Cannot authorize in ADD. Missing 'mattermost_user_id' param.", http.StatusUnauthorized) - return + return errors.New("cannot authorize in ADD. Missing 'mattermost_user_id' param") } encodedAuthURL := r.URL.Query().Get("navigateTo") if encodedAuthURL == "" { - p.API.LogError("Cannot authorize in ADD. Missing 'navigateTo' param") - http.Error(w, "Cannot authorize in ADD. Missing 'navigateTo' param.", http.StatusBadRequest) - return + return errors.New("cannot authorize in ADD. Missing 'navigateTo' param") } authURL, err := url.QueryUnescape(encodedAuthURL) if err != nil { - p.API.LogError("Cannot authorize in ADD. An error occured while decoding URL", "err", err) - http.Error(w, "Cannot authorize in ADD. An error occured while decoding URL.", http.StatusBadRequest) - return + return fmt.Errorf("cannot authorize in ADD. An error occured while decoding URL: %w", err) } authURLValues, err := url.ParseQuery(authURL) if err != nil { - p.API.LogError("Cannot authorize in ADD. An error occured while parsing URL", "err", err) - http.Error(w, "Cannot authorize in ADD. An error occured while parsing URL.", http.StatusBadRequest) - return + return fmt.Errorf("cannot authorize in ADD. An error occured while parsing URL: %w", err) } state := authURLValues.Get("state") if state == "" { - p.API.LogError("Cannot authorize in ADD. Missing state' param") - http.Error(w, "Cannot authorize in ADD. Missing state' param.", http.StatusBadRequest) - return + return errors.New("cannot authorize in ADD. Missing state' param") } p.API.KVSet(state, []byte(strings.TrimSpace(userID))) http.Redirect(w, r, authURL, http.StatusFound) + return nil } func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) { @@ -151,7 +148,7 @@ func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) idToken := r.FormValue("id_token") if idToken == "" { - p.API.LogError("Cannot complete authorization in ADD. Missing 'id_token' param") + p.API.LogWarn("Cannot complete authorization in ADD. Missing 'id_token' param") http.Error(w, "Cannot complete authorization in ADD. Missing 'id_token' param.", http.StatusBadRequest) return } @@ -159,7 +156,7 @@ func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) state := r.FormValue("state") if state == "" { - p.API.LogError("Cannot complete authorization in ADD. Missing 'state' param") + p.API.LogWarn("Cannot complete authorization in ADD. Missing 'state' param") http.Error(w, "Cannot complete authorization in ADD. Missing 'state' param.", http.StatusBadRequest) return } @@ -167,7 +164,7 @@ func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) userID, err := p.API.KVGet(state) if err != nil { - p.API.LogError("Cannot complete authorization in ADD. An error occured while fetching stored state", + p.API.LogWarn("Cannot complete authorization in ADD. An error occured while fetching stored state", "err", err) http.Error(w, "Cannot complete authorization in ADD. An error occured while fetching stored state.", http.StatusBadRequest) @@ -175,7 +172,7 @@ func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) } if userID == nil { - p.API.LogError("Cannot complete authorization in ADD. There is no stored state") + p.API.LogWarn("Cannot complete authorization in ADD. There is no stored state") http.Error(w, "Cannot complete authorization in ADD. There is no stored state.", http.StatusBadRequest) return } @@ -220,7 +217,7 @@ func (p *Plugin) handleClientID(w http.ResponseWriter, r *http.Request) { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - p.API.LogError("Cannot fetch Client ID. Missing 'Mattermost-User-Id' header") + p.API.LogWarn("Cannot fetch Client ID. Missing 'Mattermost-User-Id' header") http.Error(w, "Cannot fetch Client ID. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) return } @@ -241,14 +238,14 @@ func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - p.API.LogError("Cannot fetch Product Type. Missing 'Mattermost-User-Id' header") + p.API.LogWarn("Cannot fetch Product Type. Missing 'Mattermost-User-Id' header") http.Error(w, "Cannot fetch Product Type. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) return } config := p.getConfiguration() if config == nil { - p.API.LogError("Cannot fetch Product Type. Fetched configuration is empty") + p.API.LogWarn("Cannot fetch Product Type. Fetched configuration is empty") http.Error(w, "Cannot fetch Product Type. Fetched configuration is empty.", http.StatusUnauthorized) return } @@ -258,7 +255,7 @@ func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) { if err := json.NewEncoder(w).Encode(ProductTypeResponse{ ProductType: p.getConfiguration().ProductType, }); err != nil { - p.API.LogError("Cannot fetch Product Type. An error occured while encoding the product type response", + p.API.LogWarn("Cannot fetch Product Type. An error occured while encoding the product type response", "err", err) http.Error(w, "Cannot fetch Product Type. An error occured while encoding the product type response.", http.StatusInternalServerError) @@ -271,34 +268,34 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - p.API.LogError("Cannot register meeting. Missing 'Mattermost-User-Id' header") + p.API.LogWarn("Cannot register meeting. Missing 'Mattermost-User-Id' header") http.Error(w, "Cannot register meeting. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) return } user, appErr := p.API.GetUser(userID) if appErr != nil { - p.API.LogError("Cannot register meeting. An error occured while fetching user", + p.API.LogWarn("Cannot register meeting. An error occured while fetching user", "err", appErr) http.Error(w, "Cannot register meeting. An error occured while fetching user.", appErr.StatusCode) return } if user == nil { - p.API.LogError("Cannot register meeting. User with that ID doesn't exist", "userID", userID) + p.API.LogWarn("Cannot register meeting. User with that ID doesn't exist", "userID", userID) http.Error(w, "Cannot register meeting. User with that ID doesn't exist.", http.StatusUnauthorized) return } config := p.getConfiguration() if config == nil { - p.API.LogError("Cannot register meeting. Fetched configuration is empty") + p.API.LogWarn("Cannot register meeting. Fetched configuration is empty") http.Error(w, "Cannot register meeting. Fetched configuration is empty.", http.StatusForbidden) return } if config.ProductType == productTypeServer { - p.API.LogError("Cannot register meeting. Product Type is not set as 'online'") + p.API.LogWarn("Cannot register meeting. Product Type is not set as 'online'") http.Error(w, "Cannot register meeting. Product Type is not set as 'online'.", http.StatusForbidden) return } @@ -306,14 +303,14 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r var req StartMeetingRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - p.API.LogError("Cannot register meeting. An error occured while decoding JSON body:", + p.API.LogWarn("Cannot register meeting. An error occured while decoding JSON body:", "err", err) http.Error(w, "Cannot register meeting. An error occured while decoding JSON body.", http.StatusBadRequest) return } if _, appErr = p.API.GetChannelMember(req.ChannelID, user.Id); appErr != nil { - p.API.LogError("Cannot register meeting. An error occured while fetching channel membership", + p.API.LogWarn("Cannot register meeting. An error occured while fetching channel membership", "err", appErr.Error()) http.Error(w, "Cannot register meeting. An error occured while fetching channel membership.", http.StatusForbidden) @@ -341,7 +338,7 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r post, appErr = p.API.CreatePost(post) if appErr != nil { - p.API.LogError("Cannot register meeting. An error occured while creating a post with the meeting", + p.API.LogWarn("Cannot register meeting. An error occured while creating a post with the meeting", "err", appErr) http.Error(w, "Cannot register meeting. An error occured while creating a post with the meeting.", appErr.StatusCode) @@ -349,7 +346,7 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r } if appErr = p.API.KVSet(fmt.Sprintf("%v%v", PostMeetingKey, req.MeetingID), []byte(post.Id)); appErr != nil { - p.API.LogError("Cannot register meeting. An error occured while saving the meeting ID in the database", + p.API.LogWarn("Cannot register meeting. An error occured while saving the meeting ID in the database", "err", appErr) http.Error(w, "Cannot register meeting. An error occured while saving the meeting ID in the database.", appErr.StatusCode) @@ -362,14 +359,14 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *http.Request) { config := p.getConfiguration() if config.ProductType == productTypeOnline { - p.API.LogError("Cannot create meeting. Product Type is not set as 'server'") + p.API.LogWarn("Cannot create meeting. Product Type is not set as 'server'") http.Error(w, "Cannot create meeting. Product Type is not set as 'server'.", http.StatusForbidden) return } userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - p.API.LogError("Cannot create meeting. Missing 'Mattermost-User-Id' header") + p.API.LogWarn("Cannot create meeting. Missing 'Mattermost-User-Id' header") http.Error(w, "Cannot create meeting. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) return } @@ -378,27 +375,27 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht var appError *model.AppError user, appError = p.API.GetUser(userID) if appError != nil { - p.API.LogError("Cannot create meeting. An error occured while fetching user", + p.API.LogWarn("Cannot create meeting. An error occured while fetching user", "err", appError) http.Error(w, "Cannot create meeting. An error occured while fetching user.", appError.StatusCode) return } if user == nil { - p.API.LogError("Cannot create meeting. User with that id doesn't exist", "userID", userID) + p.API.LogWarn("Cannot create meeting. User with that id doesn't exist", "userID", userID) http.Error(w, "Cannot create meeting. User with that id doesn't exist.", http.StatusUnauthorized) return } var req StartServerMeetingRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - p.API.LogError("Cannot create meeting. An error occured while decoding JSON body", "err", err) + p.API.LogWarn("Cannot create meeting. An error occured while decoding JSON body", "err", err) http.Error(w, "Cannot create meeting. An error occured while decoding JSON body.", http.StatusBadRequest) return } if _, err := p.API.GetChannelMember(req.ChannelID, user.Id); err != nil { - p.API.LogError("Cannot create meeting. An error occured while fetching channel membership", + p.API.LogWarn("Cannot create meeting. An error occured while fetching channel membership", "err", err) http.Error(w, "Cannot create meeting. An error occured while fetching channel membership.", http.StatusForbidden) @@ -451,7 +448,7 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht post, appErr := p.API.CreatePost(post) if appErr != nil { - p.API.LogError("Cannot create meeting. An error occured while creating a post with a meeting", + p.API.LogWarn("Cannot create meeting. An error occured while creating a post with a meeting", "err", appErr) http.Error(w, "Cannot create meeting. An error occured while creating a post with a meeting.", http.StatusInternalServerError) @@ -460,7 +457,7 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht appErr = p.API.KVSet(fmt.Sprintf("%v%v", PostMeetingKey, newMeetingResponse.MeetingID), []byte(post.Id)) if appErr != nil { - p.API.LogError("Cannot create meeting. An error occured while saving the meeting ID in the database", + p.API.LogWarn("Cannot create meeting. An error occured while saving the meeting ID in the database", "err", appErr) http.Error(w, "Cannot create meeting. An error occured while saving the meeting ID in the database.", http.StatusInternalServerError) @@ -468,7 +465,7 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht } if err := json.NewEncoder(w).Encode(&newMeetingResponse); err != nil { - p.API.LogError("Cannot create meeting. An error occured while encoding the new meeting response", + p.API.LogWarn("Cannot create meeting. An error occured while encoding the new meeting response", "err", err) http.Error(w, "Cannot create meeting. An error occured while encoding the new meeting response.", http.StatusInternalServerError) @@ -485,7 +482,7 @@ func (p *Plugin) handleProfileImage(w http.ResponseWriter, r *http.Request) { } img, err := os.Open(filepath.Join(bundlePath, "assets", "profile.png")) if err != nil { - p.API.LogError("Cannot read Skype 4 Business plugin profile image", "err", err) + p.API.LogWarn("Cannot read Skype 4 Business plugin profile image", "err", err) http.NotFound(w, r) return } diff --git a/server/plugin_test.go b/server/plugin_test.go index f132ee0c2..abd6d56a5 100644 --- a/server/plugin_test.go +++ b/server/plugin_test.go @@ -83,7 +83,7 @@ func TestPlugin(t *testing.T) { }, "InvalidAuthorizeInADDRequest1": { Request: invalidAuthorizeInADDRequest1, - ExpectedStatusCode: http.StatusUnauthorized, + ExpectedStatusCode: http.StatusBadRequest, }, "InvalidAuthorizeInADDRequest2": { Request: invalidAuthorizeInADDRequest2, @@ -132,7 +132,7 @@ func TestPlugin(t *testing.T) { api.On("KVGet", "123").Return([]byte("theuserid"), (*model.AppError)(nil)) api.On("KVDelete", "123").Return((*model.AppError)(nil)) api.On("PublishWebSocketEvent", "authenticated", mock.Anything, mock.Anything).Return() - api.On("LogError", mock.AnythingOfTypeArgument("string"), mock.AnythingOfTypeArgument("string")).Return() + api.On("LogWarn", mock.AnythingOfTypeArgument("string"), mock.AnythingOfTypeArgument("string")).Return() p := Plugin{} p.setConfiguration(&configuration{ From 573480400efe65651f0a4bc838a4b1e9ef0d9bba Mon Sep 17 00:00:00 2001 From: grzegorz Date: Sat, 14 Mar 2020 19:05:06 +0100 Subject: [PATCH 3/7] * change handleProductType, handleClientID, completeAuthorizeInADD and handleRegisterMeetingFromOnlineVersion to return error --- server/plugin.go | 121 +++++++++++++++--------------------------- server/plugin_test.go | 6 +-- 2 files changed, 46 insertions(+), 81 deletions(-) diff --git a/server/plugin.go b/server/plugin.go index fc9c49c1b..69c4b70a9 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -83,30 +83,31 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req return } + var err error path := r.URL.Path switch path { case "/api/v1/product_type": - p.handleProductType(w, r) + err = p.handleProductType(w, r) case "/api/v1/create_meeting_in_server_version": p.handleCreateMeetingInServerVersion(w, r) case "/api/v1/client_id": - p.handleClientID(w, r) + err = p.handleClientID(w, r) case "/api/v1/auth": - err := p.handleAuthorizeInADD(w, r) - if err != nil { - p.API.LogWarn(err.Error()) - http.Error(w, err.Error(), http.StatusBadRequest) - } - + err = p.handleAuthorizeInADD(w, r) case "/api/v1/auth_redirect": - p.completeAuthorizeInADD(w, r) + err = p.completeAuthorizeInADD(w, r) case "/api/v1/register_meeting_from_online_version": - p.handleRegisterMeetingFromOnlineVersion(w, r) + err = p.handleRegisterMeetingFromOnlineVersion(w, r) case "/api/v1/assets/profile.png": p.handleProfileImage(w, r) default: http.NotFound(w, r) } + + if err != nil { + p.API.LogWarn(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + } } func (p *Plugin) handleAuthorizeInADD(w http.ResponseWriter, r *http.Request) error { @@ -143,38 +144,29 @@ func (p *Plugin) handleAuthorizeInADD(w http.ResponseWriter, r *http.Request) er return nil } -func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) { +func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) error { idToken := r.FormValue("id_token") if idToken == "" { - p.API.LogWarn("Cannot complete authorization in ADD. Missing 'id_token' param") - http.Error(w, "Cannot complete authorization in ADD. Missing 'id_token' param.", http.StatusBadRequest) - return + return errors.New("cannot complete authorization in ADD. Missing 'id_token' param") } state := r.FormValue("state") if state == "" { - p.API.LogWarn("Cannot complete authorization in ADD. Missing 'state' param") - http.Error(w, "Cannot complete authorization in ADD. Missing 'state' param.", http.StatusBadRequest) - return + return errors.New("cannot complete authorization in ADD. Missing 'state' param") } userID, err := p.API.KVGet(state) if err != nil { - p.API.LogWarn("Cannot complete authorization in ADD. An error occured while fetching stored state", - "err", err) - http.Error(w, "Cannot complete authorization in ADD. An error occured while fetching stored state.", - http.StatusBadRequest) - return + return fmt.Errorf("cannot complete authorization in ADD. An error occured while fetching stored state: %w", + err) } if userID == nil { - p.API.LogWarn("Cannot complete authorization in ADD. There is no stored state") - http.Error(w, "Cannot complete authorization in ADD. There is no stored state.", http.StatusBadRequest) - return + return errors.New("cannot complete authorization in ADD. There is no stored state") } err = p.API.KVDelete(state) @@ -210,16 +202,16 @@ func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "text/html") w.Write([]byte(html)) + + return nil } -func (p *Plugin) handleClientID(w http.ResponseWriter, r *http.Request) { +func (p *Plugin) handleClientID(w http.ResponseWriter, r *http.Request) error { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - p.API.LogWarn("Cannot fetch Client ID. Missing 'Mattermost-User-Id' header") - http.Error(w, "Cannot fetch Client ID. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) - return + return errors.New("cannot fetch Client ID. Missing 'Mattermost-User-Id' header") } w.Header().Set("Content-Type", "application/json") @@ -231,23 +223,19 @@ func (p *Plugin) handleClientID(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusInternalServerError) } - return + return nil } -func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) { +func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) error { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - p.API.LogWarn("Cannot fetch Product Type. Missing 'Mattermost-User-Id' header") - http.Error(w, "Cannot fetch Product Type. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) - return + return errors.New("cannot fetch Product Type. Missing 'Mattermost-User-Id' header") } config := p.getConfiguration() if config == nil { - p.API.LogWarn("Cannot fetch Product Type. Fetched configuration is empty") - http.Error(w, "Cannot fetch Product Type. Fetched configuration is empty.", http.StatusUnauthorized) - return + return errors.New("cannot fetch Product Type. Fetched configuration is empty") } w.Header().Set("Content-Type", "application/json") @@ -255,66 +243,47 @@ func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) { if err := json.NewEncoder(w).Encode(ProductTypeResponse{ ProductType: p.getConfiguration().ProductType, }); err != nil { - p.API.LogWarn("Cannot fetch Product Type. An error occured while encoding the product type response", - "err", err) - http.Error(w, "Cannot fetch Product Type. An error occured while encoding the product type response.", - http.StatusInternalServerError) + return fmt.Errorf("cannot fetch Product Type. An error occured while encoding the product type response: %w", + err) } - return + return nil } -func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r *http.Request) { +func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r *http.Request) error { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - p.API.LogWarn("Cannot register meeting. Missing 'Mattermost-User-Id' header") - http.Error(w, "Cannot register meeting. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) - return + return errors.New("cannot register meeting. Missing 'Mattermost-User-Id' header") } user, appErr := p.API.GetUser(userID) if appErr != nil { - p.API.LogWarn("Cannot register meeting. An error occured while fetching user", - "err", appErr) - http.Error(w, "Cannot register meeting. An error occured while fetching user.", appErr.StatusCode) - return + return errors.New(fmt.Sprintf("cannot register meeting. An error occured while fetching user: %+v", appErr)) } if user == nil { - p.API.LogWarn("Cannot register meeting. User with that ID doesn't exist", "userID", userID) - http.Error(w, "Cannot register meeting. User with that ID doesn't exist.", http.StatusUnauthorized) - return + return errors.New(fmt.Sprintf("cannot register meeting. User with that ID doesn't exist: %s", userID)) } config := p.getConfiguration() if config == nil { - p.API.LogWarn("Cannot register meeting. Fetched configuration is empty") - http.Error(w, "Cannot register meeting. Fetched configuration is empty.", http.StatusForbidden) - return + return errors.New("cannot register meeting. Fetched configuration is empty") } if config.ProductType == productTypeServer { - p.API.LogWarn("Cannot register meeting. Product Type is not set as 'online'") - http.Error(w, "Cannot register meeting. Product Type is not set as 'online'.", http.StatusForbidden) - return + return errors.New("cannot register meeting. Product Type is not set as 'online'") } var req StartMeetingRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - p.API.LogWarn("Cannot register meeting. An error occured while decoding JSON body:", - "err", err) - http.Error(w, "Cannot register meeting. An error occured while decoding JSON body.", http.StatusBadRequest) - return + return fmt.Errorf("cannot register meeting. An error occured while decoding JSON body: %w", err) } if _, appErr = p.API.GetChannelMember(req.ChannelID, user.Id); appErr != nil { - p.API.LogWarn("Cannot register meeting. An error occured while fetching channel membership", - "err", appErr.Error()) - http.Error(w, "Cannot register meeting. An error occured while fetching channel membership.", - http.StatusForbidden) - return + return errors.New(fmt.Sprintf("cannot register meeting. An error occured while fetching channel membership: %+v", + appErr)) } serverConfiguration := p.API.GetConfig() @@ -338,22 +307,18 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r post, appErr = p.API.CreatePost(post) if appErr != nil { - p.API.LogWarn("Cannot register meeting. An error occured while creating a post with the meeting", - "err", appErr) - http.Error(w, "Cannot register meeting. An error occured while creating a post with the meeting.", - appErr.StatusCode) - return + return errors.New(fmt.Sprintf("cannot register meeting. An error occured while creating a post with the meeting: %+v", + appErr)) } if appErr = p.API.KVSet(fmt.Sprintf("%v%v", PostMeetingKey, req.MeetingID), []byte(post.Id)); appErr != nil { - p.API.LogWarn("Cannot register meeting. An error occured while saving the meeting ID in the database", - "err", appErr) - http.Error(w, "Cannot register meeting. An error occured while saving the meeting ID in the database.", - appErr.StatusCode) - return + return errors.New(fmt.Sprintf("cannot register meeting. An error occured while saving the meeting ID in the database: %+v", + appErr)) } w.Write([]byte(fmt.Sprintf("%v", req.MeetingID))) + + return nil } func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *http.Request) { diff --git a/server/plugin_test.go b/server/plugin_test.go index abd6d56a5..eb3f21b64 100644 --- a/server/plugin_test.go +++ b/server/plugin_test.go @@ -55,7 +55,7 @@ func TestPlugin(t *testing.T) { }{ "UnauthorizedMeetingRequest": { Request: noAuthMeetingRequest, - ExpectedStatusCode: http.StatusUnauthorized, + ExpectedStatusCode: http.StatusBadRequest, }, "ValidMeetingRequest": { Request: validMeetingRequest, @@ -67,7 +67,7 @@ func TestPlugin(t *testing.T) { }, "UnauthorizedClientIdRequest": { Request: noAuthClientIDRequest, - ExpectedStatusCode: http.StatusUnauthorized, + ExpectedStatusCode: http.StatusBadRequest, }, "ValidProductTypeReqeust": { Request: validProductTypeReqeust, @@ -75,7 +75,7 @@ func TestPlugin(t *testing.T) { }, "UnauthorizedProductTypeRequest": { Request: noAuthProductTypeReqeust, - ExpectedStatusCode: http.StatusUnauthorized, + ExpectedStatusCode: http.StatusBadRequest, }, "ValidAuthorizeInADDRequest": { Request: validAuthorizeInADDRequest, From df1d197e297405271d900c071c8bdf486d01eae6 Mon Sep 17 00:00:00 2001 From: grzegorz Date: Tue, 24 Mar 2020 02:18:41 +0100 Subject: [PATCH 4/7] change functions to return http status codes --- server/plugin.go | 139 ++++++++++++++++-------------------------- server/plugin_test.go | 8 +-- 2 files changed, 57 insertions(+), 90 deletions(-) diff --git a/server/plugin.go b/server/plugin.go index 69c4b70a9..146fff3b1 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -84,20 +84,21 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req } var err error + httpStatusCode := http.StatusOK path := r.URL.Path switch path { case "/api/v1/product_type": - err = p.handleProductType(w, r) + err, httpStatusCode = p.handleProductType(w, r) case "/api/v1/create_meeting_in_server_version": - p.handleCreateMeetingInServerVersion(w, r) + err, httpStatusCode = p.handleCreateMeetingInServerVersion(w, r) case "/api/v1/client_id": - err = p.handleClientID(w, r) + err, httpStatusCode = p.handleClientID(w, r) case "/api/v1/auth": - err = p.handleAuthorizeInADD(w, r) + err, httpStatusCode = p.handleAuthorizeInADD(w, r) case "/api/v1/auth_redirect": - err = p.completeAuthorizeInADD(w, r) + err, httpStatusCode = p.completeAuthorizeInADD(w, r) case "/api/v1/register_meeting_from_online_version": - err = p.handleRegisterMeetingFromOnlineVersion(w, r) + err, httpStatusCode = p.handleRegisterMeetingFromOnlineVersion(w, r) case "/api/v1/assets/profile.png": p.handleProfileImage(w, r) default: @@ -106,67 +107,67 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req if err != nil { p.API.LogWarn(err.Error()) - http.Error(w, err.Error(), http.StatusBadRequest) + http.Error(w, err.Error(), httpStatusCode) } } -func (p *Plugin) handleAuthorizeInADD(w http.ResponseWriter, r *http.Request) error { +func (p *Plugin) handleAuthorizeInADD(w http.ResponseWriter, r *http.Request) (error, int) { userID := r.URL.Query().Get("mattermost_user_id") if userID == "" { - return errors.New("cannot authorize in ADD. Missing 'mattermost_user_id' param") + return errors.New("cannot authorize in ADD. Missing 'mattermost_user_id' param"), http.StatusUnauthorized } encodedAuthURL := r.URL.Query().Get("navigateTo") if encodedAuthURL == "" { - return errors.New("cannot authorize in ADD. Missing 'navigateTo' param") + return errors.New("cannot authorize in ADD. Missing 'navigateTo' param"), http.StatusBadRequest } authURL, err := url.QueryUnescape(encodedAuthURL) if err != nil { - return fmt.Errorf("cannot authorize in ADD. An error occured while decoding URL: %w", err) + return fmt.Errorf("cannot authorize in ADD. An error occured while decoding URL: %w", err), http.StatusBadRequest } authURLValues, err := url.ParseQuery(authURL) if err != nil { - return fmt.Errorf("cannot authorize in ADD. An error occured while parsing URL: %w", err) + return fmt.Errorf("cannot authorize in ADD. An error occured while parsing URL: %w", err), http.StatusBadRequest } state := authURLValues.Get("state") if state == "" { - return errors.New("cannot authorize in ADD. Missing state' param") + return errors.New("cannot authorize in ADD. Missing state' param"), http.StatusBadRequest } p.API.KVSet(state, []byte(strings.TrimSpace(userID))) http.Redirect(w, r, authURL, http.StatusFound) - return nil + return nil, http.StatusOK } -func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) error { +func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) (error, int) { idToken := r.FormValue("id_token") if idToken == "" { - return errors.New("cannot complete authorization in ADD. Missing 'id_token' param") + return errors.New("cannot complete authorization in ADD. Missing 'id_token' param"), http.StatusBadRequest } state := r.FormValue("state") if state == "" { - return errors.New("cannot complete authorization in ADD. Missing 'state' param") + return errors.New("cannot complete authorization in ADD. Missing 'state' param"), http.StatusBadRequest } userID, err := p.API.KVGet(state) if err != nil { return fmt.Errorf("cannot complete authorization in ADD. An error occured while fetching stored state: %w", - err) + err), http.StatusBadRequest } if userID == nil { - return errors.New("cannot complete authorization in ADD. There is no stored state") + return errors.New("cannot complete authorization in ADD. There is no stored state"), http.StatusBadRequest } err = p.API.KVDelete(state) @@ -203,15 +204,15 @@ func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) w.Header().Set("Content-Type", "text/html") w.Write([]byte(html)) - return nil + return nil, http.StatusOK } -func (p *Plugin) handleClientID(w http.ResponseWriter, r *http.Request) error { +func (p *Plugin) handleClientID(w http.ResponseWriter, r *http.Request) (error, int) { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - return errors.New("cannot fetch Client ID. Missing 'Mattermost-User-Id' header") + return errors.New("cannot fetch Client ID. Missing 'Mattermost-User-Id' header"), http.StatusUnauthorized } w.Header().Set("Content-Type", "application/json") @@ -223,19 +224,19 @@ func (p *Plugin) handleClientID(w http.ResponseWriter, r *http.Request) error { http.Error(w, err.Error(), http.StatusInternalServerError) } - return nil + return nil, http.StatusOK } -func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) error { +func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) (error, int) { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - return errors.New("cannot fetch Product Type. Missing 'Mattermost-User-Id' header") + return errors.New("cannot fetch Product Type. Missing 'Mattermost-User-Id' header"), http.StatusUnauthorized } config := p.getConfiguration() if config == nil { - return errors.New("cannot fetch Product Type. Fetched configuration is empty") + return errors.New("cannot fetch Product Type. Fetched configuration is empty"), http.StatusUnauthorized } w.Header().Set("Content-Type", "application/json") @@ -244,46 +245,46 @@ func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) error ProductType: p.getConfiguration().ProductType, }); err != nil { return fmt.Errorf("cannot fetch Product Type. An error occured while encoding the product type response: %w", - err) + err), http.StatusInternalServerError } - return nil + return nil, http.StatusOK } -func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r *http.Request) error { +func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r *http.Request) (error, int) { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - return errors.New("cannot register meeting. Missing 'Mattermost-User-Id' header") + return errors.New("cannot register meeting. Missing 'Mattermost-User-Id' header"), http.StatusUnauthorized } user, appErr := p.API.GetUser(userID) if appErr != nil { - return errors.New(fmt.Sprintf("cannot register meeting. An error occured while fetching user: %+v", appErr)) + return errors.New(fmt.Sprintf("cannot register meeting. An error occured while fetching user: %+v", appErr)), appErr.StatusCode } if user == nil { - return errors.New(fmt.Sprintf("cannot register meeting. User with that ID doesn't exist: %s", userID)) + return errors.New(fmt.Sprintf("cannot register meeting. User with that ID doesn't exist: %s", userID)), http.StatusUnauthorized } config := p.getConfiguration() if config == nil { - return errors.New("cannot register meeting. Fetched configuration is empty") + return errors.New("cannot register meeting. Fetched configuration is empty"), http.StatusForbidden } if config.ProductType == productTypeServer { - return errors.New("cannot register meeting. Product Type is not set as 'online'") + return errors.New("cannot register meeting. Product Type is not set as 'online'"), http.StatusForbidden } var req StartMeetingRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - return fmt.Errorf("cannot register meeting. An error occured while decoding JSON body: %w", err) + return fmt.Errorf("cannot register meeting. An error occured while decoding JSON body: %w", err), http.StatusBadRequest } if _, appErr = p.API.GetChannelMember(req.ChannelID, user.Id); appErr != nil { return errors.New(fmt.Sprintf("cannot register meeting. An error occured while fetching channel membership: %+v", - appErr)) + appErr)), http.StatusForbidden } serverConfiguration := p.API.GetConfig() @@ -308,72 +309,53 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r post, appErr = p.API.CreatePost(post) if appErr != nil { return errors.New(fmt.Sprintf("cannot register meeting. An error occured while creating a post with the meeting: %+v", - appErr)) + appErr)), appErr.StatusCode } if appErr = p.API.KVSet(fmt.Sprintf("%v%v", PostMeetingKey, req.MeetingID), []byte(post.Id)); appErr != nil { return errors.New(fmt.Sprintf("cannot register meeting. An error occured while saving the meeting ID in the database: %+v", - appErr)) + appErr)), appErr.StatusCode } w.Write([]byte(fmt.Sprintf("%v", req.MeetingID))) - return nil + return nil, http.StatusOK } -func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *http.Request) { +func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *http.Request) (error, int) { config := p.getConfiguration() if config.ProductType == productTypeOnline { - p.API.LogWarn("Cannot create meeting. Product Type is not set as 'server'") - http.Error(w, "Cannot create meeting. Product Type is not set as 'server'.", http.StatusForbidden) - return + return errors.New("Cannot create meeting. Product Type is not set as 'server'"), http.StatusForbidden } userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - p.API.LogWarn("Cannot create meeting. Missing 'Mattermost-User-Id' header") - http.Error(w, "Cannot create meeting. Missing 'Mattermost-User-Id' header.", http.StatusUnauthorized) - return + return errors.New("Cannot create meeting. Missing 'Mattermost-User-Id' header"), http.StatusUnauthorized } var user *model.User var appError *model.AppError user, appError = p.API.GetUser(userID) if appError != nil { - p.API.LogWarn("Cannot create meeting. An error occured while fetching user", - "err", appError) - http.Error(w, "Cannot create meeting. An error occured while fetching user.", appError.StatusCode) - return + return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while fetching user: %+v", appError)), appError.StatusCode } if user == nil { - p.API.LogWarn("Cannot create meeting. User with that id doesn't exist", "userID", userID) - http.Error(w, "Cannot create meeting. User with that id doesn't exist.", http.StatusUnauthorized) - return + return errors.New(fmt.Sprintf("Cannot create meeting. User with that id doesn't exist: %s", userID)), http.StatusUnauthorized } var req StartServerMeetingRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - p.API.LogWarn("Cannot create meeting. An error occured while decoding JSON body", "err", err) - http.Error(w, "Cannot create meeting. An error occured while decoding JSON body.", http.StatusBadRequest) - return + return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while decoding JSON body: %+v", err)), http.StatusBadRequest } if _, err := p.API.GetChannelMember(req.ChannelID, user.Id); err != nil { - p.API.LogWarn("Cannot create meeting. An error occured while fetching channel membership", - "err", err) - http.Error(w, "Cannot create meeting. An error occured while fetching channel membership.", - http.StatusForbidden) - return + return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while fetching channel membership: %+v", err)), http.StatusForbidden } applicationState, apiErr := p.fetchOnlineMeetingsURL() if apiErr != nil { - p.API.LogError("Cannot create meeting. An error occured while fetching meetings resource URL", - "err", apiErr.Message) - http.Error(w, "Cannot create meeting. An error occured while fetching meetings resource URL.", - http.StatusInternalServerError) - return + return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while fetching meetings resource URL: %+v", apiErr)), http.StatusInternalServerError } newMeetingResponse, err := p.client.createNewMeeting( @@ -385,11 +367,7 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht applicationState.Token, ) if err != nil { - p.API.LogError("Cannot create meeting. An error occured while creating a new meeting in UCWA", - "err", err) - http.Error(w, "Cannot create meeting. An error occured while creating a new meeting in UCWA.", - http.StatusInternalServerError) - return + return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while creating a new meeting in UCWA: %+v", err)), http.StatusInternalServerError } serverConfiguration := p.API.GetConfig() @@ -413,30 +391,19 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht post, appErr := p.API.CreatePost(post) if appErr != nil { - p.API.LogWarn("Cannot create meeting. An error occured while creating a post with a meeting", - "err", appErr) - http.Error(w, "Cannot create meeting. An error occured while creating a post with a meeting.", - http.StatusInternalServerError) - return + return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while creating a post with a meeting: %+v", appError)), http.StatusInternalServerError } appErr = p.API.KVSet(fmt.Sprintf("%v%v", PostMeetingKey, newMeetingResponse.MeetingID), []byte(post.Id)) if appErr != nil { - p.API.LogWarn("Cannot create meeting. An error occured while saving the meeting ID in the database", - "err", appErr) - http.Error(w, "Cannot create meeting. An error occured while saving the meeting ID in the database.", - http.StatusInternalServerError) - return + return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while saving the meeting ID in the database: %+v", appError)), http.StatusInternalServerError } if err := json.NewEncoder(w).Encode(&newMeetingResponse); err != nil { - p.API.LogWarn("Cannot create meeting. An error occured while encoding the new meeting response", - "err", err) - http.Error(w, "Cannot create meeting. An error occured while encoding the new meeting response.", - http.StatusInternalServerError) + return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while encoding the new meeting response: %+v", err)), http.StatusInternalServerError } - return + return nil, http.StatusOK } func (p *Plugin) handleProfileImage(w http.ResponseWriter, r *http.Request) { diff --git a/server/plugin_test.go b/server/plugin_test.go index eb3f21b64..4b3d511e1 100644 --- a/server/plugin_test.go +++ b/server/plugin_test.go @@ -55,7 +55,7 @@ func TestPlugin(t *testing.T) { }{ "UnauthorizedMeetingRequest": { Request: noAuthMeetingRequest, - ExpectedStatusCode: http.StatusBadRequest, + ExpectedStatusCode: http.StatusUnauthorized, }, "ValidMeetingRequest": { Request: validMeetingRequest, @@ -67,7 +67,7 @@ func TestPlugin(t *testing.T) { }, "UnauthorizedClientIdRequest": { Request: noAuthClientIDRequest, - ExpectedStatusCode: http.StatusBadRequest, + ExpectedStatusCode: http.StatusUnauthorized, }, "ValidProductTypeReqeust": { Request: validProductTypeReqeust, @@ -75,7 +75,7 @@ func TestPlugin(t *testing.T) { }, "UnauthorizedProductTypeRequest": { Request: noAuthProductTypeReqeust, - ExpectedStatusCode: http.StatusBadRequest, + ExpectedStatusCode: http.StatusUnauthorized, }, "ValidAuthorizeInADDRequest": { Request: validAuthorizeInADDRequest, @@ -83,7 +83,7 @@ func TestPlugin(t *testing.T) { }, "InvalidAuthorizeInADDRequest1": { Request: invalidAuthorizeInADDRequest1, - ExpectedStatusCode: http.StatusBadRequest, + ExpectedStatusCode: http.StatusUnauthorized, }, "InvalidAuthorizeInADDRequest2": { Request: invalidAuthorizeInADDRequest2, From ad5b25cd10a970a149b386b460b350c3e22a6f02 Mon Sep 17 00:00:00 2001 From: grzegorz Date: Wed, 25 Mar 2020 23:36:57 +0100 Subject: [PATCH 5/7] use errors.Wrapf instead of errors.New and fmt.Sprintf --- server/plugin.go | 50 ++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/server/plugin.go b/server/plugin.go index 146fff3b1..c935eedd7 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -5,8 +5,8 @@ package main import ( "encoding/json" - "errors" "fmt" + "github.com/pkg/errors" "io" "net/http" "net/url" @@ -244,8 +244,8 @@ func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) (erro if err := json.NewEncoder(w).Encode(ProductTypeResponse{ ProductType: p.getConfiguration().ProductType, }); err != nil { - return fmt.Errorf("cannot fetch Product Type. An error occured while encoding the product type response: %w", - err), http.StatusInternalServerError + return errors.Wrapf(err, "cannot fetch Product Type. An error occured while encoding the product type response"), + http.StatusInternalServerError } return nil, http.StatusOK @@ -260,11 +260,11 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r user, appErr := p.API.GetUser(userID) if appErr != nil { - return errors.New(fmt.Sprintf("cannot register meeting. An error occured while fetching user: %+v", appErr)), appErr.StatusCode + return errors.Wrapf(appErr, "cannot register meeting. An error occured while fetching user"), appErr.StatusCode } if user == nil { - return errors.New(fmt.Sprintf("cannot register meeting. User with that ID doesn't exist: %s", userID)), http.StatusUnauthorized + return fmt.Errorf("cannot register meeting. User with that ID doesn't exist: %s", userID), http.StatusUnauthorized } config := p.getConfiguration() @@ -279,12 +279,12 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r var req StartMeetingRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - return fmt.Errorf("cannot register meeting. An error occured while decoding JSON body: %w", err), http.StatusBadRequest + return errors.Wrapf(err, "cannot register meeting. An error occured while decoding JSON body"), http.StatusBadRequest } if _, appErr = p.API.GetChannelMember(req.ChannelID, user.Id); appErr != nil { - return errors.New(fmt.Sprintf("cannot register meeting. An error occured while fetching channel membership: %+v", - appErr)), http.StatusForbidden + return errors.Wrapf(appErr, "cannot register meeting. An error occured while fetching channel membership"), + http.StatusForbidden } serverConfiguration := p.API.GetConfig() @@ -308,13 +308,13 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r post, appErr = p.API.CreatePost(post) if appErr != nil { - return errors.New(fmt.Sprintf("cannot register meeting. An error occured while creating a post with the meeting: %+v", - appErr)), appErr.StatusCode + return errors.Wrapf(appErr, "cannot register meeting. An error occured while creating a post with the meeting"), + appErr.StatusCode } if appErr = p.API.KVSet(fmt.Sprintf("%v%v", PostMeetingKey, req.MeetingID), []byte(post.Id)); appErr != nil { - return errors.New(fmt.Sprintf("cannot register meeting. An error occured while saving the meeting ID in the database: %+v", - appErr)), appErr.StatusCode + return errors.Wrapf(appErr, "cannot register meeting. An error occured while saving the meeting ID in the database"), + appErr.StatusCode } w.Write([]byte(fmt.Sprintf("%v", req.MeetingID))) @@ -337,25 +337,29 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht var appError *model.AppError user, appError = p.API.GetUser(userID) if appError != nil { - return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while fetching user: %+v", appError)), appError.StatusCode + return errors.Wrapf(appError, "cannot create meeting. An error occured while fetching user"), + appError.StatusCode } if user == nil { - return errors.New(fmt.Sprintf("Cannot create meeting. User with that id doesn't exist: %s", userID)), http.StatusUnauthorized + return fmt.Errorf("cannot create meeting. User with that id doesn't exist: %s", userID), + http.StatusUnauthorized } var req StartServerMeetingRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while decoding JSON body: %+v", err)), http.StatusBadRequest + return errors.Wrapf(err, "cannot create meeting. An error occured while decoding JSON body"), http.StatusBadRequest } if _, err := p.API.GetChannelMember(req.ChannelID, user.Id); err != nil { - return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while fetching channel membership: %+v", err)), http.StatusForbidden + return errors.Wrapf(err, "cannot create meeting. An error occured while fetching channel membership"), + http.StatusForbidden } applicationState, apiErr := p.fetchOnlineMeetingsURL() if apiErr != nil { - return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while fetching meetings resource URL: %+v", apiErr)), http.StatusInternalServerError + return fmt.Errorf("cannot create meeting. An error occured while fetching meetings resource URL: %+v", apiErr), + http.StatusInternalServerError } newMeetingResponse, err := p.client.createNewMeeting( @@ -367,7 +371,8 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht applicationState.Token, ) if err != nil { - return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while creating a new meeting in UCWA: %+v", err)), http.StatusInternalServerError + return errors.Wrapf(err, "cannot create meeting. An error occured while creating a new meeting in UCWA"), + http.StatusInternalServerError } serverConfiguration := p.API.GetConfig() @@ -391,16 +396,19 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht post, appErr := p.API.CreatePost(post) if appErr != nil { - return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while creating a post with a meeting: %+v", appError)), http.StatusInternalServerError + return errors.Wrapf(appError, "cannot create meeting. An error occured while creating a post with a meeting"), + http.StatusInternalServerError } appErr = p.API.KVSet(fmt.Sprintf("%v%v", PostMeetingKey, newMeetingResponse.MeetingID), []byte(post.Id)) if appErr != nil { - return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while saving the meeting ID in the database: %+v", appError)), http.StatusInternalServerError + return errors.Wrapf(appError, "cannot create meeting. An error occured while saving the meeting ID in the database"), + http.StatusInternalServerError } if err := json.NewEncoder(w).Encode(&newMeetingResponse); err != nil { - return errors.New(fmt.Sprintf("Cannot create meeting. An error occured while encoding the new meeting response: %+v", err)), http.StatusInternalServerError + return errors.Wrapf(err, "cannot create meeting. An error occured while encoding the new meeting response"), + http.StatusInternalServerError } return nil, http.StatusOK From 3593cb5d971cfe9a66e56d308328d8b62a6cff10 Mon Sep 17 00:00:00 2001 From: grzegorz Date: Fri, 27 Mar 2020 03:48:02 +0100 Subject: [PATCH 6/7] * use errors.Wrapf instead of fmt.Errorf * change handleProfileImage function to return error and int --- server/plugin.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/server/plugin.go b/server/plugin.go index c935eedd7..96600e1f4 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -100,7 +100,7 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req case "/api/v1/register_meeting_from_online_version": err, httpStatusCode = p.handleRegisterMeetingFromOnlineVersion(w, r) case "/api/v1/assets/profile.png": - p.handleProfileImage(w, r) + err, httpStatusCode = p.handleProfileImage(w) default: http.NotFound(w, r) } @@ -126,12 +126,12 @@ func (p *Plugin) handleAuthorizeInADD(w http.ResponseWriter, r *http.Request) (e authURL, err := url.QueryUnescape(encodedAuthURL) if err != nil { - return fmt.Errorf("cannot authorize in ADD. An error occured while decoding URL: %w", err), http.StatusBadRequest + return errors.Wrapf(err, "cannot authorize in ADD. An error occured while decoding URL"), http.StatusBadRequest } authURLValues, err := url.ParseQuery(authURL) if err != nil { - return fmt.Errorf("cannot authorize in ADD. An error occured while parsing URL: %w", err), http.StatusBadRequest + return errors.Wrapf(err, "cannot authorize in ADD. An error occured while parsing URL"), http.StatusBadRequest } state := authURLValues.Get("state") @@ -162,8 +162,8 @@ func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) userID, err := p.API.KVGet(state) if err != nil { - return fmt.Errorf("cannot complete authorization in ADD. An error occured while fetching stored state: %w", - err), http.StatusBadRequest + return errors.Wrapf(err, "cannot complete authorization in ADD. An error occured while fetching stored state"), + http.StatusBadRequest } if userID == nil { @@ -342,7 +342,7 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht } if user == nil { - return fmt.Errorf("cannot create meeting. User with that id doesn't exist: %s", userID), + return errors.Errorf("cannot create meeting. User with that id doesn't exist: %s", userID), http.StatusUnauthorized } @@ -414,22 +414,23 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht return nil, http.StatusOK } -func (p *Plugin) handleProfileImage(w http.ResponseWriter, r *http.Request) { +func (p *Plugin) handleProfileImage(w http.ResponseWriter) (error, int) { bundlePath, err := p.API.GetBundlePath() if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return + return errors.Wrapf(err, "cannot fetch profile image. An error occured while fetching the bundle path"), + http.StatusInternalServerError } img, err := os.Open(filepath.Join(bundlePath, "assets", "profile.png")) if err != nil { - p.API.LogWarn("Cannot read Skype 4 Business plugin profile image", "err", err) - http.NotFound(w, r) - return + return errors.Wrapf(err, "cannot fetch profile image. An error occured while reading the profile image file"), + http.StatusNotFound } defer img.Close() w.Header().Set("Content-Type", "image/png") io.Copy(w, img) + + return nil, http.StatusOK } func (p *Plugin) fetchOnlineMeetingsURL() (*ApplicationState, *APIError) { From e2ab834ce0387e0eab3b9049e5783e5bbf2869b1 Mon Sep 17 00:00:00 2001 From: Hanzei Date: Fri, 15 May 2020 16:56:00 +0200 Subject: [PATCH 7/7] Fix build --- server/plugin.go | 160 ++++++++++++++++++++++------------------------- 1 file changed, 74 insertions(+), 86 deletions(-) diff --git a/server/plugin.go b/server/plugin.go index 12207a17e..b93790294 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -88,19 +88,19 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req path := r.URL.Path switch path { case "/api/v1/product_type": - err, httpStatusCode = p.handleProductType(w, r) + httpStatusCode, err = p.handleProductType(w, r) case "/api/v1/create_meeting_in_server_version": - err, httpStatusCode = p.handleCreateMeetingInServerVersion(w, r) + httpStatusCode, err = p.handleCreateMeetingInServerVersion(w, r) case "/api/v1/client_id": - err, httpStatusCode = p.handleClientID(w, r) + httpStatusCode, err = p.handleClientID(w, r) case "/api/v1/auth": - err, httpStatusCode = p.handleAuthorizeInADD(w, r) + httpStatusCode, err = p.handleAuthorizeInADD(w, r) case "/api/v1/auth_redirect": - err, httpStatusCode = p.completeAuthorizeInADD(w, r) + httpStatusCode, err = p.completeAuthorizeInADD(w, r) case "/api/v1/register_meeting_from_online_version": - err, httpStatusCode = p.handleRegisterMeetingFromOnlineVersion(w, r) + httpStatusCode, err = p.handleRegisterMeetingFromOnlineVersion(w, r) case "/api/v1/assets/profile.png": - err, httpStatusCode = p.handleProfileImage(w) + httpStatusCode, err = p.handleProfileImage(w) default: http.NotFound(w, r) } @@ -111,63 +111,57 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req } } -func (p *Plugin) handleAuthorizeInADD(w http.ResponseWriter, r *http.Request) (error, int) { - +func (p *Plugin) handleAuthorizeInADD(w http.ResponseWriter, r *http.Request) (int, error) { userID := r.URL.Query().Get("mattermost_user_id") - if userID == "" { - return errors.New("cannot authorize in ADD. Missing 'mattermost_user_id' param"), http.StatusUnauthorized + return http.StatusUnauthorized, errors.New("cannot authorize in ADD. Missing 'mattermost_user_id' param") } encodedAuthURL := r.URL.Query().Get("navigateTo") if encodedAuthURL == "" { - return errors.New("cannot authorize in ADD. Missing 'navigateTo' param"), http.StatusBadRequest + return http.StatusBadRequest, errors.New("cannot authorize in ADD. Missing 'navigateTo' param") } authURL, err := url.QueryUnescape(encodedAuthURL) if err != nil { - return errors.Wrapf(err, "cannot authorize in ADD. An error occured while decoding URL"), http.StatusBadRequest + return http.StatusBadRequest, errors.Wrap(err, "cannot authorize in ADD. An error occured while decoding URL") } authURLValues, err := url.ParseQuery(authURL) if err != nil { - return errors.Wrapf(err, "cannot authorize in ADD. An error occured while parsing URL"), http.StatusBadRequest + return http.StatusBadRequest, errors.Wrap(err, "cannot authorize in ADD. An error occured while parsing URL") } state := authURLValues.Get("state") if state == "" { - return errors.New("cannot authorize in ADD. Missing state' param"), http.StatusBadRequest + return http.StatusBadRequest, errors.New("cannot authorize in ADD. Missing state' param") } p.API.KVSet(state, []byte(strings.TrimSpace(userID))) http.Redirect(w, r, authURL, http.StatusFound) - return nil, http.StatusOK + return http.StatusOK, nil } -func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) (error, int) { - +func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) (int, error) { idToken := r.FormValue("id_token") - if idToken == "" { - return errors.New("cannot complete authorization in ADD. Missing 'id_token' param"), http.StatusBadRequest + return http.StatusBadRequest, errors.New("cannot complete authorization in ADD. Missing 'id_token' param") } state := r.FormValue("state") - if state == "" { - return errors.New("cannot complete authorization in ADD. Missing 'state' param"), http.StatusBadRequest + return http.StatusBadRequest, errors.New("cannot complete authorization in ADD. Missing 'state' param") } userID, err := p.API.KVGet(state) - if err != nil { - return errors.Wrapf(err, "cannot complete authorization in ADD. An error occured while fetching stored state"), - http.StatusBadRequest + return http.StatusBadRequest, + errors.Wrap(err, "cannot complete authorization in ADD. An error occured while fetching stored state") } if userID == nil { - return errors.New("cannot complete authorization in ADD. There is no stored state"), http.StatusBadRequest + return http.StatusBadRequest, errors.New("cannot complete authorization in ADD. There is no stored state") } err = p.API.KVDelete(state) @@ -204,15 +198,13 @@ func (p *Plugin) completeAuthorizeInADD(w http.ResponseWriter, r *http.Request) w.Header().Set("Content-Type", "text/html") w.Write([]byte(html)) - return nil, http.StatusOK + return http.StatusOK, nil } -func (p *Plugin) handleClientID(w http.ResponseWriter, r *http.Request) (error, int) { - +func (p *Plugin) handleClientID(w http.ResponseWriter, r *http.Request) (int, error) { userID := r.Header.Get("Mattermost-User-Id") - if userID == "" { - return errors.New("cannot fetch Client ID. Missing 'Mattermost-User-Id' header"), http.StatusUnauthorized + return http.StatusUnauthorized, errors.New("cannot fetch Client ID. Missing 'Mattermost-User-Id' header") } w.Header().Set("Content-Type", "application/json") @@ -224,71 +216,67 @@ func (p *Plugin) handleClientID(w http.ResponseWriter, r *http.Request) (error, http.Error(w, err.Error(), http.StatusInternalServerError) } - return nil, http.StatusOK + return http.StatusOK, nil } -func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) (error, int) { - +func (p *Plugin) handleProductType(w http.ResponseWriter, r *http.Request) (int, error) { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - return errors.New("cannot fetch Product Type. Missing 'Mattermost-User-Id' header"), http.StatusUnauthorized + return http.StatusUnauthorized, errors.New("cannot fetch Product Type. Missing 'Mattermost-User-Id' header") } config := p.getConfiguration() if config == nil { - return errors.New("cannot fetch Product Type. Fetched configuration is empty"), http.StatusUnauthorized + return http.StatusUnauthorized, errors.New("cannot fetch Product Type. Fetched configuration is empty") } w.Header().Set("Content-Type", "application/json") - if err := json.NewEncoder(w).Encode(ProductTypeResponse{ + err := json.NewEncoder(w).Encode(ProductTypeResponse{ ProductType: p.getConfiguration().ProductType, - }); err != nil { - return errors.Wrapf(err, "cannot fetch Product Type. An error occured while encoding the product type response"), - http.StatusInternalServerError + }) + if err != nil { + return http.StatusInternalServerError, + errors.Wrap(err, "cannot fetch Product Type. An error occured while encoding the product type response") } - return nil, http.StatusOK + return http.StatusOK, nil } -func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r *http.Request) (error, int) { - +func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r *http.Request) (int, error) { userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - return errors.New("cannot register meeting. Missing 'Mattermost-User-Id' header"), http.StatusUnauthorized + return http.StatusUnauthorized, errors.New("cannot register meeting. Missing 'Mattermost-User-Id' header") } user, appErr := p.API.GetUser(userID) if appErr != nil { - return errors.Wrapf(appErr, "cannot register meeting. An error occured while fetching user"), appErr.StatusCode + return appErr.StatusCode, errors.Wrap(appErr, "cannot register meeting. An error occured while fetching user") } if user == nil { - return fmt.Errorf("cannot register meeting. User with that ID doesn't exist: %s", userID), http.StatusUnauthorized + return http.StatusUnauthorized, errors.Errorf("cannot register meeting. User with that ID doesn't exist: %s", userID) } config := p.getConfiguration() if config == nil { - return errors.New("cannot register meeting. Fetched configuration is empty"), http.StatusForbidden + return http.StatusForbidden, errors.New("cannot register meeting. Fetched configuration is empty") } if config.ProductType == productTypeServer { - return errors.New("cannot register meeting. Product Type is not set as 'online'"), http.StatusForbidden + return http.StatusForbidden, errors.New("cannot register meeting. Product Type is not set as 'online'") } var req StartMeetingRequest - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - return errors.Wrapf(err, "cannot register meeting. An error occured while decoding JSON body"), http.StatusBadRequest + return http.StatusBadRequest, errors.Wrap(err, "cannot register meeting. An error occured while decoding JSON body") } if _, appErr = p.API.GetChannelMember(req.ChannelID, user.Id); appErr != nil { - return errors.Wrapf(appErr, "cannot register meeting. An error occured while fetching channel membership"), - http.StatusForbidden + return http.StatusForbidden, errors.Wrap(appErr, "cannot register meeting. An error occured while fetching channel membership") } serverConfiguration := p.API.GetConfig() - post := &model.Post{ UserId: user.Id, ChannelId: req.ChannelID, @@ -308,58 +296,59 @@ func (p *Plugin) handleRegisterMeetingFromOnlineVersion(w http.ResponseWriter, r post, appErr = p.API.CreatePost(post) if appErr != nil { - return errors.Wrapf(appErr, "cannot register meeting. An error occured while creating a post with the meeting"), - appErr.StatusCode + return appErr.StatusCode, + errors.Wrap(appErr, "cannot register meeting. An error occured while creating a post with the meeting") } if appErr = p.API.KVSet(fmt.Sprintf("%v%v", PostMeetingKey, req.MeetingID), []byte(post.Id)); appErr != nil { - return errors.Wrapf(appErr, "cannot register meeting. An error occured while saving the meeting ID in the database"), - appErr.StatusCode + return appErr.StatusCode, + errors.Wrap(appErr, "cannot register meeting. An error occured while saving the meeting ID in the database") } w.Write([]byte(fmt.Sprintf("%v", req.MeetingID))) - return nil, http.StatusOK + return http.StatusOK, nil } -func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *http.Request) (error, int) { +func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *http.Request) (int, error) { config := p.getConfiguration() if config.ProductType == productTypeOnline { - return errors.New("Cannot create meeting. Product Type is not set as 'server'"), http.StatusForbidden + return http.StatusForbidden, errors.New("Cannot create meeting. Product Type is not set as 'server'") } userID := r.Header.Get("Mattermost-User-Id") if userID == "" { - return errors.New("Cannot create meeting. Missing 'Mattermost-User-Id' header"), http.StatusUnauthorized + return http.StatusUnauthorized, errors.New("Cannot create meeting. Missing 'Mattermost-User-Id' header") } var user *model.User var appError *model.AppError user, appError = p.API.GetUser(userID) if appError != nil { - return errors.Wrapf(appError, "cannot create meeting. An error occured while fetching user"), - appError.StatusCode + return appError.StatusCode, + errors.Wrap(appError, "cannot create meeting. An error occured while fetching user") } if user == nil { - return errors.Errorf("cannot create meeting. User with that id doesn't exist: %s", userID), - http.StatusUnauthorized + return http.StatusUnauthorized, + errors.Errorf("cannot create meeting. User with that id doesn't exist: %s", userID) } var req StartServerMeetingRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - return errors.Wrapf(err, "cannot create meeting. An error occured while decoding JSON body"), http.StatusBadRequest + return http.StatusBadRequest, + errors.Wrap(err, "cannot create meeting. An error occured while decoding JSON body") } if _, err := p.API.GetChannelMember(req.ChannelID, user.Id); err != nil { - return errors.Wrapf(err, "cannot create meeting. An error occured while fetching channel membership"), - http.StatusForbidden + return http.StatusForbidden, + errors.Wrap(err, "cannot create meeting. An error occured while fetching channel membership") } applicationState, apiErr := p.fetchOnlineMeetingsURL() if apiErr != nil { - return fmt.Errorf("cannot create meeting. An error occured while fetching meetings resource URL: %+v", apiErr), - http.StatusInternalServerError + return http.StatusInternalServerError, + errors.Errorf("cannot create meeting. An error occured while fetching meetings resource URL: %+v", apiErr) } newMeetingResponse, err := p.client.createNewMeeting( @@ -371,12 +360,11 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht applicationState.Token, ) if err != nil { - return errors.Wrapf(err, "cannot create meeting. An error occured while creating a new meeting in UCWA"), - http.StatusInternalServerError + return http.StatusInternalServerError, + errors.Wrap(err, "cannot create meeting. An error occured while creating a new meeting in UCWA") } serverConfiguration := p.API.GetConfig() - post := &model.Post{ UserId: user.Id, ChannelId: req.ChannelID, @@ -396,41 +384,41 @@ func (p *Plugin) handleCreateMeetingInServerVersion(w http.ResponseWriter, r *ht post, appErr := p.API.CreatePost(post) if appErr != nil { - return errors.Wrapf(appError, "cannot create meeting. An error occured while creating a post with a meeting"), - http.StatusInternalServerError + return http.StatusInternalServerError, + errors.Wrap(appError, "cannot create meeting. An error occured while creating a post with a meeting") } appErr = p.API.KVSet(fmt.Sprintf("%v%v", PostMeetingKey, newMeetingResponse.MeetingID), []byte(post.Id)) if appErr != nil { - return errors.Wrapf(appError, "cannot create meeting. An error occured while saving the meeting ID in the database"), - http.StatusInternalServerError + return http.StatusInternalServerError, + errors.Wrap(appError, "cannot create meeting. An error occured while saving the meeting ID in the database") } if err := json.NewEncoder(w).Encode(&newMeetingResponse); err != nil { - return errors.Wrapf(err, "cannot create meeting. An error occured while encoding the new meeting response"), - http.StatusInternalServerError + return http.StatusInternalServerError, + errors.Wrap(err, "cannot create meeting. An error occured while encoding the new meeting response") } - return nil, http.StatusOK + return http.StatusOK, nil } -func (p *Plugin) handleProfileImage(w http.ResponseWriter) (error, int) { +func (p *Plugin) handleProfileImage(w http.ResponseWriter) (int, error) { bundlePath, err := p.API.GetBundlePath() if err != nil { - return errors.Wrapf(err, "cannot fetch profile image. An error occured while fetching the bundle path"), - http.StatusInternalServerError + return http.StatusInternalServerError, + errors.Wrap(err, "cannot fetch profile image. An error occured while fetching the bundle path") } img, err := os.Open(filepath.Join(bundlePath, "assets", "profile.png")) if err != nil { - return errors.Wrapf(err, "cannot fetch profile image. An error occured while reading the profile image file"), - http.StatusNotFound + return http.StatusNotFound, + errors.Wrap(err, "cannot fetch profile image. An error occured while reading the profile image file") } defer img.Close() w.Header().Set("Content-Type", "image/png") io.Copy(w, img) - return nil, http.StatusOK + return http.StatusOK, nil } func (p *Plugin) fetchOnlineMeetingsURL() (*ApplicationState, *APIError) {