local occurences

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
Jörn Friedrich Dreyer
2025-01-15 11:19:04 +01:00
parent 6a2e433d0b
commit 7284acdfeb
10 changed files with 45 additions and 45 deletions

View File

@@ -1,8 +1,8 @@
# Collaboration
The collaboration service connects ocis with document servers such as Collabora, ONLYOFFICE or Microsoft using the WOPI protocol.
The collaboration service connects opencloud with document servers such as Collabora, ONLYOFFICE or Microsoft using the WOPI protocol.
Since this service requires an external document server, it won't start by default when using `ocis server`. You must start it manually with the `ocis collaboration server` command.
Since this service requires an external document server, it won't start by default when using `opencloud server`. You must start it manually with the `opencloud collaboration server` command.
Because the collaboration service needs to be started manually, the following prerequisite applies: On collaboration service startup, particular environment variables are required to be populated. If environment variables have a default like the `MICRO_REGISTRY_ADDRESS`, the default will be used, if not set otherwise. Use for all others the instance values as defined. If these environment variables are not provided or misconfigured, the collaboration service will not start up.
@@ -20,7 +20,7 @@ The collaboration service requires the target document server (ONLYOFFICE, Colla
* The gateway service.
* The app-registry service.
If any of the named services above have not been started or are not reachable, the collaboration service won't start. For the binary or the docker release of Infinite Scale, check with the `ocis list` command if they have been started. If not, you must start them manually upfront before starting the collaboration service.
If any of the named services above have not been started or are not reachable, the collaboration service won't start. For the binary or the docker release of Infinite Scale, check with the `opencloud list` command if they have been started. If not, you must start them manually upfront before starting the collaboration service.
## WOPI Configuration

View File

@@ -21,7 +21,7 @@ func GetCommands(cfg *config.Config) cli.Commands {
func Execute(cfg *config.Config) error {
app := clihelper.DefaultApp(&cli.App{
Name: "collaboration",
Usage: "Serve WOPI for oCIS",
Usage: "Serve WOPI for OpenCloud",
Commands: GetCommands(cfg),
})

View File

@@ -44,7 +44,7 @@ func Server(cfg *config.Config) *cli.Command {
defer cancel()
// prepare components
if err := helpers.RegisterOcisService(ctx, cfg, logger); err != nil {
if err := helpers.RegisterOpenCloudService(ctx, cfg, logger); err != nil {
return err
}

View File

@@ -6,7 +6,7 @@ import (
"net/url"
occfg "github.com/opencloud-eu/opencloud/pkg/config"
ocisdefaults "github.com/opencloud-eu/opencloud/pkg/config/defaults"
ocdefaults "github.com/opencloud-eu/opencloud/pkg/config/defaults"
"github.com/opencloud-eu/opencloud/pkg/config/envdecode"
"github.com/opencloud-eu/opencloud/pkg/shared"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/config"
@@ -49,14 +49,14 @@ func Validate(cfg *config.Config) error {
"Make sure your %s config contains the proper values "+
"(e.g. by running opencloud init or setting it manually in "+
"the config/corresponding environment variable): %s",
cfg.Service.Name, ocisdefaults.BaseConfigPath(), err.Error())
cfg.Service.Name, ocdefaults.BaseConfigPath(), err.Error())
}
if url.Path != "" {
return fmt.Errorf("The WOPI Src must not contain a path in your config for %s. "+
"Make sure your %s config contains the proper values "+
"(e.g. by running opencloud init or setting it manually in "+
"the config/corresponding environment variable)",
cfg.Service.Name, ocisdefaults.BaseConfigPath())
cfg.Service.Name, ocdefaults.BaseConfigPath())
}
return nil

View File

@@ -5,7 +5,7 @@ type Wopi struct {
WopiSrc string `yaml:"wopisrc" env:"COLLABORATION_WOPI_SRC" desc:"The WOPI source base URL containing schema, host and port. Set this to the schema and domain where the collaboration service is reachable for the wopi app, such as https://office.example.test." introductionVersion:"6.0.0"`
Secret string `yaml:"secret" env:"COLLABORATION_WOPI_SECRET" desc:"Used to mint and verify WOPI JWT tokens and encrypt and decrypt the REVA JWT token embedded in the WOPI JWT token." introductionVersion:"6.0.0"`
DisableChat bool `yaml:"disable_chat" env:"COLLABORATION_WOPI_DISABLE_CHAT;OC_WOPI_DISABLE_CHAT" desc:"Disable chat in the office web frontend. This feature applies to OnlyOffice and Microsoft." introductionVersion:"7.0.0"`
ProxyURL string `yaml:"proxy_url" env:"COLLABORATION_WOPI_PROXY_URL" desc:"The URL to the ownCloud Office365 WOPI proxy. Optional. To use this feature, you need an office365 proxy subscription. If you become part of the Microsoft CSP program (https://learn.microsoft.com/en-us/partner-center/enroll/csp-overview), you can use WebOffice without a proxy." introductionVersion:"7.0.0"`
ProxySecret string `yaml:"proxy_secret" env:"COLLABORATION_WOPI_PROXY_SECRET" desc:"Optional, the secret to authenticate against the ownCloud Office365 WOPI proxy. This secret can be obtained from ownCloud via the office365 proxy subscription." introductionVersion:"7.0.0"`
ProxyURL string `yaml:"proxy_url" env:"COLLABORATION_WOPI_PROXY_URL" desc:"The URL to the OpenCloud WOPI proxy. Optional. To use this feature, you need an office365 proxy subscription. If you become part of the Microsoft CSP program (https://learn.microsoft.com/en-us/partner-center/enroll/csp-overview), you can use WebOffice without a proxy." introductionVersion:"7.0.0"`
ProxySecret string `yaml:"proxy_secret" env:"COLLABORATION_WOPI_PROXY_SECRET" desc:"Optional, the secret to authenticate against the OpenCloud WOPI proxy. This secret can be obtained from ownCloud via the office365 proxy subscription." introductionVersion:"7.0.0"`
ShortTokens bool `yaml:"short_tokens" env:"COLLABORATION_WOPI_SHORTTOKENS" desc:"Use short access tokens for WOPI access. This is useful for office packages, like Microsoft Office Online, which have URL length restrictions. If enabled, a persistent store must be configured." introductionVersion:"7.0.0"`
}

View File

@@ -1215,7 +1215,7 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
breadcrumbFolderName = statRes.GetInfo().GetSpace().GetName()
}
ocisURL, err := url.Parse(f.cfg.Commons.OcisURL)
ocURL, err := url.Parse(f.cfg.Commons.OcisURL)
if err != nil {
return nil, err
}
@@ -1224,17 +1224,17 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
return nil, err
}
privateLinkURL := &url.URL{}
*privateLinkURL = *ocisURL
privateLinkURL.Path = path.Join(ocisURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetId()))
*privateLinkURL = *ocURL
privateLinkURL.Path = path.Join(ocURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetId()))
parentFolderURL := &url.URL{}
*parentFolderURL = *ocisURL
*parentFolderURL = *ocURL
if !isPublicShare {
parentFolderURL.Path = path.Join(ocisURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetParentId()))
parentFolderURL.Path = path.Join(ocURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetParentId()))
} else {
if scopes, ok := ctxpkg.ContextGetScopes(ctx); ok {
publicShare := &link.PublicShare{}
if err := f.getScopeByKeyPrefix(scopes, "publicshare:", publicShare); err == nil {
parentFolderURL.Path = path.Join(ocisURL.Path, "s", publicShare.GetToken())
parentFolderURL.Path = path.Join(ocURL.Path, "s", publicShare.GetToken())
} else {
logger.Error().Err(err).Msg("CheckFileInfo: error getting public share scope")
}
@@ -1253,8 +1253,8 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
fileinfo.KeyBreadcrumbFolderName: breadcrumbFolderName,
fileinfo.KeyBreadcrumbFolderURL: parentFolderURL.String(),
fileinfo.KeyHostViewURL: createHostUrl("view", ocisURL, f.cfg.App.Name, statRes.GetInfo()),
fileinfo.KeyHostEditURL: createHostUrl("write", ocisURL, f.cfg.App.Name, statRes.GetInfo()),
fileinfo.KeyHostViewURL: createHostUrl("view", ocURL, f.cfg.App.Name, statRes.GetInfo()),
fileinfo.KeyHostEditURL: createHostUrl("write", ocURL, f.cfg.App.Name, statRes.GetInfo()),
fileinfo.KeyFileSharingURL: createShareUrl(privateLinkURL),
fileinfo.KeyFileVersionURL: createVersionsUrl(privateLinkURL),
@@ -1328,20 +1328,20 @@ func (f *FileConnector) createDownloadURL(wopiContext middleware.WopiContext, co
return downloadURL.String(), nil
}
func createHostUrl(mode string, ocisUrl *url.URL, appName string, info *providerv1beta1.ResourceInfo) string {
webUrl := createAppExternalURL(ocisUrl, appName, info)
func createHostUrl(mode string, u *url.URL, appName string, info *providerv1beta1.ResourceInfo) string {
webUrl := createAppExternalURL(u, appName, info)
addURLParams(webUrl, map[string]string{"view_mode": mode})
return webUrl.String()
}
func createShareUrl(ocisURL *url.URL) string {
shareURL := *ocisURL
func createShareUrl(u *url.URL) string {
shareURL := *u
addURLParams(&shareURL, map[string]string{"details": "sharing"})
return shareURL.String()
}
func createVersionsUrl(ocisURL *url.URL) string {
versionsURL := *ocisURL
func createVersionsUrl(u *url.URL) string {
versionsURL := *u
addURLParams(&versionsURL, map[string]string{"details": "versions"})
return versionsURL.String()
}
@@ -1354,11 +1354,11 @@ func addURLParams(u *url.URL, params map[string]string) {
u.RawQuery = q.Encode()
}
func createAppExternalURL(ocisURL *url.URL, appName string, info *providerv1beta1.ResourceInfo) *url.URL {
func createAppExternalURL(u *url.URL, appName string, info *providerv1beta1.ResourceInfo) *url.URL {
spaceAlias := utils.ReadPlainFromOpaque(info.GetSpace().GetOpaque(), "spaceAlias")
appExternalURL := *ocisURL
appExternalURL.Path = path.Join(ocisURL.Path, "external-"+strings.ToLower(appName), spaceAlias, info.GetPath())
q := ocisURL.Query()
appExternalURL := *u
appExternalURL.Path = path.Join(u.Path, "external-"+strings.ToLower(appName), spaceAlias, info.GetPath())
q := u.Query()
q.Add("fileId", storagespace.FormatResourceID(info.GetId()))
appExternalURL.RawQuery = q.Encode()
return &appExternalURL

View File

@@ -16,10 +16,10 @@ import (
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/config"
)
// RegisterOcisService will register this service.
// RegisterOpenCloudService will register this service.
// There are no explicit requirements for the context, and it will be passed
// without changes to the underlying RegisterService method.
func RegisterOcisService(ctx context.Context, cfg *config.Config, logger log.Logger) error {
func RegisterOpenCloudService(ctx context.Context, cfg *config.Config, logger log.Logger) error {
svc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name+"."+cfg.App.Name, cfg.GRPC.Protocol, cfg.GRPC.Addr, version.GetString())
return registry.RegisterService(ctx, logger, svc, cfg.Debug.Addr)
}

View File

@@ -31,19 +31,19 @@ func CollaborationTracingMiddleware(next http.Handler) http.Handler {
wopiFile := wopiContext.FileReference
attrs := []attribute.KeyValue{
attribute.String("ocis.wopi.sessionid", r.Header.Get("X-WOPI-SessionId")),
attribute.String("ocis.wopi.method", wopiMethod),
attribute.String("ocis.wopi.resource.id.storage", wopiFile.GetResourceId().GetStorageId()),
attribute.String("ocis.wopi.resource.id.opaque", wopiFile.GetResourceId().GetOpaqueId()),
attribute.String("ocis.wopi.resource.id.space", wopiFile.GetResourceId().GetSpaceId()),
attribute.String("ocis.wopi.resource.path", wopiFile.GetPath()),
attribute.String("wopi.session.id", r.Header.Get("X-WOPI-SessionId")),
attribute.String("wopi.method", wopiMethod),
attribute.String("cs3.resource.id.storage", wopiFile.GetResourceId().GetStorageId()),
attribute.String("cs3.resource.id.opaque", wopiFile.GetResourceId().GetOpaqueId()),
attribute.String("cs3.resource.id.space", wopiFile.GetResourceId().GetSpaceId()),
attribute.String("cs3.resource.path", wopiFile.GetPath()),
}
if wopiUser, ok := ctxpkg.ContextGetUser(r.Context()); ok {
attrs = append(attrs, []attribute.KeyValue{
attribute.String("ocis.wopi.user.idp", wopiUser.GetId().GetIdp()),
attribute.String("ocis.wopi.user.opaque", wopiUser.GetId().GetOpaqueId()),
attribute.String("ocis.wopi.user.type", wopiUser.GetId().GetType().String()),
attribute.String("cs3.user.idp", wopiUser.GetId().GetIdp()),
attribute.String("cs3.user.opaque", wopiUser.GetId().GetOpaqueId()),
attribute.String("cs3.user.type", wopiUser.GetId().GetType().String()),
}...)
}
span.SetAttributes(attrs...)

View File

@@ -19,7 +19,7 @@ import (
// If no proxy URL and proxy secret are configured, the URL will be generated
// as a direct URL that contains the file reference.
// Example:
// https:/ocis.team/wopi/files/12312678470610632091729803710923
// https:/cloud.example.test/wopi/files/12312678470610632091729803710923
func GenerateWopiSrc(fileRef string, cfg *config.Config) (*url.URL, error) {
wopiSrcURL, err := url.Parse(cfg.Wopi.WopiSrc)
if err != nil {

View File

@@ -16,7 +16,7 @@ var _ = Describe("Wopisrc Test", func() {
BeforeEach(func() {
c = &config.Config{
Wopi: config.Wopi{
WopiSrc: "https://ocis.team/wopi/files",
WopiSrc: "https://cloud.example.test/wopi/files",
ProxyURL: "https://cloud.proxy.com",
ProxySecret: "secret",
},
@@ -25,7 +25,7 @@ var _ = Describe("Wopisrc Test", func() {
When("WopiSrc URL is incorrect", func() {
c = &config.Config{
Wopi: config.Wopi{
WopiSrc: "https:&//ocis.team/wopi/files",
WopiSrc: "https:&//cloud.example.test/wopi/files",
},
}
url, err := wopisrc.GenerateWopiSrc("123456", c)
@@ -35,7 +35,7 @@ var _ = Describe("Wopisrc Test", func() {
When("proxy URL is incorrect", func() {
c = &config.Config{
Wopi: config.Wopi{
WopiSrc: "https://ocis.team/wopi/files",
WopiSrc: "https://cloud.example.test/wopi/files",
ProxyURL: "cloud",
ProxySecret: "secret",
},
@@ -48,7 +48,7 @@ var _ = Describe("Wopisrc Test", func() {
It("should generate a WOPI src URL as a jwt token", func() {
url, err := wopisrc.GenerateWopiSrc("123456", c)
Expect(err).ToNot(HaveOccurred())
Expect(url.String()).To(Equal("https://cloud.proxy.com/wopi/files/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1IjoiaHR0cHM6Ly9vY2lzLnRlYW0vd29waS9maWxlcy8iLCJmIjoiMTIzNDU2In0.6ol9PQXGKktKfAri8tsJ4X_a9rIeosJ7id6KTQW6Ui0"))
Expect(url.String()).To(Equal("https://cloud.proxy.com/wopi/files/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1IjoiaHR0cHM6Ly9jbG91ZC5leGFtcGxlLnRlc3Qvd29waS9maWxlcy8iLCJmIjoiMTIzNDU2In0.LzyGPanHKxjLlIPoyfGU4cAUxzy3FAmBqMIqLCSHclg"))
})
})
When("proxy URL and proxy secret are not configured", func() {
@@ -57,7 +57,7 @@ var _ = Describe("Wopisrc Test", func() {
c.Wopi.ProxySecret = ""
url, err := wopisrc.GenerateWopiSrc("123456", c)
Expect(err).ToNot(HaveOccurred())
Expect(url.String()).To(Equal("https://ocis.team/wopi/files/123456"))
Expect(url.String()).To(Equal("https://cloud.example.test/wopi/files/123456"))
})
})
})