parent
a849028b94
commit
f0089a94cb
2 changed files with 196 additions and 0 deletions
@ -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 |
||||
} |
||||
Loading…
Reference in new issue