diff --git a/api/err.go b/api/err.go index d378f1a..52cbd5f 100644 --- a/api/err.go +++ b/api/err.go @@ -1,10 +1,17 @@ package api import ( + "errors" + "github.com/fabiante/persurl/api/res" "github.com/gin-gonic/gin" ) +var ( + ErrForbidden = errors.New("you are not allowed to do this") +) + +// respondWithError responds with an error and aborts the request. func respondWithError(ctx *gin.Context, status int, err error) { response := res.ErrorList{ Errors: []res.Error{ diff --git a/api/server_admin.go b/api/server_admin.go index abdce86..d577373 100644 --- a/api/server_admin.go +++ b/api/server_admin.go @@ -30,7 +30,12 @@ func (s *Server) SavePURL(ctx *gin.Context) { return } - // todo: check user authorization on this url + // check authorization + user := getAuthenticatedUser(ctx) + if domain.OwnerID != user.ID { + respondWithError(ctx, http.StatusForbidden, ErrForbidden) + return + } err = s.admin.SavePURL(domain, name, req.Target) switch { @@ -48,7 +53,9 @@ func (s *Server) SavePURL(ctx *gin.Context) { func (s *Server) CreateDomain(ctx *gin.Context) { domain := ctx.Param("domain") - _, err := s.admin.CreateDomain(domain) + user := getAuthenticatedUser(ctx) + + _, err := s.admin.CreateDomain(user, domain) switch true { case err == nil: ctx.Status(http.StatusNoContent) diff --git a/api/server_routes.go b/api/server_routes.go index c0524db..9f54fb3 100644 --- a/api/server_routes.go +++ b/api/server_routes.go @@ -19,6 +19,8 @@ func SetupRouting(r gin.IRouter, s *Server) { swaggerUI.Register(r) } + isAuthenticated := authenticatedMiddleware(s.user) + webapp.Register(r) validDomain := validPathVar("domain", regexNamed) @@ -40,10 +42,10 @@ func SetupRouting(r gin.IRouter, s *Server) { admin.Use(validDomain) // Domain - admin.POST("/domains/:domain", s.CreateDomain) + admin.POST("/domains/:domain", isAuthenticated, s.CreateDomain) // PURL - admin.PUT("/domains/:domain/purls/:name", validName, s.SavePURL) + admin.PUT("/domains/:domain/purls/:name", isAuthenticated, validName, s.SavePURL) } // System endpoints diff --git a/app/models/purl.go b/app/models/purl.go index 061ec14..0725917 100644 --- a/app/models/purl.go +++ b/app/models/purl.go @@ -5,6 +5,8 @@ import "gorm.io/gorm" type Domain struct { gorm.Model + OwnerID uint + Name string PURLs []*PURL `gorm:"foreignKey:DomainID"` diff --git a/app/models/user.go b/app/models/user.go index 1d087eb..12f77b8 100644 --- a/app/models/user.go +++ b/app/models/user.go @@ -7,6 +7,8 @@ type User struct { Email string + Domains []*Domain `gorm:"foreignKey:OwnerID"` + Keys []*UserKey `gorm:"foreignKey:OwnerID"` } diff --git a/app/service.go b/app/service.go index 9a56ff1..b3e72a1 100644 --- a/app/service.go +++ b/app/service.go @@ -24,7 +24,7 @@ type AdminServiceInterface interface { // CreateDomain creates a new domain. // // ErrBadRequest is returned if the domain already exists. - CreateDomain(domain string) (*models.Domain, error) + CreateDomain(user *models.User, domain string) (*models.Domain, error) // GetDomain returns the domain with the given name. // diff --git a/app/service_impl.go b/app/service_impl.go index e14f3cc..4a48f34 100644 --- a/app/service_impl.go +++ b/app/service_impl.go @@ -39,9 +39,10 @@ func (s *service) Resolve(domain, name string) (string, error) { } } -func (s *service) CreateDomain(name string) (*models.Domain, error) { +func (s *service) CreateDomain(user *models.User, name string) (*models.Domain, error) { domain := &models.Domain{ - Name: name, + Name: name, + OwnerID: user.ID, } err := s.db.Create(domain).Error diff --git a/db/migrations/migrate.go b/db/migrations/migrate.go index 4adfe40..2e1d938 100644 --- a/db/migrations/migrate.go +++ b/db/migrations/migrate.go @@ -93,4 +93,11 @@ var migrationsPostgres = []any{ add constraint user_keys_owner_fk foreign key (owner_id) references users on delete restrict`), + newMigration("2023-09-25-00000060-AddOwnerIdToDomains", `alter table domains + add owner_id integer not null`,), + newMigration("2023-09-25-00000070-AddOwnerIdToDomainsFK", `alter table domains + add constraint domains_owner_fk + foreign key (owner_id) references users + on delete restrict; + `), }