From eefe9128da149739efb73931dfad9ab00f07206d Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 2 Jul 2020 12:46:24 +0200 Subject: [PATCH 1/6] Fix OCS public link share update values logic Only update a value if it was actually set in the form. Added support for clearing expiration date and password by distinguishing between an empty string and whether the value is actually set in the request. Refactored public permission parsing to use permissionFromRequest for both creation and update of public shares. --- .../handlers/apps/sharing/shares/shares.go | 307 +++++++++++------- 1 file changed, 183 insertions(+), 124 deletions(-) diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go index 3ea0b5d23e..d52ae164c4 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go @@ -351,65 +351,50 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request) return } - // TODO: the default might change depending on allowed permissions and configs - permKey := 1 - - // handle legacy "publicUpload" arg that overrides permissions differently depending on the scenario - // https://github.com/owncloud/core/blob/v10.4.0/apps/files_sharing/lib/Controller/Share20OcsController.php#L447 - if r.FormValue("publicUpload") != "" { - publicUploadFlag, err := strconv.ParseBool(r.FormValue("publicUpload")) - if err != nil { - log.Error().Err(err).Str("createShare", "shares").Str("publicUpload", r.FormValue("publicUpload")).Msg("could not parse publicUpload argument") - response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "invalid argument value for \"publicUpload\"", err) - return - } - - if publicUploadFlag { - // all perms except reshare - permKey = 15 - } - } - - // note: "permissions" value has higher priority than "publicUpload" - if r.FormValue("permissions") != "" { - // phoenix sends: {"permissions": 15}. See ocPermToRole struct for mapping - permKey, err = strconv.Atoi(r.FormValue("permissions")) - if err != nil { - log.Error().Err(err).Str("createShare", "shares").Str("permissions", r.FormValue("permissions")).Msgf("invalid type: %T", permKey) - } - } - - role, ok := ocPermToRole[permKey] - if !ok { - log.Error().Str("permissionFromRequest", "shares").Msgf("invalid oC permission: %v", role) + err = r.ParseForm() + if err != nil { + response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "Could not parse form from request", err) + return } - perm, err := conversions.NewPermissions(permKey) + newPermissions, err := permissionFromRequest(r, h) if err != nil { + response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "Could not read permission from request", err) return } - p, err := h.map2CS3Permissions(role, perm) - if err != nil { - log.Error().Str("permissionFromRequest", "shares").Msgf("role to cs3permission %v", perm) + if newPermissions == nil { + // default perms: read-only + // TODO: the default might change depending on allowed permissions and configs + newPermissions, err = ocPermToCs3(1, h) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "Could not convert default permissions", err) + return + } } req := link.CreatePublicShareRequest{ ResourceInfo: statRes.GetInfo(), Grant: &link.Grant{ Permissions: &link.PublicSharePermissions{ - Permissions: p, + Permissions: newPermissions, }, Password: r.FormValue("password"), }, } - expireTime, err := expirationTimestampFromRequest(r, h) - if err != nil { - response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "invalid date format", err) - } - if expireTime != nil { - req.Grant.Expiration = expireTime + expireTimeString, ok := r.Form["expireDate"] + if ok { + if expireTimeString[0] != "" { + expireTime, err := parseTimestamp(expireTimeString[0]) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "invalid datetime format", err) + return + } + if expireTime != nil { + req.Grant.Expiration = expireTime + } + } } // set displayname and password protected as arbitrary metadata @@ -1549,84 +1534,128 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar return } - if r.FormValue("name") != before.GetShare().DisplayName { - updates = append(updates, &link.UpdatePublicShareRequest_Update{ - Type: link.UpdatePublicShareRequest_Update_TYPE_DISPLAYNAME, - DisplayName: r.FormValue("name"), - }) + err = r.ParseForm() + if err != nil { + response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "Could not parse form from request", err) + return + } + + // indicates whether values to update were found, + // to check if the request was valid, + // not whether an actual update has been performed + updatesFound := false + + newName, ok := r.Form["name"] + if ok { + updatesFound = true + if newName[0] != before.Share.DisplayName { + updates = append(updates, &link.UpdatePublicShareRequest_Update{ + Type: link.UpdatePublicShareRequest_Update_TYPE_DISPLAYNAME, + DisplayName: newName[0], + }) + } } // Permissions - publicSharePermissions := &link.PublicSharePermissions{ - Permissions: permissionFromRequest(r, h), + newPermissions, err := permissionFromRequest(r, h) + logger.Debug().Interface("newPermissions", newPermissions).Msg("Parsed permissions") + if err != nil { + response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "invalid permissions", err) + return } - beforePerm, _ := json.Marshal(before.GetShare().Permissions) - afterPerm, _ := json.Marshal(publicSharePermissions) - if string(beforePerm) != string(afterPerm) { - logger.Info().Str("shares", "update").Msgf("updating permissions from %v to: %v", string(beforePerm), string(afterPerm)) - updates = append(updates, &link.UpdatePublicShareRequest_Update{ - Type: link.UpdatePublicShareRequest_Update_TYPE_PERMISSIONS, - Grant: &link.Grant{ - Permissions: publicSharePermissions, - }, - }) + + // update permissions if given + if newPermissions != nil { + updatesFound = true + publicSharePermissions := &link.PublicSharePermissions{ + Permissions: newPermissions, + } + beforePerm, _ := json.Marshal(before.GetShare().Permissions) + afterPerm, _ := json.Marshal(publicSharePermissions) + if string(beforePerm) != string(afterPerm) { + logger.Info().Str("shares", "update").Msgf("updating permissions from %v to: %v", string(beforePerm), string(afterPerm)) + updates = append(updates, &link.UpdatePublicShareRequest_Update{ + Type: link.UpdatePublicShareRequest_Update_TYPE_PERMISSIONS, + Grant: &link.Grant{ + Permissions: publicSharePermissions, + }, + }) + } } // ExpireDate - newExpiration, err := expirationTimestampFromRequest(r, h) - if err != nil { - response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "invalid date format", err) - } - beforeExpiration, _ := json.Marshal(before.Share.Expiration) - afterExpiration, _ := json.Marshal(newExpiration) - if newExpiration != nil || (string(afterExpiration) != string(beforeExpiration)) { - logger.Debug().Str("shares", "update").Msgf("updating expire date from %v to: %v", string(beforeExpiration), string(afterExpiration)) - updates = append(updates, &link.UpdatePublicShareRequest_Update{ - Type: link.UpdatePublicShareRequest_Update_TYPE_EXPIRATION, - Grant: &link.Grant{ - Expiration: newExpiration, - }, - }) + expireTimeString, ok := r.Form["expireDate"] + // check if value is set and must be updated or cleared + if ok { + updatesFound = true + var newExpiration *types.Timestamp + if expireTimeString[0] != "" { + newExpiration, err = parseTimestamp(expireTimeString[0]) + if err != nil { + response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "invalid datetime format", err) + return + } + } + + beforeExpiration, _ := json.Marshal(before.Share.Expiration) + afterExpiration, _ := json.Marshal(newExpiration) + if string(afterExpiration) != string(beforeExpiration) { + logger.Debug().Str("shares", "update").Msgf("updating expire date from %v to: %v", string(beforeExpiration), string(afterExpiration)) + updates = append(updates, &link.UpdatePublicShareRequest_Update{ + Type: link.UpdatePublicShareRequest_Update_TYPE_EXPIRATION, + Grant: &link.Grant{ + Expiration: newExpiration, + }, + }) + } } // Password - if len(r.FormValue("password")) > 0 { + newPassword, ok := r.Form["password"] + // update or clear password + if ok { + updatesFound = true logger.Info().Str("shares", "update").Msg("password updated") updates = append(updates, &link.UpdatePublicShareRequest_Update{ Type: link.UpdatePublicShareRequest_Update_TYPE_PASSWORD, Grant: &link.Grant{ - Password: r.FormValue("password"), + Password: newPassword[0], }, }) } - // Updates are atomical. See: https://github.com/cs3org/cs3apis/pull/67#issuecomment-617651428 so in order to get the latest updated version - if len(updates) == 0 { - response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "There is nothing to update.", nil) // TODO(refs) error? a simple noop might suffice - return - } + publicShare := before.Share - req := &link.UpdatePublicShareResponse{} - for k := range updates { - req, err = gwC.UpdatePublicShare(r.Context(), &link.UpdatePublicShareRequest{ - Ref: &link.PublicShareReference{ - Spec: &link.PublicShareReference_Id{ - Id: &link.PublicShareId{ - OpaqueId: shareID, + // Updates are atomical. See: https://github.com/cs3org/cs3apis/pull/67#issuecomment-617651428 so in order to get the latest updated version + if len(updates) > 0 { + uRes := &link.UpdatePublicShareResponse{Share: before.Share} + for k := range updates { + uRes, err = gwC.UpdatePublicShare(r.Context(), &link.UpdatePublicShareRequest{ + Ref: &link.PublicShareReference{ + Spec: &link.PublicShareReference_Id{ + Id: &link.PublicShareId{ + OpaqueId: shareID, + }, }, }, - }, - Update: updates[k], - }) - if err != nil { - log.Err(err).Str("shareID", shareID).Msg("sending update request to public link provider") + Update: updates[k], + }) + if err != nil { + log.Err(err).Str("shareID", shareID).Msg("sending update request to public link provider") + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "Error sending update request to public link provider", err) + return + } } + publicShare = uRes.Share + } else if !updatesFound { + response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "No updates specified in request", nil) + return } statReq := provider.StatRequest{ Ref: &provider.Reference{ Spec: &provider.Reference_Id{ - Id: req.GetShare().GetResourceId(), + Id: before.Share.ResourceId, }, }, } @@ -1638,7 +1667,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar return } - s := conversions.PublicShare2ShareData(req.Share, r) + s := conversions.PublicShare2ShareData(publicShare, r) err = h.addFileInfo(r.Context(), s, statRes.Info) if err != nil { @@ -1649,53 +1678,83 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar response.WriteOCSSuccess(w, r, s) } -func expirationTimestampFromRequest(r *http.Request, h *Handler) (*types.Timestamp, error) { - var expireTime time.Time - var err error - - expireDate := r.FormValue("expireDate") - if expireDate != "" { - expireTime, err = time.Parse("2006-01-02T15:04:05Z0700", expireDate) - if err != nil { - expireTime, err = time.Parse("2006-01-02", expireDate) - } - if err != nil { - return nil, fmt.Errorf("date format invalid: %v", expireDate) - } - final := expireTime.UnixNano() - - return &types.Timestamp{ - Seconds: uint64(final / 1000000000), - Nanos: uint32(final % 1000000000), - }, nil +func parseTimestamp(timestampString string) (*types.Timestamp, error) { + parsedTime, err := time.Parse("2006-01-02T15:04:05Z0700", timestampString) + if err != nil { + parsedTime, err = time.Parse("2006-01-02", timestampString) } - - return nil, nil -} - -func permissionFromRequest(r *http.Request, h *Handler) *provider.ResourcePermissions { - // phoenix sends: {"permissions": 15}. See ocPermToRole struct for mapping - permKey, err := strconv.Atoi(r.FormValue("permissions")) if err != nil { - log.Error().Str("permissionFromRequest", "shares").Msgf("invalid type: %T", permKey) + return nil, fmt.Errorf("datetime format invalid: %v", timestampString) } + final := parsedTime.UnixNano() + return &types.Timestamp{ + Seconds: uint64(final / 1000000000), + Nanos: uint32(final % 1000000000), + }, nil +} + +func ocPermToCs3(permKey int, h *Handler) (*provider.ResourcePermissions, error) { role, ok := ocPermToRole[permKey] if !ok { - log.Error().Str("permissionFromRequest", "shares").Msgf("invalid oC permission: %v", role) + log.Error().Str("ocPermToCs3", "shares").Msgf("invalid oC permission: %v", role) + return nil, fmt.Errorf("invalid oC permission: %v", role) } perm, err := conversions.NewPermissions(permKey) if err != nil { - return nil + return nil, err } p, err := h.map2CS3Permissions(role, perm) if err != nil { log.Error().Str("permissionFromRequest", "shares").Msgf("role to cs3permission %v", perm) + return nil, fmt.Errorf("role to cs3permission failed: %v", perm) } - return p + return p, nil +} + +func permissionFromRequest(r *http.Request, h *Handler) (*provider.ResourcePermissions, error) { + // phoenix sends: {"permissions": 15}. See ocPermToRole struct for mapping + + permKey := 1 + + // note: "permissions" value has higher priority than "publicUpload" + + // handle legacy "publicUpload" arg that overrides permissions differently depending on the scenario + // https://github.com/owncloud/core/blob/v10.4.0/apps/files_sharing/lib/Controller/Share20OcsController.php#L447 + publicUploadString, ok := r.Form["publicUpload"] + if ok { + publicUploadFlag, err := strconv.ParseBool(publicUploadString[0]) + if err != nil { + log.Error().Err(err).Str("publicUpload", publicUploadString[0]).Msg("could not parse publicUpload argument") + return nil, err + } + + if publicUploadFlag { + // all perms except reshare + permKey = 15 + } + } else { + permissionsString, ok := r.Form["permissions"] + if !ok { + // no permission values given + return nil, nil + } + + permKey, err := strconv.Atoi(permissionsString[0]) + if err != nil { + log.Error().Str("permissionFromRequest", "shares").Msgf("invalid type: %T", permKey) + return nil, fmt.Errorf("invalid type: %T", permKey) + } + } + + p, err := ocPermToCs3(permKey, h) + if err != nil { + return nil, err + } + return p, err } // Maps oc10 permissions to roles From 7ee05e33458a433dfd723656c2c49889299ea8a7 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 2 Jul 2020 15:31:41 +0200 Subject: [PATCH 2/6] OCS Share response format expiration date as UTC --- internal/http/services/owncloud/ocs/conversions/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/http/services/owncloud/ocs/conversions/main.go b/internal/http/services/owncloud/ocs/conversions/main.go index cec83505db..7aec420fed 100644 --- a/internal/http/services/owncloud/ocs/conversions/main.go +++ b/internal/http/services/owncloud/ocs/conversions/main.go @@ -386,7 +386,7 @@ func Permissions2OCSPermissions(p *provider.ResourcePermissions) Permissions { // timestamp is assumed to be UTC ... just human readable ... // FIXME and ambiguous / error prone because there is no time zone ... func timestampToExpiration(t *types.Timestamp) string { - return time.Unix(int64(t.Seconds), int64(t.Nanos)).Format("2006-01-02 15:05:05") + return time.Unix(int64(t.Seconds), int64(t.Nanos)).UTC().Format("2006-01-02 15:05:05") } const ( From 0bf4589d899f7bd2164157843ca729cb27360960 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 2 Jul 2020 15:59:49 +0200 Subject: [PATCH 3/6] Public share token must be longer Make it 15 chars instead of 12 to comply with the old implementation. --- pkg/publicshare/manager/json/json.go | 4 ++-- pkg/publicshare/manager/memory/memory.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/publicshare/manager/json/json.go b/pkg/publicshare/manager/json/json.go index fa22ab3e91..bd42bd7dd1 100644 --- a/pkg/publicshare/manager/json/json.go +++ b/pkg/publicshare/manager/json/json.go @@ -107,10 +107,10 @@ type manager struct { // CreatePublicShare adds a new entry to manager.shares func (m *manager) CreatePublicShare(ctx context.Context, u *user.User, rInfo *provider.ResourceInfo, g *link.Grant) (*link.PublicShare, error) { id := &link.PublicShareId{ - OpaqueId: randString(12), + OpaqueId: randString(15), } - tkn := randString(12) + tkn := randString(15) now := time.Now().UnixNano() displayName, ok := rInfo.ArbitraryMetadata.Metadata["name"] diff --git a/pkg/publicshare/manager/memory/memory.go b/pkg/publicshare/manager/memory/memory.go index ad50635adb..89d7f916e7 100644 --- a/pkg/publicshare/manager/memory/memory.go +++ b/pkg/publicshare/manager/memory/memory.go @@ -58,10 +58,10 @@ var ( // CreatePublicShare adds a new entry to manager.shares func (m *manager) CreatePublicShare(ctx context.Context, u *user.User, rInfo *provider.ResourceInfo, g *link.Grant) (*link.PublicShare, error) { id := &link.PublicShareId{ - OpaqueId: randString(12), + OpaqueId: randString(15), } - tkn := randString(12) + tkn := randString(15) now := uint64(time.Now().Unix()) displayName, ok := rInfo.ArbitraryMetadata.Metadata["name"] From 8b4a222b2a965e5c965457615d805ef9595208c9 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 2 Jul 2020 16:35:07 +0200 Subject: [PATCH 4/6] Remove nasty colon --- .../owncloud/ocs/handlers/apps/sharing/shares/shares.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go index d52ae164c4..102befc9a2 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go @@ -1716,6 +1716,7 @@ func ocPermToCs3(permKey int, h *Handler) (*provider.ResourcePermissions, error) } func permissionFromRequest(r *http.Request, h *Handler) (*provider.ResourcePermissions, error) { + var err error // phoenix sends: {"permissions": 15}. See ocPermToRole struct for mapping permKey := 1 @@ -1743,7 +1744,7 @@ func permissionFromRequest(r *http.Request, h *Handler) (*provider.ResourcePermi return nil, nil } - permKey, err := strconv.Atoi(permissionsString[0]) + permKey, err = strconv.Atoi(permissionsString[0]) if err != nil { log.Error().Str("permissionFromRequest", "shares").Msgf("invalid type: %T", permKey) return nil, fmt.Errorf("invalid type: %T", permKey) From fba9c36094958f365f0a7409559229639bad3bb2 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 2 Jul 2020 21:08:05 +0200 Subject: [PATCH 5/6] Adjust public link permission mappings Adjust the public link permission mappings to make sure that we get the same "permission" values out that were put in through the API. --- .../services/owncloud/ocs/conversions/main.go | 1 + .../owncloud/ocs/conversions/permissions.go | 2 +- .../handlers/apps/sharing/shares/shares.go | 33 +++++++++++-------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/internal/http/services/owncloud/ocs/conversions/main.go b/internal/http/services/owncloud/ocs/conversions/main.go index 7aec420fed..20b2b81346 100644 --- a/internal/http/services/owncloud/ocs/conversions/main.go +++ b/internal/http/services/owncloud/ocs/conversions/main.go @@ -361,6 +361,7 @@ func publicSharePermissions2OCSPermissions(sp *link.PublicSharePermissions) Perm } // TODO sort out mapping, this is just a first guess +// public link permissions to OCS permissions func Permissions2OCSPermissions(p *provider.ResourcePermissions) Permissions { permissions := PermissionInvalid if p != nil { diff --git a/internal/http/services/owncloud/ocs/conversions/permissions.go b/internal/http/services/owncloud/ocs/conversions/permissions.go index 9a3e3a956e..4d8a544009 100644 --- a/internal/http/services/owncloud/ocs/conversions/permissions.go +++ b/internal/http/services/owncloud/ocs/conversions/permissions.go @@ -61,7 +61,7 @@ func (p Permissions) Contain(other Permissions) bool { return p&other != 0 } -// Permissions2Role performs permission conversions +// Permissions2Role performs permission conversions for user and federated shares func Permissions2Role(p Permissions) string { role := RoleLegacy if p.Contain(PermissionRead) { diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go index 102befc9a2..3ad25a0d5e 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go @@ -366,7 +366,7 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request) if newPermissions == nil { // default perms: read-only // TODO: the default might change depending on allowed permissions and configs - newPermissions, err = ocPermToCs3(1, h) + newPermissions, err = ocPublicPermToCs3(1, h) if err != nil { response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "Could not convert default permissions", err) return @@ -647,6 +647,7 @@ func (h *Handler) map2CS3Permissions(role string, p conversions.Permissions) (*p GetQuota: p.Contain(conversions.PermissionRead), InitiateFileDownload: p.Contain(conversions.PermissionRead), + // FIXME: uploader role with only write permission can use InitiateFileUpload, not anything else Move: p.Contain(conversions.PermissionWrite), InitiateFileUpload: p.Contain(conversions.PermissionWrite), CreateContainer: p.Contain(conversions.PermissionCreate), @@ -1694,11 +1695,11 @@ func parseTimestamp(timestampString string) (*types.Timestamp, error) { }, nil } -func ocPermToCs3(permKey int, h *Handler) (*provider.ResourcePermissions, error) { - role, ok := ocPermToRole[permKey] +func ocPublicPermToCs3(permKey int, h *Handler) (*provider.ResourcePermissions, error) { + role, ok := ocPublicPermToRole[permKey] if !ok { - log.Error().Str("ocPermToCs3", "shares").Msgf("invalid oC permission: %v", role) - return nil, fmt.Errorf("invalid oC permission: %v", role) + log.Error().Str("ocPublicPermToCs3", "shares").Msgf("invalid oC permission: %s", role) + return nil, fmt.Errorf("invalid oC permission: %s", role) } perm, err := conversions.NewPermissions(permKey) @@ -1717,7 +1718,7 @@ func ocPermToCs3(permKey int, h *Handler) (*provider.ResourcePermissions, error) func permissionFromRequest(r *http.Request, h *Handler) (*provider.ResourcePermissions, error) { var err error - // phoenix sends: {"permissions": 15}. See ocPermToRole struct for mapping + // phoenix sends: {"permissions": 15}. See ocPublicPermToRole struct for mapping permKey := 1 @@ -1751,17 +1752,23 @@ func permissionFromRequest(r *http.Request, h *Handler) (*provider.ResourcePermi } } - p, err := ocPermToCs3(permKey, h) + p, err := ocPublicPermToCs3(permKey, h) if err != nil { return nil, err } return p, err } -// Maps oc10 permissions to roles -var ocPermToRole = map[int]string{ - 1: "viewer", - 15: "coowner", - 31: "editor", - // 5: contributor (?) +// TODO: add mapping for user share permissions to role + +// Maps oc10 public link permissions to roles +var ocPublicPermToRole = map[int]string{ + // Recipients can view and download contents. + 1: "viewer", + // Recipients can view, download, edit, delete and upload contents + 15: "editor", + // Recipients can upload but existing contents are not revealed + 4: "uploader", + // Recipients can view, download and upload contents + 5: "contributor", } From 09afd0f35975fa4a4a98106ff9f39ec187f99805 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 2 Jul 2020 22:39:53 +0200 Subject: [PATCH 6/6] Public link JSON don't always reset password Only reset the password when it was explicitly set to an empty string. This fix copies the old data structure and keeps the password in place if no explicit update was requested. --- pkg/publicshare/manager/json/json.go | 32 +++++++++++++++++++--------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/pkg/publicshare/manager/json/json.go b/pkg/publicshare/manager/json/json.go index bd42bd7dd1..e2b545e5c4 100644 --- a/pkg/publicshare/manager/json/json.go +++ b/pkg/publicshare/manager/json/json.go @@ -193,25 +193,32 @@ func (m *manager) UpdatePublicShare(ctx context.Context, u *user.User, req *link } now := time.Now().UnixNano() - var p string + var newPasswordEncoded string + passwordChanged := false switch req.GetUpdate().GetType() { case link.UpdatePublicShareRequest_Update_TYPE_DISPLAYNAME: - log.Debug().Str("memory", "update display name").Msgf("from: `%v` to `%v`", share.DisplayName, req.Update.GetDisplayName()) + log.Debug().Str("json", "update display name").Msgf("from: `%v` to `%v`", share.DisplayName, req.Update.GetDisplayName()) share.DisplayName = req.Update.GetDisplayName() case link.UpdatePublicShareRequest_Update_TYPE_PERMISSIONS: old, _ := json.Marshal(share.Permissions) new, _ := json.Marshal(req.Update.GetGrant().Permissions) - log.Debug().Str("memory", "update grants").Msgf("from: `%v`\nto\n`%v`", old, new) + log.Debug().Str("json", "update grants").Msgf("from: `%v`\nto\n`%v`", old, new) share.Permissions = req.Update.GetGrant().GetPermissions() case link.UpdatePublicShareRequest_Update_TYPE_EXPIRATION: old, _ := json.Marshal(share.Expiration) new, _ := json.Marshal(req.Update.GetGrant().Expiration) - log.Debug().Str("memory", "update expiration").Msgf("from: `%v`\nto\n`%v`", old, new) + log.Debug().Str("json", "update expiration").Msgf("from: `%v`\nto\n`%v`", old, new) share.Expiration = req.Update.GetGrant().Expiration case link.UpdatePublicShareRequest_Update_TYPE_PASSWORD: - p = base64.StdEncoding.EncodeToString([]byte(req.Update.GetGrant().Password)) - share.PasswordProtected = true + passwordChanged = true + if req.Update.GetGrant().Password == "" { + share.PasswordProtected = false + newPasswordEncoded = "" + } else { + newPasswordEncoded = base64.StdEncoding.EncodeToString([]byte(req.Update.GetGrant().Password)) + share.PasswordProtected = true + } default: return nil, fmt.Errorf("invalid update type: %v", req.GetUpdate().GetType()) } @@ -234,12 +241,17 @@ func (m *manager) UpdatePublicShare(ctx context.Context, u *user.User, req *link return nil, err } - db[share.GetId().OpaqueId] = buff.String() + data, ok := db[share.Id.OpaqueId].(map[string]interface{}) + if !ok { + data = map[string]interface{}{} + } - db[share.Id.GetOpaqueId()] = map[string]interface{}{ - "share": buff.String(), - "password": p, + if ok && passwordChanged { + data["password"] = newPasswordEncoded } + data["share"] = buff.String() + + db[share.Id.OpaqueId] = data err = m.writeDb(db) if err != nil {