diff --git a/api/cli/cli.go b/api/cli/cli.go index 32c60910f..d1b15975d 100644 --- a/api/cli/cli.go +++ b/api/cli/cli.go @@ -34,7 +34,6 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) { TunnelPort: kingpin.Flag("tunnel-port", "Port to serve the tunnel server").Default(defaultTunnelServerPort).String(), Assets: kingpin.Flag("assets", "Path to the assets").Default(defaultAssetsDirectory).Short('a').String(), Data: kingpin.Flag("data", "Path to the folder where the data is stored").Default(defaultDataDirectory).Short('d').String(), - DemoEnvironment: kingpin.Flag("demo", "Demo environment").Bool(), EndpointURL: kingpin.Flag("host", "Environment URL").Short('H').String(), FeatureFlags: kingpin.Flag("feat", "List of feature flags").Strings(), EnableEdgeComputeFeatures: kingpin.Flag("edge-compute", "Enable Edge Compute features").Bool(), diff --git a/api/cmd/portainer/main.go b/api/cmd/portainer/main.go index 389f94bbd..16bec1a03 100644 --- a/api/cmd/portainer/main.go +++ b/api/cmd/portainer/main.go @@ -20,7 +20,6 @@ import ( "github.com/portainer/portainer/api/datastore" "github.com/portainer/portainer/api/datastore/migrator" "github.com/portainer/portainer/api/datastore/postinit" - "github.com/portainer/portainer/api/demo" "github.com/portainer/portainer/api/docker" dockerclient "github.com/portainer/portainer/api/docker/client" "github.com/portainer/portainer/api/exec" @@ -509,14 +508,6 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server { applicationStatus := initStatus(instanceID) - demoService := demo.NewService() - if *flags.DemoEnvironment { - err := demoService.Init(dataStore, cryptoService) - if err != nil { - log.Fatal().Err(err).Msg("failed initializing demo environment") - } - } - // channel to control when the admin user is created adminCreationDone := make(chan struct{}, 1) @@ -631,7 +622,6 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server { ShutdownCtx: shutdownCtx, ShutdownTrigger: shutdownTrigger, StackDeployer: stackDeployer, - DemoService: demoService, UpgradeService: upgradeService, AdminCreationDone: adminCreationDone, PendingActionsService: pendingActionsService, diff --git a/api/demo/demo.go b/api/demo/demo.go deleted file mode 100644 index 79f442e80..000000000 --- a/api/demo/demo.go +++ /dev/null @@ -1,118 +0,0 @@ -package demo - -import ( - portainer "github.com/portainer/portainer/api" - "github.com/portainer/portainer/api/dataservices" - - "github.com/pkg/errors" - "github.com/rs/zerolog/log" -) - -type EnvironmentDetails struct { - Enabled bool `json:"enabled"` - Users []portainer.UserID `json:"users"` - Environments []portainer.EndpointID `json:"environments"` -} - -type Service struct { - details EnvironmentDetails -} - -func NewService() *Service { - return &Service{} -} - -func (service *Service) Details() EnvironmentDetails { - return service.details -} - -func (service *Service) Init(store dataservices.DataStore, cryptoService portainer.CryptoService) error { - log.Info().Msg("starting demo environment") - - isClean, err := isCleanStore(store) - if err != nil { - return errors.WithMessage(err, "failed checking if store is clean") - } - - if !isClean { - return errors.New(" Demo environment can only be initialized on a clean database") - } - - id, err := initDemoUser(store, cryptoService) - if err != nil { - return errors.WithMessage(err, "failed creating demo user") - } - - endpointIds, err := initDemoEndpoints(store) - if err != nil { - return errors.WithMessage(err, "failed creating demo endpoint") - } - - err = initDemoSettings(store) - if err != nil { - return errors.WithMessage(err, "failed updating demo settings") - } - - service.details = EnvironmentDetails{ - Enabled: true, - Users: []portainer.UserID{id}, - // endpoints 2,3 are created after deployment of portainer - Environments: endpointIds, - } - - return nil -} - -func isCleanStore(store dataservices.DataStore) (bool, error) { - endpoints, err := store.Endpoint().Endpoints() - if err != nil { - return false, err - } - - if len(endpoints) > 0 { - return false, nil - } - - users, err := store.User().ReadAll() - if err != nil { - return false, err - } - - if len(users) > 0 { - return false, nil - } - - return true, nil -} - -func (service *Service) IsDemo() bool { - return service.details.Enabled -} - -func (service *Service) IsDemoEnvironment(environmentID portainer.EndpointID) bool { - if !service.IsDemo() { - return false - } - - for _, demoEndpointID := range service.details.Environments { - if environmentID == demoEndpointID { - return true - } - } - - return false -} - -func (service *Service) IsDemoUser(userID portainer.UserID) bool { - if !service.IsDemo() { - return false - } - - for _, demoUserID := range service.details.Users { - if userID == demoUserID { - return true - } - } - - return false -} diff --git a/api/demo/init.go b/api/demo/init.go deleted file mode 100644 index da4090bb6..000000000 --- a/api/demo/init.go +++ /dev/null @@ -1,88 +0,0 @@ -package demo - -import ( - "github.com/pkg/errors" - portainer "github.com/portainer/portainer/api" - "github.com/portainer/portainer/api/dataservices" -) - -func initDemoUser( - store dataservices.DataStore, - cryptoService portainer.CryptoService, -) (portainer.UserID, error) { - - password, err := cryptoService.Hash("tryportainer") - if err != nil { - return 0, errors.WithMessage(err, "failed creating password hash") - } - - admin := &portainer.User{ - Username: "admin", - Password: password, - Role: portainer.AdministratorRole, - } - - err = store.User().Create(admin) - return admin.ID, errors.WithMessage(err, "failed creating user") -} - -func initDemoEndpoints(store dataservices.DataStore) ([]portainer.EndpointID, error) { - localEndpointId, err := initDemoLocalEndpoint(store) - if err != nil { - return nil, err - } - - // second and third endpoints are going to be created with docker-compose as a part of the demo environment set up. - // ref: https://github.com/portainer/portainer-demo/blob/master/docker-compose.yml - return []portainer.EndpointID{localEndpointId, localEndpointId + 1, localEndpointId + 2}, nil -} - -func initDemoLocalEndpoint(store dataservices.DataStore) (portainer.EndpointID, error) { - id := portainer.EndpointID(store.Endpoint().GetNextIdentifier()) - localEndpoint := &portainer.Endpoint{ - ID: id, - Name: "local", - URL: "unix:///var/run/docker.sock", - PublicURL: "demo.portainer.io", - Type: portainer.DockerEnvironment, - GroupID: portainer.EndpointGroupID(1), - TLSConfig: portainer.TLSConfiguration{ - TLS: false, - }, - AuthorizedUsers: []portainer.UserID{}, - AuthorizedTeams: []portainer.TeamID{}, - UserAccessPolicies: portainer.UserAccessPolicies{}, - TeamAccessPolicies: portainer.TeamAccessPolicies{}, - TagIDs: []portainer.TagID{}, - Status: portainer.EndpointStatusUp, - Snapshots: []portainer.DockerSnapshot{}, - Kubernetes: portainer.KubernetesDefault(), - } - - err := store.Endpoint().Create(localEndpoint) - if err != nil { - return id, errors.WithMessage(err, "failed creating local endpoint") - } - - err = store.Snapshot().Create(&portainer.Snapshot{EndpointID: id}) - if err != nil { - return id, errors.WithMessage(err, "failed creating snapshot") - } - - return id, errors.WithMessage(err, "failed creating local endpoint") -} - -func initDemoSettings( - store dataservices.DataStore, -) error { - settings, err := store.Settings().Settings() - if err != nil { - return errors.WithMessage(err, "failed fetching settings") - } - - settings.EnableTelemetry = false - settings.LogoURL = "" - - err = store.Settings().UpdateSettings(settings) - return errors.WithMessage(err, "failed updating settings") -} diff --git a/api/http/errors/errors.go b/api/http/errors/errors.go index 4b0b8dc68..df896fde0 100644 --- a/api/http/errors/errors.go +++ b/api/http/errors/errors.go @@ -9,6 +9,4 @@ var ( ErrUnauthorized = errors.New("Unauthorized") // ErrResourceAccessDenied Access denied to resource error ErrResourceAccessDenied = errors.New("Access denied to resource") - // ErrNotAvailableInDemo feature is not allowed in demo - ErrNotAvailableInDemo = errors.New("This feature is not available in the demo version of Portainer") ) diff --git a/api/http/handler/backup/backup_test.go b/api/http/handler/backup/backup_test.go index b5ff5df88..51fdf3e95 100644 --- a/api/http/handler/backup/backup_test.go +++ b/api/http/handler/backup/backup_test.go @@ -16,7 +16,6 @@ import ( "github.com/portainer/portainer/api/adminmonitor" "github.com/portainer/portainer/api/crypto" - "github.com/portainer/portainer/api/demo" "github.com/portainer/portainer/api/http/offlinegate" "github.com/portainer/portainer/api/internal/testhelpers" @@ -55,8 +54,7 @@ func Test_backupHandlerWithoutPassword_shouldCreateATarballArchive(t *testing.T) gate, "./test_assets/handler_test", func() {}, - adminMonitor, - &demo.Service{}).backup(w, r) + adminMonitor).backup(w, r) assert.Nil(t, handlerErr, "Handler should not fail") response := w.Result() @@ -99,8 +97,7 @@ func Test_backupHandlerWithPassword_shouldCreateEncryptedATarballArchive(t *test gate, "./test_assets/handler_test", func() {}, - adminMonitor, - &demo.Service{}).backup(w, r) + adminMonitor).backup(w, r) assert.Nil(t, handlerErr, "Handler should not fail") response := w.Result() diff --git a/api/http/handler/backup/handler.go b/api/http/handler/backup/handler.go index 1ed95eafa..8a99c5ffb 100644 --- a/api/http/handler/backup/handler.go +++ b/api/http/handler/backup/handler.go @@ -6,8 +6,6 @@ import ( "github.com/portainer/portainer/api/adminmonitor" "github.com/portainer/portainer/api/dataservices" - "github.com/portainer/portainer/api/demo" - "github.com/portainer/portainer/api/http/middlewares" "github.com/portainer/portainer/api/http/offlinegate" "github.com/portainer/portainer/api/http/security" httperror "github.com/portainer/portainer/pkg/libhttp/error" @@ -34,10 +32,7 @@ func NewHandler( filestorePath string, shutdownTrigger context.CancelFunc, adminMonitor *adminmonitor.Monitor, - demoService *demo.Service, - ) *Handler { - h := &Handler{ Router: mux.NewRouter(), bouncer: bouncer, @@ -48,11 +43,8 @@ func NewHandler( adminMonitor: adminMonitor, } - demoRestrictedRouter := h.NewRoute().Subrouter() - demoRestrictedRouter.Use(middlewares.RestrictDemoEnv(demoService.IsDemo)) - - demoRestrictedRouter.Handle("/backup", bouncer.RestrictedAccess(adminAccess(httperror.LoggerHandler(h.backup)))).Methods(http.MethodPost) - demoRestrictedRouter.Handle("/restore", bouncer.PublicAccess(httperror.LoggerHandler(h.restore))).Methods(http.MethodPost) + h.Handle("/backup", bouncer.RestrictedAccess(adminAccess(httperror.LoggerHandler(h.backup)))).Methods(http.MethodPost) + h.Handle("/restore", bouncer.PublicAccess(httperror.LoggerHandler(h.restore))).Methods(http.MethodPost) return h } diff --git a/api/http/handler/backup/restore_test.go b/api/http/handler/backup/restore_test.go index aacbe029b..a85eec079 100644 --- a/api/http/handler/backup/restore_test.go +++ b/api/http/handler/backup/restore_test.go @@ -14,7 +14,6 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/adminmonitor" - "github.com/portainer/portainer/api/demo" "github.com/portainer/portainer/api/http/offlinegate" "github.com/portainer/portainer/api/internal/testhelpers" @@ -63,7 +62,6 @@ func Test_restoreArchive_usingCombinationOfPasswords(t *testing.T) { "./test_assets/handler_test", func() {}, adminMonitor, - &demo.Service{}, ) //backup @@ -96,7 +94,6 @@ func Test_restoreArchive_shouldFailIfSystemWasAlreadyInitialized(t *testing.T) { "./test_assets/handler_test", func() {}, adminMonitor, - &demo.Service{}, ) //backup diff --git a/api/http/handler/endpoints/endpoint_create_global_key_test.go b/api/http/handler/endpoints/endpoint_create_global_key_test.go index aa37c3d75..ec91369dc 100644 --- a/api/http/handler/endpoints/endpoint_create_global_key_test.go +++ b/api/http/handler/endpoints/endpoint_create_global_key_test.go @@ -10,10 +10,7 @@ import ( ) func TestEmptyGlobalKey(t *testing.T) { - handler := NewHandler( - helper.NewTestRequestBouncer(), - nil, - ) + handler := NewHandler(helper.NewTestRequestBouncer()) req, err := http.NewRequest(http.MethodPost, "https://portainer.io:9443/endpoints/global-key", nil) if err != nil { diff --git a/api/http/handler/endpoints/endpoint_delete.go b/api/http/handler/endpoints/endpoint_delete.go index 1dbe8477b..5c20f6b51 100644 --- a/api/http/handler/endpoints/endpoint_delete.go +++ b/api/http/handler/endpoints/endpoint_delete.go @@ -9,7 +9,6 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" - httperrors "github.com/portainer/portainer/api/http/errors" "github.com/portainer/portainer/api/internal/endpointutils" httperror "github.com/portainer/portainer/pkg/libhttp/error" "github.com/portainer/portainer/pkg/libhttp/request" @@ -67,10 +66,6 @@ func (handler *Handler) endpointDelete(w http.ResponseWriter, r *http.Request) * return httperror.BadRequest("Invalid boolean query parameter", err) } - if handler.demoService.IsDemoEnvironment(portainer.EndpointID(endpointID)) { - return httperror.Forbidden(httperrors.ErrNotAvailableInDemo.Error(), httperrors.ErrNotAvailableInDemo) - } - err = handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error { return handler.deleteEndpoint(tx, portainer.EndpointID(endpointID), deleteCluster) }) @@ -112,15 +107,6 @@ func (handler *Handler) endpointDeleteMultiple(w http.ResponseWriter, r *http.Re err := handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error { for _, e := range p.Endpoints { - // Demo endpoints cannot be deleted. - if handler.demoService.IsDemoEnvironment(portainer.EndpointID(e.ID)) { - resps = append(resps, DeleteMultipleResp{ - Name: e.Name, - Err: httperrors.ErrNotAvailableInDemo, - }) - continue - } - // Attempt deletion. err := handler.deleteEndpoint( tx, diff --git a/api/http/handler/endpoints/endpoint_delete_test.go b/api/http/handler/endpoints/endpoint_delete_test.go index cc83633a2..e0117a9f3 100644 --- a/api/http/handler/endpoints/endpoint_delete_test.go +++ b/api/http/handler/endpoints/endpoint_delete_test.go @@ -9,7 +9,6 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/datastore" - "github.com/portainer/portainer/api/demo" "github.com/portainer/portainer/api/http/proxy" "github.com/portainer/portainer/api/internal/testhelpers" ) @@ -19,7 +18,7 @@ func TestEndpointDeleteEdgeGroupsConcurrently(t *testing.T) { _, store := datastore.MustNewTestStore(t, true, false) - handler := NewHandler(testhelpers.NewTestRequestBouncer(), demo.NewService()) + handler := NewHandler(testhelpers.NewTestRequestBouncer()) handler.DataStore = store handler.ProxyManager = proxy.NewManager(nil) handler.ProxyManager.NewProxyFactory(nil, nil, nil, nil, nil, nil, nil, nil) diff --git a/api/http/handler/endpoints/endpoint_list_test.go b/api/http/handler/endpoints/endpoint_list_test.go index 4d091638c..9ddedccef 100644 --- a/api/http/handler/endpoints/endpoint_list_test.go +++ b/api/http/handler/endpoints/endpoint_list_test.go @@ -194,7 +194,7 @@ func setupEndpointListHandler(t *testing.T, endpoints []portainer.Endpoint) *Han bouncer := testhelpers.NewTestRequestBouncer() - handler := NewHandler(bouncer, nil) + handler := NewHandler(bouncer) handler.DataStore = store handler.ComposeStackManager = testhelpers.NewComposeStackManager() handler.SnapshotService, _ = snapshot.NewService("1s", store, nil, nil, nil, nil) diff --git a/api/http/handler/endpoints/filter_test.go b/api/http/handler/endpoints/filter_test.go index aa530a7a2..f05f00cf5 100644 --- a/api/http/handler/endpoints/filter_test.go +++ b/api/http/handler/endpoints/filter_test.go @@ -194,7 +194,7 @@ func setupFilterTest(t *testing.T, endpoints []portainer.Endpoint) *Handler { is.NoError(err, "error creating a user") bouncer := testhelpers.NewTestRequestBouncer() - handler := NewHandler(bouncer, nil) + handler := NewHandler(bouncer) handler.DataStore = store handler.ComposeStackManager = testhelpers.NewComposeStackManager() diff --git a/api/http/handler/endpoints/handler.go b/api/http/handler/endpoints/handler.go index 7ead93762..438c4f33f 100644 --- a/api/http/handler/endpoints/handler.go +++ b/api/http/handler/endpoints/handler.go @@ -5,7 +5,6 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" - "github.com/portainer/portainer/api/demo" dockerclient "github.com/portainer/portainer/api/docker/client" "github.com/portainer/portainer/api/http/proxy" "github.com/portainer/portainer/api/http/security" @@ -28,7 +27,6 @@ func hideFields(endpoint *portainer.Endpoint) { type Handler struct { *mux.Router requestBouncer security.BouncerService - demoService *demo.Service DataStore dataservices.DataStore FileService portainer.FileService ProxyManager *proxy.Manager @@ -44,11 +42,10 @@ type Handler struct { } // NewHandler creates a handler to manage environment(endpoint) operations. -func NewHandler(bouncer security.BouncerService, demoService *demo.Service) *Handler { +func NewHandler(bouncer security.BouncerService) *Handler { h := &Handler{ Router: mux.NewRouter(), requestBouncer: bouncer, - demoService: demoService, } h.Handle("/endpoints", diff --git a/api/http/handler/settings/handler.go b/api/http/handler/settings/handler.go index 91da709b5..841a8b488 100644 --- a/api/http/handler/settings/handler.go +++ b/api/http/handler/settings/handler.go @@ -5,7 +5,6 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" - "github.com/portainer/portainer/api/demo" "github.com/portainer/portainer/api/http/security" httperror "github.com/portainer/portainer/pkg/libhttp/error" @@ -26,15 +25,14 @@ type Handler struct { JWTService portainer.JWTService LDAPService portainer.LDAPService SnapshotService portainer.SnapshotService - demoService *demo.Service } // NewHandler creates a handler to manage settings operations. -func NewHandler(bouncer security.BouncerService, demoService *demo.Service) *Handler { +func NewHandler(bouncer security.BouncerService) *Handler { h := &Handler{ - Router: mux.NewRouter(), - demoService: demoService, + Router: mux.NewRouter(), } + h.Handle("/settings", bouncer.AdminAccess(httperror.LoggerHandler(h.settingsInspect))).Methods(http.MethodGet) h.Handle("/settings", diff --git a/api/http/handler/settings/settings_update.go b/api/http/handler/settings/settings_update.go index eff0eb93b..c7a1df833 100644 --- a/api/http/handler/settings/settings_update.go +++ b/api/http/handler/settings/settings_update.go @@ -149,11 +149,6 @@ func (handler *Handler) updateSettings(tx dataservices.DataStoreTx, payload sett return nil, httperror.InternalServerError("Unable to retrieve the settings from the database", err) } - if handler.demoService.IsDemo() { - payload.EnableTelemetry = nil - payload.LogoURL = nil - } - if payload.AuthenticationMethod != nil { settings.AuthenticationMethod = portainer.AuthenticationMethod(*payload.AuthenticationMethod) } diff --git a/api/http/handler/system/handler.go b/api/http/handler/system/handler.go index dadcd2ec7..d5a9adbd9 100644 --- a/api/http/handler/system/handler.go +++ b/api/http/handler/system/handler.go @@ -5,7 +5,6 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" - "github.com/portainer/portainer/api/demo" "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/upgrade" httperror "github.com/portainer/portainer/pkg/libhttp/error" @@ -18,21 +17,18 @@ type Handler struct { *mux.Router status *portainer.Status dataStore dataservices.DataStore - demoService *demo.Service upgradeService upgrade.Service } // NewHandler creates a handler to manage status operations. func NewHandler(bouncer security.BouncerService, status *portainer.Status, - demoService *demo.Service, dataStore dataservices.DataStore, upgradeService upgrade.Service) *Handler { h := &Handler{ Router: mux.NewRouter(), dataStore: dataStore, - demoService: demoService, status: status, upgradeService: upgradeService, } diff --git a/api/http/handler/system/status.go b/api/http/handler/system/status.go index c37d9b38b..ff4251875 100644 --- a/api/http/handler/system/status.go +++ b/api/http/handler/system/status.go @@ -4,7 +4,6 @@ import ( "net/http" portainer "github.com/portainer/portainer/api" - "github.com/portainer/portainer/api/demo" httperror "github.com/portainer/portainer/pkg/libhttp/error" "github.com/portainer/portainer/pkg/libhttp/response" @@ -13,7 +12,6 @@ import ( type status struct { *portainer.Status - DemoEnvironment demo.EnvironmentDetails } // @id systemStatus @@ -26,8 +24,7 @@ type status struct { // @router /system/status [get] func (handler *Handler) systemStatus(w http.ResponseWriter, r *http.Request) *httperror.HandlerError { return response.JSON(w, &status{ - Status: handler.status, - DemoEnvironment: handler.demoService.Details(), + Status: handler.status, }) } diff --git a/api/http/handler/system/version_test.go b/api/http/handler/system/version_test.go index 0eda6558d..cee3f4015 100644 --- a/api/http/handler/system/version_test.go +++ b/api/http/handler/system/version_test.go @@ -10,7 +10,6 @@ import ( "github.com/portainer/portainer/api/apikey" "github.com/portainer/portainer/api/database/models" "github.com/portainer/portainer/api/datastore" - "github.com/portainer/portainer/api/demo" "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/testhelpers" "github.com/portainer/portainer/api/jwt" @@ -40,7 +39,7 @@ func Test_getSystemVersion(t *testing.T) { apiKeyService := apikey.NewAPIKeyService(store.APIKeyRepository(), store.User()) requestBouncer := security.NewRequestBouncer(store, jwtService, apiKeyService) - h := NewHandler(requestBouncer, &portainer.Status{}, &demo.Service{}, store, nil) + h := NewHandler(requestBouncer, &portainer.Status{}, store, nil) // generate standard and admin user tokens jwt, _, _ := jwtService.GenerateToken(&portainer.TokenData{ID: adminUser.ID, Username: adminUser.Username, Role: adminUser.Role}) diff --git a/api/http/handler/users/handler.go b/api/http/handler/users/handler.go index 269c7cfbc..c0abba8c4 100644 --- a/api/http/handler/users/handler.go +++ b/api/http/handler/users/handler.go @@ -7,7 +7,6 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/apikey" "github.com/portainer/portainer/api/dataservices" - "github.com/portainer/portainer/api/demo" "github.com/portainer/portainer/api/http/security" httperror "github.com/portainer/portainer/pkg/libhttp/error" @@ -31,7 +30,6 @@ type Handler struct { *mux.Router bouncer security.BouncerService apiKeyService apikey.APIKeyService - demoService *demo.Service DataStore dataservices.DataStore CryptoService portainer.CryptoService passwordStrengthChecker security.PasswordStrengthChecker @@ -40,12 +38,11 @@ type Handler struct { } // NewHandler creates a handler to manage user operations. -func NewHandler(bouncer security.BouncerService, rateLimiter *security.RateLimiter, apiKeyService apikey.APIKeyService, demoService *demo.Service, passwordStrengthChecker security.PasswordStrengthChecker) *Handler { +func NewHandler(bouncer security.BouncerService, rateLimiter *security.RateLimiter, apiKeyService apikey.APIKeyService, passwordStrengthChecker security.PasswordStrengthChecker) *Handler { h := &Handler{ Router: mux.NewRouter(), bouncer: bouncer, apiKeyService: apiKeyService, - demoService: demoService, passwordStrengthChecker: passwordStrengthChecker, } diff --git a/api/http/handler/users/user_create_access_token_test.go b/api/http/handler/users/user_create_access_token_test.go index 8e79a9555..5199366a2 100644 --- a/api/http/handler/users/user_create_access_token_test.go +++ b/api/http/handler/users/user_create_access_token_test.go @@ -41,7 +41,7 @@ func Test_userCreateAccessToken(t *testing.T) { rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour) passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService) - h := NewHandler(requestBouncer, rateLimiter, apiKeyService, nil, passwordChecker) + h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker) h.DataStore = store h.CryptoService = testhelpers.NewCryptoService() diff --git a/api/http/handler/users/user_delete_test.go b/api/http/handler/users/user_delete_test.go index aa3e84f3a..f3cff97db 100644 --- a/api/http/handler/users/user_delete_test.go +++ b/api/http/handler/users/user_delete_test.go @@ -32,7 +32,7 @@ func Test_deleteUserRemovesAccessTokens(t *testing.T) { rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour) passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService) - h := NewHandler(requestBouncer, rateLimiter, apiKeyService, nil, passwordChecker) + h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker) h.DataStore = store t.Run("standard user deletion removes all associated access tokens", func(t *testing.T) { diff --git a/api/http/handler/users/user_get_access_tokens_test.go b/api/http/handler/users/user_get_access_tokens_test.go index fc20b7f4c..0d471d858 100644 --- a/api/http/handler/users/user_get_access_tokens_test.go +++ b/api/http/handler/users/user_get_access_tokens_test.go @@ -40,7 +40,7 @@ func Test_userGetAccessTokens(t *testing.T) { rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour) passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService) - h := NewHandler(requestBouncer, rateLimiter, apiKeyService, nil, passwordChecker) + h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker) h.DataStore = store // generate standard and admin user tokens diff --git a/api/http/handler/users/user_list_test.go b/api/http/handler/users/user_list_test.go index c7b0cf0ef..2fde780bb 100644 --- a/api/http/handler/users/user_list_test.go +++ b/api/http/handler/users/user_list_test.go @@ -12,7 +12,6 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/apikey" "github.com/portainer/portainer/api/datastore" - "github.com/portainer/portainer/api/demo" "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/authorization" "github.com/portainer/portainer/api/internal/testhelpers" @@ -40,7 +39,7 @@ func Test_userList(t *testing.T) { rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour) passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService) - h := NewHandler(requestBouncer, rateLimiter, apiKeyService, &demo.Service{}, passwordChecker) + h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker) h.DataStore = store // generate admin user tokens diff --git a/api/http/handler/users/user_remove_access_token_test.go b/api/http/handler/users/user_remove_access_token_test.go index 26b6648a5..7534b2b5d 100644 --- a/api/http/handler/users/user_remove_access_token_test.go +++ b/api/http/handler/users/user_remove_access_token_test.go @@ -38,7 +38,7 @@ func Test_userRemoveAccessToken(t *testing.T) { rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour) passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService) - h := NewHandler(requestBouncer, rateLimiter, apiKeyService, nil, passwordChecker) + h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker) h.DataStore = store // generate standard and admin user tokens diff --git a/api/http/handler/users/user_update.go b/api/http/handler/users/user_update.go index d963ef68b..d656fd8ec 100644 --- a/api/http/handler/users/user_update.go +++ b/api/http/handler/users/user_update.go @@ -68,10 +68,6 @@ func (handler *Handler) userUpdate(w http.ResponseWriter, r *http.Request) *http return httperror.BadRequest("Invalid user identifier route variable", err) } - if handler.demoService.IsDemoUser(portainer.UserID(userID)) { - return httperror.Forbidden(httperrors.ErrNotAvailableInDemo.Error(), httperrors.ErrNotAvailableInDemo) - } - tokenData, err := security.RetrieveTokenData(r) if err != nil { return httperror.InternalServerError("Unable to retrieve user authentication token", err) diff --git a/api/http/handler/users/user_update_password.go b/api/http/handler/users/user_update_password.go index 38818e8cb..3a73f74b6 100644 --- a/api/http/handler/users/user_update_password.go +++ b/api/http/handler/users/user_update_password.go @@ -55,10 +55,6 @@ func (handler *Handler) userUpdatePassword(w http.ResponseWriter, r *http.Reques return httperror.BadRequest("Invalid user identifier route variable", err) } - if handler.demoService.IsDemoUser(portainer.UserID(userID)) { - return httperror.Forbidden(httperrors.ErrNotAvailableInDemo.Error(), httperrors.ErrNotAvailableInDemo) - } - tokenData, err := security.RetrieveTokenData(r) if err != nil { return httperror.InternalServerError("Unable to retrieve user authentication token", err) diff --git a/api/http/handler/users/user_update_test.go b/api/http/handler/users/user_update_test.go index dc75fbc99..b0728a89c 100644 --- a/api/http/handler/users/user_update_test.go +++ b/api/http/handler/users/user_update_test.go @@ -32,7 +32,7 @@ func Test_updateUserRemovesAccessTokens(t *testing.T) { rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour) passwordChecker := security.NewPasswordStrengthChecker(store.SettingsService) - h := NewHandler(requestBouncer, rateLimiter, apiKeyService, nil, passwordChecker) + h := NewHandler(requestBouncer, rateLimiter, apiKeyService, passwordChecker) h.DataStore = store t.Run("standard user deletion removes all associated access tokens", func(t *testing.T) { diff --git a/api/http/middlewares/demo.go b/api/http/middlewares/demo.go deleted file mode 100644 index cf95cac98..000000000 --- a/api/http/middlewares/demo.go +++ /dev/null @@ -1,24 +0,0 @@ -package middlewares - -import ( - "net/http" - - "github.com/portainer/portainer/api/http/errors" - httperror "github.com/portainer/portainer/pkg/libhttp/error" - - "github.com/gorilla/mux" -) - -// restrict functionality on demo environments -func RestrictDemoEnv(isDemo func() bool) mux.MiddlewareFunc { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !isDemo() { - next.ServeHTTP(w, r) - return - } - - httperror.WriteError(w, http.StatusBadRequest, errors.ErrNotAvailableInDemo.Error(), errors.ErrNotAvailableInDemo) - }) - } -} diff --git a/api/http/middlewares/demo_test.go b/api/http/middlewares/demo_test.go deleted file mode 100644 index 385d36456..000000000 --- a/api/http/middlewares/demo_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package middlewares - -import ( - "io" - "net/http" - "net/http/httptest" - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_demoEnvironment_shouldFail(t *testing.T) { - r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{}`)) - w := httptest.NewRecorder() - - h := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {}) - - RestrictDemoEnv(func() bool { return true }).Middleware(h).ServeHTTP(w, r) - - response := w.Result() - defer response.Body.Close() - - assert.Equal(t, http.StatusBadRequest, response.StatusCode) - - body, _ := io.ReadAll(response.Body) - assert.Contains(t, string(body), "This feature is not available in the demo version of Portainer") -} - -func Test_notDemoEnvironment_shouldSucceed(t *testing.T) { - r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{}`)) - w := httptest.NewRecorder() - - h := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {}) - - RestrictDemoEnv(func() bool { return false }).Middleware(h).ServeHTTP(w, r) - - response := w.Result() - assert.Equal(t, http.StatusOK, response.StatusCode) - -} diff --git a/api/http/server.go b/api/http/server.go index 32540bc0d..cf1b2cac8 100644 --- a/api/http/server.go +++ b/api/http/server.go @@ -13,7 +13,6 @@ import ( "github.com/portainer/portainer/api/apikey" "github.com/portainer/portainer/api/crypto" "github.com/portainer/portainer/api/dataservices" - "github.com/portainer/portainer/api/demo" "github.com/portainer/portainer/api/docker" dockerclient "github.com/portainer/portainer/api/docker/client" "github.com/portainer/portainer/api/http/csrf" @@ -109,7 +108,6 @@ type Server struct { ShutdownCtx context.Context ShutdownTrigger context.CancelFunc StackDeployer deployments.StackDeployer - DemoService *demo.Service UpgradeService upgrade.Service AdminCreationDone chan struct{} PendingActionsService *pendingactions.PendingActionsService @@ -145,7 +143,6 @@ func (server *Server) Start() error { server.FileService.GetDatastorePath(), server.ShutdownTrigger, adminMonitor, - server.DemoService, ) var roleHandler = roles.NewHandler(requestBouncer) @@ -170,7 +167,7 @@ func (server *Server) Start() error { var edgeTemplatesHandler = edgetemplates.NewHandler(requestBouncer) edgeTemplatesHandler.DataStore = server.DataStore - var endpointHandler = endpoints.NewHandler(requestBouncer, server.DemoService) + var endpointHandler = endpoints.NewHandler(requestBouncer) endpointHandler.DataStore = server.DataStore endpointHandler.FileService = server.FileService endpointHandler.ProxyManager = server.ProxyManager @@ -226,7 +223,7 @@ func (server *Server) Start() error { var resourceControlHandler = resourcecontrols.NewHandler(requestBouncer) resourceControlHandler.DataStore = server.DataStore - var settingsHandler = settings.NewHandler(requestBouncer, server.DemoService) + var settingsHandler = settings.NewHandler(requestBouncer) settingsHandler.DataStore = server.DataStore settingsHandler.FileService = server.FileService settingsHandler.JWTService = server.JWTService @@ -269,7 +266,6 @@ func (server *Server) Start() error { var systemHandler = system.NewHandler(requestBouncer, server.Status, - server.DemoService, server.DataStore, server.UpgradeService) @@ -281,7 +277,7 @@ func (server *Server) Start() error { var uploadHandler = upload.NewHandler(requestBouncer) uploadHandler.FileService = server.FileService - var userHandler = users.NewHandler(requestBouncer, rateLimiter, server.APIKeyService, server.DemoService, passwordStrengthChecker) + var userHandler = users.NewHandler(requestBouncer, rateLimiter, server.APIKeyService, passwordStrengthChecker) userHandler.DataStore = server.DataStore userHandler.CryptoService = server.CryptoService userHandler.AdminCreationDone = server.AdminCreationDone diff --git a/api/portainer.go b/api/portainer.go index 3c6da319f..557f5da20 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -124,7 +124,6 @@ type ( Assets *string Data *string FeatureFlags *[]string - DemoEnvironment *bool EnableEdgeComputeFeatures *bool EndpointURL *string Labels *[]Pair diff --git a/app/portainer/components/demo-feature-indicator/demo-feature-indicator.controller.js b/app/portainer/components/demo-feature-indicator/demo-feature-indicator.controller.js deleted file mode 100644 index 51c0a89ef..000000000 --- a/app/portainer/components/demo-feature-indicator/demo-feature-indicator.controller.js +++ /dev/null @@ -1,16 +0,0 @@ -class DemoFeatureIndicatorController { - /* @ngInject */ - constructor(StateManager) { - Object.assign(this, { StateManager }); - - this.isDemo = false; - } - - $onInit() { - const state = this.StateManager.getState(); - - this.isDemo = state.application.demoEnvironment.enabled; - } -} - -export default DemoFeatureIndicatorController; diff --git a/app/portainer/components/demo-feature-indicator/demo-feature-indicator.html b/app/portainer/components/demo-feature-indicator/demo-feature-indicator.html deleted file mode 100644 index 5e7c113b7..000000000 --- a/app/portainer/components/demo-feature-indicator/demo-feature-indicator.html +++ /dev/null @@ -1,10 +0,0 @@ -
-
- - - - {{ $ctrl.content }} - - -
-
diff --git a/app/portainer/components/demo-feature-indicator/index.js b/app/portainer/components/demo-feature-indicator/index.js deleted file mode 100644 index e81a981ef..000000000 --- a/app/portainer/components/demo-feature-indicator/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import angular from 'angular'; -import controller from './demo-feature-indicator.controller.js'; - -export const demoFeatureIndicator = { - templateUrl: './demo-feature-indicator.html', - controller, - bindings: { - content: '<', - }, -}; - -angular.module('portainer.app').component('demoFeatureIndicator', demoFeatureIndicator); diff --git a/app/portainer/components/theme/theme-settings.controller.js b/app/portainer/components/theme/theme-settings.controller.js index 3b847ced6..bb614d768 100644 --- a/app/portainer/components/theme/theme-settings.controller.js +++ b/app/portainer/components/theme/theme-settings.controller.js @@ -30,10 +30,8 @@ export default class ThemeSettingsController { async updateThemeSettings(theme) { try { - if (!this.state.isDemo) { - await this.UserService.updateUserTheme(this.state.userId, theme); - await queryClient.invalidateQueries(userQueryKeys.user(this.state.userId)); - } + await this.UserService.updateUserTheme(this.state.userId, theme); + await queryClient.invalidateQueries(userQueryKeys.user(this.state.userId)); notifySuccess('Success', 'User theme settings successfully updated'); } catch (err) { @@ -43,12 +41,9 @@ export default class ThemeSettingsController { $onInit() { return this.$async(async () => { - const state = this.StateManager.getState(); - this.state = { userId: null, themeColor: 'auto', - isDemo: state.application.demoEnvironment.enabled, }; this.state.availableThemes = options; diff --git a/app/portainer/models/status.js b/app/portainer/models/status.js index a38c6db9c..70460922b 100644 --- a/app/portainer/models/status.js +++ b/app/portainer/models/status.js @@ -4,7 +4,6 @@ export function StatusViewModel(data) { this.Version = data.Version; this.Edition = data.Edition; this.InstanceID = data.InstanceID; - this.DemoEnvironment = data.DemoEnvironment; } export function StatusVersionViewModel(data) { diff --git a/app/portainer/services/stateManager.js b/app/portainer/services/stateManager.js index 2e4577a5a..b9aba5b3f 100644 --- a/app/portainer/services/stateManager.js +++ b/app/portainer/services/stateManager.js @@ -109,7 +109,6 @@ function StateManagerFactory( state.application.version = status.Version; state.application.edition = status.Edition; state.application.instanceId = status.InstanceID; - state.application.demoEnvironment = status.DemoEnvironment; state.application.enableTelemetry = settings.EnableTelemetry; state.application.logo = settings.LogoURL; diff --git a/app/portainer/views/account/account.html b/app/portainer/views/account/account.html index 6321d63e2..6631fbf3b 100644 --- a/app/portainer/views/account/account.html +++ b/app/portainer/views/account/account.html @@ -1,7 +1,5 @@ - -
@@ -56,7 +54,7 @@
- -
You can find more information about this in our{' '} ('logo'); - const isDemoQuery = useIsDemo(); const [isEnabled, setIsEnabled] = useToggledValue('logo'); @@ -26,12 +21,9 @@ export function LogoFieldset() { checked={isEnabled} name="toggle_logo" labelClass="col-sm-3 col-lg-2" - disabled={isDemoQuery.data} onChange={(checked) => setIsEnabled(checked)} />
- -
{isEnabled && ( diff --git a/app/react/portainer/settings/SettingsView/ApplicationSettingsPanel/ScreenBannerFieldset.tsx b/app/react/portainer/settings/SettingsView/ApplicationSettingsPanel/ScreenBannerFieldset.tsx index 6c086b04a..c6459af84 100644 --- a/app/react/portainer/settings/SettingsView/ApplicationSettingsPanel/ScreenBannerFieldset.tsx +++ b/app/react/portainer/settings/SettingsView/ApplicationSettingsPanel/ScreenBannerFieldset.tsx @@ -1,7 +1,6 @@ import { useField, Field } from 'formik'; import { FeatureId } from '@/react/portainer/feature-flags/enums'; -import { useIsDemo } from '@/react/portainer/system/useSystemStatus'; import { FormControl } from '@@/form-components/FormControl'; import { TextArea } from '@@/form-components/Input/Textarea'; @@ -9,10 +8,7 @@ import { SwitchField } from '@@/form-components/SwitchField'; import { useToggledValue } from '../useToggledValue'; -import { DemoAlert } from './DemoAlert'; - export function ScreenBannerFieldset() { - const isDemoQuery = useIsDemo(); const [{ name }, { error }] = useField('loginBanner'); const [isEnabled, setIsEnabled] = useToggledValue('loginBanner'); @@ -26,14 +22,11 @@ export function ScreenBannerFieldset() { label="Login screen banner" checked={isEnabled} name="toggle_login_banner" - disabled={isDemoQuery.data} onChange={(checked) => setIsEnabled(checked)} featureId={FeatureId.CUSTOM_LOGIN_BANNER} /> - -
You can set a custom banner that will be shown to all users during login. diff --git a/app/react/portainer/system/useSystemStatus.ts b/app/react/portainer/system/useSystemStatus.ts index 0b675f205..0d447397c 100644 --- a/app/react/portainer/system/useSystemStatus.ts +++ b/app/react/portainer/system/useSystemStatus.ts @@ -1,10 +1,8 @@ import { UseQueryOptions, useQuery } from '@tanstack/react-query'; import axios, { parseAxiosError } from '@/portainer/services/axios'; -import { UserId } from '@/portainer/users/types'; import { isBE } from '../feature-flags/feature-flags.service'; -import { EnvironmentId } from '../environments/types'; import { buildUrl } from './build-url'; import { queryKeys } from './query-keys'; @@ -15,11 +13,6 @@ export interface StatusResponse { Edition: string; Version: string; InstanceID: string; - DemoEnvironment: { - Enabled: boolean; - Users: Array; - Environments: Array; - }; } export async function getSystemStatus() { @@ -53,9 +46,3 @@ export function useSystemStatus({ onSuccess, }); } - -export function useIsDemo() { - return useSystemStatus({ - select: (status) => status.DemoEnvironment.Enabled, - }); -}