diff --git a/changelog/unreleased/add-providerinfo-secure-view-flag.md b/changelog/unreleased/add-providerinfo-secure-view-flag.md index 1e2e4f277c4..bcf0e1242ae 100644 --- a/changelog/unreleased/add-providerinfo-secure-view-flag.md +++ b/changelog/unreleased/add-providerinfo-secure-view-flag.md @@ -1,6 +1,7 @@ Enhancement: add secureview flag when listing apps via http -To allow clients to see which application supports secure view we add a flag to the http response when the app name matches a configured secure view app. The app can be configured by setting `FRONTEND_APP_HANDLER_SECURE_VIEW_APP` to the name of the app registered as a CS3 app provider. +To allow clients to see which application supports secure view, we add a flag to the http response when the app service name matches a configured secure view app provider. The app can be configured by setting `FRONTEND_APP_HANDLER_SECURE_VIEW_APP_ADDR` to the address of the registered CS3 app provider. +https://github.com/owncloud/ocis/pull/9289 https://github.com/owncloud/ocis/pull/9280 https://github.com/owncloud/ocis/pull/9277 diff --git a/deployments/examples/ocis_wopi/docker-compose.yml b/deployments/examples/ocis_wopi/docker-compose.yml index 7359324ed3e..e8c8532fcc9 100644 --- a/deployments/examples/ocis_wopi/docker-compose.yml +++ b/deployments/examples/ocis_wopi/docker-compose.yml @@ -92,6 +92,8 @@ services: PROXY_CSP_CONFIG_FILE_LOCATION: /etc/ocis/csp.yaml COLLABORA_DOMAIN: ${COLLABORA_DOMAIN:-collabora.owncloud.test} ONLYOFFICE_DOMAIN: ${ONLYOFFICE_DOMAIN:-onlyoffice.owncloud.test} + # make collabora the secure view app + FRONTEND_APP_HANDLER_SECURE_VIEW_APP_ADDR: com.owncloud.api.app-provider-collabora volumes: - ./config/ocis/app-registry.yaml:/etc/ocis/app-registry.yaml - ./config/ocis/csp.yaml:/etc/ocis/csp.yaml diff --git a/go.mod b/go.mod index 951eba9c1ac..58ee8279763 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/cenkalti/backoff v2.2.1+incompatible github.com/coreos/go-oidc/v3 v3.10.0 github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781 - github.com/cs3org/reva/v2 v2.19.2-0.20240530092407-7f72f379ea89 + github.com/cs3org/reva/v2 v2.19.2-0.20240603112905-634bf103c8be github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25 github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e github.com/egirna/icap-client v0.1.1 diff --git a/go.sum b/go.sum index aae68fa41de..12a893385d3 100644 --- a/go.sum +++ b/go.sum @@ -1025,8 +1025,8 @@ github.com/crewjam/saml v0.4.14 h1:g9FBNx62osKusnFzs3QTN5L9CVA/Egfgm+stJShzw/c= github.com/crewjam/saml v0.4.14/go.mod h1:UVSZCf18jJkk6GpWNVqcyQJMD5HsRugBPf4I1nl2mME= github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781 h1:BUdwkIlf8IS2FasrrPg8gGPHQPOrQ18MS1Oew2tmGtY= github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= -github.com/cs3org/reva/v2 v2.19.2-0.20240530092407-7f72f379ea89 h1:74khAslYAD8kXrBZVJOOCd3iXcp1gY00vgpqGw8lmh0= -github.com/cs3org/reva/v2 v2.19.2-0.20240530092407-7f72f379ea89/go.mod h1:lKqw0VuP1NcZbhj0e6tGoAGq3tgWO/pLafVJyDK0yVI= +github.com/cs3org/reva/v2 v2.19.2-0.20240603112905-634bf103c8be h1:iD1L1MEeoLieeAcoa9iWKVdXHhhftCtJVjOmBRxn8y0= +github.com/cs3org/reva/v2 v2.19.2-0.20240603112905-634bf103c8be/go.mod h1:lKqw0VuP1NcZbhj0e6tGoAGq3tgWO/pLafVJyDK0yVI= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= diff --git a/services/frontend/pkg/config/config.go b/services/frontend/pkg/config/config.go index a3e1670e7ac..9288577e49f 100644 --- a/services/frontend/pkg/config/config.go +++ b/services/frontend/pkg/config/config.go @@ -107,9 +107,9 @@ type Auth struct { } type AppHandler struct { - Prefix string `yaml:"-"` - Insecure bool `yaml:"insecure" env:"OCIS_INSECURE;FRONTEND_APP_HANDLER_INSECURE" desc:"Allow insecure connections to the frontend." introductionVersion:"pre5.0"` - SecureViewApp string `yaml:"secure_view_app" env:"FRONTEND_APP_HANDLER_SECURE_VIEW_APP" desc:"Name of the app to use for secure view. Should match COLLABORATION_APP_NAME, the name configured for the CS3 app provider." introductionVersion:"5.1"` + Prefix string `yaml:"-"` + Insecure bool `yaml:"insecure" env:"OCIS_INSECURE;FRONTEND_APP_HANDLER_INSECURE" desc:"Allow insecure connections to the frontend." introductionVersion:"pre5.0"` + SecureViewAppAddr string `yaml:"secure_view_app_addr" env:"FRONTEND_APP_HANDLER_SECURE_VIEW_APP_ADDR" desc:"Service name or address of the app provider to use for secure view. Should match the service name or address of the registered CS3 app provider." introductionVersion:"5.1"` } type Archiver struct { diff --git a/services/frontend/pkg/config/defaults/defaultconfig.go b/services/frontend/pkg/config/defaults/defaultconfig.go index 848ccc0c2f9..a448f8acda3 100644 --- a/services/frontend/pkg/config/defaults/defaultconfig.go +++ b/services/frontend/pkg/config/defaults/defaultconfig.go @@ -93,8 +93,8 @@ func DefaultConfig() *config.Config { PreferredUploadType: "sha1", }, AppHandler: config.AppHandler{ - Prefix: "app", - SecureViewApp: "Collabora", + Prefix: "app", + SecureViewAppAddr: "com.owncloud.api.collaboration", }, Archiver: config.Archiver{ Insecure: false, diff --git a/services/frontend/pkg/revaconfig/config.go b/services/frontend/pkg/revaconfig/config.go index d3ebbbbf57f..0df042ecd86 100644 --- a/services/frontend/pkg/revaconfig/config.go +++ b/services/frontend/pkg/revaconfig/config.go @@ -137,7 +137,7 @@ func FrontendConfigFromStruct(cfg *config.Config, logger log.Logger) (map[string "contextRouteName": "files-spaces-personal", // TODO: remove when https://github.com/owncloud/web/pull/7437 arrived in oCIS }, }, - "secure_view_app": cfg.AppHandler.SecureViewApp, + "secure_view_app_addr": cfg.AppHandler.SecureViewAppAddr, }, "archiver": map[string]interface{}{ "prefix": cfg.Archiver.Prefix, diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/appprovider/appprovider.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/appprovider/appprovider.go index 5c8cf641c22..5ab334cac63 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/appprovider/appprovider.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/appprovider/appprovider.go @@ -56,12 +56,12 @@ func init() { // Config holds the config options for the HTTP appprovider service type Config struct { - Prefix string `mapstructure:"prefix"` - GatewaySvc string `mapstructure:"gatewaysvc"` - Insecure bool `mapstructure:"insecure"` - WebBaseURI string `mapstructure:"webbaseuri"` - Web Web `mapstructure:"web"` - SecureViewApp string `mapstructure:"secure_view_app"` + Prefix string `mapstructure:"prefix"` + GatewaySvc string `mapstructure:"gatewaysvc"` + Insecure bool `mapstructure:"insecure"` + WebBaseURI string `mapstructure:"webbaseuri"` + Web Web `mapstructure:"web"` + SecureViewAppAddr string `mapstructure:"secure_view_app_addr"` } // Web holds the config options for the URL parameters for Web @@ -342,16 +342,7 @@ func (s *svc) handleList(w http.ResponseWriter, r *http.Request) { return } - res := filterAppsByUserAgent(listRes.MimeTypes, r.UserAgent()) - - // if app name or address matches the configured secure view app add that flag to the response - for _, mt := range res { - for _, app := range mt.AppProviders { - if app.Name == s.conf.SecureViewApp { - app.SecureView = true - } - } - } + res := buildApps(listRes.MimeTypes, r.UserAgent(), s.conf.SecureViewAppAddr) js, err := json.Marshal(map[string]interface{}{"mime-types": res}) if err != nil { @@ -569,19 +560,29 @@ type ProviderInfo struct { SecureView bool `json:"secure_view"` } -// filterAppsByUserAgent rewrites the mime type info to only include apps that can be called by the user agent -// it also wraps the provider info to be able to add a secure view flag -func filterAppsByUserAgent(mimeTypes []*appregistry.MimeTypeInfo, userAgent string) []*MimeTypeInfo { +// buildApps rewrites the mime type info to only include apps that +// * have a name +// * can be called by the user agent, eg Desktop-only +// +// it also +// * wraps the provider info to be able to add a secure view flag +// * adds a secure view flag if the address matches the secure view app address and +// * removes the address from the provider info to not expose internal addresses +func buildApps(mimeTypes []*appregistry.MimeTypeInfo, userAgent, secureViewAppAddr string) []*MimeTypeInfo { ua := ua.Parse(userAgent) res := []*MimeTypeInfo{} for _, m := range mimeTypes { apps := []*ProviderInfo{} for _, p := range m.AppProviders { + ep := &ProviderInfo{ProviderInfo: *p} + if p.Address == secureViewAppAddr { + ep.SecureView = true + } p.Address = "" // address is internal only and not needed in the client // apps are called by name, so if it has no name it cannot be called and should not be advertised // also filter Desktop-only apps if ua is not Desktop if p.Name != "" && (ua.Desktop || !p.DesktopOnly) { - apps = append(apps, &ProviderInfo{ProviderInfo: *p}) + apps = append(apps, ep) } } if len(apps) > 0 { diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/ocis/blobstore/blobstore.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/ocis/blobstore/blobstore.go index 43dadd4cebf..b4293fa645a 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/ocis/blobstore/blobstore.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/ocis/blobstore/blobstore.go @@ -32,6 +32,9 @@ import ( "github.com/pkg/errors" ) +// ErrBlobIDEmpty is returned when the BlobID is empty +var ErrBlobIDEmpty = fmt.Errorf("blobstore: BlobID is empty") + // Blobstore provides an interface to an filesystem based blobstore type Blobstore struct { root string @@ -51,10 +54,12 @@ func New(root string) (*Blobstore, error) { // Upload stores some data in the blobstore under the given key func (bs *Blobstore) Upload(node *node.Node, source string) error { - dest, err := bs.path(node) - if err != nil { - return err + if node.BlobID == "" { + return ErrBlobIDEmpty } + + dest := bs.Path(node) + // ensure parent path exists if err := os.MkdirAll(filepath.Dir(dest), 0700); err != nil { return errors.Wrap(err, "Decomposedfs: oCIS blobstore: error creating parent folders for blob") @@ -87,10 +92,11 @@ func (bs *Blobstore) Upload(node *node.Node, source string) error { // Download retrieves a blob from the blobstore for reading func (bs *Blobstore) Download(node *node.Node) (io.ReadCloser, error) { - dest, err := bs.path(node) - if err != nil { - return nil, err + if node.BlobID == "" { + return nil, ErrBlobIDEmpty } + + dest := bs.Path(node) file, err := os.Open(dest) if err != nil { return nil, errors.Wrapf(err, "could not read blob '%s'", dest) @@ -100,10 +106,10 @@ func (bs *Blobstore) Download(node *node.Node) (io.ReadCloser, error) { // Delete deletes a blob from the blobstore func (bs *Blobstore) Delete(node *node.Node) error { - dest, err := bs.path(node) - if err != nil { - return err + if node.BlobID == "" { + return ErrBlobIDEmpty } + dest := bs.Path(node) if err := utils.RemoveItem(dest); err != nil { return errors.Wrapf(err, "could not delete blob '%s'", dest) } @@ -111,37 +117,28 @@ func (bs *Blobstore) Delete(node *node.Node) error { } // List lists all blobs in the Blobstore -func (bs *Blobstore) List() ([]string, error) { +func (bs *Blobstore) List() ([]*node.Node, error) { dirs, err := filepath.Glob(filepath.Join(bs.root, "spaces", "*", "*", "blobs", "*", "*", "*", "*", "*")) if err != nil { return nil, err } - blobids := make([]string, 0, len(dirs)) + blobids := make([]*node.Node, 0, len(dirs)) for _, d := range dirs { - seps := strings.Split(d, "/") - var b string - var now bool - for _, s := range seps { - if now { - b += s - } - if s == "blobs" { - now = true - } - } - blobids = append(blobids, b) + _, s, _ := strings.Cut(d, "spaces") + spaceraw, blobraw, _ := strings.Cut(s, "blobs") + blobids = append(blobids, &node.Node{ + SpaceID: strings.ReplaceAll(spaceraw, "/", ""), + BlobID: strings.ReplaceAll(blobraw, "/", ""), + }) } return blobids, nil } -func (bs *Blobstore) path(node *node.Node) (string, error) { - if node.BlobID == "" { - return "", fmt.Errorf("blobstore: BlobID is empty") - } +func (bs *Blobstore) Path(node *node.Node) string { return filepath.Join( bs.root, filepath.Clean(filepath.Join( "/", "spaces", lookup.Pathify(node.SpaceID, 1, 2), "blobs", lookup.Pathify(node.BlobID, 4, 2)), ), - ), nil + ) } diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/s3ng/blobstore/blobstore.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/s3ng/blobstore/blobstore.go index 2105ddef095..aaeecf65f8c 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/s3ng/blobstore/blobstore.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/s3ng/blobstore/blobstore.go @@ -84,7 +84,7 @@ func (bs *Blobstore) Upload(node *node.Node, source string) error { } defer reader.Close() - _, err = bs.client.PutObject(context.Background(), bs.bucket, bs.path(node), reader, node.Blobsize, minio.PutObjectOptions{ + _, err = bs.client.PutObject(context.Background(), bs.bucket, bs.Path(node), reader, node.Blobsize, minio.PutObjectOptions{ ContentType: "application/octet-stream", SendContentMd5: bs.defaultPutOptions.SendContentMd5, ConcurrentStreamParts: bs.defaultPutOptions.ConcurrentStreamParts, @@ -95,21 +95,21 @@ func (bs *Blobstore) Upload(node *node.Node, source string) error { }) if err != nil { - return errors.Wrapf(err, "could not store object '%s' into bucket '%s'", bs.path(node), bs.bucket) + return errors.Wrapf(err, "could not store object '%s' into bucket '%s'", bs.Path(node), bs.bucket) } return nil } // Download retrieves a blob from the blobstore for reading func (bs *Blobstore) Download(node *node.Node) (io.ReadCloser, error) { - reader, err := bs.client.GetObject(context.Background(), bs.bucket, bs.path(node), minio.GetObjectOptions{}) + reader, err := bs.client.GetObject(context.Background(), bs.bucket, bs.Path(node), minio.GetObjectOptions{}) if err != nil { - return nil, errors.Wrapf(err, "could not download object '%s' from bucket '%s'", bs.path(node), bs.bucket) + return nil, errors.Wrapf(err, "could not download object '%s' from bucket '%s'", bs.Path(node), bs.bucket) } stat, err := reader.Stat() if err != nil { - return nil, errors.Wrapf(err, "blob path: %s", bs.path(node)) + return nil, errors.Wrapf(err, "blob path: %s", bs.Path(node)) } if node.Blobsize != stat.Size { @@ -121,31 +121,34 @@ func (bs *Blobstore) Download(node *node.Node) (io.ReadCloser, error) { // Delete deletes a blob from the blobstore func (bs *Blobstore) Delete(node *node.Node) error { - err := bs.client.RemoveObject(context.Background(), bs.bucket, bs.path(node), minio.RemoveObjectOptions{}) + err := bs.client.RemoveObject(context.Background(), bs.bucket, bs.Path(node), minio.RemoveObjectOptions{}) if err != nil { - return errors.Wrapf(err, "could not delete object '%s' from bucket '%s'", bs.path(node), bs.bucket) + return errors.Wrapf(err, "could not delete object '%s' from bucket '%s'", bs.Path(node), bs.bucket) } return nil } // List lists all blobs in the Blobstore -func (bs *Blobstore) List() ([]string, error) { +func (bs *Blobstore) List() ([]*node.Node, error) { ch := bs.client.ListObjects(context.Background(), bs.bucket, minio.ListObjectsOptions{Recursive: true}) var err error - ids := make([]string, 0) + ids := make([]*node.Node, 0) for oi := range ch { if oi.Err != nil { err = oi.Err continue } - _, blobid, _ := strings.Cut(oi.Key, "/") - ids = append(ids, strings.ReplaceAll(blobid, "/", "")) + spaceid, blobid, _ := strings.Cut(oi.Key, "/") + ids = append(ids, &node.Node{ + SpaceID: strings.ReplaceAll(spaceid, "/", ""), + BlobID: strings.ReplaceAll(blobid, "/", ""), + }) } return ids, err } -func (bs *Blobstore) path(node *node.Node) string { +func (bs *Blobstore) Path(node *node.Node) string { // https://aws.amazon.com/de/premiumsupport/knowledge-center/s3-prefix-nested-folders-difference/ // Prefixes are used to partion a bucket. A prefix is everything except the filename. // For a file `BucketName/foo/bar/lorem.ipsum`, `BucketName/foo/bar/` is the prefix. diff --git a/vendor/modules.txt b/vendor/modules.txt index 8681e7db28a..20868f3d18f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -366,7 +366,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.19.2-0.20240530092407-7f72f379ea89 +# github.com/cs3org/reva/v2 v2.19.2-0.20240603112905-634bf103c8be ## explicit; go 1.21 github.com/cs3org/reva/v2/cmd/revad/internal/grace github.com/cs3org/reva/v2/cmd/revad/runtime