forked from gravitational/teleport
-
Notifications
You must be signed in to change notification settings - Fork 0
/
profile.go
153 lines (136 loc) · 3.77 KB
/
profile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package client
import (
"fmt"
"io/ioutil"
"os"
"os/user"
"path"
"github.com/gravitational/trace"
"gopkg.in/yaml.v2"
)
type ProfileOptions int
const (
ProfileMakeCurrent = 1 << iota
)
// CurrentProfileSymlink is a filename which is a symlink to the
// current profile, usually something like this:
//
// ~/.tsh/profile -> ~/.tsh/staging.yaml
//
const CurrentProfileSymlink = "profile"
// ClientProfile is a collection of most frequently used CLI flags
// for "tsh".
//
// Profiles can be stored in a profile file, allowing TSH users to
// type fewer CLI args.
//
type ClientProfile struct {
//
// proxy configuration
//
ProxyHost string `yaml:"proxy_host,omitempty"`
ProxySSHPort int `yaml:"proxy_port,omitempty"`
ProxyWebPort int `yaml:"proxy_web_port,omitempty"`
//
// auth/identity
//
Username string `yaml:"user,omitempty"`
// AuthType (like "google")
AuthType string `yaml:"auth_type,omitempty"`
// SiteName is equivalient to --cluster argument
SiteName string `yaml:"cluster,omitempty"`
//
// other stuff
//
ForwardedPorts []string `yaml:"forward_ports,omitempty"`
}
// FullProfilePath returns the full path to the user profile directory.
// If the parameter is empty, it returns expanded "~/.tsh", otherwise
// returns its unmodified parameter
func FullProfilePath(pDir string) string {
if pDir != "" {
return pDir
}
// get user home dir:
home := os.TempDir()
u, err := user.Current()
if err == nil {
home = u.HomeDir
}
return path.Join(home, ProfileDir)
}
// If there's a current profile symlink, remove it
func UnlinkCurrentProfile() error {
return trace.Wrap(os.Remove(path.Join(FullProfilePath(""), CurrentProfileSymlink)))
}
// ProfileFromDir reads the user profile from a given directory. It works
// by looking for a "profile" symlink in that directory pointing to the
// profile's YAML file.
func ProfileFromDir(dirPath string) (*ClientProfile, error) {
return ProfileFromFile(path.Join(dirPath, CurrentProfileSymlink))
}
// ProfileFromFile loads the profile from a YAML file
func ProfileFromFile(filePath string) (*ClientProfile, error) {
bytes, err := ioutil.ReadFile(filePath)
if err != nil {
return nil, trace.Wrap(err)
}
var cp *ClientProfile
if err = yaml.Unmarshal(bytes, &cp); err != nil {
return nil, trace.Wrap(err)
}
return cp, nil
}
// SaveTo saves the profile into a given filename, optionally overwriting it.
func (cp *ClientProfile) SaveTo(filePath string, opts ProfileOptions) error {
bytes, err := yaml.Marshal(&cp)
if err != nil {
return trace.Wrap(err)
}
if err = ioutil.WriteFile(filePath, bytes, 0660); err != nil {
return trace.Wrap(err)
}
// set 'current' symlink:
if opts&ProfileMakeCurrent != 0 {
symlink := path.Join(path.Dir(filePath), CurrentProfileSymlink)
os.Remove(symlink)
err = os.Symlink(path.Base(filePath), symlink)
}
return trace.Wrap(err)
}
// LogoutFromEverywhere looks at the list of proxy servers tsh is currently logged into
// by examining ~/.tsh and logs him out of them all
func LogoutFromEverywhere(username string) error {
// if no --user flag was passed, get the current OS user:
if username == "" {
me, err := user.Current()
if err != nil {
return trace.Wrap(err)
}
username = me.Username
}
// load all current keys:
agent, err := NewLocalAgent("", username)
if err != nil {
return trace.Wrap(err)
}
keys, err := agent.GetKeys(username)
if err != nil {
return trace.Wrap(err)
}
if len(keys) == 0 {
fmt.Printf("%s is not logged in\n", username)
return nil
}
// ... and delete them:
for _, key := range keys {
err = agent.DeleteKey(key.ProxyHost, username)
if err != nil {
fmt.Fprintf(os.Stderr, "error logging %s out of %s: %s\n",
username, key.ProxyHost, err)
} else {
fmt.Printf("logged %s out of %s\n", username, key.ProxyHost)
}
}
return nil
}