...

Source file src/edge-infra.dev/pkg/sds/emergencyaccess/emulatorsvc/config.go

Documentation: edge-infra.dev/pkg/sds/emergencyaccess/emulatorsvc

     1  package emulatorsvc
     2  
     3  import (
     4  	"bufio"
     5  	"errors"
     6  	"fmt"
     7  	"io/fs"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	"golang.org/x/term"
    12  	"gopkg.in/yaml.v2"
    13  )
    14  
    15  const (
    16  	envFilePathDir = "RCLI_WORKSPACE_DIR"
    17  	defaultDir     = "./"
    18  	authFileName   = "rcli_auth.yaml"
    19  
    20  	DefaultProfileName = "default"
    21  
    22  	ProfileFlag      = "profile"
    23  	UsernameFlag     = "username"
    24  	PasswordFlag     = "password"
    25  	Endpoint         = "api-endpoint"
    26  	OrganizationFlag = "organization"
    27  )
    28  
    29  type AuthFile struct {
    30  	path           string
    31  	DefaultProfile string             `yaml:"defaultProfile"`
    32  	Profiles       map[string]Profile `yaml:"profiles"`
    33  }
    34  
    35  func OpenAuthFile(dir string) (*AuthFile, error) {
    36  	path := filepath.Join(dir, authFileName)
    37  	auth := AuthFile{path: path}
    38  	auth.Profiles = make(map[string]Profile)
    39  
    40  	data, err := os.ReadFile(path)
    41  	// If file does not exist, don't return error
    42  	if errors.Is(err, fs.ErrNotExist) {
    43  		return &auth, nil
    44  	}
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	err = yaml.UnmarshalStrict(data, &auth)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	return &auth, nil
    53  }
    54  
    55  func (af AuthFile) Path() string {
    56  	return af.path
    57  }
    58  
    59  func (af *AuthFile) isInitialized() bool {
    60  	return af.DefaultProfile != "" && len(af.Profiles) > 0
    61  }
    62  
    63  func (af *AuthFile) UpdateAuthFile(profile Profile, name string) error {
    64  	if af.isInitialized() {
    65  		return nil
    66  	}
    67  
    68  	// If file has no defaultProfile, set it to either user-input profile or "default"
    69  	if af.DefaultProfile == "" {
    70  		if name != "" {
    71  			af.DefaultProfile = name
    72  		} else {
    73  			af.DefaultProfile = DefaultProfileName
    74  		}
    75  	}
    76  	// If there are no profiles, add default profile
    77  	if len(af.Profiles) == 0 {
    78  		af.Profiles[af.DefaultProfile] = profile
    79  	}
    80  	return af.writeFile()
    81  }
    82  
    83  func (af *AuthFile) writeFile() error {
    84  	var data []byte
    85  	data, err := yaml.Marshal(af)
    86  	if err != nil {
    87  		return err
    88  	}
    89  	return os.WriteFile(af.path, data, 0640)
    90  }
    91  
    92  func (af *AuthFile) LoadProfile(profile Profile, name string) (Profile, error) {
    93  	// Authfile has not been set up yet
    94  	if !af.isInitialized() {
    95  		return profile, nil
    96  	}
    97  
    98  	if name == "" {
    99  		name = af.DefaultProfile
   100  	}
   101  
   102  	p, ok := af.Profiles[name]
   103  	if !ok {
   104  		return Profile{}, fmt.Errorf("profile does not exist in rcli auth file")
   105  	}
   106  
   107  	if profile.Username == "" {
   108  		profile.Username = p.Username
   109  	}
   110  	if profile.Organization == "" {
   111  		profile.Organization = p.Organization
   112  	}
   113  	if profile.API == "" {
   114  		profile.API = p.API
   115  	}
   116  	return profile, nil
   117  }
   118  
   119  type Config struct {
   120  	dir     string
   121  	Profile Profile
   122  }
   123  
   124  func NewConfig(dir string, profile Profile) Config {
   125  	return Config{
   126  		dir:     dir,
   127  		Profile: profile,
   128  	}
   129  }
   130  
   131  type Profile struct {
   132  	Username      string `yaml:"username"`
   133  	Password      string `yaml:"-"`
   134  	API           string `yaml:"apiEndpoint"`
   135  	Organization  string `yaml:"organization"`
   136  	SessionCookie string `yaml:"-"`
   137  }
   138  
   139  func (profile *Profile) RequestEmptyFields() error {
   140  	var err error
   141  	if profile.Username == "" {
   142  		fmt.Print("Please enter your username: ")
   143  		profile.Username, err = promptGeneric()
   144  		if err != nil {
   145  			return err
   146  		}
   147  	}
   148  	if profile.Password == "" {
   149  		fmt.Print("Please enter your password: ")
   150  		profile.Password, err = promptPassword()
   151  		if err != nil {
   152  			return err
   153  		}
   154  	}
   155  	if profile.API == "" {
   156  		fmt.Print("Please enter the Edge API URL: ")
   157  		profile.API, err = promptGeneric()
   158  		if err != nil {
   159  			return err
   160  		}
   161  	}
   162  	if profile.Organization == "" {
   163  		fmt.Print("Please enter your Edge organization: ")
   164  		profile.Organization, err = promptGeneric()
   165  		if err != nil {
   166  			return err
   167  		}
   168  	}
   169  	return nil
   170  }
   171  
   172  func promptGeneric() (string, error) {
   173  	var input string
   174  	scanner := bufio.NewScanner(os.Stdin)
   175  	for scanner.Scan() {
   176  		if err := scanner.Err(); err != nil {
   177  			return "", err
   178  		}
   179  		if input = scanner.Text(); input != "" {
   180  			break
   181  		}
   182  		fmt.Print("Please enter a valid value: ")
   183  	}
   184  	return input, nil
   185  }
   186  
   187  func promptPassword() (string, error) {
   188  	byteInput, err := term.ReadPassword(int(os.Stdin.Fd()))
   189  	if err != nil {
   190  		return "", err
   191  	}
   192  	fmt.Println()
   193  	for string(byteInput) == "" {
   194  		fmt.Print("Please enter a valid value: ")
   195  		byteInput, err = term.ReadPassword(int(os.Stdin.Fd()))
   196  		if err != nil {
   197  			return "", err
   198  		}
   199  		fmt.Println()
   200  	}
   201  	return string(byteInput), nil
   202  }
   203  

View as plain text