Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Branding api #5559

Merged
merged 10 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog/unreleased/branding-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Add endpoints to upload a custom logo

Added endpoints to upload and reset custom logos. The files are stored under the `WEB_ASSET_PATH`
which defaults to `$OCIS_BASE_DATA_PATH/web/assets`.

https://github.com/owncloud/ocis/pull/5559
46 changes: 22 additions & 24 deletions ocis-pkg/assetsfs/assetsfs.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package assetsfs

import (
"embed"
"fmt"
"io/fs"
"net/http"
"os"
"path"
"path/filepath"

"github.com/owncloud/ocis/v2/ocis-pkg/log"
)
Expand All @@ -21,22 +20,35 @@ type FileSystem struct {
// Open checks if assetPath is set and tries to load from there. Falls back to fs if that is not possible
func (f *FileSystem) Open(original string) (http.File, error) {
if f.assetPath != "" {
file, err := read(f.assetPath, original)
file, err := os.Open(filepath.Join(f.assetPath, original))
if err == nil {
return file, nil
}
f.log.Warn().
Str("path", f.assetPath).
Str("filename", original).
Str("error", err.Error()).
Msg("error reading from assetPath")
}

return f.fs.Open(original)
}

func (f *FileSystem) OpenEmbedded(name string) (http.File, error) {
return f.fs.Open(name)
}

// Create creates a new file in the assetPath
func (f *FileSystem) Create(name string) (*os.File, error) {
fullPath := f.jailPath(name)
if err := os.MkdirAll(filepath.Dir(fullPath), 0770); err != nil {
return nil, err
}
return os.Create(fullPath)
}

// jailPath returns the fullPath `<assetPath>/<name>`. It makes sure that the path is
// always under `<assetPath>` to prevent directory traversal.
func (f *FileSystem) jailPath(name string) string {
return filepath.Join(f.assetPath, filepath.Join("/", name))
}

// New initializes a new FileSystem. Quits on error
func New(embedFS embed.FS, assetPath string, logger log.Logger) *FileSystem {
func New(embedFS fs.FS, assetPath string, logger log.Logger) *FileSystem {
f, err := fs.Sub(embedFS, "assets")
if err != nil {
fmt.Println("Cannot load subtree fs:", err.Error())
Expand All @@ -49,17 +61,3 @@ func New(embedFS embed.FS, assetPath string, logger log.Logger) *FileSystem {
log: logger,
}
}

// tries to read file from disk or errors
func read(assetPath string, fileName string) (http.File, error) {
if stat, err := os.Stat(assetPath); err != nil || !stat.IsDir() {
return nil, fmt.Errorf("can't load asset path: %s", err)
}

p := path.Join(assetPath, fileName)
if _, err := os.Stat(p); err != nil {
return nil, err
}

return os.Open(p)
}
4 changes: 4 additions & 0 deletions services/proxy/pkg/config/defaults/defaultconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ func DefaultPolicies() []config.Policy {
Service: "com.owncloud.web.idp",
Unprotected: true,
},
{
Endpoint: "/branding/logo",
Service: "com.owncloud.web.web",
},
{
Endpoint: "/konnect/",
Service: "com.owncloud.web.idp",
Expand Down
23 changes: 23 additions & 0 deletions services/settings/pkg/service/v0/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ const (
SelfManagementPermissionID string = "e03070e9-4362-4cc6-a872-1c7cb2eb2b8e"
// SelfManagementPermissionName is the hardcoded setting name for the self management permission
SelfManagementPermissionName string = "self-management"

// ChangeLogoPermissionID is the hardcoded setting UUID for the change-logo permission
ChangeLogoPermissionID string = "ed83fc10-1f54-4a9e-b5a7-fb517f5f3e01"
// ChangeLogoPermissionName is the hardcoded setting name for the change-logo permission
ChangeLogoPermissionName string = "change-logo"
)

// generateBundlesDefaultRoles bootstraps the default roles.
Expand Down Expand Up @@ -438,6 +443,24 @@ func generatePermissionRequests() []*settingssvc.AddSettingToBundleRequest {
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settingsmsg.Setting{
Id: ChangeLogoPermissionID,
Name: ChangeLogoPermissionName,
DisplayName: "Change logo",
Description: "This permission permits to change the system logo.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleSpaceAdmin,
Setting: &settingsmsg.Setting{
Expand Down
20 changes: 20 additions & 0 deletions services/settings/pkg/store/defaults/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ const (
SelfManagementPermissionID string = "e03070e9-4362-4cc6-a872-1c7cb2eb2b8e"
// SelfManagementPermissionName is the hardcoded setting name for the self management permission
SelfManagementPermissionName string = "self-management"

// ChangeLogoPermissionID is the hardcoded setting UUID for the change-logo permission
ChangeLogoPermissionID string = "ed83fc10-1f54-4a9e-b5a7-fb517f5f3e01"
// ChangeLogoPermissionName is the hardcoded setting name for the change-logo permission
ChangeLogoPermissionName string = "change-logo"
)

// GenerateBundlesDefaultRoles bootstraps the default roles.
Expand Down Expand Up @@ -260,6 +265,21 @@ func generateBundleAdminRole() *settingsmsg.Bundle {
},
},
},
{
Id: ChangeLogoPermissionID,
Name: ChangeLogoPermissionName,
DisplayName: "Change logo",
Description: "This permission permits to change the system logo.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
}
}
Expand Down
50 changes: 0 additions & 50 deletions services/web/pkg/assets/option.go

This file was deleted.

3 changes: 2 additions & 1 deletion services/web/pkg/assets/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package assets

import (
"bytes"
"golang.org/x/net/html"
"io"
"mime"
"net/http"
"path"
"path/filepath"

"golang.org/x/net/html"
)

type fileServer struct {
Expand Down
25 changes: 17 additions & 8 deletions services/web/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ type Config struct {
File string `yaml:"file" env:"WEB_UI_CONFIG" desc:"Read the ownCloud Web configuration from this file."` // TODO: rename this to a more self explaining string
Web Web `yaml:"web"`

Context context.Context `yaml:"-"`
TokenManager *TokenManager `yaml:"token_manager"`

GatewayAddress string `yaml:"gateway_addr" env:"WEB_GATEWAY_GRPC_ADDR" desc:"GRPC address of the Reva gateway service."`
butonic marked this conversation as resolved.
Show resolved Hide resolved
Context context.Context `yaml:"-"`
}

// Asset defines the available asset configuration.
Expand Down Expand Up @@ -60,13 +63,14 @@ type Application struct {
}

// ExternalApp defines an external web app.
// {
// "name": "hello",
// "path": "http://localhost:9105/hello.js",
// "config": {
// "url": "http://localhost:9105"
// }
// }
//
// {
// "name": "hello",
// "path": "http://localhost:9105/hello.js",
// "config": {
// "url": "http://localhost:9105"
// }
// }
type ExternalApp struct {
ID string `json:"id,omitempty" yaml:"id"`
Path string `json:"path,omitempty" yaml:"path"`
Expand All @@ -86,3 +90,8 @@ type Web struct {
ThemePath string `yaml:"theme_path" env:"WEB_UI_THEME_PATH" desc:"URL path to load themes from. The theme server will be prepended."` // used to build Theme in WebConfig
Config WebConfig `yaml:"config"`
}

// TokenManager is the config for using the reva token manager
type TokenManager struct {
JWTSecret string `yaml:"jwt_secret" env:"OCIS_JWT_SECRET;WEB_JWT_SECRET" desc:"The secret to mint and validate jwt tokens."`
}
12 changes: 11 additions & 1 deletion services/web/pkg/config/defaults/defaultconfig.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package defaults

import (
"path/filepath"
"strings"

"github.com/owncloud/ocis/v2/ocis-pkg/config/defaults"
"github.com/owncloud/ocis/v2/services/web/pkg/config"
)

Expand Down Expand Up @@ -31,8 +33,9 @@ func DefaultConfig() *config.Config {
Name: "web",
},
Asset: config.Asset{
Path: "",
Path: filepath.Join(defaults.BaseDataPath(), "web/assets"),
},
GatewayAddress: "127.0.0.1:9142",
Web: config.Web{
Path: "",
ThemeServer: "https://localhost:9200",
Expand Down Expand Up @@ -93,6 +96,13 @@ func EnsureDefaults(cfg *config.Config) {
cfg.Tracing = &config.Tracing{}
}

if cfg.TokenManager == nil && cfg.Commons != nil && cfg.Commons.TokenManager != nil {
cfg.TokenManager = &config.TokenManager{
JWTSecret: cfg.Commons.TokenManager.JWTSecret,
}
} else if cfg.TokenManager == nil {
cfg.TokenManager = &config.TokenManager{}
}
if cfg.Commons != nil {
cfg.HTTP.TLS = cfg.Commons.HTTPServiceTLS
}
Expand Down
4 changes: 4 additions & 0 deletions services/web/pkg/config/parser/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"

ociscfg "github.com/owncloud/ocis/v2/ocis-pkg/config"
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
"github.com/owncloud/ocis/v2/services/web/pkg/config"
"github.com/owncloud/ocis/v2/services/web/pkg/config/defaults"

Expand Down Expand Up @@ -33,5 +34,8 @@ func ParseConfig(cfg *config.Config) error {
}

func Validate(cfg *config.Config) error {
if cfg.TokenManager.JWTSecret == "" {
return shared.MissingJWTTokenError(cfg.Service.Name)
}
return nil
}
7 changes: 7 additions & 0 deletions services/web/pkg/server/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package http
import (
"fmt"

"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
chimiddleware "github.com/go-chi/chi/v5/middleware"
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
"github.com/owncloud/ocis/v2/ocis-pkg/service/http"
Expand Down Expand Up @@ -33,9 +34,15 @@ func Server(opts ...Option) (http.Service, error) {
return http.Service{}, fmt.Errorf("could not initialize http service: %w", err)
}

client, err := pool.GetGatewayServiceClient(options.Config.GatewayAddress)
if err != nil {
return http.Service{}, err
}

handle := svc.NewService(
svc.Logger(options.Logger),
svc.Config(options.Config),
svc.GatewayClient(client),
svc.Middleware(
chimiddleware.RealIP,
chimiddleware.RequestID,
Expand Down
Loading