mirror of
https://github.com/ente-io/ente.git
synced 2025-05-07 21:43:22 +00:00
270 lines
9.5 KiB
Go
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
|
|
}
|