From 24f11f305e44bb0e6636bee08a58f95e2aa8ba91 Mon Sep 17 00:00:00 2001 From: David Christofas Date: Mon, 6 Mar 2023 16:29:21 +0100 Subject: [PATCH] add option to enforce passwords on public links (#3698) --- changelog/unreleased/public-link-password.md | 5 ++++ .../services/gateway/publicshareprovider.go | 18 +++++++++------ .../publicshareprovider.go | 23 ++++++++++++++++--- .../handlers/apps/sharing/shares/public.go | 5 ++++ pkg/publicshare/publicshare.go | 7 ++++++ 5 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 changelog/unreleased/public-link-password.md diff --git a/changelog/unreleased/public-link-password.md b/changelog/unreleased/public-link-password.md new file mode 100644 index 0000000000..e9e50d883d --- /dev/null +++ b/changelog/unreleased/public-link-password.md @@ -0,0 +1,5 @@ +Enhancement: Add config option to enforce passwords on public links + +Added a new config option to enforce passwords on public links with "Uploader, Editor, Contributor" roles. + +https://github.com/cs3org/reva/pull/3698 diff --git a/internal/grpc/services/gateway/publicshareprovider.go b/internal/grpc/services/gateway/publicshareprovider.go index 24e932ee78..747309ce42 100644 --- a/internal/grpc/services/gateway/publicshareprovider.go +++ b/internal/grpc/services/gateway/publicshareprovider.go @@ -44,7 +44,9 @@ func (s *svc) CreatePublicShare(ctx context.Context, req *link.CreatePublicShare return nil, err } - s.statCache.RemoveStat(ctxpkg.ContextMustGetUser(ctx).GetId(), res.Share.ResourceId) + if res.GetShare() != nil { + s.statCache.RemoveStat(ctxpkg.ContextMustGetUser(ctx).GetId(), res.Share.ResourceId) + } return res, nil } @@ -139,11 +141,13 @@ func (s *svc) UpdatePublicShare(ctx context.Context, req *link.UpdatePublicShare if err != nil { return nil, errors.Wrap(err, "error updating share") } - s.statCache.RemoveStat( - &userprovider.UserId{ - OpaqueId: res.Share.Owner.GetOpaqueId(), - }, - res.Share.ResourceId, - ) + if res.GetShare() != nil { + s.statCache.RemoveStat( + &userprovider.UserId{ + OpaqueId: res.Share.Owner.GetOpaqueId(), + }, + res.Share.ResourceId, + ) + } return res, nil } diff --git a/internal/grpc/services/publicshareprovider/publicshareprovider.go b/internal/grpc/services/publicshareprovider/publicshareprovider.go index 5f01e2bae7..b52e1d6939 100644 --- a/internal/grpc/services/publicshareprovider/publicshareprovider.go +++ b/internal/grpc/services/publicshareprovider/publicshareprovider.go @@ -40,9 +40,10 @@ func init() { } type config struct { - Driver string `mapstructure:"driver"` - Drivers map[string]map[string]interface{} `mapstructure:"drivers"` - AllowedPathsForShares []string `mapstructure:"allowed_paths_for_shares"` + Driver string `mapstructure:"driver"` + Drivers map[string]map[string]interface{} `mapstructure:"drivers"` + AllowedPathsForShares []string `mapstructure:"allowed_paths_for_shares"` + WriteableShareMustHavePassword bool `mapstructure:"writeable_share_must_have_password"` } func (c *config) init() { @@ -140,6 +141,14 @@ func (s *service) CreatePublicShare(ctx context.Context, req *link.CreatePublicS }, nil } + grant := req.GetGrant() + if grant != nil && s.conf.WriteableShareMustHavePassword && + publicshare.IsWriteable(grant) && grant.Password == "" { + return &link.CreatePublicShareResponse{ + Status: status.NewInvalid(ctx, "writeable shares must have a password protection"), + }, nil + } + u, ok := ctxpkg.ContextGetUser(ctx) if !ok { log.Error().Msg("error getting user from context") @@ -244,6 +253,14 @@ func (s *service) UpdatePublicShare(ctx context.Context, req *link.UpdatePublicS log := appctx.GetLogger(ctx) log.Info().Str("publicshareprovider", "update").Msg("update public share") + grant := req.GetUpdate().GetGrant() + if grant != nil && s.conf.WriteableShareMustHavePassword && + publicshare.IsWriteable(grant) && grant.Password == "" { + return &link.UpdatePublicShareResponse{ + Status: status.NewInvalid(ctx, "writeable shares must have a password protection"), + }, nil + } + u, ok := ctxpkg.ContextGetUser(ctx) if !ok { log.Error().Msg("error getting user from context") diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go index 0556794ede..418cd22aaa 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go @@ -470,6 +470,11 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "Error sending update request to public link provider", err) return } + if uRes.Status.Code != rpc.Code_CODE_OK { + log.Debug().Str("shareID", shareID).Msgf("sending update request to public link provider failed: %s", uRes.Status.Message) + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, fmt.Sprintf("Error sending update request to public link provider: %s", uRes.Status.Message), nil) + return + } } publicShare = uRes.Share } else if !updatesFound { diff --git a/pkg/publicshare/publicshare.go b/pkg/publicshare/publicshare.go index 695eb3984d..2f3ba444e4 100644 --- a/pkg/publicshare/publicshare.go +++ b/pkg/publicshare/publicshare.go @@ -211,3 +211,10 @@ func Authenticate(share *link.PublicShare, pw string, auth *link.PublicShareAuth func IsCreatedByUser(share link.PublicShare, user *user.User) bool { return utils.UserEqual(user.Id, share.Owner) || utils.UserEqual(user.Id, share.Creator) } + +// IsWriteable checks if the grant for a publicshare allows writes or uploads. +func IsWriteable(g *link.Grant) bool { + p := g.Permissions.Permissions + return p.CreateContainer || p.Delete || p.InitiateFileUpload || + p.Move || p.AddGrant || p.PurgeRecycle || p.RestoreFileVersion || p.RestoreRecycleItem +}