Mercurial > projects > sievemgr
view cmd/sievemgr/common.go @ 22:fc5e6970a0d5 default tip
Add support for specifying an authorization identity on the command line
author | Guido Berhoerster <guido+sievemgr@berhoerster.name> |
---|---|
date | Wed, 17 Feb 2021 07:50:55 +0100 |
parents | 29769b9e2f09 |
children |
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 ( "crypto/tls" "errors" "fmt" "io" "io/ioutil" "net" "os" "runtime" "strings" "go.guido-berhoerster.org/managesieve" "go.guido-berhoerster.org/sievemgr/cmd/sievemgr/internal/config" "golang.org/x/term" ) var errTooBig = errors.New("too big") func getAccount(conf *config.Configuration, name string) (*config.Account, error) { if name == "" { if conf.Default == nil { return nil, fmt.Errorf("no default account configured") } return conf.Default, nil } for _, acct := range conf.Accounts { if acct.Name == name { return acct, nil } } return nil, fmt.Errorf("account %q does not exist", name) } func readPassword(acct *config.Account) error { if acct.Password != "" { return nil } 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 := term.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") } acct.Password = password return nil } func lookupHostPort(acct *config.Account) error { if acct.Port != "" { return nil } // 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(acct.Host) if err != nil { return fmt.Errorf("failed to look up service record: %s", err) } host, port, err := net.SplitHostPort(services[0]) if err != nil { return fmt.Errorf("failed to parse service record: %s", err) } acct.Host = host acct.Port = port return nil } func dialPlainAuth(acct *config.Account) (*managesieve.Client, error) { c, err := managesieve.Dial(net.JoinHostPort(acct.Host, acct.Port)) if err != nil { return nil, fmt.Errorf("failed to connect: %s", err) } // switch to a TLS connection except for localhost if acct.Host != "localhost" && acct.Host != "127.0.0.1" && acct.Host != "::1" { tlsConf := &tls.Config{ ServerName: acct.Host, InsecureSkipVerify: acct.Insecure, } if err := c.StartTLS(tlsConf); err != nil { return nil, fmt.Errorf("failed to start TLS connection: %s", err) } } auth := managesieve.PlainAuth(authzID, acct.User, acct.Password, acct.Host) if err := c.Authenticate(auth); err != nil { return nil, fmt.Errorf("failed to authenticate user %s: %s", acct.User, 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 }