Skip to content

Commit

Permalink
Improve e-mail validation and subscription checks on frontend (#161)
Browse files Browse the repository at this point in the history
* Fix dropdown article links on docs

* Lil fixes here and there

* Update index.tsx

* Fix playwright tests
  • Loading branch information
th0th authored Mar 6, 2023
1 parent 1ed4ea6 commit 2c7edc5
Show file tree
Hide file tree
Showing 19 changed files with 271 additions and 179 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,77 +16,75 @@ import (
"gorm.io/gorm"
)

func NewUserAccessTokenFormAuth() fiber.Handler {
return func(c *fiber.Ctx) error {
dateTime := time.Now()
func NewUserAccessTokenFormAuth(c *fiber.Ctx) error {
dateTime := time.Now()

dp := dm.Get(c)
dp := dm.Get(c)

userAccessToken := c.FormValue("user-access-token")
userAccessToken := c.FormValue("user-access-token")

if userAccessToken == "" {
return c.Next()
}

modelUserAccessToken := &model.UserAccessToken{}
if userAccessToken == "" {
return c.Next()
}

err := dp.Postgres().
Model(&model.UserAccessToken{}).
Where("token = ?", userAccessToken).
First(modelUserAccessToken).
Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fiber.ErrUnauthorized
}
modelUserAccessToken := &model.UserAccessToken{}

return err
err := dp.Postgres().
Model(&model.UserAccessToken{}).
Where("token = ?", userAccessToken).
First(modelUserAccessToken).
Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fiber.ErrUnauthorized
}

modelUser := &model.User{}
return err
}

err = dp.Postgres().
Model(&model.User{}).
Where("is_active is true").
Where("id = ?", modelUserAccessToken.UserId).
First(modelUser).
Error
if err != nil {
return err
}
modelUser := &model.User{}

modelOrganization := &model.Organization{}
err = dp.Postgres().
Model(&model.User{}).
Where("is_active is true").
Where("id = ?", modelUserAccessToken.UserId).
First(modelUser).
Error
if err != nil {
return err
}

err = dp.Postgres().
Model(&model.Organization{}).
Joins("Plan").
Where("organizations.id = ?", modelUser.OrganizationId).
First(modelOrganization).
Error
if err != nil {
return err
}
modelOrganization := &model.Organization{}

c.Locals("auth", &Auth{
Kind: pointer.Get(AuthKindRestApiUserAccessToken),
Organization: modelOrganization,
User: modelUser,
UserAccessToken: modelUserAccessToken,
})

fibersentry.GetHubFromContext(c).Scope().SetUser(sentry.User{
Email: modelUser.Email,
ID: strconv.Itoa(int(modelUser.Id)),
})

err = dp.Redis().
Set(depot.Ctx, modelUserAccessToken.LastUsedAtRedisKey(), dateTime.Unix(), time.Hour).
Err()
if err != nil {
// TODO: handle the error better
log.Println(err)
}
err = dp.Postgres().
Model(&model.Organization{}).
Joins("Plan").
Where("organizations.id = ?", modelUser.OrganizationId).
First(modelOrganization).
Error
if err != nil {
return err
}

return c.Next()
c.Locals("auth", &Auth{
Kind: pointer.Get(AuthKindRestApiUserAccessToken),
Organization: modelOrganization,
User: modelUser,
UserAccessToken: modelUserAccessToken,
})

fibersentry.GetHubFromContext(c).Scope().SetUser(sentry.User{
Email: modelUser.Email,
ID: strconv.Itoa(int(modelUser.Id)),
})

err = dp.Redis().
Set(depot.Ctx, modelUserAccessToken.LastUsedAtRedisKey(), dateTime.Unix(), time.Hour).
Err()
if err != nil {
// TODO: handle the error better
log.Println(err)
}

return c.Next()
}
13 changes: 8 additions & 5 deletions backend/pkg/restapi/middleware/permission/organization.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ package permission

import (
"github.com/gofiber/fiber/v2"
am "github.com/th0th/poeticmetric/backend/pkg/restapi/middleware/authentication"
"github.com/th0th/poeticmetric/backend/pkg/restapi/helpers"
"github.com/th0th/poeticmetric/backend/pkg/restapi/middleware/authentication"
)

func OrganizationNonStripeCustomer(c *fiber.Ctx) error {
auth := am.Get(c)
func OrganizationSubscription(c *fiber.Ctx) error {
auth := c.Locals("auth").(*authentication.Auth)

if auth.Organization.StripeCustomerId != nil {
return fiber.ErrForbidden
if auth.Organization.Plan == nil {
return c.
Status(fiber.StatusForbidden).
JSON(helpers.Detail("You need to subscribe to continue to use PoeticMetric"))
}

return c.Next()
Expand Down
21 changes: 0 additions & 21 deletions backend/pkg/restapi/middleware/permission/organization_plan.go

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,6 @@ func UserBasicAuthenticated(c *fiber.Ctx) error {
})(c)
}

func UserEmailVerified(c *fiber.Ctx) error {
return User(&userPermissionMiddlewareConfig{
IsEmailVerified: pointer.Get(true),
})(c)
}

func UserOwner(c *fiber.Ctx) error {
return User(&userPermissionMiddlewareConfig{
IsOrganizationOwner: pointer.Get(true),
Expand Down
2 changes: 1 addition & 1 deletion backend/pkg/restapi/site/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func Add(app *fiber.App) {

group.Get("/public/:domain", readPublic)

group.Use(permission.UserAuthenticated)
group.Use(permission.UserAuthenticated, permission.OrganizationSubscription)

group.Get("/", list)
group.Post("/", create)
Expand Down
52 changes: 25 additions & 27 deletions backend/pkg/restapi/sitereport/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,28 @@ package sitereport

import (
"encoding/json"
"errors"
"fmt"

"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/skip"
"github.com/th0th/poeticmetric/backend/pkg/model"
"github.com/th0th/poeticmetric/backend/pkg/restapi/middleware/authentication"
dm "github.com/th0th/poeticmetric/backend/pkg/restapi/middleware/depot"
"github.com/th0th/poeticmetric/backend/pkg/restapi/middleware/permission"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/browsername"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/browserversion"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/filter"
language2 "github.com/th0th/poeticmetric/backend/pkg/service/sitereport/language"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/operatingsystemname"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/operatingsystemversion"
path2 "github.com/th0th/poeticmetric/backend/pkg/service/sitereport/path"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/referrerpath"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/referrersite"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/utmcampaign"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/utmcontent"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/utmmedium"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/utmsource"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/utmterm"
"gorm.io/gorm"

"github.com/gofiber/fiber/v2"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/filter"
language2 "github.com/th0th/poeticmetric/backend/pkg/service/sitereport/language"
path2 "github.com/th0th/poeticmetric/backend/pkg/service/sitereport/path"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/referrerpath"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/referrersite"
)

const localsFiltersKey = "filters"
Expand All @@ -34,10 +32,19 @@ const localsPaginationCursorKey = "paginationCursor"
func Add(app *fiber.App) {
baseGroup := app.Group("/site-reports", filtersMiddleware)

baseGroup.Post("/export/reports", authentication.NewUserAccessTokenFormAuth(), authenticatedOrPublicMiddleware, exportReports)
baseGroup.Post("/export/events", authentication.NewUserAccessTokenFormAuth(), authenticatedOrPublicMiddleware, exportEvents)
exportGroup := baseGroup.Use(
authentication.NewUserAccessTokenFormAuth,
skip.New(permission.UserAuthenticated, isPublic),
skip.New(permission.OrganizationSubscription, isPublic),
)

exportGroup.Post("/export/reports", exportReports)
exportGroup.Post("/export/events", exportEvents)

group := baseGroup.Use(authenticatedOrPublicMiddleware)
group := baseGroup.Use(
skip.New(permission.UserAuthenticated, isPublic),
skip.New(permission.OrganizationSubscription, isPublic),
)

group.Get("/browser-name", paginationCursorMiddleware[browsername.PaginationCursor], browserName)
group.Get("/browser-version", paginationCursorMiddleware[browserversion.PaginationCursor], browserVersion)
Expand All @@ -62,30 +69,21 @@ func Add(app *fiber.App) {
group.Get("/visitor", visitor)
}

func authenticatedOrPublicMiddleware(c *fiber.Ctx) error {
func isPublic(c *fiber.Ctx) bool {
dp := dm.Get(c)

modelSite := &model.Site{}

err := dp.Postgres().
Model(&model.Site{}).
Select("is_public").
Where("id = ?", getFilters(c).SiteId).
Joins("inner join organizations on organizations.id = sites.organization_id").
Select("sites.is_public").
Where("organizations.plan_id is not null").
Where("sites.id = ?", getFilters(c).SiteId).
First(modelSite).
Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fiber.ErrNotFound
}

return err
}

if modelSite.IsPublic {
return c.Next()
}

return permission.UserAuthenticated(c)
return err == nil && modelSite.IsPublic
}

func getFilters(c *fiber.Ctx) *filter.Filters {
Expand Down
6 changes: 3 additions & 3 deletions backend/pkg/restapi/user/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func Add(app *fiber.App) {
group.Get("/", permission.UserAuthenticated, list)
group.Get("/me", permission.UserAuthenticated, readSelf)
group.Patch("/me", permission.UserAuthenticated, updateSelf)
group.Post("/", permission.UserOwner, invite)
group.Post("/", permission.UserOwner, permission.OrganizationSubscription, invite)
group.Post("/activate", permission.UserUnauthenticated, activate)
group.Post("/change-password", permission.UserBasicAuthenticated, changePassword)
group.Post("/make-owner", permission.UserOwner, makeOwner)
Expand All @@ -21,6 +21,6 @@ func Add(app *fiber.App) {
group.Post("/verify-email-address", verifyEmailAddress)

group.Get("/:id", permission.UserAuthenticated, read)
group.Delete("/:id", permission.UserOwner, destroy)
group.Patch("/:id", permission.UserOwner, update)
group.Delete("/:id", permission.UserOwner, permission.OrganizationSubscription, destroy)
group.Patch("/:id", permission.UserOwner, permission.OrganizationSubscription, update)
}
6 changes: 4 additions & 2 deletions backend/pkg/service/site/read_public.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ func ReadPublic(dp *depot.Depot, domain string) (*Site, error) {

err := dp.Postgres().
Model(&model.Site{}).
Where("is_public is true").
Where("domain = ?", domain).
Joins("inner join organizations on organizations.id = sites.organization_id").
Where("organizations.plan_id is not null").
Where("sites.is_public is true").
Where("sites.domain = ?", domain).
First(site).
Error
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/AuthHandler/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type AuthHandlerProps = {

const fetcher = getFetcher(true, false);

export function AuthHandler({ children }: AuthHandlerProps) {
export function AuthHandler({ children }: AuthHandlerProps) {
const { data: userData, isValidating: isValidatingUser, mutate: mutateUserData } = useSWR<AuthUser, Error>("/users/me", fetcher);
const {
data: organizationData,
Expand Down
8 changes: 7 additions & 1 deletion frontend/components/DocsArticle/Menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ export function Menu({ article: articleFromProps, categories, className, ...prop
<h6 className="px-3">{category.title}</h6>

{category.articles.map((article) => (
<Dropdown.Item key={article.slug}>{article.title}</Dropdown.Item>
<Dropdown.Item
as={Link}
href={`/docs/${category.slug}/${article.slug}`}
key={article.slug}
>
{article.title}
</Dropdown.Item>
))}
</div>
))}
Expand Down
Loading

0 comments on commit 2c7edc5

Please sign in to comment.