mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-24 16:41:35 -04:00
set secureview flag based on addr
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
2
go.mod
2
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
|
||||
|
||||
4
go.sum
4
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=
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
41
vendor/github.com/cs3org/reva/v2/internal/http/services/appprovider/appprovider.go
generated
vendored
41
vendor/github.com/cs3org/reva/v2/internal/http/services/appprovider/appprovider.go
generated
vendored
@@ -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 {
|
||||
|
||||
53
vendor/github.com/cs3org/reva/v2/pkg/storage/fs/ocis/blobstore/blobstore.go
generated
vendored
53
vendor/github.com/cs3org/reva/v2/pkg/storage/fs/ocis/blobstore/blobstore.go
generated
vendored
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
27
vendor/github.com/cs3org/reva/v2/pkg/storage/fs/s3ng/blobstore/blobstore.go
generated
vendored
27
vendor/github.com/cs3org/reva/v2/pkg/storage/fs/s3ng/blobstore/blobstore.go
generated
vendored
@@ -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.
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user