Initial QSfera import
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
SHELL := bash
|
||||
NAME := sharing
|
||||
|
||||
ifneq (, $(shell command -v go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
|
||||
include ../../.bingo/Variables.mk
|
||||
endif
|
||||
|
||||
include ../../.make/default.mk
|
||||
include ../../.make/go.mk
|
||||
include ../../.make/release.mk
|
||||
include ../../.make/docs.mk
|
||||
@@ -0,0 +1,42 @@
|
||||
# Sharing
|
||||
|
||||
The `sharing` service provides the CS3 Sharing API for КуСфера. It manages user shares and public link shares, implementing the core sharing functionality.
|
||||
|
||||
## Overview
|
||||
|
||||
The sharing service handles:
|
||||
- User-to-user shares (share a file or folder with another user)
|
||||
- Public link shares (share via a public URL)
|
||||
- Share permissions and roles
|
||||
- Share lifecycle management (create, update, delete)
|
||||
|
||||
This service works in conjunction with the storage providers (`storage-shares` and `storage-publiclink`) to persist and manage share information.
|
||||
|
||||
## Integration
|
||||
|
||||
The sharing service integrates with:
|
||||
- `frontend` and `ocs` - Provide HTTP APIs that translate to CS3 sharing calls
|
||||
- `storage-shares` - Stores and manages received shares
|
||||
- `storage-publiclink` - Manages public link shares
|
||||
- `graph` - Provides LibreGraph API for sharing with roles
|
||||
|
||||
## Share Types
|
||||
|
||||
The service supports different types of shares:
|
||||
- **User shares** - Share resources with specific users
|
||||
- **Group shares** - Share resources with groups
|
||||
- **Public link shares** - Create public URLs for sharing
|
||||
- **Federated shares** - Share with users on other КуСфера instances (via `ocm` service)
|
||||
|
||||
## Configuration
|
||||
|
||||
Share behavior can be configured via environment variables:
|
||||
- Password enforcement for public shares
|
||||
- Auto-acceptance of shares
|
||||
- Share permissions and restrictions
|
||||
|
||||
See the `frontend` service README for more details on share-related configuration options.
|
||||
|
||||
## Scalability
|
||||
|
||||
The sharing service depends on the configured storage backends for share metadata. Scalability characteristics depend on the chosen storage backend configuration.
|
||||
@@ -0,0 +1,54 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/qsfera/server/pkg/config/configlog"
|
||||
"github.com/qsfera/server/pkg/log"
|
||||
"github.com/qsfera/server/services/sharing/pkg/config"
|
||||
"github.com/qsfera/server/services/sharing/pkg/config/parser"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// Health is the entrypoint for the health command.
|
||||
func Health(cfg *config.Config) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "health",
|
||||
Short: "check health status",
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return configlog.ReturnError(parser.ParseConfig(cfg))
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
logger := log.Configure(cfg.Service.Name, cfg.Commons, cfg.LogLevel)
|
||||
|
||||
resp, err := http.Get(
|
||||
fmt.Sprintf(
|
||||
"http://%s/healthz",
|
||||
cfg.Debug.Addr,
|
||||
),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
logger.Fatal().
|
||||
Err(err).
|
||||
Msg("Failed to request health check")
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
logger.Fatal().
|
||||
Int("code", resp.StatusCode).
|
||||
Msg("Health seems to be in bad state")
|
||||
}
|
||||
|
||||
logger.Debug().
|
||||
Int("code", resp.StatusCode).
|
||||
Msg("Health got a good state")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/qsfera/server/pkg/clihelper"
|
||||
"github.com/qsfera/server/services/sharing/pkg/config"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// GetCommands provides all commands for this service
|
||||
func GetCommands(cfg *config.Config) []*cobra.Command {
|
||||
return []*cobra.Command{
|
||||
// start this service
|
||||
Server(cfg),
|
||||
|
||||
// interaction with this service
|
||||
|
||||
// infos about this service
|
||||
Health(cfg),
|
||||
Version(cfg),
|
||||
}
|
||||
}
|
||||
|
||||
// Execute is the entry point for the sharing command.
|
||||
func Execute(cfg *config.Config) error {
|
||||
app := clihelper.DefaultApp(&cobra.Command{
|
||||
Use: "sharing",
|
||||
Short: "Provide sharing for КуСфера",
|
||||
})
|
||||
app.AddCommand(GetCommands(cfg)...)
|
||||
app.SetArgs(os.Args[1:])
|
||||
|
||||
return app.ExecuteContext(cfg.Context)
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/qsfera/server/pkg/config/configlog"
|
||||
"github.com/qsfera/server/pkg/log"
|
||||
"github.com/qsfera/server/pkg/registry"
|
||||
"github.com/qsfera/server/pkg/runner"
|
||||
"github.com/qsfera/server/pkg/tracing"
|
||||
"github.com/qsfera/server/pkg/version"
|
||||
"github.com/qsfera/server/services/sharing/pkg/config"
|
||||
"github.com/qsfera/server/services/sharing/pkg/config/parser"
|
||||
"github.com/qsfera/server/services/sharing/pkg/revaconfig"
|
||||
"github.com/qsfera/server/services/sharing/pkg/server/debug"
|
||||
"github.com/opencloud-eu/reva/v2/cmd/revad/runtime"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// Server is the entry point for the server command.
|
||||
func Server(cfg *config.Config) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "server",
|
||||
Short: fmt.Sprintf("start the %s service without runtime (unsupervised mode)", cfg.Service.Name),
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return configlog.ReturnFatal(parser.ParseConfig(cfg))
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
logger := log.Configure(cfg.Service.Name, cfg.Commons, cfg.LogLevel)
|
||||
traceProvider, err := tracing.GetTraceProvider(cmd.Context(), cfg.Commons.TracesExporter, cfg.Service.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// precreate folders
|
||||
if cfg.UserSharingDriver == "json" && cfg.UserSharingDrivers.JSON.File != "" {
|
||||
if err := os.MkdirAll(filepath.Dir(cfg.UserSharingDrivers.JSON.File), os.FileMode(0700)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if cfg.PublicSharingDriver == "json" && cfg.PublicSharingDrivers.JSON.File != "" {
|
||||
if err := os.MkdirAll(filepath.Dir(cfg.PublicSharingDrivers.JSON.File), os.FileMode(0700)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var cancel context.CancelFunc
|
||||
if cfg.Context == nil {
|
||||
cfg.Context, cancel = signal.NotifyContext(context.Background(), runner.StopSignals...)
|
||||
defer cancel()
|
||||
}
|
||||
ctx := cfg.Context
|
||||
|
||||
gr := runner.NewGroup()
|
||||
|
||||
{
|
||||
rCfg, err := revaconfig.SharingConfigFromStruct(cfg, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// run the appropriate reva servers based on the config
|
||||
if rServer := runtime.NewDrivenHTTPServerWithOptions(rCfg,
|
||||
runtime.WithLogger(&logger.Logger),
|
||||
runtime.WithRegistry(registry.GetRegistry()),
|
||||
runtime.WithTraceProvider(traceProvider),
|
||||
); rServer != nil {
|
||||
gr.Add(runner.NewRevaServiceRunner(cfg.Service.Name+".rhttp", rServer))
|
||||
}
|
||||
if rServer := runtime.NewDrivenGRPCServerWithOptions(rCfg,
|
||||
runtime.WithLogger(&logger.Logger),
|
||||
runtime.WithRegistry(registry.GetRegistry()),
|
||||
runtime.WithTraceProvider(traceProvider),
|
||||
); rServer != nil {
|
||||
gr.Add(runner.NewRevaServiceRunner(cfg.Service.Name+".rgrpc", rServer))
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
debugServer, err := debug.Server(
|
||||
debug.Logger(logger),
|
||||
debug.Context(ctx),
|
||||
debug.Config(cfg),
|
||||
)
|
||||
if err != nil {
|
||||
logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
|
||||
return err
|
||||
}
|
||||
|
||||
gr.Add(runner.NewGolangHttpServerRunner(cfg.Service.Name+".debug", debugServer))
|
||||
}
|
||||
|
||||
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Protocol, cfg.GRPC.Addr, version.GetString())
|
||||
if err := registry.RegisterService(ctx, logger, grpcSvc, cfg.Debug.Addr); err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to register the grpc service")
|
||||
}
|
||||
|
||||
grResults := gr.Run(ctx)
|
||||
|
||||
// return the first non-nil error found in the results
|
||||
for _, grResult := range grResults {
|
||||
if grResult.RunnerError != nil {
|
||||
return grResult.RunnerError
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/qsfera/server/pkg/registry"
|
||||
"github.com/qsfera/server/pkg/version"
|
||||
"github.com/qsfera/server/services/sharing/pkg/config"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// Version prints the service versions of all running instances.
|
||||
func Version(cfg *config.Config) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "print the version of this binary and the running service instances",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
fmt.Println("Version: " + version.GetString())
|
||||
fmt.Printf("Compiled: %s\n", version.Compiled())
|
||||
fmt.Println("")
|
||||
|
||||
reg := registry.GetRegistry()
|
||||
services, err := reg.GetService(cfg.GRPC.Namespace + "." + cfg.Service.Name)
|
||||
if err != nil {
|
||||
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
|
||||
return err
|
||||
}
|
||||
|
||||
if len(services) == 0 {
|
||||
fmt.Println("No running " + cfg.Service.Name + " service found.")
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
}
|
||||
}
|
||||
table.Render()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qsfera/server/pkg/shared"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Commons *shared.Commons `yaml:"-"` // don't use this directly as configuration for a service
|
||||
Service Service `yaml:"-"`
|
||||
LogLevel string `yaml:"loglevel" env:"OC_LOG_LEVEL;SHARING_LOG_LEVEL" desc:"The log level. Valid values are: 'panic', 'fatal', 'error', 'warn', 'info', 'debug', 'trace'." introductionVersion:"1.0.0"`
|
||||
Debug Debug `yaml:"debug"`
|
||||
|
||||
GRPC GRPCConfig `yaml:"grpc"`
|
||||
|
||||
TokenManager *TokenManager `yaml:"token_manager"`
|
||||
Reva *shared.Reva `yaml:"reva"`
|
||||
Events Events `yaml:"events"`
|
||||
|
||||
ServiceAccount ServiceAccount `yaml:"service_account"`
|
||||
SkipUserGroupsInToken bool `yaml:"skip_user_groups_in_token" env:"SHARING_SKIP_USER_GROUPS_IN_TOKEN" desc:"Disables the loading of user's group memberships from the reva access token." introductionVersion:"1.0.0"`
|
||||
|
||||
UserSharingDriver string `yaml:"user_sharing_driver" env:"SHARING_USER_DRIVER" desc:"Driver to be used to persist shares. Supported values are 'jsoncs3', 'json', 'cs3' (deprecated) and 'owncloudsql'." introductionVersion:"1.0.0"`
|
||||
UserSharingDrivers UserSharingDrivers `yaml:"user_sharing_drivers"`
|
||||
PublicSharingDriver string `yaml:"public_sharing_driver" env:"SHARING_PUBLIC_DRIVER" desc:"Driver to be used to persist public shares. Supported values are 'jsoncs3', 'json' and 'cs3' (deprecated)." introductionVersion:"1.0.0"`
|
||||
PublicSharingDrivers PublicSharingDrivers `yaml:"public_sharing_drivers"`
|
||||
WriteableShareMustHavePassword bool `yaml:"public_sharing_writeableshare_must_have_password" env:"OC_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD;SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD" desc:"Set this to true if you want to enforce passwords on Uploader, Editor or Contributor shares. If not using the global OC_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD, you must define the FRONTEND_OCS_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD (deprecated) in the frontend service." introductionVersion:"1.0.0"`
|
||||
PublicShareMustHavePassword bool `yaml:"public_sharing_share_must_have_password" env:"OC_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD;SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD" desc:"Set this to true if you want to enforce passwords on all public shares." introductionVersion:"1.0.0"`
|
||||
EnableExpiredSharesCleanup bool `yaml:"enable_expired_shares_cleanup"`
|
||||
PasswordPolicy PasswordPolicy `yaml:"password_policy"`
|
||||
|
||||
Context context.Context `yaml:"-"`
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
Name string `yaml:"-"`
|
||||
}
|
||||
|
||||
type Debug struct {
|
||||
Addr string `yaml:"addr" env:"SHARING_DEBUG_ADDR" desc:"Bind address of the debug server, where metrics, health, config and debug endpoints will be exposed." introductionVersion:"1.0.0"`
|
||||
Token string `yaml:"token" env:"SHARING_DEBUG_TOKEN" desc:"Token to secure the metrics endpoint." introductionVersion:"1.0.0"`
|
||||
Pprof bool `yaml:"pprof" env:"SHARING_DEBUG_PPROF" desc:"Enables pprof, which can be used for profiling." introductionVersion:"1.0.0"`
|
||||
Zpages bool `yaml:"zpages" env:"SHARING_DEBUG_ZPAGES" desc:"Enables zpages, which can be used for collecting and viewing in-memory traces." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
type GRPCConfig struct {
|
||||
Addr string `yaml:"addr" env:"SHARING_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"1.0.0"`
|
||||
TLS *shared.GRPCServiceTLS `yaml:"tls"`
|
||||
Namespace string `yaml:"-"`
|
||||
Protocol string `yaml:"protocol" env:"OC_GRPC_PROTOCOL;SHARING_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
type UserSharingDrivers struct {
|
||||
JSONCS3 UserSharingJSONCS3Driver `yaml:"jsoncs3"`
|
||||
JSON UserSharingJSONDriver `yaml:"json"`
|
||||
CS3 UserSharingCS3Driver `yaml:"cs3"`
|
||||
OwnCloudSQL UserSharingOwnCloudSQLDriver `yaml:"owncloudsql"`
|
||||
|
||||
SQL UserSharingSQLDriver `yaml:"sql,omitempty"` // not supported by the КуСфера product, therefore not part of docs
|
||||
}
|
||||
|
||||
type UserSharingJSONDriver struct {
|
||||
File string `yaml:"file" env:"SHARING_USER_JSON_FILE" desc:"Path to the JSON file where shares will be persisted. If not defined, the root directory derives from $OC_BASE_DATA_PATH/storage." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
type UserSharingSQLDriver struct {
|
||||
DBUsername string `yaml:"db_username"`
|
||||
DBPassword string `yaml:"db_password"`
|
||||
DBHost string `yaml:"db_host"`
|
||||
DBPort int `yaml:"db_port"`
|
||||
DBName string `yaml:"db_name"`
|
||||
PasswordHashCost int `yaml:"password_hash_cost"`
|
||||
EnableExpiredSharesCleanup bool `yaml:"enable_expired_shares_cleanup"`
|
||||
JanitorRunInterval int `yaml:"janitor_run_interval"`
|
||||
UserStorageMountID string `yaml:"user_storage_mount_id"`
|
||||
}
|
||||
|
||||
type UserSharingOwnCloudSQLDriver struct {
|
||||
DBUsername string `yaml:"db_username" env:"SHARING_USER_OWNCLOUDSQL_DB_USERNAME" desc:"Username for the database." introductionVersion:"1.0.0"`
|
||||
DBPassword string `yaml:"db_password" env:"SHARING_USER_OWNCLOUDSQL_DB_PASSWORD" desc:"Password for the database." introductionVersion:"1.0.0"`
|
||||
DBHost string `yaml:"db_host" env:"SHARING_USER_OWNCLOUDSQL_DB_HOST" desc:"Hostname or IP of the database server." introductionVersion:"1.0.0"`
|
||||
DBPort int `yaml:"db_port" env:"SHARING_USER_OWNCLOUDSQL_DB_PORT" desc:"Port that the database server is listening on." introductionVersion:"1.0.0"`
|
||||
DBName string `yaml:"db_name" env:"SHARING_USER_OWNCLOUDSQL_DB_NAME" desc:"Name of the database to be used." introductionVersion:"1.0.0"`
|
||||
UserStorageMountID string `yaml:"user_storage_mount_id" env:"SHARING_USER_OWNCLOUDSQL_USER_STORAGE_MOUNT_ID" desc:"Mount ID of the ownCloudSQL users storage for mapping ownCloud 10 shares." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
type UserSharingCS3Driver struct {
|
||||
ProviderAddr string `yaml:"provider_addr" env:"SHARING_USER_CS3_PROVIDER_ADDR" desc:"GRPC address of the STORAGE-SYSTEM service." introductionVersion:"1.0.0"`
|
||||
SystemUserID string `yaml:"system_user_id" env:"OC_SYSTEM_USER_ID;SHARING_USER_CS3_SYSTEM_USER_ID" desc:"ID of the КуСфера STORAGE-SYSTEM system user. Admins need to set the ID for the STORAGE-SYSTEM system user in this config option which is then used to reference the user. Any reasonable long string is possible, preferably this would be an UUIDv4 format." introductionVersion:"1.0.0"`
|
||||
SystemUserIDP string `yaml:"system_user_idp" env:"OC_SYSTEM_USER_IDP;SHARING_USER_CS3_SYSTEM_USER_IDP" desc:"IDP of the КуСфера STORAGE-SYSTEM system user." introductionVersion:"1.0.0"`
|
||||
SystemUserAPIKey string `yaml:"system_user_api_key" env:"OC_SYSTEM_USER_API_KEY;SHARING_USER_CS3_SYSTEM_USER_API_KEY" desc:"API key for the STORAGE-SYSTEM system user." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
// UserSharingJSONCS3Driver holds the jsoncs3 driver config
|
||||
type UserSharingJSONCS3Driver struct {
|
||||
ProviderAddr string `yaml:"provider_addr" env:"SHARING_USER_JSONCS3_PROVIDER_ADDR" desc:"GRPC address of the STORAGE-SYSTEM service." introductionVersion:"1.0.0"`
|
||||
SystemUserID string `yaml:"system_user_id" env:"OC_SYSTEM_USER_ID;SHARING_USER_JSONCS3_SYSTEM_USER_ID" desc:"ID of the КуСфера STORAGE-SYSTEM system user. Admins need to set the ID for the STORAGE-SYSTEM system user in this config option which is then used to reference the user. Any reasonable long string is possible, preferably this would be an UUIDv4 format." introductionVersion:"1.0.0"`
|
||||
SystemUserIDP string `yaml:"system_user_idp" env:"OC_SYSTEM_USER_IDP;SHARING_USER_JSONCS3_SYSTEM_USER_IDP" desc:"IDP of the КуСфера STORAGE-SYSTEM system user." introductionVersion:"1.0.0"`
|
||||
SystemUserAPIKey string `yaml:"system_user_api_key" env:"OC_SYSTEM_USER_API_KEY;SHARING_USER_JSONCS3_SYSTEM_USER_API_KEY" desc:"API key for the STORAGE-SYSTEM system user." introductionVersion:"1.0.0"`
|
||||
CacheTTL int `yaml:"cache_ttl" env:"SHARING_USER_JSONCS3_CACHE_TTL" desc:"TTL for the internal caches in seconds." introductionVersion:"1.0.0"`
|
||||
MaxConcurrency int `yaml:"max_concurrency" env:"OC_MAX_CONCURRENCY;SHARING_USER_JSONCS3_MAX_CONCURRENCY" desc:"Maximum number of concurrent go-routines. Higher values can potentially get work done faster but will also cause more load on the system. Values of 0 or below will be ignored and the default value will be used." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
// ServiceAccount is the configuration for the used service account
|
||||
type ServiceAccount struct {
|
||||
ServiceAccountID string `yaml:"service_account_id" env:"OC_SERVICE_ACCOUNT_ID;SHARING_SERVICE_ACCOUNT" desc:"The ID of the service account the service should use. See the 'auth-service' service description for more details." introductionVersion:"7.0.0"`
|
||||
ServiceAccountSecret string `yaml:"service_account_secret" env:"OC_SERVICE_ACCOUNT_SECRET;SHARING_SERVICE_ACCOUNT_SECRET" desc:"The service account secret." introductionVersion:"7.0.0"`
|
||||
}
|
||||
|
||||
type PublicSharingDrivers struct {
|
||||
JSON PublicSharingJSONDriver `yaml:"json"`
|
||||
JSONCS3 PublicSharingJSONCS3Driver `yaml:"jsoncs3"`
|
||||
CS3 PublicSharingCS3Driver `yaml:"cs3"`
|
||||
|
||||
SQL PublicSharingSQLDriver `yaml:"sql,omitempty"` // not supported by the КуСфера product, therefore not part of docs
|
||||
}
|
||||
|
||||
type PublicSharingJSONDriver struct {
|
||||
File string `yaml:"file" env:"SHARING_PUBLIC_JSON_FILE" desc:"Path to the JSON file where public share meta-data will be stored. This JSON file contains the information about public shares that have been created. If not defined, the root directory derives from $OC_BASE_DATA_PATH/storage." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
type PublicSharingSQLDriver struct {
|
||||
DBUsername string `yaml:"db_username"`
|
||||
DBPassword string `yaml:"db_password"`
|
||||
DBHost string `yaml:"db_host"`
|
||||
DBPort int `yaml:"db_port"`
|
||||
DBName string `yaml:"db_name"`
|
||||
PasswordHashCost int `yaml:"password_hash_cost"`
|
||||
EnableExpiredSharesCleanup bool `yaml:"enable_expired_shares_cleanup"`
|
||||
JanitorRunInterval int `yaml:"janitor_run_interval"`
|
||||
UserStorageMountID string `yaml:"user_storage_mount_id"`
|
||||
}
|
||||
|
||||
type PublicSharingCS3Driver struct {
|
||||
ProviderAddr string `yaml:"provider_addr" env:"SHARING_PUBLIC_CS3_PROVIDER_ADDR" desc:"GRPC address of the STORAGE-SYSTEM service." introductionVersion:"1.0.0"`
|
||||
SystemUserID string `yaml:"system_user_id" env:"OC_SYSTEM_USER_ID;SHARING_PUBLIC_CS3_SYSTEM_USER_ID" desc:"ID of the КуСфера STORAGE-SYSTEM system user. Admins need to set the ID for the STORAGE-SYSTEM system user in this config option which is then used to reference the user. Any reasonable long string is possible, preferably this would be an UUIDv4 format." introductionVersion:"1.0.0"`
|
||||
SystemUserIDP string `yaml:"system_user_idp" env:"OC_SYSTEM_USER_IDP;SHARING_PUBLIC_CS3_SYSTEM_USER_IDP" desc:"IDP of the КуСфера STORAGE-SYSTEM system user." introductionVersion:"1.0.0"`
|
||||
SystemUserAPIKey string `yaml:"system_user_api_key" env:"OC_SYSTEM_USER_API_KEY;SHARING_PUBLIC_CS3_SYSTEM_USER_API_KEY" desc:"API key for the STORAGE-SYSTEM system user." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
// PublicSharingJSONCS3Driver holds the jsoncs3 driver config
|
||||
type PublicSharingJSONCS3Driver struct {
|
||||
ProviderAddr string `yaml:"provider_addr" env:"SHARING_PUBLIC_JSONCS3_PROVIDER_ADDR" desc:"GRPC address of the STORAGE-SYSTEM service." introductionVersion:"1.0.0"`
|
||||
SystemUserID string `yaml:"system_user_id" env:"OC_SYSTEM_USER_ID;SHARING_PUBLIC_JSONCS3_SYSTEM_USER_ID" desc:"ID of the КуСфера STORAGE-SYSTEM system user. Admins need to set the ID for the STORAGE-SYSTEM system user in this config option which is then used to reference the user. Any reasonable long string is possible, preferably this would be an UUIDv4 format." introductionVersion:"1.0.0"`
|
||||
SystemUserIDP string `yaml:"system_user_idp" env:"OC_SYSTEM_USER_IDP;SHARING_PUBLIC_JSONCS3_SYSTEM_USER_IDP" desc:"IDP of the КуСфера STORAGE-SYSTEM system user." introductionVersion:"1.0.0"`
|
||||
SystemUserAPIKey string `yaml:"system_user_api_key" env:"OC_SYSTEM_USER_API_KEY;SHARING_PUBLIC_JSONCS3_SYSTEM_USER_API_KEY" desc:"API key for the STORAGE-SYSTEM system user." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
type Events struct {
|
||||
Addr string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;SHARING_EVENTS_ENDPOINT" desc:"The address of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture." introductionVersion:"1.0.0"`
|
||||
ClusterID string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;SHARING_EVENTS_CLUSTER" desc:"The clusterID of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture. Mandatory when using NATS as event system." introductionVersion:"1.0.0"`
|
||||
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;SHARING_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
|
||||
TLSRootCaCertPath string `yaml:"tls_root_ca_cert_path" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;SHARING_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided SHARING_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
|
||||
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;SHARING_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the КуСфера service which receives and delivers events between the services." introductionVersion:"1.0.0"`
|
||||
AuthUsername string `yaml:"auth_username" env:"OC_EVENTS_AUTH_USERNAME;SHARING_EVENTS_AUTH_USERNAME" desc:"Username for the events broker." introductionVersion:"1.0.0"`
|
||||
AuthPassword string `yaml:"auth_password" env:"OC_EVENTS_AUTH_PASSWORD;SHARING_EVENTS_AUTH_PASSWORD" desc:"Password for the events broker." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
// PasswordPolicy configures reva password policy
|
||||
type PasswordPolicy struct {
|
||||
Disabled bool `yaml:"disabled,omitempty" env:"OC_PASSWORD_POLICY_DISABLED;SHARING_PASSWORD_POLICY_DISABLED" desc:"Disable the password policy. Defaults to false if not set." introductionVersion:"1.0.0"`
|
||||
MinCharacters int `yaml:"min_characters,omitempty" env:"OC_PASSWORD_POLICY_MIN_CHARACTERS;SHARING_PASSWORD_POLICY_MIN_CHARACTERS" desc:"Define the minimum password length. Defaults to 8 if not set." introductionVersion:"1.0.0"`
|
||||
MinLowerCaseCharacters int `yaml:"min_lowercase_characters" env:"OC_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS;SHARING_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS" desc:"Define the minimum number of uppercase letters. Defaults to 1 if not set." introductionVersion:"1.0.0"`
|
||||
MinUpperCaseCharacters int `yaml:"min_uppercase_characters" env:"OC_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS;SHARING_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS" desc:"Define the minimum number of lowercase letters. Defaults to 1 if not set." introductionVersion:"1.0.0"`
|
||||
MinDigits int `yaml:"min_digits" env:"OC_PASSWORD_POLICY_MIN_DIGITS;SHARING_PASSWORD_POLICY_MIN_DIGITS" desc:"Define the minimum number of digits. Defaults to 1 if not set." introductionVersion:"1.0.0"`
|
||||
MinSpecialCharacters int `yaml:"min_special_characters" env:"OC_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS;SHARING_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS" desc:"Define the minimum number of characters from the special characters list to be present. Defaults to 1 if not set." introductionVersion:"1.0.0"`
|
||||
BannedPasswordsList string `yaml:"banned_passwords_list" env:"OC_PASSWORD_POLICY_BANNED_PASSWORDS_LIST;SHARING_PASSWORD_POLICY_BANNED_PASSWORDS_LIST" desc:"Path to the 'banned passwords list' file. This only impacts public link password validation. See the documentation for more details." introductionVersion:"1.0.0"`
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package defaults
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/qsfera/server/pkg/config/defaults"
|
||||
"github.com/qsfera/server/pkg/shared"
|
||||
"github.com/qsfera/server/pkg/structs"
|
||||
"github.com/qsfera/server/services/sharing/pkg/config"
|
||||
)
|
||||
|
||||
// FullDefaultConfig returns a fully initialized default configuration
|
||||
func FullDefaultConfig() *config.Config {
|
||||
cfg := DefaultConfig()
|
||||
EnsureDefaults(cfg)
|
||||
Sanitize(cfg)
|
||||
return cfg
|
||||
}
|
||||
|
||||
// DefaultConfig returns a basic default configuration
|
||||
func DefaultConfig() *config.Config {
|
||||
return &config.Config{
|
||||
Debug: config.Debug{
|
||||
Addr: "127.0.0.1:9151",
|
||||
Token: "",
|
||||
Pprof: false,
|
||||
Zpages: false,
|
||||
},
|
||||
GRPC: config.GRPCConfig{
|
||||
Addr: "127.0.0.1:9150",
|
||||
Namespace: "qsfera.api",
|
||||
Protocol: "tcp",
|
||||
},
|
||||
Service: config.Service{
|
||||
Name: "sharing",
|
||||
},
|
||||
Reva: shared.DefaultRevaConfig(),
|
||||
UserSharingDriver: "jsoncs3",
|
||||
UserSharingDrivers: config.UserSharingDrivers{
|
||||
JSON: config.UserSharingJSONDriver{
|
||||
File: filepath.Join(defaults.BaseDataPath(), "storage", "shares.json"),
|
||||
},
|
||||
CS3: config.UserSharingCS3Driver{
|
||||
ProviderAddr: "qsfera.api.storage-system",
|
||||
SystemUserIDP: "internal",
|
||||
},
|
||||
JSONCS3: config.UserSharingJSONCS3Driver{
|
||||
ProviderAddr: "qsfera.api.storage-system",
|
||||
SystemUserIDP: "internal",
|
||||
MaxConcurrency: 1,
|
||||
},
|
||||
OwnCloudSQL: config.UserSharingOwnCloudSQLDriver{
|
||||
DBUsername: "owncloud",
|
||||
DBHost: "mysql",
|
||||
DBPort: 3306,
|
||||
DBName: "owncloud",
|
||||
},
|
||||
},
|
||||
PublicSharingDriver: "jsoncs3",
|
||||
PublicSharingDrivers: config.PublicSharingDrivers{
|
||||
JSON: config.PublicSharingJSONDriver{
|
||||
File: filepath.Join(defaults.BaseDataPath(), "storage", "publicshares.json"),
|
||||
},
|
||||
CS3: config.PublicSharingCS3Driver{
|
||||
ProviderAddr: "qsfera.api.storage-system", // system storage
|
||||
SystemUserIDP: "internal",
|
||||
},
|
||||
JSONCS3: config.PublicSharingJSONCS3Driver{
|
||||
ProviderAddr: "qsfera.api.storage-system", // system storage
|
||||
SystemUserIDP: "internal",
|
||||
},
|
||||
// TODO implement and add owncloudsql publicshare driver
|
||||
},
|
||||
Events: config.Events{
|
||||
Addr: "127.0.0.1:9233",
|
||||
ClusterID: "qsfera-cluster",
|
||||
EnableTLS: false,
|
||||
},
|
||||
EnableExpiredSharesCleanup: true,
|
||||
PublicShareMustHavePassword: true,
|
||||
PasswordPolicy: config.PasswordPolicy{
|
||||
MinCharacters: 8,
|
||||
MinLowerCaseCharacters: 1,
|
||||
MinUpperCaseCharacters: 1,
|
||||
MinDigits: 1,
|
||||
MinSpecialCharacters: 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// EnsureDefaults adds default values to the configuration if they are not set yet
|
||||
func EnsureDefaults(cfg *config.Config) {
|
||||
if cfg.LogLevel == "" {
|
||||
cfg.LogLevel = "error"
|
||||
}
|
||||
|
||||
if cfg.Reva == nil && cfg.Commons != nil {
|
||||
cfg.Reva = structs.CopyOrZeroValue(cfg.Commons.Reva)
|
||||
}
|
||||
|
||||
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.GRPC.TLS == nil && cfg.Commons != nil {
|
||||
cfg.GRPC.TLS = structs.CopyOrZeroValue(cfg.Commons.GRPCServiceTLS)
|
||||
}
|
||||
|
||||
if cfg.UserSharingDrivers.CS3.SystemUserAPIKey == "" && cfg.Commons != nil && cfg.Commons.SystemUserAPIKey != "" {
|
||||
cfg.UserSharingDrivers.CS3.SystemUserAPIKey = cfg.Commons.SystemUserAPIKey
|
||||
}
|
||||
|
||||
if cfg.UserSharingDrivers.CS3.SystemUserID == "" && cfg.Commons != nil && cfg.Commons.SystemUserID != "" {
|
||||
cfg.UserSharingDrivers.CS3.SystemUserID = cfg.Commons.SystemUserID
|
||||
}
|
||||
|
||||
if cfg.UserSharingDrivers.JSONCS3.SystemUserAPIKey == "" && cfg.Commons != nil && cfg.Commons.SystemUserAPIKey != "" {
|
||||
cfg.UserSharingDrivers.JSONCS3.SystemUserAPIKey = cfg.Commons.SystemUserAPIKey
|
||||
}
|
||||
|
||||
if cfg.UserSharingDrivers.JSONCS3.SystemUserID == "" && cfg.Commons != nil && cfg.Commons.SystemUserID != "" {
|
||||
cfg.UserSharingDrivers.JSONCS3.SystemUserID = cfg.Commons.SystemUserID
|
||||
}
|
||||
|
||||
if cfg.PublicSharingDrivers.CS3.SystemUserAPIKey == "" && cfg.Commons != nil && cfg.Commons.SystemUserAPIKey != "" {
|
||||
cfg.PublicSharingDrivers.CS3.SystemUserAPIKey = cfg.Commons.SystemUserAPIKey
|
||||
}
|
||||
|
||||
if cfg.PublicSharingDrivers.CS3.SystemUserID == "" && cfg.Commons != nil && cfg.Commons.SystemUserID != "" {
|
||||
cfg.PublicSharingDrivers.CS3.SystemUserID = cfg.Commons.SystemUserID
|
||||
}
|
||||
|
||||
if cfg.PublicSharingDrivers.JSONCS3.SystemUserAPIKey == "" && cfg.Commons != nil && cfg.Commons.SystemUserAPIKey != "" {
|
||||
cfg.PublicSharingDrivers.JSONCS3.SystemUserAPIKey = cfg.Commons.SystemUserAPIKey
|
||||
}
|
||||
|
||||
if cfg.PublicSharingDrivers.JSONCS3.SystemUserID == "" && cfg.Commons != nil && cfg.Commons.SystemUserID != "" {
|
||||
cfg.PublicSharingDrivers.JSONCS3.SystemUserID = cfg.Commons.SystemUserID
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize sanitized the configuration
|
||||
func Sanitize(cfg *config.Config) {
|
||||
// nothing to sanitize here atm
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
occfg "github.com/qsfera/server/pkg/config"
|
||||
"github.com/qsfera/server/pkg/shared"
|
||||
"github.com/qsfera/server/services/sharing/pkg/config"
|
||||
"github.com/qsfera/server/services/sharing/pkg/config/defaults"
|
||||
|
||||
"github.com/qsfera/server/pkg/config/envdecode"
|
||||
)
|
||||
|
||||
const (
|
||||
_backendCS3 = "cs3"
|
||||
)
|
||||
|
||||
// ParseConfig loads configuration from known paths.
|
||||
func ParseConfig(cfg *config.Config) error {
|
||||
err := occfg.BindSourcesToStructs(cfg.Service.Name, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defaults.EnsureDefaults(cfg)
|
||||
|
||||
// load all env variables relevant to the config in the current context.
|
||||
if err := envdecode.Decode(cfg); err != nil {
|
||||
// no environment variable set for this config is an expected "error"
|
||||
if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
defaults.Sanitize(cfg)
|
||||
|
||||
return Validate(cfg)
|
||||
}
|
||||
|
||||
func Validate(cfg *config.Config) error {
|
||||
if cfg.TokenManager.JWTSecret == "" {
|
||||
return shared.MissingJWTTokenError(cfg.Service.Name)
|
||||
}
|
||||
|
||||
if cfg.PublicSharingDriver == _backendCS3 && cfg.PublicSharingDrivers.CS3.SystemUserAPIKey == "" {
|
||||
return shared.MissingSystemUserApiKeyError(cfg.Service.Name)
|
||||
}
|
||||
|
||||
if cfg.PublicSharingDriver == _backendCS3 && cfg.PublicSharingDrivers.CS3.SystemUserID == "" {
|
||||
return shared.MissingSystemUserID(cfg.Service.Name)
|
||||
}
|
||||
|
||||
if cfg.UserSharingDriver == _backendCS3 && cfg.UserSharingDrivers.CS3.SystemUserAPIKey == "" {
|
||||
return shared.MissingSystemUserApiKeyError(cfg.Service.Name)
|
||||
}
|
||||
|
||||
if cfg.UserSharingDriver == _backendCS3 && cfg.UserSharingDrivers.CS3.SystemUserID == "" {
|
||||
return shared.MissingSystemUserID(cfg.Service.Name)
|
||||
}
|
||||
|
||||
if cfg.ServiceAccount.ServiceAccountID == "" {
|
||||
return shared.MissingServiceAccountID(cfg.Service.Name)
|
||||
}
|
||||
|
||||
if cfg.ServiceAccount.ServiceAccountSecret == "" {
|
||||
return shared.MissingServiceAccountSecret(cfg.Service.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package config
|
||||
|
||||
// TokenManager is the config for using the reva token manager
|
||||
type TokenManager struct {
|
||||
JWTSecret string `yaml:"jwt_secret" env:"OC_JWT_SECRET;SHARING_JWT_SECRET" desc:"The secret to mint and validate jwt tokens." introductionVersion:"1.0.0"`
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package revaconfig
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/qsfera/server/pkg/config/defaults"
|
||||
"github.com/qsfera/server/pkg/generators"
|
||||
"github.com/qsfera/server/pkg/log"
|
||||
"github.com/qsfera/server/services/sharing/pkg/config"
|
||||
)
|
||||
|
||||
// SharingConfigFromStruct will adapt a КуСфера config struct into a reva mapstructure to start a reva service.
|
||||
func SharingConfigFromStruct(cfg *config.Config, logger log.Logger) (map[string]any, error) {
|
||||
passwordPolicyCfg, err := passwordPolicyConfig(cfg)
|
||||
if err != nil {
|
||||
logger.Err(err).Send()
|
||||
return nil, err
|
||||
}
|
||||
rcfg := map[string]any{
|
||||
"shared": map[string]any{
|
||||
"jwt_secret": cfg.TokenManager.JWTSecret,
|
||||
"gatewaysvc": cfg.Reva.Address,
|
||||
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
|
||||
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
|
||||
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
|
||||
},
|
||||
"grpc": map[string]any{
|
||||
"network": cfg.GRPC.Protocol,
|
||||
"address": cfg.GRPC.Addr,
|
||||
"tls_settings": map[string]any{
|
||||
"enabled": cfg.GRPC.TLS.Enabled,
|
||||
"certificate": cfg.GRPC.TLS.Cert,
|
||||
"key": cfg.GRPC.TLS.Key,
|
||||
},
|
||||
// TODO build services dynamically
|
||||
"services": map[string]any{
|
||||
"usershareprovider": map[string]any{
|
||||
"driver": cfg.UserSharingDriver,
|
||||
"drivers": map[string]any{
|
||||
"json": map[string]any{
|
||||
"file": cfg.UserSharingDrivers.JSON.File,
|
||||
"gateway_addr": cfg.Reva.Address,
|
||||
},
|
||||
"sql": map[string]any{ // cernbox sql
|
||||
"db_username": cfg.UserSharingDrivers.SQL.DBUsername,
|
||||
"db_password": cfg.UserSharingDrivers.SQL.DBPassword,
|
||||
"db_host": cfg.UserSharingDrivers.SQL.DBHost,
|
||||
"db_port": cfg.UserSharingDrivers.SQL.DBPort,
|
||||
"db_name": cfg.UserSharingDrivers.SQL.DBName,
|
||||
"password_hash_cost": cfg.UserSharingDrivers.SQL.PasswordHashCost,
|
||||
"enable_expired_shares_cleanup": cfg.UserSharingDrivers.SQL.EnableExpiredSharesCleanup,
|
||||
"janitor_run_interval": cfg.UserSharingDrivers.SQL.JanitorRunInterval,
|
||||
},
|
||||
"owncloudsql": map[string]any{
|
||||
"gateway_addr": cfg.Reva.Address,
|
||||
"storage_mount_id": cfg.UserSharingDrivers.OwnCloudSQL.UserStorageMountID,
|
||||
"db_username": cfg.UserSharingDrivers.OwnCloudSQL.DBUsername,
|
||||
"db_password": cfg.UserSharingDrivers.OwnCloudSQL.DBPassword,
|
||||
"db_host": cfg.UserSharingDrivers.OwnCloudSQL.DBHost,
|
||||
"db_port": cfg.UserSharingDrivers.OwnCloudSQL.DBPort,
|
||||
"db_name": cfg.UserSharingDrivers.OwnCloudSQL.DBName,
|
||||
},
|
||||
"cs3": map[string]any{
|
||||
"gateway_addr": cfg.UserSharingDrivers.CS3.ProviderAddr,
|
||||
"provider_addr": cfg.UserSharingDrivers.CS3.ProviderAddr,
|
||||
"service_user_id": cfg.UserSharingDrivers.CS3.SystemUserID,
|
||||
"service_user_idp": cfg.UserSharingDrivers.CS3.SystemUserIDP,
|
||||
"machine_auth_apikey": cfg.UserSharingDrivers.CS3.SystemUserAPIKey,
|
||||
},
|
||||
"jsoncs3": map[string]any{
|
||||
"gateway_addr": cfg.Reva.Address,
|
||||
"provider_addr": cfg.UserSharingDrivers.JSONCS3.ProviderAddr,
|
||||
"system_user_id": cfg.UserSharingDrivers.JSONCS3.SystemUserID,
|
||||
"system_user_idp": cfg.UserSharingDrivers.JSONCS3.SystemUserIDP,
|
||||
"machine_auth_apikey": cfg.UserSharingDrivers.JSONCS3.SystemUserAPIKey,
|
||||
"ttl": cfg.UserSharingDrivers.JSONCS3.CacheTTL,
|
||||
"max_concurrency": cfg.UserSharingDrivers.JSONCS3.MaxConcurrency,
|
||||
"service_account_id": cfg.ServiceAccount.ServiceAccountID,
|
||||
"service_account_secret": cfg.ServiceAccount.ServiceAccountSecret,
|
||||
"events": map[string]any{
|
||||
"natsaddress": cfg.Events.Addr,
|
||||
"natsclusterid": cfg.Events.ClusterID,
|
||||
"tlsinsecure": cfg.Events.TLSInsecure,
|
||||
"tlsrootcacertificate": cfg.Events.TLSRootCaCertPath,
|
||||
"authusername": cfg.Events.AuthUsername,
|
||||
"authpassword": cfg.Events.AuthPassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"publicshareprovider": map[string]any{
|
||||
"gateway_addr": cfg.Reva.Address,
|
||||
"writeable_share_must_have_password": cfg.WriteableShareMustHavePassword,
|
||||
"public_share_must_have_password": cfg.PublicShareMustHavePassword,
|
||||
"password_policy": passwordPolicyCfg,
|
||||
"driver": cfg.PublicSharingDriver,
|
||||
"drivers": map[string]any{
|
||||
"json": map[string]any{
|
||||
"file": cfg.PublicSharingDrivers.JSON.File,
|
||||
"gateway_addr": cfg.Reva.Address,
|
||||
},
|
||||
"sql": map[string]any{
|
||||
"db_username": cfg.PublicSharingDrivers.SQL.DBUsername,
|
||||
"db_password": cfg.PublicSharingDrivers.SQL.DBPassword,
|
||||
"db_host": cfg.PublicSharingDrivers.SQL.DBHost,
|
||||
"db_port": cfg.PublicSharingDrivers.SQL.DBPort,
|
||||
"db_name": cfg.PublicSharingDrivers.SQL.DBName,
|
||||
"password_hash_cost": cfg.PublicSharingDrivers.SQL.PasswordHashCost,
|
||||
"enable_expired_shares_cleanup": cfg.PublicSharingDrivers.SQL.EnableExpiredSharesCleanup,
|
||||
"janitor_run_interval": cfg.PublicSharingDrivers.SQL.JanitorRunInterval,
|
||||
},
|
||||
"cs3": map[string]any{
|
||||
"gateway_addr": cfg.PublicSharingDrivers.CS3.ProviderAddr,
|
||||
"provider_addr": cfg.PublicSharingDrivers.CS3.ProviderAddr,
|
||||
"service_user_id": cfg.PublicSharingDrivers.CS3.SystemUserID,
|
||||
"service_user_idp": cfg.PublicSharingDrivers.CS3.SystemUserIDP,
|
||||
"machine_auth_apikey": cfg.PublicSharingDrivers.CS3.SystemUserAPIKey,
|
||||
},
|
||||
"jsoncs3": map[string]any{
|
||||
"gateway_addr": cfg.Reva.Address,
|
||||
"provider_addr": cfg.PublicSharingDrivers.JSONCS3.ProviderAddr,
|
||||
"service_user_id": cfg.PublicSharingDrivers.JSONCS3.SystemUserID,
|
||||
"service_user_idp": cfg.PublicSharingDrivers.JSONCS3.SystemUserIDP,
|
||||
"machine_auth_apikey": cfg.PublicSharingDrivers.JSONCS3.SystemUserAPIKey,
|
||||
"enable_expired_shares_cleanup": cfg.EnableExpiredSharesCleanup,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"interceptors": map[string]any{
|
||||
"eventsmiddleware": map[string]any{
|
||||
"group": "sharing",
|
||||
"type": "nats",
|
||||
"address": cfg.Events.Addr,
|
||||
"clusterID": cfg.Events.ClusterID,
|
||||
"tls-insecure": cfg.Events.TLSInsecure,
|
||||
"tls-root-ca-cert": cfg.Events.TLSRootCaCertPath,
|
||||
"enable-tls": cfg.Events.EnableTLS,
|
||||
"name": generators.GenerateConnectionName(cfg.Service.Name, generators.NTypeBus),
|
||||
"username": cfg.Events.AuthUsername,
|
||||
"password": cfg.Events.AuthPassword,
|
||||
},
|
||||
"prometheus": map[string]any{
|
||||
"namespace": "qsfera",
|
||||
"subsystem": "sharing",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return rcfg, nil
|
||||
}
|
||||
|
||||
func readMultilineFile(path string) (map[string]struct{}, error) {
|
||||
if !fileExists(path) {
|
||||
path = filepath.Join(defaults.BaseConfigPath(), path)
|
||||
}
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
data := make(map[string]struct{})
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if line != "" {
|
||||
data[line] = struct{}{}
|
||||
}
|
||||
}
|
||||
return data, err
|
||||
}
|
||||
|
||||
func fileExists(path string) bool {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return !info.IsDir()
|
||||
}
|
||||
|
||||
func passwordPolicyConfig(cfg *config.Config) (map[string]any, error) {
|
||||
_maxCharacters := 72
|
||||
if cfg.PasswordPolicy.Disabled {
|
||||
return map[string]any{
|
||||
"max_characters": _maxCharacters,
|
||||
"banned_passwords_list": nil,
|
||||
}, nil
|
||||
}
|
||||
var bannedPasswordsList map[string]struct{}
|
||||
var err error
|
||||
if cfg.PasswordPolicy.BannedPasswordsList != "" {
|
||||
bannedPasswordsList, err = readMultilineFile(cfg.PasswordPolicy.BannedPasswordsList)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load the banned passwords from a file %s: %w", cfg.PasswordPolicy.BannedPasswordsList, err)
|
||||
}
|
||||
}
|
||||
return map[string]any{
|
||||
"max_characters": _maxCharacters,
|
||||
"min_digits": cfg.PasswordPolicy.MinDigits,
|
||||
"min_characters": cfg.PasswordPolicy.MinCharacters,
|
||||
"min_lowercase_characters": cfg.PasswordPolicy.MinLowerCaseCharacters,
|
||||
"min_uppercase_characters": cfg.PasswordPolicy.MinUpperCaseCharacters,
|
||||
"min_special_characters": cfg.PasswordPolicy.MinSpecialCharacters,
|
||||
"banned_passwords_list": bannedPasswordsList,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qsfera/server/pkg/log"
|
||||
"github.com/qsfera/server/services/sharing/pkg/config"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
type Option func(o *Options)
|
||||
|
||||
// Options defines the available options for this package.
|
||||
type Options struct {
|
||||
Logger log.Logger
|
||||
Context context.Context
|
||||
Config *config.Config
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
func newOptions(opts ...Option) Options {
|
||||
opt := Options{}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
return opt
|
||||
}
|
||||
|
||||
// Logger provides a function to set the logger option.
|
||||
func Logger(val log.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = val
|
||||
}
|
||||
}
|
||||
|
||||
// Context provides a function to set the context option.
|
||||
func Context(val context.Context) Option {
|
||||
return func(o *Options) {
|
||||
o.Context = val
|
||||
}
|
||||
}
|
||||
|
||||
// Config provides a function to set the config option.
|
||||
func Config(val *config.Config) Option {
|
||||
return func(o *Options) {
|
||||
o.Config = val
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/qsfera/server/pkg/checks"
|
||||
"github.com/qsfera/server/pkg/handlers"
|
||||
"github.com/qsfera/server/pkg/service/debug"
|
||||
"github.com/qsfera/server/pkg/version"
|
||||
)
|
||||
|
||||
// Server initializes the debug service and server.
|
||||
func Server(opts ...Option) (*http.Server, error) {
|
||||
options := newOptions(opts...)
|
||||
|
||||
readyHandlerConfiguration := handlers.NewCheckHandlerConfiguration().
|
||||
WithLogger(options.Logger).
|
||||
WithCheck("nats reachability", checks.NewNatsCheck(options.Config.Events.Addr)).
|
||||
WithCheck("grpc reachability", checks.NewGRPCCheck(options.Config.GRPC.Addr))
|
||||
|
||||
return debug.NewService(
|
||||
debug.Logger(options.Logger),
|
||||
debug.Name(options.Config.Service.Name),
|
||||
debug.Version(version.GetString()),
|
||||
debug.Address(options.Config.Debug.Addr),
|
||||
debug.Token(options.Config.Debug.Token),
|
||||
debug.Pprof(options.Config.Debug.Pprof),
|
||||
debug.Zpages(options.Config.Debug.Zpages),
|
||||
debug.Ready(handlers.NewCheckHandler(readyHandlerConfiguration)),
|
||||
//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
|
||||
//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
|
||||
//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
|
||||
//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
|
||||
), nil
|
||||
}
|
||||
Reference in New Issue
Block a user