hunk.code_window:     const settings = await this.SettingsService.publicSettings();
       try {
         await this.Authentication.logout();
       } finally {
         this.LocalStorage.storeLogoutReason(error);
         if (settings.OAuthLogoutURI && this.Authentication.getUserDetails().ID !== 1) {
           this.$window.location.href = settings.OAuthLogoutURI;
         } else {
           this.$state.go('portainer.auth', { reload: true });
  
hunk.labels: keep keep keep keep add keep keep keep keep keep
hunk.after_edit:       // always clear the kubernetes cache
         dispatchCacheRefreshEvent();
  
hunk.file_path: app/portainer/views/logout/logoutController.js
hunk.type: add
file: package ssl
  
  import (
  	"context"
  	"crypto/tls"
  	"os"
  	"time"
  
  	portainer "github.com/portainer/portainer/api"
  	"github.com/portainer/portainer/api/dataservices"
  	"github.com/portainer/portainer/pkg/libcrypto"
  
  	"github.com/pkg/errors"
  	"github.com/rs/zerolog/log"
  )
  
  // Service represents a service to manage SSL certificates
  type Service struct {
  	fileService     portainer.FileService
  	dataStore       dataservices.DataStore
  	rawCert         *tls.Certificate
  	shutdownTrigger context.CancelFunc
  }
  
  // NewService returns a pointer to a new Service
  func NewService(fileService portainer.FileService, dataStore dataservices.DataStore, shutdownTrigger context.CancelFunc) *Service {
  	return &Service{
  		fileService:     fileService,
  		dataStore:       dataStore,
  		shutdownTrigger: shutdownTrigger,
  	}
  }
  
  // Init initializes the service
  func (service *Service) Init(host, certPath, keyPath string) error {
  	certSupplied := certPath != "" && keyPath != ""
  	if certSupplied {
  		newCertPath, newKeyPath, err := service.fileService.CopySSLCertPair(certPath, keyPath)
  		if err != nil {
  			return errors.Wrap(err, "failed copying supplied certs")
  		}
  
  		return service.cacheInfo(newCertPath, newKeyPath, false)
  	}
  
  	settings, err := service.GetSSLSettings()
  	if err != nil {
  		return errors.Wrap(err, "failed fetching SSL settings")
  	}
  
  	// certificates already exist
  	if settings.CertPath != "" && settings.KeyPath != "" {
  		err := service.cacheCertificate(settings.CertPath, settings.KeyPath)
  		if err != nil && !os.IsNotExist(err) {
  			return err
  		}
  
  		// continue if certs don't exist
  		if err == nil {
  			return nil
  		}
  	}
  
  	// path not supplied and certificates doesn't exist - generate self-signed
  	certPath, keyPath = service.fileService.GetDefaultSSLCertsPath()
  
  	err = generateSelfSignedCertificates(host, certPath, keyPath)
  	if err != nil {
  		return errors.Wrap(err, "failed generating self signed certs")
  	}
  
  	return service.cacheInfo(certPath, keyPath, true)
  }
  
  func generateSelfSignedCertificates(ip, certPath, keyPath string) error {
  	if ip == "" {
  		return errors.New("host can't be empty")
  	}
  
  	log.Info().Msg("no cert files found, generating self signed SSL certificates")
  
  	return libcrypto.GenerateCertsForHost("localhost", ip, certPath, keyPath, time.Now().AddDate(5, 0, 0))
  }
  
  // GetRawCertificate gets the raw certificate
  func (service *Service) GetRawCertificate() *tls.Certificate {
  	return service.rawCert
  }
  
  // GetSSLSettings gets the certificate info
  func (service *Service) GetSSLSettings() (*portainer.SSLSettings, error) {
  	return service.dataStore.SSLSettings().Settings()
  }
  
  // SetCertificates sets the certificates
  func (service *Service) SetCertificates(certData, keyData []byte) error {
  	if len(certData) == 0 || len(keyData) == 0 {
  		return errors.New("missing certificate files")
  	}
  
  	_, err := tls.X509KeyPair(certData, keyData)
  	if err != nil {
  		return err
  	}
  
  	certPath, keyPath, err := service.fileService.StoreSSLCertPair(certData, keyData)
  	if err != nil {
  		return err
  	}
  
  	err = service.cacheInfo(certPath, keyPath, false)
  	if err != nil {
  		return err
  	}
  
  	service.shutdownTrigger()
  
  	return nil
  }
  
  func (service *Service) SetHTTPEnabled(httpEnabled bool) error {
  	settings, err := service.dataStore.SSLSettings().Settings()
  	if err != nil {
  		return err
  	}
  
  	if settings.HTTPEnabled == httpEnabled {
  		return nil
  	}
  
  	settings.HTTPEnabled = httpEnabled
  
  	err = service.dataStore.SSLSettings().UpdateSettings(settings)
  	if err != nil {
  		return err
  	}
  
  	service.shutdownTrigger()
  
  	return nil
  }
  
  func (service *Service) cacheCertificate(certPath, keyPath string) error {
  	rawCert, err := tls.LoadX509KeyPair(certPath, keyPath)
  	if err != nil {
  		return err
  	}
  
  	service.rawCert = &rawCert
  
  	return nil
  }
  
  func (service *Service) cacheInfo(certPath string, keyPath string, selfSigned bool) error {
  	err := service.cacheCertificate(certPath, keyPath)
  	if err != nil {
  		return err
  	}
  
  	settings, err := service.dataStore.SSLSettings().Settings()
  	if err != nil {
  		return err
  	}
  
  	settings.CertPath = certPath
  	settings.KeyPath = keyPath
  	settings.SelfSigned = selfSigned
  
  	return service.dataStore.SSLSettings().UpdateSettings(settings)
  }
  