2025-02-21 12:28:11 +05:30

270 lines
9.5 KiB
Go

package collections
import (
"context"
"fmt"
"github.com/ente-io/museum/ente"
"github.com/ente-io/museum/pkg/controller/access"
"github.com/ente-io/museum/pkg/utils/array"
"github.com/ente-io/museum/pkg/utils/auth"
"github.com/ente-io/museum/pkg/utils/time"
"github.com/ente-io/stacktrace"
"github.com/gin-contrib/requestid"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
"strings"
)
func (c *CollectionController) Share(ctx *gin.Context, req ente.AlterShareRequest) ([]ente.CollectionUser, error) {
fromUserID := auth.GetUserID(ctx.Request.Header)
cID := req.CollectionID
encryptedKey := req.EncryptedKey
toUserEmail := strings.ToLower(strings.TrimSpace(req.Email))
// default role type
role := ente.VIEWER
if req.Role != nil {
role = *req.Role
}
toUserID, err := c.UserRepo.GetUserIDWithEmail(toUserEmail)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
if toUserID == fromUserID {
return nil, stacktrace.Propagate(ente.ErrBadRequest, "Can not share collection with self")
}
collection, err := c.CollectionRepo.Get(cID)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
if !collection.AllowSharing() {
return nil, stacktrace.Propagate(ente.ErrBadRequest, fmt.Sprintf("sharing %s is not allowed", collection.Type))
}
if fromUserID != collection.Owner.ID {
return nil, stacktrace.Propagate(ente.ErrPermissionDenied, "")
}
err = c.BillingCtrl.HasActiveSelfOrFamilySubscription(fromUserID, true)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
err = c.CollectionRepo.Share(cID, fromUserID, toUserID, encryptedKey, role, time.Microseconds())
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
sharees, err := c.GetSharees(ctx, cID, fromUserID)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
return sharees, nil
}
func (c *CollectionController) JoinViaLink(ctx *gin.Context, req ente.JoinCollectionViaLinkRequest) error {
userID := auth.GetUserID(ctx.Request.Header)
collection, err := c.CollectionRepo.Get(req.CollectionID)
if err != nil {
return stacktrace.Propagate(err, "")
}
if collection.Owner.ID == userID {
return stacktrace.Propagate(ente.ErrBadRequest, "owner can not join via link")
}
if !collection.AllowSharing() {
return stacktrace.Propagate(ente.ErrBadRequest, fmt.Sprintf("joining %s is not allowed", collection.Type))
}
publicCollectionToken, err := c.PublicCollectionCtrl.GetActivePublicCollectionToken(ctx, req.CollectionID)
if err != nil {
return stacktrace.Propagate(err, "")
}
if canJoin := publicCollectionToken.CanJoin(); canJoin != nil {
return stacktrace.Propagate(ente.ErrBadRequest, fmt.Sprintf("can not join collection: %s", canJoin.Error()))
}
accessToken := auth.GetAccessToken(ctx)
if publicCollectionToken.Token != accessToken {
return stacktrace.Propagate(ente.ErrPermissionDenied, "token doesn't match collection")
}
if publicCollectionToken.PassHash != nil && *publicCollectionToken.PassHash != "" {
accessTokenJWT := auth.GetAccessTokenJWT(ctx)
if passCheckErr := c.PublicCollectionCtrl.ValidateJWTToken(ctx, accessTokenJWT, *publicCollectionToken.PassHash); passCheckErr != nil {
return stacktrace.Propagate(passCheckErr, "")
}
}
err = c.BillingCtrl.HasActiveSelfOrFamilySubscription(collection.Owner.ID, true)
if err != nil {
return stacktrace.Propagate(err, "")
}
role := ente.VIEWER
if publicCollectionToken.EnableCollect {
role = ente.COLLABORATOR
}
joinErr := c.CollectionRepo.Share(req.CollectionID, collection.Owner.ID, userID, req.EncryptedKey, role, time.Microseconds())
if joinErr != nil {
return stacktrace.Propagate(joinErr, "")
}
go c.EmailCtrl.OnLinkJoined(collection.Owner.ID, userID, role)
return nil
}
// UnShare unshares a collection with a user
func (c *CollectionController) UnShare(ctx *gin.Context, cID int64, fromUserID int64, toUserEmail string) ([]ente.CollectionUser, error) {
toUserID, err := c.UserRepo.GetUserIDWithEmail(toUserEmail)
if err != nil {
return nil, stacktrace.Propagate(ente.ErrNotFound, "")
}
collection, err := c.CollectionRepo.Get(cID)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
isLeavingCollection := toUserID == fromUserID
if fromUserID != collection.Owner.ID || isLeavingCollection {
return nil, stacktrace.Propagate(ente.ErrPermissionDenied, "")
}
err = c.CollectionRepo.UnShare(cID, toUserID)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
err = c.CastRepo.RevokeForGivenUserAndCollection(ctx, cID, toUserID)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
sharees, err := c.GetSharees(ctx, cID, fromUserID)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
return sharees, nil
}
// Leave leaves the collection owned by someone else,
func (c *CollectionController) Leave(ctx *gin.Context, cID int64) error {
userID := auth.GetUserID(ctx.Request.Header)
collection, err := c.CollectionRepo.Get(cID)
if err != nil {
return stacktrace.Propagate(err, "")
}
if userID == collection.Owner.ID {
return stacktrace.Propagate(ente.ErrPermissionDenied, "can not leave collection owned by self")
}
sharedCollectionIDs, err := c.CollectionRepo.GetCollectionIDsSharedWithUser(userID)
if err != nil {
return stacktrace.Propagate(err, "")
}
if !array.Int64InList(cID, sharedCollectionIDs) {
return nil
}
err = c.CastRepo.RevokeForGivenUserAndCollection(ctx, cID, userID)
if err != nil {
return stacktrace.Propagate(err, "")
}
err = c.CollectionRepo.UnShare(cID, userID)
if err != nil {
return stacktrace.Propagate(err, "")
}
return nil
}
func (c *CollectionController) UpdateShareeMagicMetadata(ctx *gin.Context, req ente.UpdateCollectionMagicMetadata) error {
actorUserId := auth.GetUserID(ctx.Request.Header)
resp, err := c.AccessCtrl.GetCollection(ctx, &access.GetCollectionParams{
CollectionID: req.ID,
ActorUserID: actorUserId,
})
if err != nil {
return stacktrace.Propagate(err, "")
}
if resp.Collection.Owner.ID == actorUserId {
return stacktrace.Propagate(ente.NewBadRequestWithMessage("owner can not update sharee magic metadata"), "")
}
err = c.CollectionRepo.UpdateShareeMetadata(req.ID, resp.Collection.Owner.ID, actorUserId, req.MagicMetadata, time.Microseconds())
if err != nil {
return stacktrace.Propagate(err, "failed to update sharee magic metadata")
}
return nil
}
// ShareURL generates a public auth-token for the given collectionID
func (c *CollectionController) ShareURL(ctx context.Context, userID int64, req ente.CreatePublicAccessTokenRequest) (
ente.PublicURL, error) {
collection, err := c.CollectionRepo.Get(req.CollectionID)
if err != nil {
return ente.PublicURL{}, stacktrace.Propagate(err, "")
}
if !collection.AllowSharing() {
return ente.PublicURL{}, stacktrace.Propagate(ente.ErrBadRequest, fmt.Sprintf("sharing %s is not allowed", collection.Type))
}
if userID != collection.Owner.ID {
return ente.PublicURL{}, stacktrace.Propagate(ente.ErrPermissionDenied, "")
}
err = c.BillingCtrl.HasActiveSelfOrFamilySubscription(userID, true)
if err != nil {
return ente.PublicURL{}, stacktrace.Propagate(err, "")
}
response, err := c.PublicCollectionCtrl.CreateAccessToken(ctx, req)
if err != nil {
return ente.PublicURL{}, stacktrace.Propagate(err, "")
}
return response, nil
}
// UpdateShareURL updates the shared url configuration
func (c *CollectionController) UpdateShareURL(ctx context.Context, userID int64, req ente.UpdatePublicAccessTokenRequest) (
ente.PublicURL, error) {
if err := c.verifyOwnership(req.CollectionID, userID); err != nil {
return ente.PublicURL{}, stacktrace.Propagate(err, "")
}
err := c.BillingCtrl.HasActiveSelfOrFamilySubscription(userID, true)
if err != nil {
return ente.PublicURL{}, stacktrace.Propagate(err, "")
}
response, err := c.PublicCollectionCtrl.UpdateSharedUrl(ctx, req)
if err != nil {
return ente.PublicURL{}, stacktrace.Propagate(err, "")
}
return response, nil
}
// DisableSharedURL disable a public auth-token for the given collectionID
func (c *CollectionController) DisableSharedURL(ctx context.Context, userID int64, cID int64) error {
if err := c.verifyOwnership(cID, userID); err != nil {
return stacktrace.Propagate(err, "")
}
err := c.PublicCollectionCtrl.Disable(ctx, cID)
return stacktrace.Propagate(err, "")
}
// GetSharees returns the list of users a collection has been shared with
func (c *CollectionController) GetSharees(ctx *gin.Context, cID int64, userID int64) ([]ente.CollectionUser, error) {
_, err := c.AccessCtrl.GetCollection(ctx, &access.GetCollectionParams{
CollectionID: cID,
ActorUserID: userID,
})
if err != nil {
return nil, stacktrace.Propagate(err, "Access check failed")
}
sharees, err := c.CollectionRepo.GetSharees(cID)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
return sharees, nil
}
// GetPublicDiff returns the changes in the collections since a timestamp, along with hasMore bool flag.
func (c *CollectionController) GetPublicDiff(ctx *gin.Context, sinceTime int64) ([]ente.File, bool, error) {
accessContext := auth.MustGetPublicAccessContext(ctx)
reqContextLogger := log.WithFields(log.Fields{
"public_id": accessContext.ID,
"collection_id": accessContext.CollectionID,
"since_time": sinceTime,
"req_id": requestid.Get(ctx),
})
diff, hasMore, err := c.getDiff(accessContext.CollectionID, sinceTime, CollectionDiffLimit, reqContextLogger)
if err != nil {
return nil, false, stacktrace.Propagate(err, "")
}
// hide private metadata before returning files info in diff
for idx := range diff {
if diff[idx].MagicMetadata != nil {
diff[idx].MagicMetadata = nil
}
}
return diff, hasMore, nil
}