Skip to content

Commit

Permalink
Merge pull request #396 from reubenmiller/feat-session-banner-setting
Browse files Browse the repository at this point in the history
feat: independent session banner setting
  • Loading branch information
reubenmiller authored Jun 15, 2024
2 parents 418bb13 + 6b79f6c commit 7846c4f
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 31 deletions.
28 changes: 20 additions & 8 deletions pkg/c8ysession/c8ysession.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,25 +117,37 @@ func PrintSessionInfo(w io.Writer, client *c8y.Client, cfg *config.Config, sessi
label := labelS.SprintfFunc()
value := color.New(color.FgWhite).SprintFunc()
header := color.New(color.FgCyan).SprintFunc()
maybeHideMessage := func(client *c8y.Client, message string) string {
return message
}
hideInfo := cfg.HideSessionBanner()
if hideInfo {
maybeHideMessage = cfg.HideSensitiveInformation
}

labelS.Fprintf(w, "--------------------- Cumulocity Session ---------------------\n")
if hideInfo {
labelS.Fprintf(w, "--------------------- Cumulocity Session (sensitive info is hidden) ---------------------\n")
} else {
labelS.Fprintf(w, "--------------------- Cumulocity Session ---------------------\n")
}
// Always show the source of the session
if session.SessionUri != "" {
fmt.Fprintf(w, "\n %s: %s\n\n\n", label("%s", "source"), header(cfg.HideSensitiveInformationIfActive(client, session.SessionUri)))
fmt.Fprintf(w, "\n %s: %s\n\n\n", label("%s", "source"), header(session.SessionUri))
} else {
fmt.Fprintf(w, "\n %s: %s\n\n\n", label("%s", "path"), header(cfg.HideSensitiveInformationIfActive(client, session.Path)))
fmt.Fprintf(w, "\n %s: %s\n\n\n", label("%s", "path"), header(session.Path))
}
if session.Description != "" {
fmt.Fprintf(w, "%s : %s\n", label(fmt.Sprintf("%-12s", "description")), value(cfg.HideSensitiveInformationIfActive(client, session.Host)))
fmt.Fprintf(w, "%s : %s\n", label(fmt.Sprintf("%-12s", "description")), value(maybeHideMessage(client, session.Host)))
}

fmt.Fprintf(w, "%s : %s\n", label(fmt.Sprintf("%-12s", "host")), value(cfg.HideSensitiveInformationIfActive(client, session.Host)))
fmt.Fprintf(w, "%s : %s\n", label(fmt.Sprintf("%-12s", "host")), value(maybeHideMessage(client, session.Host)))
if session.Tenant != "" {
fmt.Fprintf(w, "%s : %s\n", label(fmt.Sprintf("%-12s", "tenant")), value(cfg.HideSensitiveInformationIfActive(client, session.Tenant)))
fmt.Fprintf(w, "%s : %s\n", label(fmt.Sprintf("%-12s", "tenant")), value(maybeHideMessage(client, session.Tenant)))
}
if session.Version != "" {
fmt.Fprintf(w, "%s : %s\n", label(fmt.Sprintf("%-12s", "version")), value(cfg.HideSensitiveInformationIfActive(client, session.Version)))
fmt.Fprintf(w, "%s : %s\n", label(fmt.Sprintf("%-12s", "version")), value(maybeHideMessage(client, session.Version)))
}
fmt.Fprintf(w, "%s : %s\n", label(fmt.Sprintf("%-12s", "username")), value(cfg.HideSensitiveInformationIfActive(client, session.Username)))
fmt.Fprintf(w, "%s : %s\n", label(fmt.Sprintf("%-12s", "username")), value(maybeHideMessage(client, session.Username)))
fmt.Fprintf(w, "\n")
}

Expand Down
8 changes: 7 additions & 1 deletion pkg/cmd/sessions/login/login.manual.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,11 @@ func (n *CmdLogin) FromFile(file string, format string) (*c8ysession.CumulocityS
return nil, err
}

return n.FromViper(v)
session, err := n.FromViper(v)
if session.SessionUri == "" {
session.SessionUri = "file://" + file
}
return session, err
}

func (n *CmdLogin) FromReader(r io.Reader, format string) (*c8ysession.CumulocitySession, error) {
Expand Down Expand Up @@ -366,6 +370,8 @@ func (n *CmdLogin) RunE(cmd *cobra.Command, args []string) error {
session.Path = cfg.GetSessionFile()

// Write session details to stderr (for humans)
cs := n.factory.IOStreams.ColorScheme()
fmt.Fprintf(n.factory.IOStreams.ErrOut, "%s Session is now active\n", cs.SuccessIcon())
if !n.NoBanner {
c8ysession.PrintSessionInfo(n.SubCommand.GetCommand().ErrOrStderr(), client, cfg, *session)
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/sessions/selectsession/selectsession.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func SelectSession(io *iostreams.IOStreams, cfg *config.Config, log *logger.Logg
funcMap["highlight"] = customStyle()

funcMap["hide"] = func(v interface{}) string {
if cfg.HideSensitive() {
if cfg.HideSessionBanner() {
return "*****"
}
return fmt.Sprintf("%v", v)
Expand All @@ -131,7 +131,7 @@ func SelectSession(io *iostreams.IOStreams, cfg *config.Config, log *logger.Logg
funcMap["hideUser"] = func(v interface{}) string {
msg := fmt.Sprintf("%v", v)

if !cfg.HideSensitive() {
if !cfg.HideSessionBanner() {
return msg
}
if os.Getenv("USERNAME") != "" {
Expand Down
15 changes: 13 additions & 2 deletions pkg/cmd/sessions/set/set.manual.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package login

import (
"fmt"
"os"
"slices"
"strings"
"time"

Expand All @@ -28,6 +30,7 @@ type CmdSet struct {
LoginType string
Shell string
ClearToken bool
NoBanner bool
sessionFilter string

*subcommand.SubCommand
Expand Down Expand Up @@ -68,6 +71,7 @@ func NewCmdSet(f *cmdutil.Factory) *CmdSet {
cmd.Flags().StringVar(&ccmd.TFACode, "tfaCode", "", "Two Factor Authentication code")
cmd.Flags().StringVar(&ccmd.Shell, "shell", defaultShell, "Shell type to return the environment variables")
cmd.Flags().StringVar(&ccmd.LoginType, "loginType", "", "Login type preference, e.g. OAUTH2_INTERNAL or BASIC. When set to BASIC, any existing token will be cleared")
cmd.Flags().BoolVar(&ccmd.NoBanner, "no-banner", false, "Don't show the session banner")
cmd.Flags().BoolVar(&ccmd.ClearToken, "clear", false, "Clear any existing tokens")

completion.WithOptions(
Expand Down Expand Up @@ -120,12 +124,15 @@ func (n *CmdSet) RunE(cmd *cobra.Command, args []string) error {
// the user is most likely switching session so does not want to inherit any environment variables
// set from the last instance.
// But this has a side effect that you can't control the profile handing via environment variables when using the interact session selection
allowedEnvValues := []string{"C8Y_SETTINGS_SESSION_HIDE"}
env_prefix := strings.ToUpper(config.EnvSettingsPrefix)
for _, env := range os.Environ() {
if strings.HasPrefix(env, env_prefix) && !strings.HasPrefix(env, config.EnvPassphrase) && !strings.HasPrefix(env, config.EnvSessionHome) {
parts := strings.SplitN(env, "=", 2)
if len(parts) == 2 {
os.Unsetenv(parts[0])
if !slices.Contains(allowedEnvValues, parts[0]) {
os.Unsetenv(parts[0])
}
}
}
}
Expand Down Expand Up @@ -233,7 +240,11 @@ func (n *CmdSet) RunE(cmd *cobra.Command, args []string) error {

// Write session details to stderr (for humans)
if outputFormat != config.OutputJSON.String() {
c8ysession.PrintSessionInfo(n.SubCommand.GetCommand().ErrOrStderr(), client, cfg, *session)
cs := n.factory.IOStreams.ColorScheme()
fmt.Fprintf(n.factory.IOStreams.ErrOut, "%s Session is now active\n", cs.SuccessIcon())
if !n.NoBanner {
c8ysession.PrintSessionInfo(n.factory.IOStreams.ErrOut, client, cfg, *session)
}
}

if outputFormat == config.OutputUnknown.String() {
Expand Down
6 changes: 6 additions & 0 deletions pkg/cmd/settings/update/update.manual.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,12 @@ var updateSettingsOptions = map[string]argumentHandler{
"7d",
}, nil, cobra.ShellCompDirectiveNoFileComp},

// Hide session info when setting a session
"session.hide": {"session.hide", "bool", "settings.session.hide", []string{
"true",
"false",
}, nil, cobra.ShellCompDirectiveNoFileComp},

// cache
"defaults.cache": {"defaults.cache", "bool", config.SettingsDefaultsCacheEnabled, []string{
"true",
Expand Down
46 changes: 28 additions & 18 deletions pkg/config/cliConfiguration.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ const (
// SettingsSessionTokenValidFor interval which the token must be valid for in order to reuse it
SettingsSessionTokenValidFor = "settings.session.tokenValidFor"

// SettingsSessionHide hide sensitive information in the session banner
SettingsSessionHide = "settings.session.hide"

// Cache settings
// SettingsDefaultsCacheEnabled enable caching
SettingsDefaultsCacheEnabled = "settings.defaults.cache"
Expand Down Expand Up @@ -532,6 +535,7 @@ func (c *Config) bindSettings() {
// Session options
WithBindEnv(SettingsSessionAlwaysIncludePassword, false),
WithBindEnv(SettingsSessionTokenValidFor, "8h"),
WithBindEnv(SettingsSessionHide, false),

WithBindEnv(SettingsBrowser, ""),

Expand Down Expand Up @@ -1513,6 +1517,11 @@ func (c *Config) HideSensitive() bool {
return c.viper.GetBool(SettingsLoggerHideSensitive)
}

// HideSessionBanner hide sensitive information in the session banner
func (c *Config) HideSessionBanner() bool {
return c.viper.GetBool(SettingsSessionHide)
}

// DisableStdin hide sensitive information in log entries
func (c *Config) DisableStdin() bool {
return c.viper.GetBool(SettingsDisableInput)
Expand Down Expand Up @@ -1978,11 +1987,14 @@ func (c *Config) ReadConfigFiles(client *c8y.Client) (path string, err error) {
}

func (c *Config) HideSensitiveInformationIfActive(client *c8y.Client, message string) string {
if client == nil {
if !c.HideSensitive() {
return message
}
return c.HideSensitiveInformation(client, message)
}

if !c.HideSensitive() {
func (c *Config) HideSensitiveInformation(client *c8y.Client, message string) string {
if client == nil {
return message
}

Expand All @@ -1991,22 +2003,20 @@ func (c *Config) HideSensitiveInformationIfActive(client *c8y.Client, message st
message = strings.ReplaceAll(message, username, "******")
}

if client != nil {
if client.TenantName != "" {
message = strings.ReplaceAll(message, client.TenantName, "{tenant}")
}
if client.Username != "" {
message = strings.ReplaceAll(message, client.Username, "{username}")
}
if client.Password != "" {
message = strings.ReplaceAll(message, client.Password, "{password}")
}
if client.Token != "" {
message = strings.ReplaceAll(message, client.Token, "{token}")
}
if client.BaseURL != nil {
message = strings.ReplaceAll(message, strings.TrimRight(client.BaseURL.Host, "/"), "{host}")
}
if client.TenantName != "" {
message = strings.ReplaceAll(message, client.TenantName, "{tenant}")
}
if client.Username != "" {
message = strings.ReplaceAll(message, client.Username, "{username}")
}
if client.Password != "" {
message = strings.ReplaceAll(message, client.Password, "{password}")
}
if client.Token != "" {
message = strings.ReplaceAll(message, client.Token, "{token}")
}
if client.BaseURL != nil {
message = strings.ReplaceAll(message, strings.TrimRight(client.BaseURL.Host, "/"), "{host}")
}

basicAuthMatcher := regexp.MustCompile(`(Basic\s+)[A-Za-z0-9=]+`)
Expand Down
28 changes: 28 additions & 0 deletions tests/manual/sessions/login/session_login.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,31 @@ tests:
version: r/^.+$
username: r/^.+$
token: r/^.+$

It does not hide sensitive info in the session banner by default:
command: |
c8y sessions login --from-env
exit-code: 0
stderr:
not-contains:
- "{host}"
- "{tenant}"
- "{username}"
- "hidden"

It hides sensitive information in the session banner:
command: |
c8y sessions login --from-env
exit-code: 0
config:
retries: 0
inherit-env: false
env:
C8Y_SETTINGS_SESSION_HIDE: true
stderr:
contains:
- "✓ Session is now active"
- --------------------- Cumulocity Session (sensitive info is hidden) ---------------------
- "host : {host}"
- "tenant : {tenant}"
- "username : {username}"

0 comments on commit 7846c4f

Please sign in to comment.