cfg: Add account management

Fix #3
create-reload-action
Lukasz Janyst 4 years ago
parent a849028b94
commit f0089a94cb
No known key found for this signature in database
GPG Key ID: 32DE641041F17A9A
  1. 164
      cmd/peroxide-cfg/accounts.go
  2. 32
      cmd/peroxide-cfg/main.go

@ -0,0 +1,164 @@
// Copyright (c) 2022 Lukasz Janyst <lukasz@jany.st>
//
// This file is part of Peroxide.
//
// Peroxide is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Peroxide is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Peroxide. If not, see <https://www.gnu.org/licenses/>.
package main
import (
"bufio"
"context"
"fmt"
"os"
"github.com/mattn/go-isatty"
"golang.org/x/crypto/ssh/terminal"
"github.com/ljanyst/peroxide/pkg/bridge"
"github.com/ljanyst/peroxide/pkg/users"
)
func askPass(prompt string) ([]byte, error) {
f := os.Stdin
if !isatty.IsTerminal(f.Fd()) {
// This can happen if stdin is used for piping data
var err error
if f, err = os.Open("/dev/tty"); err != nil {
return nil, err
}
defer f.Close()
}
fmt.Fprintf(os.Stderr, "%v: ", prompt)
b, err := terminal.ReadPassword(int(f.Fd()))
if err == nil {
fmt.Fprintf(os.Stderr, "\n")
}
return b, err
}
func listAccounts(b *bridge.Bridge) {
spacing := "%3d: %-20s %-20s %-15s %-15s "
for idx, user := range b.Users.GetUsers() {
connected := "disconnected"
if user.IsConnected() {
connected = "connected"
}
mode := "split"
if user.IsCombinedAddressMode() {
mode = "combined"
}
fmt.Printf(spacing, idx, user.Username(), user.GetPrimaryAddress(), connected, mode)
for _, address := range user.GetAddresses() {
fmt.Printf("%-20s", address)
}
fmt.Println()
}
}
func deleteAccount(b *bridge.Bridge, accountName string) error {
if accountName == "" {
return fmt.Errorf("Missing account name")
}
userArr := b.Users.GetUsers()
if len(userArr) == 0 {
return fmt.Errorf("No registered user accounts")
}
var user *users.User
for _, u := range userArr {
if u.Username() == accountName {
user = u
break
}
}
if user == nil {
return fmt.Errorf("Account %s not found", accountName)
}
if err := user.Logout(); err != nil {
return fmt.Errorf("Logout of account %s failed: %s", accountName, err)
}
if err := b.Users.DeleteUser(user.ID(), true); err != nil {
return fmt.Errorf("Deletion of account %s failed: %s", accountName, err)
}
return nil
}
func addAccount(b *bridge.Bridge, accountName string) error {
if accountName == "" {
return fmt.Errorf("Missing account name")
}
password, err := askPass("Password")
if err != nil {
return fmt.Errorf("Unable to read password: %s", err)
}
if len(password) == 0 {
return fmt.Errorf("Empty password")
}
fmt.Printf("Authenticating %s...\n", accountName)
client, auth, err := b.Users.Login(accountName, password)
if err != nil {
return fmt.Errorf("Login of account %s failed: %s", accountName, err)
}
if auth.HasTwoFactor() {
scanner := bufio.NewScanner(os.Stdin)
fmt.Printf("2FA TOTP code: ")
scanner.Scan()
code := scanner.Text()
if code == "" {
return fmt.Errorf("Empty 2FA TOTP code")
}
err = client.Auth2FA(context.Background(), code)
if err != nil {
return fmt.Errorf("2FA of account %s failed: %s", accountName, err)
}
}
mailboxPassword := password
if auth.HasMailboxPassword() {
mailboxPassword, err = askPass("Mailbox password: ")
if err != nil {
return fmt.Errorf("Unable to read mailbox password: %s", err)
}
}
if len(mailboxPassword) == 0 {
return fmt.Errorf("Empty mailbox password")
}
user, err := b.Users.FinishLogin(client, auth, mailboxPassword)
if err != nil {
return fmt.Errorf("Login of account %s failed: %s", accountName, err)
}
fmt.Printf("Account %s has been added successfully.\n", user.Username())
return nil
}

@ -24,14 +24,23 @@ import (
"fmt"
"io"
"os"
"github.com/ljanyst/peroxide/pkg/bridge"
"github.com/ljanyst/peroxide/pkg/files"
"github.com/sirupsen/logrus"
)
var config = flag.String("config", files.ExpandTilde("~/.config/protonmail/bridge/prefs.json"), "configuration file")
var genKey = flag.Bool("gen-key", false, "generate a random key for the encryption of credentials")
var genX509 = flag.Bool("gen-x509", false, "generate a self-signed X509 certificate")
var x509Org = flag.String("x509-org", "", "organization name to be used in X509 certificate")
var x509Cn = flag.String("x509-cn", "", "common name to be used in X509 certificate")
var x509KeyFile = flag.String("x509-key", "key.pem", "output file for the RSA key")
var x509CertFile = flag.String("x509-cert", "cert.pem", "output file for the X509 certificate")
var list = flag.Bool("list-accounts", false, "list user accounts")
var delete = flag.Bool("delete-account", false, "delete user account")
var add = flag.Bool("add-account", false, "add user account")
var name = flag.String("name", "", "account name")
func main() {
flag.Parse()
@ -52,6 +61,29 @@ func main() {
os.Exit(1)
}
done = true
} else {
b := &bridge.Bridge{}
err := b.Configure(*config)
if err != nil {
logrus.WithError(err).Fatal("Failed to configure the bridge")
}
if *list {
listAccounts(b)
done = true
} else if *delete {
err = deleteAccount(b, *name)
done = true
} else if *add {
err = addAccount(b, *name)
done = true
}
if err != nil {
logrus.WithError(err).Fatal("Failed to execute command")
os.Exit(1)
}
}
if !done {

Loading…
Cancel
Save