Merge pull request #7097 from kobergj/AutoAcceptShares

Auto Accept Shares
This commit is contained in:
kobergj
2023-09-07 09:06:59 +02:00
committed by GitHub
21 changed files with 375 additions and 38 deletions
@@ -0,0 +1,5 @@
Enhancement: Auto-Accept Shares
Automatically accept shares when configured by the user or admin
https://github.com/owncloud/ocis/pull/7097
+1 -1
View File
@@ -13,7 +13,7 @@ require (
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/coreos/go-oidc/v3 v3.6.0
github.com/cs3org/go-cs3apis v0.0.0-20230516150832-730ac860c71d
github.com/cs3org/reva/v2 v2.16.1-0.20230831084113-cb0897d2eefe
github.com/cs3org/reva/v2 v2.16.1-0.20230904124812-2ebd3e92cdb9
github.com/disintegration/imaging v1.6.2
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
github.com/egirna/icap-client v0.1.1
+2 -2
View File
@@ -858,8 +858,8 @@ github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo
github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
github.com/crewjam/saml v0.4.13 h1:TYHggH/hwP7eArqiXSJUvtOPNzQDyQ7vwmwEqlFWhMc=
github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA=
github.com/cs3org/reva/v2 v2.16.1-0.20230831084113-cb0897d2eefe h1:kCM/ZPcbG0wWDgOFrvHV/KP6d1l1PVbcPje9QfQUVAU=
github.com/cs3org/reva/v2 v2.16.1-0.20230831084113-cb0897d2eefe/go.mod h1:RvhuweTFqzezjUFU0SIdTXakrEx9vJlMvQ7znPXSP1g=
github.com/cs3org/reva/v2 v2.16.1-0.20230904124812-2ebd3e92cdb9 h1:YWkkoagYryRH56z5pw04Py0Ebg7spCZaWpsxjwGiNgU=
github.com/cs3org/reva/v2 v2.16.1-0.20230904124812-2ebd3e92cdb9/go.mod h1:RvhuweTFqzezjUFU0SIdTXakrEx9vJlMvQ7znPXSP1g=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+6 -2
View File
@@ -73,7 +73,8 @@ type IdmService struct {
}
type FrontendService struct {
Archiver InsecureService
Archiver InsecureService
ServiceAccount ServiceAccount `yaml:"service_account"`
}
type AuthbasicService struct {
@@ -377,6 +378,9 @@ func CreateConfig(insecure, forceOverwrite bool, configPath, adminPassword strin
Notifications: Notifications{
ServiceAccount: serviceAccount,
},
Frontend: FrontendService{
ServiceAccount: serviceAccount,
},
}
if insecure {
@@ -384,7 +388,7 @@ func CreateConfig(insecure, forceOverwrite bool, configPath, adminPassword strin
cfg.AuthBearer = AuthbearerService{
AuthProviders: AuthProviderSettings{Oidc: _insecureService},
}
cfg.Frontend = FrontendService{Archiver: _insecureService}
cfg.Frontend.Archiver = _insecureService
cfg.Graph.Spaces = _insecureService
cfg.Graph.Events = _insecureEvents
cfg.Notifications.Notifications.Events = _insecureEvents
+8
View File
@@ -55,3 +55,11 @@ The `frontend` service can use a configured store via `FRONTEND_OCS_STAT_CACHE_S
2. Though usually not necessary, a database name and a database table can be configured for event stores if the event store supports this. Generally not applicable for stores of type `in-memory`. These settings are blank by default which means that the standard settings of the configured store apply.
3. The frontend service can be scaled if not using `in-memory` stores and the stores are configured identically over all instances.
4. When using `redis-sentinel`, the Redis master to use is configured via `FRONTEND_OCS_STAT_CACHE_STORE_NODES` in the form of `<sentinel-host>:<sentinel-port>/<redis-master>` like `10.10.0.200:26379/mymaster`.
## Event Handler
The `frontend` service contains an eventhandler for handling `ocs` related events. As of now, it only listens to the `ShareCreated` event.
### Auto-Accept Shares
When setting the `FRONTEND_AUTO_ACCEPT_SHARES` to `true`, all incoming shares will be accepted automatically. Users can overwrite this setting individually in their profile.
+177
View File
@@ -0,0 +1,177 @@
package command
import (
"context"
"errors"
"github.com/cs3org/reva/v2/pkg/events"
"github.com/cs3org/reva/v2/pkg/events/stream"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
"github.com/owncloud/ocis/v2/ocis-pkg/registry"
"github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
"github.com/owncloud/ocis/v2/services/frontend/pkg/config"
"github.com/owncloud/ocis/v2/services/settings/pkg/store/defaults"
"go-micro.dev/v4/metadata"
"google.golang.org/protobuf/types/known/fieldmaskpb"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
)
var _registeredEvents = []events.Unmarshaller{
events.ShareCreated{},
}
// ListenForEvents listens for events and acts accordingly
func ListenForEvents(ctx context.Context, cfg *config.Config, l log.Logger) error {
bus, err := stream.NatsFromConfig(cfg.Service.Name, stream.NatsConfig(cfg.Events))
if err != nil {
l.Error().Err(err).Msg("cannot connect to nats")
return err
}
evChannel, err := events.Consume(bus, "frontend", _registeredEvents...)
if err != nil {
l.Error().Err(err).Msg("cannot consume from nats")
return err
}
tm, err := pool.StringToTLSMode(cfg.GRPCClientTLS.Mode)
if err != nil {
return err
}
gatewaySelector, err := pool.GatewaySelector(
cfg.Reva.Address,
pool.WithTLSCACert(cfg.GRPCClientTLS.CACert),
pool.WithTLSMode(tm),
pool.WithRegistry(registry.GetRegistry()),
)
if err != nil {
l.Error().Err(err).Msg("cannot get gateway selector")
return err
}
gwc, err := gatewaySelector.Next()
if err != nil {
l.Error().Err(err).Msg("cannot get gateway client")
return err
}
traceProvider, err := tracing.GetServiceTraceProvider(cfg.Tracing, cfg.Service.Name)
if err != nil {
l.Error().Err(err).Msg("cannot initialize tracing")
return err
}
grpcClient, err := grpc.NewClient(
append(
grpc.GetClientOptions(cfg.GRPCClientTLS),
grpc.WithTraceProvider(traceProvider),
)...,
)
if err != nil {
l.Error().Err(err).Msg("cannot create grpc client")
return err
}
valueService := settingssvc.NewValueService("com.owncloud.api.settings", grpcClient)
for {
select {
case e := <-evChannel:
switch ev := e.Event.(type) {
default:
l.Error().Interface("event", e).Msg("unhandled event")
case events.ShareCreated:
AutoAcceptShares(ev, cfg.AutoAcceptShares, l, gwc, valueService, cfg.ServiceAccount)
}
case <-ctx.Done():
l.Info().Msg("context cancelled")
return ctx.Err()
}
}
}
// AutoAcceptShares automatically accepts shares if configured by the admin or user
func AutoAcceptShares(ev events.ShareCreated, autoAcceptDefault bool, l log.Logger, gwc gateway.GatewayAPIClient, vs settingssvc.ValueService, cfg config.ServiceAccount) {
ctx, err := utils.GetServiceUserContext(cfg.ServiceAccountID, gwc, cfg.ServiceAccountSecret)
if err != nil {
l.Error().Err(err).Msg("cannot impersonate user")
return
}
uids, err := getUserIDs(ctx, gwc, ev.GranteeUserID, ev.GranteeGroupID)
if err != nil {
l.Error().Err(err).Msg("cannot get granteess")
return
}
for _, uid := range uids {
if !autoAcceptShares(ctx, uid, autoAcceptDefault, vs) {
continue
}
resp, err := gwc.UpdateReceivedShare(ctx, updateShareRequest(ev.ShareID, uid))
if err != nil {
l.Error().Err(err).Msg("error sending grpc request")
continue
}
if resp.GetStatus().GetCode() != rpc.Code_CODE_OK {
l.Error().Interface("status", resp.GetStatus()).Str("userid", uid.GetOpaqueId()).Msg("unexpected status code while accepting share")
}
}
}
func getUserIDs(ctx context.Context, gwc gateway.GatewayAPIClient, uid *user.UserId, gid *group.GroupId) ([]*user.UserId, error) {
if uid != nil {
return []*user.UserId{uid}, nil
}
res, err := gwc.GetGroup(ctx, &group.GetGroupRequest{GroupId: gid})
if err != nil {
return nil, err
}
if res.GetStatus().GetCode() != rpc.Code_CODE_OK {
return nil, errors.New("could not get group")
}
return res.GetGroup().GetMembers(), nil
}
func autoAcceptShares(ctx context.Context, u *user.UserId, defaultValue bool, vs settingssvc.ValueService) bool {
granteeCtx := metadata.Set(ctx, middleware.AccountID, u.OpaqueId)
if resp, err := vs.GetValueByUniqueIdentifiers(granteeCtx,
&settingssvc.GetValueByUniqueIdentifiersRequest{
AccountUuid: u.OpaqueId,
SettingId: defaults.SettingUUIDProfileAutoAcceptShares,
},
); err == nil {
return resp.GetValue().GetValue().GetBoolValue()
}
return defaultValue
}
func updateShareRequest(shareID *collaboration.ShareId, uid *user.UserId) *collaboration.UpdateReceivedShareRequest {
return &collaboration.UpdateReceivedShareRequest{
Opaque: utils.AppendJSONToOpaque(nil, "userid", uid),
Share: &collaboration.ReceivedShare{
Share: &collaboration.Share{
Id: shareID,
},
State: collaboration.ShareState_SHARE_STATE_ACCEPTED,
},
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"state"}},
}
}
+7
View File
@@ -90,6 +90,13 @@ func Server(cfg *config.Config) *cli.Command {
logger.Fatal().Err(err).Msg("failed to register the http service")
}
// add event handler
gr.Add(func() error {
return ListenForEvents(ctx, cfg, logger)
}, func(_ error) {
cancel()
})
return gr.Run()
},
}
+20
View File
@@ -53,6 +53,11 @@ type Config struct {
Middleware Middleware `yaml:"middleware"`
Events Events `yaml:"events"`
GRPCClientTLS *shared.GRPCClientTLS `yaml:"grpc_client_tls"`
AutoAcceptShares bool `yaml:"auto_accept_shares" env:"FRONTEND_AUTO_ACCEPT_SHARES" desc:"Defines if shares should be auto accepted by default. Users can change this setting individually in their profile."`
ServiceAccount ServiceAccount `yaml:"service_account"`
Supervised bool `yaml:"-"`
Context context.Context `yaml:"-"`
}
@@ -151,3 +156,18 @@ type Checksums struct {
SupportedTypes []string `yaml:"supported_types" env:"FRONTEND_CHECKSUMS_SUPPORTED_TYPES" desc:"Define the checksum types that indicate to clients which hashes the server can use to verify upload integrity. You can provide multiple types separated by blank or comma. Supported types are 'sha1', 'md5' and 'adler32'."`
PreferredUploadType string `yaml:"preferred_upload_type" env:"FRONTEND_CHECKSUMS_PREFERRED_UPLOAD_TYPE" desc:"The supported checksum type for uploads that indicates to clients supporting multiple hash algorithms which one is preferred by the server. Must be one out of the defined list of SUPPORTED_TYPES."`
}
// Events combines the configuration options for the event bus.
type Events struct {
Endpoint string `yaml:"endpoint" env:"OCIS_EVENTS_ENDPOINT;FRONTEND_EVENTS_ENDPOINT" desc:"The address of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture."`
Cluster string `yaml:"cluster" env:"OCIS_EVENTS_CLUSTER;FRONTEND_EVENTS_CLUSTER" desc:"The clusterID of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture. Mandatory when using NATS as event system."`
TLSInsecure bool `yaml:"tls_insecure" env:"OCIS_INSECURE;FRONTEND_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates."`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"FRONTEND_EVENTS_TLS_ROOT_CA_CERTIFICATE;OCS_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided NOTIFICATIONS_EVENTS_TLS_INSECURE will be seen as false."`
EnableTLS bool `yaml:"enable_tls" env:"OCIS_EVENTS_ENABLE_TLS;FRONTEND_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the ocis service which receives and delivers events between the services.."`
}
// ServiceAccount is the configuration for the used service account
type ServiceAccount struct {
ServiceAccountID string `yaml:"service_account_id" env:"OCIS_SERVICE_ACCOUNT_ID;FRONTEND_SERVICE_ACCOUNT_ID" desc:"The ID of the service account the service should use. See the 'auth-service' service description for more details."`
ServiceAccountSecret string `yaml:"service_account_secret" env:"OCIS_SERVICE_ACCOUNT_SECRET;FRONTEND_SERVICE_ACCOUNT_SECRET" desc:"The service account secret."`
}
@@ -120,6 +120,11 @@ func DefaultConfig() *config.Config {
},
},
LDAPServerWriteEnabled: true,
Events: config.Events{
Endpoint: "127.0.0.1:9233",
Cluster: "ocis-cluster",
EnableTLS: false,
},
}
}
@@ -5,6 +5,7 @@ import (
ociscfg "github.com/owncloud/ocis/v2/ocis-pkg/config"
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
"github.com/owncloud/ocis/v2/ocis-pkg/structs"
"github.com/owncloud/ocis/v2/services/frontend/pkg/config"
"github.com/owncloud/ocis/v2/services/frontend/pkg/config/defaults"
@@ -46,5 +47,9 @@ func Validate(cfg *config.Config) error {
return shared.MissingMachineAuthApiKeyError(cfg.Service.Name)
}
if cfg.GRPCClientTLS == nil && cfg.Commons != nil {
cfg.GRPCClientTLS = structs.CopyOrZeroValue(cfg.Commons.GRPCClientTLS)
}
return nil
}
+6 -2
View File
@@ -1,3 +1,7 @@
# OCS
# OCS Service
The ocs service is an ...
The `ocs` service (open collaboration services) serves one purpose: it has an endpoint for signing keys which the web frontend accesses when uploading data.
## Signing-Keys Endpoint
The `ocs` service contains an endpoint `/cloud/user/signing-key` on which a user can GET a signing key. Note, this functionality might be deprecated or moved in the future.
@@ -40,6 +40,13 @@ const (
// DisableEmailNotificationsPermissionDisplayName is the hardcoded setting name for the disable email notifications permission
DisableEmailNotificationsPermissionDisplayName string = "Disable Email Notifications"
// AutoAcceptSharesPermissionID is the hardcoded setting UUID for the disable email notifications permission
AutoAcceptSharesPermissionID string = "4e41363c-a058-40a5-aec8-958897511209"
// AutoAcceptSharesPermissionName is the hardcoded setting name for the disable email notifications permission
AutoAcceptSharesPermissionName string = "AutoAcceptShares.ReadWriteDisabled"
// AutoAcceptSharesPermissionDisplayName is the hardcoded setting name for the disable email notifications permission
AutoAcceptSharesPermissionDisplayName string = "enable/disable auto accept shares"
// SetPersonalSpaceQuotaPermissionID is the hardcoded setting UUID for the set personal space quota permission
SetPersonalSpaceQuotaPermissionID string = "4e6f9709-f9e7-44f1-95d4-b762d27b7896"
// SetPersonalSpaceQuotaPermissionName is the hardcoded setting name for the set personal space quota permission
@@ -84,6 +91,8 @@ const (
SettingUUIDProfileLanguage = "aa8cfbe5-95d4-4f7e-a032-c3c01f5f062f"
// SettingUUIDProfileDisableNotifications is the hardcoded setting UUID for the disable notifications setting
SettingUUIDProfileDisableNotifications = "33ffb5d6-cd07-4dc0-afb0-84f7559ae438"
// SettingUUIDProfileAutoAcceptShares is the hardcoded setting UUID for the disable notifications setting
SettingUUIDProfileAutoAcceptShares = "ec3ed4a3-3946-4efc-8f9f-76d38b12d3a9"
// AccountManagementPermissionID is the hardcoded setting UUID for the account management permission
AccountManagementPermissionID string = "8e587774-d929-4215-910b-a317b1e80f73"
@@ -193,6 +202,21 @@ func generateBundleAdminRole() *settingsmsg.Bundle {
},
},
},
{
Id: AutoAcceptSharesPermissionID,
Name: AutoAcceptSharesPermissionName,
DisplayName: AutoAcceptSharesPermissionDisplayName,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SETTING,
Id: SettingUUIDProfileAutoAcceptShares,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
},
},
},
{
Id: AccountManagementPermissionID,
Name: AccountManagementPermissionName,
@@ -510,6 +534,21 @@ func generateBundleSpaceAdminRole() *settingsmsg.Bundle {
},
},
},
{
Id: AutoAcceptSharesPermissionID,
Name: AutoAcceptSharesPermissionName,
DisplayName: AutoAcceptSharesPermissionDisplayName,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SETTING,
Id: SettingUUIDProfileAutoAcceptShares,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
},
},
},
{
Id: SelfManagementPermissionID,
Name: SelfManagementPermissionName,
@@ -601,6 +640,21 @@ func generateBundleUserRole() *settingsmsg.Bundle {
},
},
},
{
Id: AutoAcceptSharesPermissionID,
Name: AutoAcceptSharesPermissionName,
DisplayName: AutoAcceptSharesPermissionDisplayName,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SETTING,
Id: SettingUUIDProfileAutoAcceptShares,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
},
},
},
{
Id: SelfManagementPermissionID,
Name: SelfManagementPermissionName,
@@ -692,6 +746,21 @@ func generateBundleUserLightRole() *settingsmsg.Bundle {
},
},
},
{
Id: AutoAcceptSharesPermissionID,
Name: AutoAcceptSharesPermissionName,
DisplayName: AutoAcceptSharesPermissionDisplayName,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SETTING,
Id: SettingUUIDProfileAutoAcceptShares,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
},
},
},
},
}
}
@@ -727,6 +796,16 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
},
Value: &settingsmsg.Setting_BoolValue{BoolValue: &settingsmsg.Bool{Default: false, Label: "disable notifications"}},
},
{
Id: SettingUUIDProfileAutoAcceptShares,
Name: "auto-accept-shares",
DisplayName: "Auto accept shares",
Description: "Automatically accept shares",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
Value: &settingsmsg.Setting_BoolValue{BoolValue: &settingsmsg.Bool{Default: true, Label: "auto accept shares"}},
},
},
}
}
@@ -301,7 +301,9 @@ func (s *service) UpdateReceivedShare(ctx context.Context, req *collaboration.Up
}, nil
}
share, err := s.sm.UpdateReceivedShare(ctx, req.Share, req.UpdateMask)
var uid userpb.UserId
_ = utils.ReadJSONFromOpaque(req.Opaque, "userid", &uid)
share, err := s.sm.UpdateReceivedShare(ctx, req.Share, req.UpdateMask, &uid)
if err != nil {
return &collaboration.UpdateReceivedShareResponse{
Status: status.NewInternal(ctx, "error updating received share"),
+2 -1
View File
@@ -27,6 +27,7 @@ import (
"strings"
"time"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
@@ -453,7 +454,7 @@ func (m *mgr) GetReceivedShare(ctx context.Context, ref *collaboration.ShareRefe
}
func (m *mgr) UpdateReceivedShare(ctx context.Context, share *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) {
func (m *mgr) UpdateReceivedShare(ctx context.Context, share *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask, _ *userpb.UserId) (*collaboration.ReceivedShare, error) {
user := ctxpkg.ContextMustGetUser(ctx)
rs, err := m.GetReceivedShare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share.Share.Id}})
+8 -3
View File
@@ -343,7 +343,7 @@ func (m *Manager) GetShare(ctx context.Context, ref *collaboration.ShareReferenc
// check if we are the owner or the grantee
user := ctxpkg.ContextMustGetUser(ctx)
if share.IsCreatedByUser(s, user) || share.IsGrantedToUser(s, user) {
if user.GetId().GetType() == userpb.UserType_USER_TYPE_SERVICE || share.IsCreatedByUser(s, user) || share.IsGrantedToUser(s, user) {
return s, nil
}
@@ -617,7 +617,7 @@ func (m *Manager) GetReceivedShare(ctx context.Context, ref *collaboration.Share
}
// UpdateReceivedShare updates the received share with share state.
func (m *Manager) UpdateReceivedShare(ctx context.Context, rshare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) {
func (m *Manager) UpdateReceivedShare(ctx context.Context, rshare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask, forUser *userpb.UserId) (*collaboration.ReceivedShare, error) {
if err := m.initialize(); err != nil {
return nil, err
}
@@ -643,7 +643,12 @@ func (m *Manager) UpdateReceivedShare(ctx context.Context, rshare *collaboration
}
}
err = m.persistReceivedShare(ctx, user.Id, rs)
uid := user.GetId()
if user.GetId().GetType() == userpb.UserType_USER_TYPE_SERVICE {
uid = forUser
}
err = m.persistReceivedShare(ctx, uid, rs)
if err != nil {
return nil, err
}
+13 -9
View File
@@ -542,13 +542,13 @@ func (m *mgr) getReceived(ctx context.Context, ref *collaboration.ShareReference
return nil, err
}
user := ctxpkg.ContextMustGetUser(ctx)
if !share.IsGrantedToUser(s, user) {
if user.GetId().GetType() != userv1beta1.UserType_USER_TYPE_SERVICE && !share.IsGrantedToUser(s, user) {
return nil, errtypes.NotFound(ref.String())
}
return m.convert(user.Id, s), nil
}
func (m *mgr) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) {
func (m *mgr) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask, forUser *userv1beta1.UserId) (*collaboration.ReceivedShare, error) {
rs, err := m.getReceived(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: receivedShare.Share.Id}})
if err != nil {
return nil, err
@@ -568,27 +568,31 @@ func (m *mgr) UpdateReceivedShare(ctx context.Context, receivedShare *collaborat
}
}
user := ctxpkg.ContextMustGetUser(ctx)
u := ctxpkg.ContextMustGetUser(ctx)
uid := u.GetId().String()
if u.GetId().GetType() == userv1beta1.UserType_USER_TYPE_SERVICE {
uid = forUser.String()
}
// Persist state
if v, ok := m.model.State[user.Id.String()]; ok {
if v, ok := m.model.State[uid]; ok {
v[rs.Share.Id.String()] = rs.State
m.model.State[user.Id.String()] = v
m.model.State[uid] = v
} else {
a := map[string]collaboration.ShareState{
rs.Share.Id.String(): rs.State,
}
m.model.State[user.Id.String()] = a
m.model.State[uid] = a
}
// Persist mount point
if v, ok := m.model.MountPoint[user.Id.String()]; ok {
if v, ok := m.model.MountPoint[uid]; ok {
v[rs.Share.Id.String()] = rs.MountPoint
m.model.MountPoint[user.Id.String()] = v
m.model.MountPoint[uid] = v
} else {
a := map[string]*provider.Reference{
rs.Share.Id.String(): rs.MountPoint,
}
m.model.MountPoint[user.Id.String()] = a
m.model.MountPoint[uid] = a
}
if err := m.model.Save(); err != nil {
+8 -5
View File
@@ -955,7 +955,7 @@ func (m *Manager) getReceived(ctx context.Context, ref *collaboration.ShareRefer
return nil, err
}
user := ctxpkg.ContextMustGetUser(ctx)
if !share.IsGrantedToUser(s, user) {
if user.GetId().GetType() != userv1beta1.UserType_USER_TYPE_SERVICE && !share.IsGrantedToUser(s, user) {
return nil, errtypes.NotFound(ref.String())
}
if share.IsExpired(s) {
@@ -978,7 +978,7 @@ func (m *Manager) getReceived(ctx context.Context, ref *collaboration.ShareRefer
}
// UpdateReceivedShare updates the received share with share state.
func (m *Manager) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) {
func (m *Manager) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask, forUser *userv1beta1.UserId) (*collaboration.ReceivedShare, error) {
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "UpdateReceivedShare")
defer span.End()
@@ -1003,10 +1003,13 @@ func (m *Manager) UpdateReceivedShare(ctx context.Context, receivedShare *collab
}
// write back
u := ctxpkg.ContextMustGetUser(ctx)
uid := u.GetId().GetOpaqueId()
if u.GetId().GetType() == userv1beta1.UserType_USER_TYPE_SERVICE {
uid = forUser.GetOpaqueId()
}
userID := ctxpkg.ContextMustGetUser(ctx)
err = m.UserReceivedStates.Add(ctx, userID.GetId().GetOpaqueId(), rs.Share.ResourceId.StorageId+shareid.IDDelimiter+rs.Share.ResourceId.SpaceId, rs)
err = m.UserReceivedStates.Add(ctx, uid, rs.Share.ResourceId.StorageId+shareid.IDDelimiter+rs.Share.ResourceId.SpaceId, rs)
if err != nil {
return nil, err
}
+15 -9
View File
@@ -29,6 +29,7 @@ import (
"github.com/cs3org/reva/v2/pkg/share"
"google.golang.org/genproto/protobuf/field_mask"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
@@ -334,7 +335,7 @@ func (m *manager) getReceived(ctx context.Context, ref *collaboration.ShareRefer
user := ctxpkg.ContextMustGetUser(ctx)
for _, s := range m.shares {
if sharesEqual(ref, s) {
if share.IsGrantedToUser(s, user) {
if user.GetId().GetType() == userv1beta1.UserType_USER_TYPE_SERVICE || share.IsGrantedToUser(s, user) {
rs := m.convert(ctx, s)
return rs, nil
}
@@ -343,13 +344,12 @@ func (m *manager) getReceived(ctx context.Context, ref *collaboration.ShareRefer
return nil, errtypes.NotFound(ref.String())
}
func (m *manager) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) {
func (m *manager) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask, forUser *userv1beta1.UserId) (*collaboration.ReceivedShare, error) {
rs, err := m.getReceived(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: receivedShare.Share.Id}})
if err != nil {
return nil, err
}
user := ctxpkg.ContextMustGetUser(ctx)
m.lock.Lock()
defer m.lock.Unlock()
@@ -364,25 +364,31 @@ func (m *manager) UpdateReceivedShare(ctx context.Context, receivedShare *collab
}
}
u := ctxpkg.ContextMustGetUser(ctx)
uid := u.GetId().String()
if u.GetId().GetType() == userv1beta1.UserType_USER_TYPE_SERVICE {
uid = forUser.String()
}
// Persist state
if v, ok := m.shareState[user.Id.String()]; ok {
if v, ok := m.shareState[uid]; ok {
v[rs.Share.Id] = rs.State
m.shareState[user.Id.String()] = v
m.shareState[uid] = v
} else {
a := map[*collaboration.ShareId]collaboration.ShareState{
rs.Share.Id: rs.State,
}
m.shareState[user.Id.String()] = a
m.shareState[uid] = a
}
// Persist mount point
if v, ok := m.shareMountPoint[user.Id.String()]; ok {
if v, ok := m.shareMountPoint[uid]; ok {
v[rs.Share.Id] = rs.MountPoint
m.shareMountPoint[user.Id.String()] = v
m.shareMountPoint[uid] = v
} else {
a := map[*collaboration.ShareId]*provider.Reference{
rs.Share.Id: rs.MountPoint,
}
m.shareMountPoint[user.Id.String()] = a
m.shareMountPoint[uid] = a
}
return rs, nil
@@ -27,6 +27,7 @@ import (
"strings"
"time"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
@@ -422,7 +423,8 @@ func (m *mgr) GetReceivedShare(ctx context.Context, ref *collaboration.ShareRefe
}
func (m *mgr) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) {
func (m *mgr) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask, _ *userpb.UserId) (*collaboration.ReceivedShare, error) {
// TODO: How to inject the uid when a UserId is set? override it in the ctx? Add parameter to GetReceivedShare?
rs, err := m.GetReceivedShare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: receivedShare.Share.Id}})
if err != nil {
return nil, err
+1 -1
View File
@@ -69,7 +69,7 @@ type Manager interface {
GetReceivedShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.ReceivedShare, error)
// UpdateReceivedShare updates the received share with share state.
UpdateReceivedShare(ctx context.Context, share *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error)
UpdateReceivedShare(ctx context.Context, share *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask, forUser *userv1beta1.UserId) (*collaboration.ReceivedShare, error)
}
// ReceivedShareWithUser holds the relevant information for representing a received share of a user
+1 -1
View File
@@ -354,7 +354,7 @@ github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1
github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1
github.com/cs3org/go-cs3apis/cs3/tx/v1beta1
github.com/cs3org/go-cs3apis/cs3/types/v1beta1
# github.com/cs3org/reva/v2 v2.16.1-0.20230831084113-cb0897d2eefe
# github.com/cs3org/reva/v2 v2.16.1-0.20230904124812-2ebd3e92cdb9
## explicit; go 1.20
github.com/cs3org/reva/v2/cmd/revad/internal/grace
github.com/cs3org/reva/v2/cmd/revad/runtime