diff --git a/.drone.star b/.drone.star index 1d373dbd9..9471ed9a9 100644 --- a/.drone.star +++ b/.drone.star @@ -928,9 +928,14 @@ def wopiValidatorTests(ctx, storage, wopiServerType, accounts_hash_difficulty = "MICRO_REGISTRY_ADDRESS": "ocis-server:9233", "COLLABORATION_LOG_LEVEL": "debug", "COLLABORATION_APP_NAME": "FakeOffice", - "COLLABORATION_WOPIAPP_WOPISRC": "http://fakeoffice:8080", - "COLLABORATION_WOPIAPP_INSECURE": "true", + "COLLABORATION_APP_ADDR": "http://fakeoffice:8080", + "COLLABORATION_APP_INSECURE": "true", + "COLLABORATION_WOPI_SRC": "http://wopiserver", + "COLLABORATION_WOPI_SECRET": "some-wopi-secret", "COLLABORATION_CS3API_DATAGATEWAY_INSECURE": "true", + "OCIS_JWT_SECRET": { + "from_secret": "ocis_jwt_secret", + }, }, "commands": [ "%s collaboration server" % ocis_bin, diff --git a/services/collaboration/README.md b/services/collaboration/README.md index a94766c9d..ffc5755e7 100644 --- a/services/collaboration/README.md +++ b/services/collaboration/README.md @@ -18,14 +18,14 @@ If any of the named services above have not been started or are not reachable, t There are a few variables that you need to set: -* `COLLABORATION_WOPIAPP_ADDR`:\ +* `COLLABORATION_APP_ADDR`:\ The URL of the WOPI app (onlyoffice, collabora, etc).\ For example: `https://office.example.com`. -* `COLLABORATION_WOPIAPP_INSECURE`:\ +* `COLLABORATION_APP_INSECURE`:\ In case you are using a self signed certificate for the WOPI app you can tell the collaboration service to allow an insecure connection. -* `COLLABORATION_WOPIAPP_WOPISRC`:\ +* `COLLABORATION_APP_WOPISRC`:\ The external address of the collaboration service. The target app (onlyoffice, collabora, etc) will use this address to read and write files from Infinite Scale. \ For example: `https://wopi.example.com`. diff --git a/services/collaboration/pkg/config/app.go b/services/collaboration/pkg/config/app.go index 69c5447f0..bbe08ef09 100644 --- a/services/collaboration/pkg/config/app.go +++ b/services/collaboration/pkg/config/app.go @@ -6,4 +6,7 @@ type App struct { Description string `yaml:"description" env:"COLLABORATION_APP_DESCRIPTION" desc:"App description" introductionVersion:"5.1"` Icon string `yaml:"icon" env:"COLLABORATION_APP_ICON" desc:"Icon for the app" introductionVersion:"5.1"` LockName string `yaml:"lockname" env:"COLLABORATION_APP_LOCKNAME" desc:"Name for the app lock" introductionVersion:"5.1"` + + Addr string `yaml:"addr" env:"COLLABORATION_APP_ADDR" desc:"The URL where the WOPI app is located, such as https://127.0.0.1:8080." introductionVersion:"5.1"` + Insecure bool `yaml:"insecure" env:"COLLABORATION_APP_INSECURE" desc:"Skip TLS certificate verification when connecting to the WOPI app" introductionVersion:"5.1"` } diff --git a/services/collaboration/pkg/config/config.go b/services/collaboration/pkg/config/config.go index 2a04b53b3..054529d94 100644 --- a/services/collaboration/pkg/config/config.go +++ b/services/collaboration/pkg/config/config.go @@ -16,10 +16,11 @@ type Config struct { TokenManager *TokenManager `yaml:"token_manager"` - GRPC GRPC `yaml:"grpc"` - HTTP HTTP `yaml:"http"` - WopiApp WopiApp `yaml:"wopiapp"` - CS3Api CS3Api `yaml:"cs3api"` + GRPC GRPC `yaml:"grpc"` + HTTP HTTP `yaml:"http"` + + Wopi Wopi `yaml:"wopi"` + CS3Api CS3Api `yaml:"cs3api"` Tracing *Tracing `yaml:"tracing"` Log *Log `yaml:"log"` diff --git a/services/collaboration/pkg/config/defaults/defaultconfig.go b/services/collaboration/pkg/config/defaults/defaultconfig.go index 50b17030d..ee49d5163 100644 --- a/services/collaboration/pkg/config/defaults/defaultconfig.go +++ b/services/collaboration/pkg/config/defaults/defaultconfig.go @@ -24,6 +24,8 @@ func DefaultConfig() *config.Config { Description: "Open office documents with a WOPI app", Icon: "image-edit", LockName: "com.github.owncloud.collaboration", + Addr: "https://127.0.0.1:9980", + Insecure: false, }, GRPC: config.GRPC{ Addr: "127.0.0.1:9301", @@ -39,10 +41,8 @@ func DefaultConfig() *config.Config { Pprof: false, Zpages: false, }, - WopiApp: config.WopiApp{ - Addr: "https://127.0.0.1:9980", - Insecure: false, - WopiSrc: "https://localhost:9300", + Wopi: config.Wopi{ + WopiSrc: "https://localhost:9300", }, CS3Api: config.CS3Api{ Gateway: config.Gateway{ diff --git a/services/collaboration/pkg/config/parser/parse.go b/services/collaboration/pkg/config/parser/parse.go index 98cae9f32..ee38fc318 100644 --- a/services/collaboration/pkg/config/parser/parse.go +++ b/services/collaboration/pkg/config/parser/parse.go @@ -2,8 +2,11 @@ package parser import ( "errors" + "fmt" + "net/url" ociscfg "github.com/owncloud/ocis/v2/ocis-pkg/config" + ocisdefaults "github.com/owncloud/ocis/v2/ocis-pkg/config/defaults" "github.com/owncloud/ocis/v2/ocis-pkg/config/envdecode" "github.com/owncloud/ocis/v2/ocis-pkg/shared" "github.com/owncloud/ocis/v2/services/collaboration/pkg/config" @@ -37,8 +40,24 @@ func Validate(cfg *config.Config) error { if cfg.TokenManager.JWTSecret == "" { return shared.MissingJWTTokenError(cfg.Service.Name) } - if cfg.WopiApp.Secret == "" { + if cfg.Wopi.Secret == "" { return shared.MissingWOPISecretError(cfg.Service.Name) } + url, err := url.Parse(cfg.Wopi.WopiSrc) + if err != nil { + return fmt.Errorf("The WOPI Src has not been set properly in your config for %s. "+ + "Make sure your %s config contains the proper values "+ + "(e.g. by running ocis init or setting it manually in "+ + "the config/corresponding environment variable): %s", + cfg.Service.Name, ocisdefaults.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 ocis init or setting it manually in "+ + "the config/corresponding environment variable)", + cfg.Service.Name, ocisdefaults.BaseConfigPath()) + } + return nil } diff --git a/services/collaboration/pkg/config/wopi.go b/services/collaboration/pkg/config/wopi.go new file mode 100644 index 000000000..fd1b0e618 --- /dev/null +++ b/services/collaboration/pkg/config/wopi.go @@ -0,0 +1,7 @@ +package config + +// Wopi defines the available configuration for the WOPI endpoint. +type Wopi struct { + WopiSrc string `yaml:"wopisrc" env:"COLLABORATION_WOPI_SRC" desc:"The WOPISrc 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.owncloud.test." introductionVersion:"5.1"` + 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:"5.1"` +} diff --git a/services/collaboration/pkg/config/wopiapp.go b/services/collaboration/pkg/config/wopiapp.go deleted file mode 100644 index c47caaf02..000000000 --- a/services/collaboration/pkg/config/wopiapp.go +++ /dev/null @@ -1,9 +0,0 @@ -package config - -// WopiApp defines the available configuration in order to connect to a WOPI app. -type WopiApp struct { - Addr string `yaml:"addr" env:"COLLABORATION_WOPIAPP_ADDR" desc:"The URL where the WOPI app is located, such as https://127.0.0.1:8080." introductionVersion:"5.1"` - Insecure bool `yaml:"insecure" env:"COLLABORATION_WOPIAPP_INSECURE" desc:"Skip TLS certificate verification when connecting to the WOPI app" introductionVersion:"5.1"` - WopiSrc string `yaml:"wopisrc" env:"COLLABORATION_WOPIAPP_WOPISRC" desc:"The WOPISrc base URL containing schema, host and port. Path will be set to /wopi/files/{fileid} if not given. {fileid} will be replaced with the WOPI file id. Set this to the schema and domain where the collaboration service is reachable for the wopi app, such as https://office.owncloud.test." introductionVersion:"5.1"` - Secret string `yaml:"secret" env:"COLLABORATION_WOPIAPP_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:"5.1"` -} diff --git a/services/collaboration/pkg/helpers/discovery.go b/services/collaboration/pkg/helpers/discovery.go index 893ca7568..4165609ba 100644 --- a/services/collaboration/pkg/helpers/discovery.go +++ b/services/collaboration/pkg/helpers/discovery.go @@ -17,12 +17,12 @@ import ( // target WOPI app (onlyoffice, collabora, etc) via their "/hosting/discovery" // endpoint. func GetAppURLs(cfg *config.Config, logger log.Logger) (map[string]map[string]string, error) { - wopiAppUrl := cfg.WopiApp.Addr + "/hosting/discovery" + wopiAppUrl := cfg.App.Addr + "/hosting/discovery" httpClient := http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ - InsecureSkipVerify: cfg.WopiApp.Insecure, + InsecureSkipVerify: cfg.App.Insecure, }, }, } diff --git a/services/collaboration/pkg/helpers/discovery_test.go b/services/collaboration/pkg/helpers/discovery_test.go index cb1679045..6fb44ffcc 100644 --- a/services/collaboration/pkg/helpers/discovery_test.go +++ b/services/collaboration/pkg/helpers/discovery_test.go @@ -67,7 +67,7 @@ var _ = Describe("Discovery", func() { Describe("GetAppURLs", func() { It("Good discovery URL", func() { cfg := &config.Config{ - WopiApp: config.WopiApp{ + App: config.App{ Addr: srv.URL + "/good", Insecure: true, }, @@ -95,7 +95,7 @@ var _ = Describe("Discovery", func() { It("Wrong discovery URL", func() { cfg := &config.Config{ - WopiApp: config.WopiApp{ + App: config.App{ Addr: srv.URL + "/bad", Insecure: true, }, @@ -109,7 +109,7 @@ var _ = Describe("Discovery", func() { It("Not XML formatted", func() { cfg := &config.Config{ - WopiApp: config.WopiApp{ + App: config.App{ Addr: srv.URL + "/wrongformat", Insecure: true, }, diff --git a/services/collaboration/pkg/server/http/server.go b/services/collaboration/pkg/server/http/server.go index 35ceac59e..0e70bacc2 100644 --- a/services/collaboration/pkg/server/http/server.go +++ b/services/collaboration/pkg/server/http/server.go @@ -116,7 +116,7 @@ func prepareRoutes(r *chi.Mux, options Options) { r.Use(func(h stdhttp.Handler) stdhttp.Handler { // authentication and wopi context - return colabmiddleware.WopiContextAuthMiddleware(options.Config.WopiApp.Secret, h) + return colabmiddleware.WopiContextAuthMiddleware(options.Config.Wopi.Secret, h) }, ) diff --git a/services/collaboration/pkg/service/grpc/v0/service.go b/services/collaboration/pkg/service/grpc/v0/service.go index 06f85bb3a..67ae47eb0 100644 --- a/services/collaboration/pkg/service/grpc/v0/service.go +++ b/services/collaboration/pkg/service/grpc/v0/service.go @@ -8,7 +8,6 @@ import ( "net/url" "path" "strconv" - "strings" appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1" gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" @@ -124,13 +123,11 @@ func (s *Service) OpenInApp( viewAppURL = editAppURL } - wopiSrcURL, err := url.Parse(strings.Replace(s.config.WopiApp.WopiSrc, "{fileid}", fileRef, 1)) + wopiSrcURL, err := url.Parse(s.config.Wopi.WopiSrc) if err != nil { return nil, err } - if wopiSrcURL.Path == "" { - wopiSrcURL.Path = path.Join("wopi", "files", fileRef) - } + wopiSrcURL.Path = path.Join("wopi", "files", fileRef) addWopiSrcQueryParam := func(baseURL string) (string, error) { u, err := url.Parse(baseURL) @@ -172,7 +169,7 @@ func (s *Service) OpenInApp( appURL = editAppURL } - cryptedReqAccessToken, err := middleware.EncryptAES([]byte(s.config.WopiApp.Secret), req.GetAccessToken()) + cryptedReqAccessToken, err := middleware.EncryptAES([]byte(s.config.Wopi.Secret), req.GetAccessToken()) if err != nil { s.logger.Error(). Err(err). @@ -216,7 +213,7 @@ func (s *Service) OpenInApp( } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - accessToken, err := token.SignedString([]byte(s.config.WopiApp.Secret)) + accessToken, err := token.SignedString([]byte(s.config.Wopi.Secret)) if err != nil { s.logger.Error(). diff --git a/services/collaboration/pkg/service/grpc/v0/service_test.go b/services/collaboration/pkg/service/grpc/v0/service_test.go index 8ebf58f60..c8b6544bc 100644 --- a/services/collaboration/pkg/service/grpc/v0/service_test.go +++ b/services/collaboration/pkg/service/grpc/v0/service_test.go @@ -103,7 +103,7 @@ var _ = Describe("Discovery", func() { It("Invalid access token", func() { ctx := context.Background() - cfg.WopiApp.WopiSrc = "https://wopiserver.test.prv" + cfg.Wopi.WopiSrc = "https://wopiserver.test.prv" req := &appproviderv1beta1.OpenInAppRequest{ ResourceInfo: &providerv1beta1.ResourceInfo{ @@ -139,8 +139,8 @@ var _ = Describe("Discovery", func() { ctx := context.Background() nowTime := time.Now() - cfg.WopiApp.WopiSrc = "https://wopiserver.test.prv" - cfg.WopiApp.Secret = "my_supa_secret" + cfg.Wopi.WopiSrc = "https://wopiserver.test.prv" + cfg.Wopi.Secret = "my_supa_secret" myself := &userv1beta1.User{ Id: &userv1beta1.UserId{ @@ -161,7 +161,7 @@ var _ = Describe("Discovery", func() { Path: "/path/to/file.docx", }, ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE, - AccessToken: MintToken(myself, cfg.WopiApp.Secret, nowTime), + AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime), } gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{