Skip to content

Commit

Permalink
Add portal link checks to subscription apis (#2016)
Browse files Browse the repository at this point in the history
* added metrics for the data plane (#2005)

* added metrics for the data plane

* updated docker-compose.dev.yml with optional prometheus image

* updated RedisQueue as a metrics collector

* updated postgres as a metrics collector

* revert error check in process_meta_event.go

* updated metrics collection for different http status codes

* updated postgres_collector.go

* fixed lint issues and updated some queries

* updated metrics to be configurable

* updated test config

* fixed failing CI tests

* gated metrics with feature flags

* fixed CI issues

* updated metrics tests

* refactored postgres_collector.go

* Update rate limit function (#2002)

* chore: update rate limit function

* fix: return when locked row is null

* fix: select only specific rows

* chore: create record if not exists

* Add subscription name filter to GetSubscriptions (#2014)

* fix: add subscription name filter to GetSubscriptions

* fix: add % directly in arg map

* fix: add portal link checks to subscription apis

* fix: remove isPortaLinkReq

* fix: use util.StringSliceContains

* fix: revert envs

* fix: check if data.FilterBy.EndpointIDs was present before setting it

---------

Co-authored-by: Smart Mekiliuwa <st.nonso@gmail.com>
Co-authored-by: Raymond Tukpe <jirevwe@users.noreply.github.com>
Co-authored-by: Pelumi Muyiwa-Oni <Pelumioni25@gmail.com>
  • Loading branch information
4 people authored May 27, 2024
1 parent e5481ea commit ce55abf
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 3 deletions.
114 changes: 112 additions & 2 deletions api/handlers/subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package handlers

import (
"errors"
"github.com/frain-dev/convoy/pkg/transform"
"net/http"

"github.com/frain-dev/convoy/internal/pkg/middleware"
"github.com/frain-dev/convoy/pkg/transform"

"github.com/frain-dev/convoy/pkg/log"

"github.com/frain-dev/convoy/api/models"
Expand Down Expand Up @@ -39,8 +41,43 @@ func (h *Handler) GetSubscriptions(w http.ResponseWriter, r *http.Request) {
}

var q *models.QueryListSubscription

data := q.Transform(r)

authUser := middleware.GetAuthUserFromContext(r.Context())

if h.IsReqWithPortalLinkToken(authUser) {
portalLink, err := h.retrievePortalLinkFromToken(r)
if err != nil {
_ = render.Render(w, r, util.NewServiceErrResponse(err))
return
}

endpointIDs, err := h.getEndpoints(r, portalLink)
if err != nil {
_ = render.Render(w, r, util.NewServiceErrResponse(err))
return
}

if len(endpointIDs) == 0 {
_ = render.Render(w, r, util.NewServerResponse("Subscriptions fetched successfully",
models.PagedResponse{Content: []models.SubscriptionResponse{}, Pagination: &datastore.PaginationData{PerPage: 0}}, http.StatusOK))
return
}

// verify that the listed endpoints are all in this portal link
if len(data.FilterBy.EndpointIDs) != 0 {
for _, endpointID := range data.FilterBy.EndpointIDs {
if !util.StringSliceContains(endpointIDs, endpointID) {
_ = render.Render(w, r, util.NewErrorResponse("unauthorized", http.StatusUnauthorized))
return
}
}
} else {
data.FilterBy.EndpointIDs = endpointIDs
}

}

subscriptions, paginationData, err := postgres.NewSubscriptionRepo(h.A.DB, h.A.Cache).LoadSubscriptionsPaged(r.Context(), project.UID, data.FilterBy, data.Pageable)
if err != nil {
log.FromContext(r.Context()).WithError(err).Error("an error occurred while fetching subscriptions")
Expand Down Expand Up @@ -154,6 +191,27 @@ func (h *Handler) CreateSubscription(w http.ResponseWriter, r *http.Request) {
return
}

authUser := middleware.GetAuthUserFromContext(r.Context())

if h.IsReqWithPortalLinkToken(authUser) {
portalLink, err := h.retrievePortalLinkFromToken(r)
if err != nil {
_ = render.Render(w, r, util.NewServiceErrResponse(err))
return
}

endpointIDs, err := h.getEndpoints(r, portalLink)
if err != nil {
_ = render.Render(w, r, util.NewServiceErrResponse(err))
return
}

if !util.StringSliceContains(endpointIDs, sub.EndpointID) {
_ = render.Render(w, r, util.NewErrorResponse("unauthorized", http.StatusUnauthorized))
return
}
}

cs := services.CreateSubscriptionService{
SubRepo: postgres.NewSubscriptionRepo(h.A.DB, h.A.Cache),
EndpointRepo: postgres.NewEndpointRepo(h.A.DB, h.A.Cache),
Expand Down Expand Up @@ -205,6 +263,26 @@ func (h *Handler) DeleteSubscription(w http.ResponseWriter, r *http.Request) {
return
}

authUser := middleware.GetAuthUserFromContext(r.Context())
if h.IsReqWithPortalLinkToken(authUser) {
portalLink, err := h.retrievePortalLinkFromToken(r)
if err != nil {
_ = render.Render(w, r, util.NewServiceErrResponse(err))
return
}

endpointIDs, err := h.getEndpoints(r, portalLink)
if err != nil {
_ = render.Render(w, r, util.NewServiceErrResponse(err))
return
}

if !util.StringSliceContains(endpointIDs, sub.EndpointID) {
_ = render.Render(w, r, util.NewErrorResponse("unauthorized", http.StatusUnauthorized))
return
}
}

err = postgres.NewSubscriptionRepo(h.A.DB, h.A.Cache).DeleteSubscription(r.Context(), project.UID, sub)
if err != nil {
log.FromContext(r.Context()).WithError(err).Error("failed to delete subscription")
Expand Down Expand Up @@ -251,6 +329,38 @@ func (h *Handler) UpdateSubscription(w http.ResponseWriter, r *http.Request) {
return
}

authUser := middleware.GetAuthUserFromContext(r.Context())

if h.IsReqWithPortalLinkToken(authUser) {
portalLink, err := h.retrievePortalLinkFromToken(r)
if err != nil {
_ = render.Render(w, r, util.NewServiceErrResponse(err))
return
}

endpointIDs, err := h.getEndpoints(r, portalLink)
if err != nil {
_ = render.Render(w, r, util.NewServiceErrResponse(err))
return
}

sub, err := postgres.NewSubscriptionRepo(h.A.DB, h.A.Cache).FindSubscriptionByID(r.Context(), project.UID, chi.URLParam(r, "subscriptionID"))
if err != nil {
log.FromContext(r.Context()).WithError(err).Error("failed to find subscription")
if errors.Is(err, datastore.ErrSubscriptionNotFound) {
_ = render.Render(w, r, util.NewErrorResponse("failed to find subscription", http.StatusNotFound))
return
}
_ = render.Render(w, r, util.NewServiceErrResponse(err))
return
}

if !util.StringSliceContains(endpointIDs, sub.EndpointID) {
_ = render.Render(w, r, util.NewErrorResponse("unauthorized", http.StatusUnauthorized))
return
}
}

us := services.UpdateSubscriptionService{
SubRepo: postgres.NewSubscriptionRepo(h.A.DB, h.A.Cache),
EndpointRepo: postgres.NewEndpointRepo(h.A.DB, h.A.Cache),
Expand Down
2 changes: 1 addition & 1 deletion docs/docs.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Package docs Code generated by swaggo/swag at 2024-05-22 13:46:04.95428 +0100 BST m=+2.371629584. DO NOT EDIT
// Package docs Code generated by swaggo/swag at 2024-05-24 16:10:26.884378 +0100 BST m=+2.442021417. DO NOT EDIT
package docs

import "github.com/swaggo/swag"
Expand Down
10 changes: 10 additions & 0 deletions util/strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,13 @@ func GenerateRandomString(n int) (string, error) {
}
return string(b), nil
}

func StringSliceContains(sl []string, s string) bool {
for _, v := range sl {
if v == s {
return true
}
}

return false
}

0 comments on commit ce55abf

Please sign in to comment.