Files
protonmail-bridge-docker/http_rest_frontend/cli/frontend.go
2022-05-28 17:28:20 +08:00

162 lines
4.8 KiB
Go

// Package cli provides HTTP interface of the bridge
package cli
import (
"context"
"fmt"
"net/http"
"os"
"strings"
"github.com/ProtonMail/proton-bridge/internal/config/settings"
"github.com/ProtonMail/proton-bridge/internal/events"
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
"github.com/ProtonMail/proton-bridge/internal/locations"
"github.com/ProtonMail/proton-bridge/internal/updater"
"github.com/ProtonMail/proton-bridge/pkg/listener"
"github.com/julienschmidt/httprouter"
"github.com/sirupsen/logrus"
)
type frontendCLI struct {
*httprouter.Router
locations *locations.Locations
settings *settings.Settings
eventListener listener.Listener
updater types.Updater
bridge types.Bridger
restarter types.Restarter
}
func New(
panicHandler types.PanicHandler,
locations *locations.Locations,
settings *settings.Settings,
eventListener listener.Listener,
updater types.Updater,
bridge types.Bridger,
restarter types.Restarter,
) *frontendCLI {
fe := &frontendCLI{
Router: httprouter.New(),
locations: locations,
settings: settings,
eventListener: eventListener,
updater: updater,
bridge: bridge,
restarter: restarter,
}
fe.PUT("/accounts", fe.loginAccount)
fe.GET("/accounts", fe.listAccounts)
fe.GET("/accounts/:account", fe.showAccountInfo)
fe.DELETE("/accounts/:account", fe.deleteAccount)
return fe
}
func (f *frontendCLI) loginWithEnv() {
if len(f.bridge.GetUsers()) > 0 {
fmt.Println("More than 0 accounts found. Skip auto login.")
return
}
username := os.Getenv("PROTON_USERNAME")
password := os.Getenv("PROTON_PASSWORD")
if username == "" {
logrus.Info("PROTON_USERNAME and PROTON_PASSWORD are not set. Skip auto login.")
return
}
client, auth, err := f.bridge.Login(username, []byte(password))
if err != nil {
f.processAPIError(err)
logrus.WithError(err).Warn("Login failed.")
return
}
if auth.HasTwoFactor() {
twoFactor := os.Getenv("PROTON_2FA")
if twoFactor == "" {
logrus.Warn("Login failed: 2FA enabled for the account but PROTON_2FA was not set.")
return
}
err = client.Auth2FA(context.Background(), twoFactor)
if err != nil {
f.processAPIError(err)
logrus.WithError(err).Warn("Login failed.")
return
}
}
mailboxPassword := password
if auth.HasMailboxPassword() {
mailboxPassword = os.Getenv("PROTON_MAILBOX_PASSWORD")
if mailboxPassword == "" {
logrus.Warn("Login failed: Two password mode enabled but PROTON_MAILBOX_PASSWORD was not set.")
return
}
}
user, err := f.bridge.FinishLogin(client, auth, []byte(mailboxPassword))
if err != nil {
f.processAPIError(err)
logrus.WithError(err).Warn("Login failed.")
return
}
logrus.Infof("Account %s was added successfully.\n", user.Username())
if strings.ToLower(os.Getenv("PROTON_PRINT_ACCOUNT_INFO")) != "off" {
f.printAccountInfo(os.Stdout, user)
}
}
func (f *frontendCLI) watchEvents() {
errorCh := f.eventListener.ProvideChannel(events.ErrorEvent)
credentialsErrorCh := f.eventListener.ProvideChannel(events.CredentialsErrorEvent)
internetOffCh := f.eventListener.ProvideChannel(events.InternetOffEvent)
internetOnCh := f.eventListener.ProvideChannel(events.InternetOnEvent)
addressChangedCh := f.eventListener.ProvideChannel(events.AddressChangedEvent)
addressChangedLogoutCh := f.eventListener.ProvideChannel(events.AddressChangedLogoutEvent)
logoutCh := f.eventListener.ProvideChannel(events.LogoutEvent)
certIssue := f.eventListener.ProvideChannel(events.TLSCertIssue)
for {
select {
case errorDetails := <-errorCh:
fmt.Println("Bridge failed:", errorDetails)
case <-credentialsErrorCh:
f.notifyCredentialsError()
case <-internetOffCh:
f.notifyInternetOff()
case <-internetOnCh:
f.notifyInternetOn()
case address := <-addressChangedCh:
fmt.Printf("Address changed for %s. You may need to reconfigure your email client.", address)
case address := <-addressChangedLogoutCh:
f.notifyLogout(address)
case userID := <-logoutCh:
user, err := f.bridge.GetUser(userID)
if err != nil {
return
}
f.notifyLogout(user.Username())
case <-certIssue:
f.notifyCertIssue()
}
}
}
func (f *frontendCLI) Loop() error {
f.loginWithEnv()
managementPort := os.Getenv("PROTON_MANAGEMENT_PORT")
if managementPort == "" {
managementPort = "1080"
}
http.ListenAndServe(":"+managementPort, f)
return nil
}
func (f *frontendCLI) NotifyManualUpdate(update updater.VersionInfo, canInstall bool) {}
func (f *frontendCLI) WaitUntilFrontendIsReady() {}
func (f *frontendCLI) SetVersion(version updater.VersionInfo) {}
func (f *frontendCLI) NotifySilentUpdateInstalled() {}
func (f *frontendCLI) NotifySilentUpdateError(err error) {}