From c6f23139bc6b3003f4b2cb98a48fd52669cd8ef3 Mon Sep 17 00:00:00 2001
From: Deluan <deluan@deluan.com>
Date: Fri, 5 Jun 2020 10:59:23 -0400
Subject: [PATCH] Handle playlist's permissions on server

---
 persistence/persistence_suite_test.go    |  2 +-
 persistence/playlist_repository.go       | 14 ++++++++++++
 persistence/playlist_track_repository.go | 27 +++++++++++++++++++++++-
 3 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/persistence/persistence_suite_test.go b/persistence/persistence_suite_test.go
index 8b2968ce2..ade7e3e2c 100644
--- a/persistence/persistence_suite_test.go
+++ b/persistence/persistence_suite_test.go
@@ -86,7 +86,7 @@ var _ = Describe("Initialize test DB", func() {
 	BeforeSuite(func() {
 		o := orm.NewOrm()
 		ctx := log.NewContext(context.TODO())
-		ctx = request.WithUser(ctx, model.User{ID: "userid"})
+		ctx = request.WithUser(ctx, model.User{ID: "userid", UserName: "userid"})
 		mr := NewMediaFileRepository(ctx, o)
 		for i := range testSongs {
 			s := testSongs[i]
diff --git a/persistence/playlist_repository.go b/persistence/playlist_repository.go
index a7ccbd280..c29a18d46 100644
--- a/persistence/playlist_repository.go
+++ b/persistence/playlist_repository.go
@@ -45,6 +45,16 @@ func (r *playlistRepository) Exists(id string) (bool, error) {
 }
 
 func (r *playlistRepository) Delete(id string) error {
+	usr := loggedUser(r.ctx)
+	if !usr.IsAdmin {
+		pls, err := r.Get(id)
+		if err != nil {
+			return err
+		}
+		if pls.Owner != usr.UserName {
+			return rest.ErrPermissionDenied
+		}
+	}
 	err := r.delete(And{Eq{"id": id}, r.userFilter()})
 	if err != nil {
 		return err
@@ -158,6 +168,10 @@ func (r *playlistRepository) Save(entity interface{}) (string, error) {
 
 func (r *playlistRepository) Update(entity interface{}, cols ...string) error {
 	pls := entity.(*model.Playlist)
+	usr := loggedUser(r.ctx)
+	if !usr.IsAdmin && pls.Owner != usr.UserName {
+		return rest.ErrPermissionDenied
+	}
 	err := r.Put(pls)
 	if err == model.ErrNotFound {
 		return rest.ErrNotFound
diff --git a/persistence/playlist_track_repository.go b/persistence/playlist_track_repository.go
index 6f53d0054..c66dd9a5a 100644
--- a/persistence/playlist_track_repository.go
+++ b/persistence/playlist_track_repository.go
@@ -11,11 +11,13 @@ import (
 type playlistTrackRepository struct {
 	sqlRepository
 	sqlRestful
-	playlistId string
+	playlistId   string
+	playlistRepo model.PlaylistRepository
 }
 
 func (r *playlistRepository) Tracks(playlistId string) model.PlaylistTrackRepository {
 	p := &playlistTrackRepository{}
+	p.playlistRepo = NewPlaylistRepository(r.ctx, r.ormer)
 	p.playlistId = playlistId
 	p.ctx = r.ctx
 	p.ormer = r.ormer
@@ -67,6 +69,10 @@ func (r *playlistTrackRepository) NewInstance() interface{} {
 }
 
 func (r *playlistTrackRepository) Add(mediaFileIds []string) error {
+	if !r.isWritable() {
+		return rest.ErrPermissionDenied
+	}
+
 	if len(mediaFileIds) > 0 {
 		log.Debug(r.ctx, "Adding songs to playlist", "playlistId", r.playlistId, "mediaFileIds", mediaFileIds)
 	}
@@ -100,6 +106,10 @@ func (r *playlistTrackRepository) getTracks() ([]string, error) {
 }
 
 func (r *playlistTrackRepository) Update(mediaFileIds []string) error {
+	if !r.isWritable() {
+		return rest.ErrPermissionDenied
+	}
+
 	// Remove old tracks
 	del := Delete(r.tableName).Where(Eq{"playlist_id": r.playlistId})
 	_, err := r.executeSQL(del)
@@ -158,6 +168,9 @@ func (r *playlistTrackRepository) updateStats() error {
 }
 
 func (r *playlistTrackRepository) Delete(id string) error {
+	if !r.isWritable() {
+		return rest.ErrPermissionDenied
+	}
 	err := r.delete(And{Eq{"playlist_id": r.playlistId}, Eq{"id": id}})
 	if err != nil {
 		return err
@@ -166,6 +179,9 @@ func (r *playlistTrackRepository) Delete(id string) error {
 }
 
 func (r *playlistTrackRepository) Reorder(pos int, newPos int) error {
+	if !r.isWritable() {
+		return rest.ErrPermissionDenied
+	}
 	ids, err := r.getTracks()
 	if err != nil {
 		return err
@@ -174,4 +190,13 @@ func (r *playlistTrackRepository) Reorder(pos int, newPos int) error {
 	return r.Update(newOrder)
 }
 
+func (r *playlistTrackRepository) isWritable() bool {
+	usr := loggedUser(r.ctx)
+	if usr.IsAdmin {
+		return true
+	}
+	pls, err := r.playlistRepo.Get(r.playlistId)
+	return err == nil && pls.Owner == usr.UserName
+}
+
 var _ model.PlaylistTrackRepository = (*playlistTrackRepository)(nil)