github.com/webonyx/up@v0.7.4-0.20180808230834-91b94e551323/internal/userconfig/userconfig.go (about) 1 // Package userconfig provides user machine-level configuration. 2 package userconfig 3 4 import ( 5 "encoding/base64" 6 "encoding/json" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 11 "github.com/apex/up/internal/util" 12 "github.com/mitchellh/go-homedir" 13 "github.com/pkg/errors" 14 ) 15 16 var ( 17 // configDir is the dir name where up config is stored relative to HOME. 18 configDir = ".up" 19 20 // envName is the environment variable which can be used to store 21 // Up's configuration, primarily for continuous integration. 22 envName = "UP_CONFIG" 23 ) 24 25 // Team is the user configuration for a given team. 26 type Team struct { 27 // ID is the team identifier. 28 ID string `json:"team"` 29 30 // Email is the user's email. 31 Email string `json:"email"` 32 33 // Token is the access token. 34 Token string `json:"token"` 35 } 36 37 // IsPersonal returns true if it is a personal team. 38 func (t *Team) IsPersonal() bool { 39 return t.Email == t.ID 40 } 41 42 // Config is the user configuration. 43 type Config struct { 44 // Team is the active team. 45 Team string `json:"team"` 46 47 // Teams is the user's active teams. 48 Teams map[string]*Team `json:"teams"` 49 } 50 51 // initTeams inits the map. 52 func (c *Config) initTeams() { 53 if c.Teams == nil { 54 c.Teams = make(map[string]*Team) 55 } 56 } 57 58 // AddTeam adds or replaces the given team. 59 func (c *Config) AddTeam(t *Team) { 60 c.initTeams() 61 c.Teams[t.ID] = t 62 } 63 64 // GetTeams returns a list of teams. 65 func (c *Config) GetTeams() (teams []*Team) { 66 for _, t := range c.Teams { 67 teams = append(teams, t) 68 } 69 return 70 } 71 72 // GetTeam returns a team by id or nil 73 func (c *Config) GetTeam(id string) *Team { 74 return c.Teams[id] 75 } 76 77 // GetActiveTeam returns the active team. 78 func (c *Config) GetActiveTeam() *Team { 79 return c.GetTeam(c.Team) 80 } 81 82 // Authenticated returns true if the user has an active team. 83 func (c *Config) Authenticated() bool { 84 return c.GetActiveTeam() != nil 85 } 86 87 // Require requires authentication and returns the active team. 88 func Require() (*Team, error) { 89 var c Config 90 91 if err := c.Load(); err != nil { 92 return nil, errors.Wrap(err, "loading config") 93 } 94 95 if !c.Authenticated() { 96 return nil, errors.New("user credentials missing, make sure to `up team login` first") 97 } 98 99 return c.GetActiveTeam(), nil 100 } 101 102 // Alter config, loading and saving after manipulation. 103 func Alter(fn func(*Config)) error { 104 var config Config 105 106 if err := config.Load(); err != nil { 107 return errors.Wrap(err, "loading") 108 } 109 110 fn(&config) 111 112 if err := config.Save(); err != nil { 113 return errors.Wrap(err, "saving") 114 } 115 116 return nil 117 } 118 119 // Load the configuration. 120 func (c *Config) Load() error { 121 path, err := c.path() 122 if err != nil { 123 return errors.Wrap(err, "getting path") 124 } 125 126 // env 127 if s := os.Getenv(envName); s != "" { 128 // if not JSON, check for base64 encoding 129 if !util.IsJSON(s) { 130 decoded, err := base64.StdEncoding.DecodeString(s) 131 if err != nil { 132 return errors.Wrap(err, "decoding base64") 133 } 134 s = string(decoded) 135 } 136 137 if err := json.Unmarshal([]byte(s), &c); err != nil { 138 return errors.Wrap(err, "unmarshaling") 139 } 140 return nil 141 } 142 143 // file 144 b, err := ioutil.ReadFile(path) 145 146 if os.IsNotExist(err) { 147 return nil 148 } 149 150 if err != nil { 151 return errors.Wrap(err, "reading") 152 } 153 154 if err := json.Unmarshal(b, c); err != nil { 155 return errors.Wrap(err, "unmarshaling") 156 } 157 158 return nil 159 } 160 161 // Save the configuration. 162 func (c *Config) Save() error { 163 b, err := json.MarshalIndent(c, "", " ") 164 if err != nil { 165 return errors.Wrap(err, "marshaling") 166 } 167 168 path, err := c.path() 169 if err != nil { 170 return errors.Wrap(err, "getting path") 171 } 172 173 if err := ioutil.WriteFile(path, b, 0755); err != nil { 174 return errors.Wrap(err, "writing") 175 } 176 177 return nil 178 } 179 180 // path returns the path and sets up dir if necessary. 181 func (c *Config) path() (string, error) { 182 home, err := homedir.Dir() 183 if err != nil { 184 return "", errors.Wrap(err, "homedir") 185 } 186 187 dir := filepath.Join(home, configDir) 188 if err := os.MkdirAll(dir, 0755); err != nil { 189 return "", errors.Wrap(err, "mkdir") 190 } 191 192 path := filepath.Join(dir, "config.json") 193 return path, nil 194 }