github.com/devops-filetransfer/sshego@v7.0.4+incompatible/usermgt.go (about) 1 package sshego 2 3 import ( 4 "bufio" 5 "bytes" 6 "fmt" 7 "io" 8 "os" 9 "runtime" 10 "strings" 11 "time" 12 13 "github.com/skratchdot/open-golang/open" 14 ) 15 16 func AddUserAndExit(cfg *SshegoConfig) { 17 18 err := cfg.NewHostDb() 19 panicOn(err) 20 21 mylogin := cfg.AddUser 22 23 if cfg.HostDb.UserExists(mylogin) { 24 fmt.Fprintf(os.Stderr, "\nerror: user '%s' already exists. If you want to replace them, use -deluser first.\n", mylogin) 25 os.Exit(1) 26 } 27 if cfg.SshegoSystemMutexPort < 0 { 28 fmt.Fprintf(os.Stderr, "\nerror: cfg.SshegoSystemMutexPort is negative, so we cannot configure users.\n") 29 os.Exit(1) 30 } 31 var ok bool 32 ok, err = cfg.HostDb.ValidLogin(mylogin) 33 if !ok { 34 fmt.Printf("\n%s\n", err) 35 os.Exit(1) 36 } 37 38 reader := bufio.NewReader(os.Stdin) 39 40 var myemail string 41 fmt.Printf("\nEnter the email address for '%s' (for backups/recovery): ", 42 mylogin) 43 myemail, err = reader.ReadString('\n') 44 panicOn(err) 45 myemail = strings.Trim(myemail, "\n\r\t ") 46 ok, err = cfg.HostDb.ValidEmail(myemail) 47 if !ok { 48 fmt.Printf("\n%s\n", err) 49 os.Exit(1) 50 } 51 52 fmt.Printf("\n'%s' should be a valid email, but may be fake if you insist.\n\nIf this email is real, we can backup the passphrase you will create in the next step. This convenience feature is optional, but strongly recommended. The RSA key and One-time-password secret will not be sent by email, but their locations on disk will be noted for ease of retreival.\n\nDo you want to backup the passphase to email '%s'? [y/n]:", myemail, myemail) 53 yn, err := reader.ReadString('\n') 54 panicOn(err) 55 yn = strings.ToLower(strings.Trim(yn, "\n\r\t ")) 56 sendEmail := false 57 if yn == "y" || yn == "yes" { 58 sendEmail = true 59 fmt.Printf("\n\n Very good. Upon completion, your passphrase "+ 60 "will backed up to '%s'\n\n", myemail) 61 } else { 62 fmt.Printf("\n\n As you wish. No email will be sent.\n\n") 63 } 64 65 var fullname string 66 fmt.Printf("\nCorresponding to '%s'/'%s', enter the first and last name (e.g. 'John Q. Smith'). This helps identify the account during maintenance. First and last name:\n", mylogin, myemail) 67 fullname, err = reader.ReadString('\n') 68 panicOn(err) 69 fullname = strings.Trim(fullname, "\n\r\t ") 70 71 var pw string 72 if !cfg.SkipPassphrase { 73 pw, err = PromptForPassword(cfg.AddUser) 74 if err != nil { 75 fmt.Printf("\n%v\n", err) 76 os.Exit(1) 77 } 78 fmt.Printf("\n account: '%s', passphrase: '%s'\n", cfg.AddUser, pw) 79 } 80 if !cfg.SkipRSA { 81 fmt.Printf("\n generating a strong RSA key, this may take a 5-10 seconds... \n") 82 } 83 user := NewUser() 84 user.MyLogin = mylogin 85 user.MyEmail = myemail 86 user.MyFullname = fullname 87 user.ClearPw = pw 88 user.Issuer = "gosshtun" 89 90 var toptPath, qrPath, rsaPath string 91 92 var prt TcpPort 93 prt.Port = cfg.SshegoSystemMutexPort 94 95 limitMsec := 5000 96 err = prt.Lock(limitMsec) 97 if err == ErrCouldNotAquirePort { 98 // already running... 99 p("we see gosshtun is already running and has the xport open") 100 toptPath, qrPath, rsaPath, err = cfg.TcpClientUserAdd(user) 101 } else { 102 p("we got xport, so while holding it, modify the database directly") 103 // we must do it ourselves; other process is not 104 // up and we now hold the port (listening on it) as a lock. 105 toptPath, qrPath, rsaPath, err = cfg.HostDb.AddUser( 106 mylogin, myemail, pw, "gosshtun", fullname, "") 107 prt.Unlock() 108 } 109 if err != nil { 110 es := err.Error() 111 if strings.HasPrefix(es, 112 "bad email: give a full email address.") { 113 fmt.Printf("\n%s\n", es) 114 os.Exit(1) 115 } 116 } 117 panicOn(err) 118 119 hostname, _ := os.Hostname() 120 var plain bytes.Buffer 121 var html bytes.Buffer 122 both := io.MultiWriter(&plain, &html) 123 ip := GetExternalIP() 124 userEnv := os.Getenv("USER") 125 126 fmt.Fprintf(&html, "<html><body>") 127 fmt.Fprintf(both, "%s:\n\n", fullname) 128 fmt.Fprintf(&html, "<p><font size=3>") 129 130 fmt.Fprintf(both, "## ===============================================\n") 131 fmt.Fprintf(&html, "<br>") 132 fmt.Fprintf(both, "## \n") 133 fmt.Fprintf(&html, "<br>") 134 authDetail := "tri-factor" 135 if cfg.SkipPassphrase || cfg.SkipRSA || cfg.SkipTOTP { 136 authDetail = "" 137 } 138 authList := cfg.GenAuthString() 139 fmt.Fprintf(both, "## %s auth details:\n", authDetail) 140 fmt.Fprintf(&html, "<br>") 141 fmt.Fprintf(both, "## \n") 142 fmt.Fprintf(&html, "<br>") 143 fmt.Fprintf(both, "## %s\n", authList) 144 fmt.Fprintf(&html, "<br>") 145 fmt.Fprintf(both, "## \n") 146 fmt.Fprintf(&html, "<br>") 147 fmt.Fprintf(both, "## == run: gosshtun -adduser %s\n", 148 cfg.AddUser) 149 fmt.Fprintf(&html, "<br>") 150 fmt.Fprintf(both, "## == run on host: %s (%s)\n", hostname, ip) 151 fmt.Fprintf(&html, "<br>") 152 fmt.Fprintf(both, "## == run by user: %s\n", userEnv) 153 fmt.Fprintf(&html, "<br>") 154 fmt.Fprintf(both, "## == at UTC time: %s\n", time.Now().UTC()) 155 fmt.Fprintf(&html, "<br>") 156 fmt.Fprintf(both, "## ===============================================\n") 157 fmt.Fprintf(&html, "<br>") 158 159 fmt.Fprintf(&plain, "\nyour login:\n%s\n\n", mylogin) 160 fmt.Fprintf(&html, "\n<p>your login:<br>\n<b>%s</b><p>\n\n", mylogin) 161 162 fmt.Fprintf(&plain, "your email:\n%s\n\n", myemail) 163 fmt.Fprintf(&html, "\n<p>your email:<br>\n<b>%s</b><p>\n\n", myemail) 164 165 fmt.Fprintf(&plain, "your fullname:\n%s\n\n", fullname) 166 fmt.Fprintf(&html, "\n<p>your fullname:<br>\n<b>%s</b><p>\n\n", fullname) 167 168 if !cfg.SkipPassphrase { 169 fmt.Fprintf(&plain, "Passphrase:\n%v\n\n", pw) 170 fmt.Fprintf(&html, "<p>Passphrase:\n<br>\n<b>%v</b>\n\n", pw) 171 fmt.Fprintf(&html, "<p><p>") 172 } 173 if !cfg.SkipTOTP { 174 fmt.Fprintf(&plain, "GoogleAuthenticator (time-based-one-time-password; RFC6238) secret location (on host %s):\n%s\n\n", hostname, toptPath) 175 fmt.Fprintf(&html, "GoogleAuthenticator (time-based-one-time-password; RFC6238) secret location (on host %s):\n<br>\n<b>%s</b><p><p>\n", hostname, toptPath) 176 177 qrUrl := fmt.Sprintf("file://%s", qrPath) 178 179 fmt.Printf("\n checking if we should open the QR-code automajically...\n") 180 if runtime.GOOS == "darwin" { // "windows", "linux" 181 fmt.Printf("...runtime.GOOS='%s'; try to open the QR-code\n", 182 runtime.GOOS) 183 open.Start(qrUrl) 184 } 185 186 fmt.Fprintf(&plain, "GoogleAuthenticator QR-code url (on host %s):\n%s\n\n", hostname, qrPath) 187 fmt.Fprintf(&html, "GoogleAuthenticator QR-code url (on host %s):\n<br><b><a href=\"%s\" target=\"_blank\">%s</a></b><p>\n\n", hostname, qrUrl, qrUrl) 188 fmt.Fprintf(&html, "<p>") 189 } 190 if !cfg.SkipRSA { 191 fmt.Fprintf(&plain, "Your new RSA Private key is here (on host %s):\n%s\n\n", hostname, rsaPath) 192 fmt.Fprintf(&html, "Your new RSA Private key is here (on host %s):\n<br><b>%s\n\n</b><p>", hostname, rsaPath) 193 194 fmt.Fprintf(&plain, "Your new RSA Public key is here (on host %s):\n%s\n\n", hostname, rsaPath+".pub") 195 fmt.Fprintf(&html, "Your new RSA Public key is here (on host %s):\n<br><b>%s</b><p>\n\n", hostname, rsaPath+".pub") 196 } 197 fmt.Fprintf(&html, "</body></html>") 198 199 os.Stdout.Write(plain.Bytes()) 200 201 if sendEmail { 202 if cfg.MailCfg.Domain == "" || 203 cfg.MailCfg.PublicApiKey == "" || 204 cfg.MailCfg.SecretApiKey == "" { 205 fmt.Printf("\n\n alert! -- mailgun not configured; not sending backup email.\n\n") 206 } else { 207 subject := fmt.Sprintf("gosshtun passphrase backup "+ 208 "- from %s@%s (%s)", userEnv, hostname, ip) 209 senderEmail := fmt.Sprintf("%s@%s", userEnv, hostname) 210 211 pl := string(plain.Bytes()) 212 ht := string(html.Bytes()) 213 214 id, err := cfg.MailCfg.SendEmail(senderEmail, 215 subject, 216 pl, 217 ht, 218 myemail) 219 if err != nil { 220 fmt.Printf("\n mailCfg.SendEmail() failed: %s\n", err) 221 } else { 222 fmt.Printf("\n backup email sent; id: '%s'\n", id) 223 } 224 } 225 } 226 227 os.Exit(0) 228 } 229 230 func DelUserAndExit(cfg *SshegoConfig) { 231 232 fmt.Printf("\ndeleting user '%s'...\n", cfg.DelUser) 233 234 user := NewUser() 235 user.MyLogin = cfg.DelUser 236 237 var prt TcpPort 238 prt.Port = cfg.SshegoSystemMutexPort 239 240 limitMsec := 5000 241 err := prt.Lock(limitMsec) 242 if err == ErrCouldNotAquirePort { 243 // already running... 244 p("we see gosshtun is already running and has the xport open") 245 err = cfg.TcpClientUserDel(user) 246 if err != nil { 247 fmt.Printf("\n error: %s\n", err) 248 os.Exit(1) 249 } 250 } else { 251 p("we got xport, so while holding it, modify the database directly") 252 // we must do it ourselves; other process is not 253 // up and we now hold the port (listening on it) as a lock. 254 255 err := cfg.NewHostDb() 256 if err != nil { 257 fmt.Printf("\n%s\n", err) 258 os.Exit(1) 259 } 260 err = cfg.HostDb.DelUser(cfg.DelUser) 261 if err != nil { 262 fmt.Printf("\n%s\n", err) 263 os.Exit(1) 264 } 265 prt.Unlock() 266 } 267 fmt.Printf("\n deleted user '%s'\n", cfg.DelUser) 268 os.Exit(0) 269 }