Mercurial > projects > sievemgr
view cmd/sievemgr/common.go @ 1:0cd5a454dfb4
Add README file
Adjust email address.
author | Guido Berhoerster <guido+sievemgr@berhoerster.name> |
---|---|
date | Mon, 26 Oct 2020 14:46:39 +0100 |
parents | b00673734e58 |
children | 4dff4c3f0fbb |
line wrap: on
line source
// Copyright (C) 2020 Guido Berhoerster <guido+sievemgr@berhoerster.name> // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. package main import ( "bufio" "crypto/tls" "errors" "fmt" "io" "io/ioutil" "net" "os" "os/user" "runtime" "strings" "go.guido-berhoerster.org/managesieve" "golang.org/x/crypto/ssh/terminal" ) var errTooBig = errors.New("too big") func parseHostPort(s string) (string, string, error) { var host string host, port, err := net.SplitHostPort(s) if err != nil { // error may be due to a missing port but there is no usable // error value to test for, thus try again with a port added var tmpErr error host, _, tmpErr = net.SplitHostPort(s + ":4190") if tmpErr != nil { return "", "", err } } if port == "" { // no port given, try to look up a SRV record for given domain // and fall back to the domain and port 4190 services, err := managesieve.LookupService(host) if err != nil { return "", "", err } host, port, err = net.SplitHostPort(services[0]) if err != nil { return "", "", err } } return host, port, nil } func readPassword() (string, error) { var tty *os.File var fd int var w io.Writer if runtime.GOOS == "windows" { fd = int(os.Stdin.Fd()) w = os.Stdout } else { var err error tty, err = os.OpenFile("/dev/tty", os.O_RDWR, 0666) if err != nil { return "", err } defer tty.Close() fd = int(tty.Fd()) w = tty } io.WriteString(w, "Password: ") rawPassword, err := terminal.ReadPassword(fd) io.WriteString(w, "\n") if err != nil { return "", fmt.Errorf("failed to read password: %s", err) } password := string(rawPassword) if password == "" { return "", fmt.Errorf("invalid password") } return password, nil } func readPasswordFile(filename string) (string, error) { f, err := os.Open(filename) if err != nil { return "", err } defer f.Close() scanner := bufio.NewScanner(f) if !scanner.Scan() { err := scanner.Err() if err == nil { err = fmt.Errorf("failed to read from %q: unexpected EOF", filename) } return "", err } password := scanner.Text() if password == "" { return "", fmt.Errorf("invalid password") } return password, nil } func usernamePassword(host, port, username, passwordFile string) (string, string, error) { // fall back to the system username if username == "" { u, err := user.Current() if err != nil { return "", "", fmt.Errorf("failed to obtain username: %s", err) } username = u.Username } var password string var err error if passwordFile != "" { password, err = readPasswordFile(passwordFilename) } else { password, err = readPassword() } if err != nil { return "", "", err } return username, password, nil } func dialPlainAuth(hostport, username, password string) (*managesieve.Client, error) { c, err := managesieve.Dial(hostport) if err != nil { return nil, fmt.Errorf("failed to connect: %s", err) } host, _, _ := net.SplitHostPort(hostport) // switch to a TLS connection except for localhost if host != "localhost" && host != "127.0.0.1" && host != "::1" { tlsConf := &tls.Config{ ServerName: host, InsecureSkipVerify: skipCertVerify, } if err := c.StartTLS(tlsConf); err != nil { return nil, fmt.Errorf("failed to start TLS connection: %s", err) } } auth := managesieve.PlainAuth("", username, password, host) if err := c.Authenticate(auth); err != nil { return nil, fmt.Errorf("failed to authenticate user %s: %s", username, err) } return c, nil } func readLimitedString(r io.Reader, n int64) (string, error) { var s strings.Builder _, err := io.CopyN(&s, r, n) if err == nil { // check for EOF _, err = io.CopyN(ioutil.Discard, r, 1) if err == nil { return s.String(), errTooBig } } if err != io.EOF { return s.String(), err } return s.String(), nil }