Merge branch 'master' into toggle-unified-roles

This commit is contained in:
Florian Schade
2024-08-27 17:43:05 +02:00
232 changed files with 2859 additions and 4916 deletions
@@ -73,13 +73,13 @@ const (
)
// NewDriveItemPermissionsService creates a new DriveItemPermissionsService
func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache identity.IdentityCache, c *config.Config) (DriveItemPermissionsService, error) {
func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache identity.IdentityCache, config *config.Config) (DriveItemPermissionsService, error) {
return DriveItemPermissionsService{
BaseGraphService: BaseGraphService{
logger: &log.Logger{Logger: logger.With().Str("graph api", "DrivesDriveItemService").Logger()},
gatewaySelector: gatewaySelector,
identityCache: identityCache,
config: c,
config: config,
},
}, nil
}
@@ -130,7 +130,7 @@ func (s DriveItemPermissionsService) Invite(ctx context.Context, resourceId *sto
permission := &libregraph.Permission{}
availableRoles := unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(s.config.UnifiedRoles.AvailableRoles...))
if role := unifiedrole.CS3ResourcePermissionsToRole(availableRoles, cs3ResourcePermissions, condition); role != nil {
if role := unifiedrole.CS3ResourcePermissionsToRole(availableRoles, cs3ResourcePermissions, condition, false); role != nil {
permission.Roles = []string{role.GetId()}
}
@@ -389,6 +389,17 @@ func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID
if err != nil {
return collectionOfPermissions, err
}
if s.config.IncludeOCMSharees {
driveItems, err = s.listOCMShares(ctx, []*ocm.ListOCMSharesRequest_Filter{
{
Type: ocm.ListOCMSharesRequest_Filter_TYPE_RESOURCE_ID,
Term: &ocm.ListOCMSharesRequest_Filter_ResourceId{ResourceId: itemID},
},
}, driveItems)
if err != nil {
return collectionOfPermissions, err
}
}
}
// finally get public shares, which are possible for spaceroots and "normal" resources
driveItems, err = s.listPublicShares(ctx, []*link.ListPublicSharesRequest_Filter{
+150
View File
@@ -197,6 +197,7 @@ func (g BaseGraphService) cs3SpacePermissionsToLibreGraph(ctx context.Context, s
availableRoles,
perm,
unifiedrole.UnifiedRoleConditionDrive,
false,
); role != nil {
switch apiVersion {
case APIVersion_1:
@@ -287,6 +288,34 @@ func (g BaseGraphService) listUserShares(ctx context.Context, filters []*collabo
return driveItems, nil
}
func (g BaseGraphService) listOCMShares(ctx context.Context, filters []*ocm.ListOCMSharesRequest_Filter, driveItems driveItemsByResourceID) (driveItemsByResourceID, error) {
gatewayClient, err := g.gatewaySelector.Next()
if err != nil {
g.logger.Error().Err(err).Msg("could not select next gateway client")
return driveItems, errorcode.New(errorcode.GeneralException, err.Error())
}
concreteFilters := []*ocm.ListOCMSharesRequest_Filter{}
concreteFilters = append(concreteFilters, filters...)
lsOCMSharesRequest := ocm.ListOCMSharesRequest{
Filters: concreteFilters,
}
lsOCMSharesResponse, err := gatewayClient.ListOCMShares(ctx, &lsOCMSharesRequest)
if err != nil {
return driveItems, errorcode.New(errorcode.GeneralException, err.Error())
}
if statusCode := lsOCMSharesResponse.GetStatus().GetCode(); statusCode != rpc.Code_CODE_OK {
return driveItems, errorcode.New(cs3StatusToErrCode(statusCode), lsOCMSharesResponse.Status.Message)
}
driveItems, err = g.cs3OCMSharesToDriveItems(ctx, lsOCMSharesResponse.Shares, driveItems)
if err != nil {
return driveItems, errorcode.New(errorcode.GeneralException, err.Error())
}
return driveItems, nil
}
func (g BaseGraphService) listPublicShares(ctx context.Context, filters []*link.ListPublicSharesRequest_Filter, driveItems driveItemsByResourceID) (driveItemsByResourceID, error) {
gatewayClient, err := g.gatewaySelector.Next()
@@ -355,6 +384,42 @@ func (g BaseGraphService) cs3UserSharesToDriveItems(ctx context.Context, shares
}
return driveItems, nil
}
func (g BaseGraphService) cs3OCMSharesToDriveItems(ctx context.Context, shares []*ocm.Share, driveItems driveItemsByResourceID) (driveItemsByResourceID, error) {
for _, s := range shares {
g.logger.Debug().Interface("CS3 OCMShare", s).Msg("Got Share")
resIDStr := storagespace.FormatResourceID(s.ResourceId)
item, ok := driveItems[resIDStr]
if !ok {
itemptr, err := g.getDriveItem(ctx, &storageprovider.Reference{ResourceId: s.ResourceId})
if err != nil {
g.logger.Debug().Err(err).Interface("Share", s.ResourceId).Msg("could not stat ocm share, skipping")
continue
}
item = *itemptr
}
var condition string
switch {
case item.Folder != nil:
condition = unifiedrole.UnifiedRoleConditionFolderFederatedUser
case item.File != nil:
condition = unifiedrole.UnifiedRoleConditionFileFederatedUser
}
perm, err := g.cs3OCMShareToPermission(ctx, s, condition)
var errcode errorcode.Error
switch {
case errors.As(err, &errcode) && errcode.GetCode() == errorcode.ItemNotFound:
// The Grantee couldn't be found (user/group does not exist anymore)
continue
case err != nil:
return driveItems, err
}
item.Permissions = append(item.Permissions, *perm)
driveItems[resIDStr] = item
}
return driveItems, nil
}
func (g BaseGraphService) cs3UserShareToPermission(ctx context.Context, share *collaboration.Share, roleCondition string) (*libregraph.Permission, error) {
perm := libregraph.Permission{}
@@ -408,6 +473,7 @@ func (g BaseGraphService) cs3UserShareToPermission(ctx context.Context, share *c
unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(g.config.UnifiedRoles.AvailableRoles...)),
share.GetPermissions().GetPermissions(),
roleCondition,
false,
)
if role != nil {
perm.SetRoles([]string{role.GetId()})
@@ -432,6 +498,90 @@ func (g BaseGraphService) cs3UserShareToPermission(ctx context.Context, share *c
}
return &perm, nil
}
func (g BaseGraphService) cs3OCMShareToPermission(ctx context.Context, share *ocm.Share, roleCondition string) (*libregraph.Permission, error) {
perm := libregraph.Permission{}
perm.SetRoles([]string{})
if roleCondition != unifiedrole.UnifiedRoleConditionDrive {
perm.SetId(share.GetId().GetOpaqueId())
}
grantedTo := libregraph.SharePointIdentitySet{}
// hm or use share.GetShareType() to determine the type of share???
switch share.GetGrantee().GetType() {
case storageprovider.GranteeType_GRANTEE_TYPE_USER:
user, err := cs3UserIdToIdentity(ctx, g.identityCache, share.Grantee.GetUserId())
switch {
case errors.Is(err, identity.ErrNotFound):
g.logger.Warn().Str("userid", share.Grantee.GetUserId().GetOpaqueId()).Msg("User not found by id")
// User does not seem to exist anymore, don't add a permission for this
return nil, errorcode.New(errorcode.ItemNotFound, "grantee does not exist")
case err != nil:
return nil, errorcode.New(errorcode.GeneralException, err.Error())
default:
grantedTo.SetUser(user)
if roleCondition == unifiedrole.UnifiedRoleConditionDrive {
perm.SetId("u:" + user.GetId())
}
}
case storageprovider.GranteeType_GRANTEE_TYPE_GROUP:
group, err := groupIdToIdentity(ctx, g.identityCache, share.Grantee.GetGroupId().GetOpaqueId())
switch {
case errors.Is(err, identity.ErrNotFound):
g.logger.Warn().Str("groupid", share.Grantee.GetGroupId().GetOpaqueId()).Msg("Group not found by id")
// Group not seem to exist anymore, don't add a permission for this
return nil, errorcode.New(errorcode.ItemNotFound, "grantee does not exist")
case err != nil:
return nil, errorcode.New(errorcode.GeneralException, err.Error())
default:
grantedTo.SetGroup(group)
if roleCondition == unifiedrole.UnifiedRoleConditionDrive {
perm.SetId("g:" + group.GetId())
}
}
}
// set expiration date
if share.GetExpiration() != nil {
perm.SetExpirationDateTime(cs3TimestampToTime(share.GetExpiration()))
}
// set cTime
if share.GetCtime() != nil {
perm.SetCreatedDateTime(cs3TimestampToTime(share.GetCtime()))
}
var permissions *storageprovider.ResourcePermissions
for _, role := range share.GetAccessMethods() {
if role.GetWebdavOptions().GetPermissions() != nil {
permissions = role.GetWebdavOptions().GetPermissions()
}
}
role := unifiedrole.CS3ResourcePermissionsToUnifiedRole(
permissions,
roleCondition,
true,
)
if role != nil {
perm.SetRoles([]string{role.GetId()})
} else {
actions := unifiedrole.CS3ResourcePermissionsToLibregraphActions(permissions)
perm.SetLibreGraphPermissionsActions(actions)
perm.SetRoles(nil)
}
perm.SetGrantedToV2(grantedTo)
if share.GetCreator() != nil {
identity, err := cs3UserIdToIdentity(ctx, g.identityCache, share.GetCreator())
if err != nil {
return nil, errorcode.New(errorcode.GeneralException, err.Error())
}
perm.SetInvitation(
libregraph.SharingInvitation{
InvitedBy: &libregraph.IdentitySet{
User: &identity,
},
},
)
}
return &perm, nil
}
func (g BaseGraphService) cs3PublicSharesToDriveItems(ctx context.Context, shares []*link.PublicShare, driveItems driveItemsByResourceID) (driveItemsByResourceID, error) {
for _, s := range shares {
@@ -12,7 +12,7 @@ import (
func init() {
r := registry.GetRegistry(registry.Inmemory())
service := registry.BuildGRPCService("com.owncloud.api.gateway", "", "")
service := registry.BuildGRPCService("com.owncloud.api.gateway", "", "", "")
service.Nodes = []*mRegistry.Node{{
Address: "any",
}}
@@ -25,6 +25,14 @@ func (g Graph) GetSharedByMe(w http.ResponseWriter, r *http.Request) {
return
}
if g.config.IncludeOCMSharees {
driveItems, err = g.listOCMShares(ctx, nil, driveItems)
if err != nil {
errorcode.RenderError(w, r, err)
return
}
}
driveItems, err = g.listPublicShares(ctx, nil, driveItems)
if err != nil {
errorcode.RenderError(w, r, err)
@@ -71,7 +71,7 @@ func (g Graph) applyDefaultTemplate(ctx context.Context, gwc gateway.GatewayAPIC
opaque = utils.AppendPlainToOpaque(opaque, SpaceImageSpecialFolderName, iid)
// upload readme.md
rid, err := readmeUpload(ctx, mdc, locale, g.config.Spaces.DefaultLanguage)
rid, err := readmeUpload(ctx, mdc, locale, g.config.Spaces.DefaultLanguage, g.config.Spaces.TranslationPath)
if err != nil {
return err
}
@@ -112,10 +112,10 @@ func imageUpload(ctx context.Context, mdc *metadata.CS3) (string, error) {
return res.FileID, nil
}
func readmeUpload(ctx context.Context, mdc *metadata.CS3, locale string, defaultLocale string) (string, error) {
func readmeUpload(ctx context.Context, mdc *metadata.CS3, locale string, defaultLocale string, translationPath string) (string, error) {
res, err := mdc.Upload(ctx, metadata.UploadRequest{
Path: filepath.Join(_spaceFolderName, _readmeName),
Content: []byte(l10n_pkg.Translate(_readmeText, locale, defaultLocale)),
Content: []byte(l10n_pkg.Translate(_readmeText, locale, defaultLocale, translationPath)),
})
if err != nil {
return "", err
+58 -20
View File
@@ -109,6 +109,22 @@ func userIdToIdentity(ctx context.Context, cache identity.IdentityCache, userID
user, err := cache.GetUser(ctx, userID)
if err == nil {
identity.SetDisplayName(user.GetDisplayName())
identity.SetLibreGraphUserType(user.GetUserType())
}
return identity, err
}
// federatedIdToIdentity looks the user for the supplied id using the cache and returns it
// as a libregraph.Identity
func federatedIdToIdentity(ctx context.Context, cache identity.IdentityCache, userID string) (libregraph.Identity, error) {
identity := libregraph.Identity{
Id: libregraph.PtrString(userID),
LibreGraphUserType: libregraph.PtrString("Federated"),
}
user, err := cache.GetAcceptedUser(ctx, userID)
if err == nil {
identity.SetDisplayName(user.GetDisplayName())
identity.SetLibreGraphUserType(user.GetUserType())
}
return identity, err
}
@@ -116,6 +132,9 @@ func userIdToIdentity(ctx context.Context, cache identity.IdentityCache, userID
// cs3UserIdToIdentity looks up the user for the supplied cs3 userid using the cache and returns it
// as a libregraph.Identity. Skips the user lookup if the id type is USER_TYPE_SPACE_OWNER
func cs3UserIdToIdentity(ctx context.Context, cache identity.IdentityCache, cs3UserID *cs3User.UserId) (libregraph.Identity, error) {
if cs3UserID.GetType() == cs3User.UserType_USER_TYPE_FEDERATED {
return federatedIdToIdentity(ctx, cache, cs3UserID.GetOpaqueId())
}
if cs3UserID.GetType() != cs3User.UserType_USER_TYPE_SPACE_OWNER {
return userIdToIdentity(ctx, cache, cs3UserID.GetOpaqueId())
}
@@ -434,6 +453,7 @@ func cs3ReceivedShareToLibreGraphPermissions(ctx context.Context, logger *log.Lo
availableRoles,
permissionSet,
condition,
false,
)
if role != nil {
permission.SetRoles([]string{role.GetId()})
@@ -479,6 +499,17 @@ func roleConditionForResourceType(ri *storageprovider.ResourceInfo) (string, err
}
}
func federatedRoleConditionForResourceType(ri *storageprovider.ResourceInfo) (string, error) {
switch {
case ri.Type == storageprovider.ResourceType_RESOURCE_TYPE_CONTAINER:
return unifiedrole.UnifiedRoleConditionFolderFederatedUser, nil
case ri.Type == storageprovider.ResourceType_RESOURCE_TYPE_FILE:
return unifiedrole.UnifiedRoleConditionFileFederatedUser, nil
default:
return "", errorcode.New(errorcode.InvalidRequest, "unsupported resource type for federated role")
}
}
// ExtractShareIdFromResourceId is a bit of a hack.
// We should not rely on a specific format of the item id.
// But currently there is no other way to get the ShareID.
@@ -752,36 +783,43 @@ func fillDriveItemPropertiesFromReceivedOCMShare(ctx context.Context, logger *lo
func cs3ReceivedOCMShareToLibreGraphPermissions(ctx context.Context, logger *log.Logger,
identityCache identity.IdentityCache, receivedShare *ocm.ReceivedShare,
_ *storageprovider.ResourceInfo) (*libregraph.Permission, error) {
resourceInfo *storageprovider.ResourceInfo) (*libregraph.Permission, error) {
permission := libregraph.NewPermission()
if id := receivedShare.GetId().GetOpaqueId(); id != "" {
permission.SetId(id)
}
if cTime := receivedShare.GetCtime(); cTime != nil {
permission.SetCreatedDateTime(cs3TimestampToTime(cTime))
}
if expiration := receivedShare.GetExpiration(); expiration != nil {
permission.SetExpirationDateTime(cs3TimestampToTime(expiration))
}
/*
if permissionSet := receivedShare.GetShare().GetPermissions().GetPermissions(); permissionSet != nil {
condition, err := roleConditionForResourceType(resourceInfo)
if err != nil {
return nil, err
}
role := unifiedrole.CS3ResourcePermissionsToUnifiedRole(*permissionSet, condition)
if role != nil {
permission.SetRoles([]string{role.GetId()})
}
actions := unifiedrole.CS3ResourcePermissionsToLibregraphActions(*permissionSet)
// actions only make sense if no role is set
if role == nil && len(actions) > 0 {
permission.SetLibreGraphPermissionsActions(actions)
}
var permissions *storageprovider.ResourcePermissions
for _, protocol := range receivedShare.GetProtocols() {
if protocol.GetWebdavOptions().GetPermissions() != nil {
permissions = protocol.GetWebdavOptions().GetPermissions().GetPermissions()
}
*/
}
condition, err := federatedRoleConditionForResourceType(resourceInfo)
if err != nil {
return nil, err
}
role := unifiedrole.CS3ResourcePermissionsToUnifiedRole(
permissions,
condition,
true,
)
if role != nil {
permission.SetRoles([]string{role.GetId()})
} else {
actions := unifiedrole.CS3ResourcePermissionsToLibregraphActions(permissions)
permission.SetLibreGraphPermissionsActions(actions)
permission.SetRoles(nil)
}
switch grantee := receivedShare.GetGrantee(); {
case grantee.GetType() == storageprovider.GranteeType_GRANTEE_TYPE_USER:
user, err := cs3UserIdToIdentity(ctx, identityCache, grantee.GetUserId())