diff --git a/go.mod b/go.mod index a9d1ba9acf5..094c0e6f879 100644 --- a/go.mod +++ b/go.mod @@ -354,4 +354,4 @@ replace go-micro.dev/v4 => github.com/kobergj/go-micro/v4 v4.0.0-20250117084952- // see https://github.com/mattn/go-sqlite3/issues/965 for more details exclude github.com/mattn/go-sqlite3 v2.0.3+incompatible -replace github.com/cs3org/reva/v2 => github.com/owncloud/reva/v2 v2.0.0-20250724132414-1d9f38a30619 +replace github.com/cs3org/reva/v2 => github.com/owncloud/reva/v2 v2.0.0-20251021080010-097583854168 diff --git a/go.sum b/go.sum index 1386eee7216..deb0e6d8421 100644 --- a/go.sum +++ b/go.sum @@ -881,8 +881,8 @@ github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CF github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA= github.com/owncloud/libre-graph-api-go v1.0.5-0.20250217093259-fa3804be6c27 h1:ID8s5lGBntmrlI6TbDAjTzRyHucn3bVM2wlW+HBplv4= github.com/owncloud/libre-graph-api-go v1.0.5-0.20250217093259-fa3804be6c27/go.mod h1:+gT+x62AS9u2Farh9wE2uYmgdvTg0MQgsSI62D+xoRg= -github.com/owncloud/reva/v2 v2.0.0-20250724132414-1d9f38a30619 h1:CB8hisJolJSTk+Inu6kJ8NWzU7nr6a7xtFvNnybTC/g= -github.com/owncloud/reva/v2 v2.0.0-20250724132414-1d9f38a30619/go.mod h1:1H26PMXoa1rDrIoZ7lGOerq1Bg07/5srYfRaKfxBSsc= +github.com/owncloud/reva/v2 v2.0.0-20251021080010-097583854168 h1:LX479ALlXTaOnmhC+KggRyPoMI33wN7jEMxxPFVg9fs= +github.com/owncloud/reva/v2 v2.0.0-20251021080010-097583854168/go.mod h1:1H26PMXoa1rDrIoZ7lGOerq1Bg07/5srYfRaKfxBSsc= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= github.com/pablodz/inotifywaitgo v0.0.7 h1:1ii49dGBnRn0t1Sz7RGZS6/NberPEDQprwKHN49Bv6U= diff --git a/ocis/Makefile b/ocis/Makefile index bcbe4b5c273..c08dec9506a 100644 --- a/ocis/Makefile +++ b/ocis/Makefile @@ -33,7 +33,7 @@ docs-generate: config-docs-generate .PHONY: dev-docker dev-docker: $(MAKE) --no-print-directory release-linux-docker-$(GOARCH) - docker build -f docker/Dockerfile.linux.$(GOARCH) -t owncloud/ocis:dev . + docker build --platform linux/$(GOARCH) -f docker/Dockerfile.linux.$(GOARCH) -t owncloud/ocis:dev . ############ debug-docker ############ .PHONY: debug-docker diff --git a/services/graph/pkg/service/v0/utils.go b/services/graph/pkg/service/v0/utils.go index 5a0936b8e1c..223fe9eb9ac 100644 --- a/services/graph/pkg/service/v0/utils.go +++ b/services/graph/pkg/service/v0/utils.go @@ -4,8 +4,10 @@ import ( "context" "encoding/base64" "encoding/json" + "fmt" "io" "net/http" + "path" "reflect" gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" @@ -544,7 +546,7 @@ func cs3ReceivedOCMSharesToDriveItems(ctx context.Context, // file shares resOpaqueID := "/" if receivedShares[0].GetResourceType() == storageprovider.ResourceType_RESOURCE_TYPE_FILE { - resOpaqueID += receivedShares[0].GetName() + resOpaqueID = path.Join(resOpaqueID, receivedShares[0].GetName()) } shareStat, err := gatewayClient.Stat(ctx, &storageprovider.StatRequest{ diff --git a/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocmcore/ocmcore.go b/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocmcore/ocmcore.go index ffd12898672..6e0e116a163 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocmcore/ocmcore.go +++ b/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocmcore/ocmcore.go @@ -158,7 +158,7 @@ func (s *service) UpdateOCMCoreShare(ctx context.Context, req *ocmcore.UpdateOCM } fileMask := &fieldmaskpb.FieldMask{Paths: []string{"protocols"}} - user := &userpb.User{Id: ocmuser.RemoteID(&userpb.UserId{OpaqueId: grantee})} + user := &userpb.User{Id: ocmuser.DecodeRemoteUserFederatedID(&userpb.UserId{OpaqueId: grantee})} _, err := s.repo.UpdateReceivedShare(ctx, user, &ocm.ReceivedShare{ Id: &ocm.ShareId{ OpaqueId: req.GetOcmShareId(), @@ -185,7 +185,7 @@ func (s *service) DeleteOCMCoreShare(ctx context.Context, req *ocmcore.DeleteOCM return nil, errtypes.UserRequired("missing remote user id in a metadata") } - user := &userpb.User{Id: ocmuser.RemoteID(&userpb.UserId{OpaqueId: grantee})} + user := &userpb.User{Id: ocmuser.DecodeRemoteUserFederatedID(&userpb.UserId{OpaqueId: grantee})} err := s.repo.DeleteReceivedShare(ctx, user, &ocm.ShareReference{ Spec: &ocm.ShareReference_Id{ diff --git a/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocminvitemanager/ocminvitemanager.go b/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocminvitemanager/ocminvitemanager.go index 05f92c91ae4..13b99b989a3 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocminvitemanager/ocminvitemanager.go +++ b/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocminvitemanager/ocminvitemanager.go @@ -180,9 +180,9 @@ func (s *service) ForwardInvite(ctx context.Context, req *invitepb.ForwardInvite remoteUser, err := s.ocmClient.InviteAccepted(ctx, ocmEndpoint, &client.InviteAcceptedRequest{ Token: req.InviteToken.GetToken(), RecipientProvider: s.conf.ProviderDomain, - // The UserID is only a string here. To not loose the IDP information we use the FederatedID encoding - // i.e. base64(UserID@IDP) - UserID: ocmuser.FederatedID(user.GetId(), "").GetOpaqueId(), + // The UserID is only a string here. To not lose the IDP information we use the LocalUserFederatedID encoding + // i.e. UserID@IDP + UserID: ocmuser.LocalUserFederatedID(user.GetId(), "").GetOpaqueId(), Email: user.GetMail(), Name: user.GetDisplayName(), }) @@ -223,6 +223,9 @@ func (s *service) ForwardInvite(ctx context.Context, req *invitepb.ForwardInvite OpaqueId: remoteUser.UserID, } + // we need to use a unique identifier for federated users + remoteUserID = ocmuser.LocalUserFederatedID(remoteUserID, "") + if err := s.repo.AddRemoteUser(ctx, user.Id, &userpb.User{ Id: remoteUserID, Mail: remoteUser.Email, @@ -282,6 +285,8 @@ func (s *service) AcceptInvite(ctx context.Context, req *invitepb.AcceptInviteRe } remoteUser := req.GetRemoteUser() + // we need to use a unique identifier for federated users + remoteUser.Id = ocmuser.LocalUserFederatedID(remoteUser.Id, "") if err := s.repo.AddRemoteUser(ctx, token.GetUserId(), remoteUser); err != nil { if !errors.Is(err, invite.ErrUserAlreadyAccepted) { diff --git a/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocmshareprovider/ocmshareprovider.go b/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocmshareprovider/ocmshareprovider.go index ba1fdaaca38..b0ed5c0ff07 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocmshareprovider/ocmshareprovider.go +++ b/vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocmshareprovider/ocmshareprovider.go @@ -187,7 +187,7 @@ func (s *service) getWebdavProtocol(ctx context.Context, share *ocm.Share, m *oc return &ocmd.WebDAV{ Permissions: perms, - URL: s.webdavURL(ctx, share), + URI: s.webdavURL(ctx, share), SharedSecret: share.Token, } } @@ -325,11 +325,11 @@ func (s *service) CreateOCMShare(ctx context.Context, req *ocm.CreateOCMShareReq // 2.b replace outgoing user ids with ocm user ids // unpack the federated user id - shareWith := ocmuser.FormatOCMUser(ocmuser.RemoteID(req.GetGrantee().GetUserId())) + shareWith := ocmuser.FormatOCMUser(ocmuser.LocalUserFederatedID(req.GetGrantee().GetUserId(), "")) - // wrap the local user id in a federated user id - owner := ocmuser.FormatOCMUser(ocmuser.FederatedID(info.Owner, s.conf.ProviderDomain)) - sender := ocmuser.FormatOCMUser(ocmuser.FederatedID(user.Id, s.conf.ProviderDomain)) + // wrap the local user id in a local federated user id + owner := ocmuser.FormatOCMUser(ocmuser.LocalUserFederatedID(info.Owner, s.conf.ProviderDomain)) + sender := ocmuser.FormatOCMUser(ocmuser.LocalUserFederatedID(user.Id, s.conf.ProviderDomain)) newShareReq := &client.NewShareRequest{ ShareWith: shareWith, diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/invites.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/invites.go index 1fda2059fdf..fbba971d3c1 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/invites.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/invites.go @@ -60,7 +60,7 @@ type acceptInviteRequest struct { Email string `json:"email"` } -// AcceptInvite informs avout an accepted invitation so that the users +// AcceptInvite informs about an accepted invitation so that the users // can initiate the OCM share creation. func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -73,7 +73,7 @@ func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) { } if req.Token == "" || req.UserID == "" || req.RecipientProvider == "" { - reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token, userID and recipiendProvider must not be null", nil) + reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token, userID and recipientProvider must not be null", nil) return } @@ -146,7 +146,7 @@ func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) { } if err := json.NewEncoder(w).Encode(&user{ - UserID: ocmuser.FederatedID(acceptInviteResponse.UserId, "").GetOpaqueId(), + UserID: ocmuser.LocalUserFederatedID(acceptInviteResponse.UserId, "").GetOpaqueId(), Email: acceptInviteResponse.Email, Name: acceptInviteResponse.DisplayName, }); err != nil { diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/protocols.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/protocols.go index 00e2d51f117..c8e10834be6 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/protocols.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/protocols.go @@ -47,7 +47,37 @@ type Protocol interface { type WebDAV struct { SharedSecret string `json:"sharedSecret" validate:"required"` Permissions []string `json:"permissions" validate:"required,dive,required,oneof=read write share"` - URL string `json:"url" validate:"required"` + URI string `json:"uri" validate:"required"` +} + +// UnmarshalJSON implements custom JSON unmarshaling for backward compatibility. +// It supports both "url" (legacy) and "uri" (new) field names. +func (w *WebDAV) UnmarshalJSON(data []byte) error { + // Define a temporary struct with both url and uri fields + type WebDAVAlias struct { + SharedSecret string `json:"sharedSecret"` + Permissions []string `json:"permissions"` + URL string `json:"url"` + URI string `json:"uri"` + } + + var alias WebDAVAlias + if err := json.Unmarshal(data, &alias); err != nil { + return err + } + + // Copy common fields + w.SharedSecret = alias.SharedSecret + w.Permissions = alias.Permissions + + // Use URI if present, otherwise fall back to URL for backward compatibility + if alias.URI != "" { + w.URI = alias.URI + } else { + w.URI = alias.URL + } + + return nil } // ToOCMProtocol convert the protocol to a ocm Protocol struct. @@ -73,7 +103,7 @@ func (w *WebDAV) ToOCMProtocol() *ocm.Protocol { } } - return ocmshare.NewWebDAVProtocol(w.URL, w.SharedSecret, perms) + return ocmshare.NewWebDAVProtocol(w.URI, w.SharedSecret, perms) } // Webapp contains the parameters for the Webapp protocol. diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/shares.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/shares.go index cb7de98ae60..ee0e5752f98 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/shares.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/shares.go @@ -124,7 +124,7 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) { return } - shareWith, _, err := getIDAndMeshProvider(req.ShareWith) + shareWith, _, err := getLocalUserID(req.ShareWith) if err != nil { reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil) return @@ -194,6 +194,22 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) } +func getLocalUserID(user string) (id, provider string, err error) { + idPart, provider, err := getIDAndMeshProvider(user) + if err != nil { + return "", "", err + } + + // Handle nested @ in idPart (e.g. "user@idp@provider") + if inner := strings.LastIndex(idPart, "@"); inner != -1 { + id = idPart[:inner] + } else { + id = idPart + } + + return id, provider, nil +} + func getUserIDFromOCMUser(user string) (*userpb.UserId, error) { id, idp, err := getIDAndMeshProvider(user) if err != nil { @@ -207,13 +223,12 @@ func getUserIDFromOCMUser(user string) (*userpb.UserId, error) { }, nil } -func getIDAndMeshProvider(user string) (string, string, error) { - // the user is in the form of dimitri@apiwise.nl - split := strings.Split(user, "@") - if len(split) < 2 { +func getIDAndMeshProvider(user string) (id, provider string, err error) { + last := strings.LastIndex(user, "@") + if last == -1 { return "", "", errors.New("not in the form @") } - return strings.Join(split[:len(split)-1], "@"), split[len(split)-1], nil + return user[:last], user[last+1:], nil } func getCreateShareRequest(r *http.Request) (*createShareRequest, error) { diff --git a/vendor/github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/json/json.go b/vendor/github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/json/json.go index 152140fdba4..5a8bf296a9b 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/json/json.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/json/json.go @@ -173,10 +173,12 @@ func (a *authorizer) IsProviderAllowed(ctx context.Context, pi *ocmprovider.Prov } switch { - case !providerAuthorized: - return errtypes.NotFound(pi.GetDomain()) case !a.conf.VerifyRequestHostname: + log.Info().Msg("VerifyRequestHostname is disabled. any provider is allowed") return nil + case !providerAuthorized: + log.Info().Msg("providerAuthorized is false") + return errtypes.NotFound(pi.GetDomain()) case len(pi.Services) == 0: return ErrNoIP } diff --git a/vendor/github.com/cs3org/reva/v2/pkg/ocm/user/user.go b/vendor/github.com/cs3org/reva/v2/pkg/ocm/user/user.go index 9be8add2b4d..8fb67563699 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/ocm/user/user.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/ocm/user/user.go @@ -1,39 +1,44 @@ package user import ( - "encoding/base64" "fmt" + "net/url" "strings" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" ) -// FederatedID creates a federated user id by +// LocalUserFederatedID creates a federated id for local users by // 1. stripping the protocol from the domain and -// 2. base64 encoding the opaque id with the domain to get a unique identifier that cannot collide with other users -func FederatedID(id *userpb.UserId, domain string) *userpb.UserId { - opaqueId := base64.URLEncoding.EncodeToString([]byte(id.OpaqueId + "@" + id.Idp)) - return &userpb.UserId{ +// 2. if the domain is different from the idp, add the idp to the opaque id +func LocalUserFederatedID(id *userpb.UserId, domain string) *userpb.UserId { + if u, err := url.Parse(domain); err == nil && u.Host != "" { + domain = u.Host + } + + u := &userpb.UserId{ Type: userpb.UserType_USER_TYPE_FEDERATED, - Idp: domain, - OpaqueId: opaqueId, + Idp: id.Idp, + OpaqueId: id.OpaqueId, } + + if id.Idp != "" && domain != "" && id.Idp != domain { + u.OpaqueId = id.OpaqueId + "@" + id.Idp + u.Idp = domain + } + return u } -// RemoteID creates a remote user id by +// DecodeRemoteUserFederatedID decodes opaque id into remote user's federated id by // 1. decoding the base64 encoded opaque id // 2. splitting the opaque id at the last @ to get the opaque id and the domain -func RemoteID(id *userpb.UserId) *userpb.UserId { +func DecodeRemoteUserFederatedID(id *userpb.UserId) *userpb.UserId { remoteId := &userpb.UserId{ Type: userpb.UserType_USER_TYPE_PRIMARY, Idp: id.Idp, OpaqueId: id.OpaqueId, } - bytes, err := base64.URLEncoding.DecodeString(id.GetOpaqueId()) - if err != nil { - return remoteId - } - remote := string(bytes) + remote := id.OpaqueId last := strings.LastIndex(remote, "@") if last == -1 { return remoteId @@ -46,5 +51,8 @@ func RemoteID(id *userpb.UserId) *userpb.UserId { // FormatOCMUser formats a user id in the form of @ used by the OCM API in shareWith, owner and creator fields func FormatOCMUser(u *userpb.UserId) string { + if u.Idp == "" { + return u.OpaqueId + } return fmt.Sprintf("%s@%s", u.OpaqueId, u.Idp) } diff --git a/vendor/modules.txt b/vendor/modules.txt index bc5895a4145..11017ecffaa 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -371,7 +371,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.27.7 => github.com/owncloud/reva/v2 v2.0.0-20250724132414-1d9f38a30619 +# github.com/cs3org/reva/v2 v2.27.7 => github.com/owncloud/reva/v2 v2.0.0-20251021080010-097583854168 ## explicit; go 1.22.7 github.com/cs3org/reva/v2/cmd/revad/internal/grace github.com/cs3org/reva/v2/cmd/revad/runtime @@ -2408,4 +2408,4 @@ stash.kopano.io/kgol/rndm # github.com/unrolled/secure => github.com/DeepDiver1975/secure v0.0.0-20240611112133-abc838fb797c # github.com/go-micro/plugins/v4/store/nats-js-kv => github.com/kobergj/plugins/v4/store/nats-js-kv v0.0.0-20240807130109-f62bb67e8c90 # go-micro.dev/v4 => github.com/kobergj/go-micro/v4 v4.0.0-20250117084952-d07d30666b7c -# github.com/cs3org/reva/v2 => github.com/owncloud/reva/v2 v2.0.0-20250724132414-1d9f38a30619 +# github.com/cs3org/reva/v2 => github.com/owncloud/reva/v2 v2.0.0-20251021080010-097583854168