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  }