mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 04:36:43 +00:00
GODT-1816: Connect Gluon Logs to bridge Logs
Ensure the IMAP commands and SMTP commands are logged to trace channels with an entry so they are recognizable as before.
This commit is contained in:
committed by
James Houlahan
parent
03e14154a6
commit
f01c70e506
@ -32,6 +32,9 @@ const (
|
||||
|
||||
flagNoWindow = "no-window"
|
||||
flagNonInteractive = "non-interactive"
|
||||
|
||||
flagLogIMAP = "log-imap"
|
||||
flagLogSMTP = "log-smtp"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -69,6 +72,14 @@ func New() *cli.App {
|
||||
Usage: "Don't show window after start",
|
||||
Hidden: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: flagLogIMAP,
|
||||
Usage: "Enable logging of IMAP communications (all|client|server) (may contain decrypted data!)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: flagLogSMTP,
|
||||
Usage: "Enable logging of SMTP communications (may contain decrypted data!)",
|
||||
},
|
||||
}
|
||||
|
||||
app.Action = run
|
||||
@ -124,7 +135,7 @@ func run(c *cli.Context) error {
|
||||
}
|
||||
|
||||
// Create the bridge.
|
||||
bridge, err := newBridge(locations, identifier)
|
||||
bridge, err := newBridge(c, locations, identifier)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create bridge: %w", err)
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package app
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/urfave/cli/v2"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
@ -25,7 +26,7 @@ import (
|
||||
|
||||
const vaultSecretName = "bridge-vault-key"
|
||||
|
||||
func newBridge(locations *locations.Locations, identifier *useragent.UserAgent) (*bridge.Bridge, error) {
|
||||
func newBridge(c *cli.Context, locations *locations.Locations, identifier *useragent.UserAgent) (*bridge.Bridge, error) {
|
||||
// Create the underlying dialer used by the bridge.
|
||||
// It only connects to trusted servers and reports any untrusted servers it finds.
|
||||
pinningDialer := dialer.NewPinningTLSDialer(
|
||||
@ -92,6 +93,9 @@ func newBridge(locations *locations.Locations, identifier *useragent.UserAgent)
|
||||
autostarter,
|
||||
updater,
|
||||
version,
|
||||
c.String(flagLogIMAP) == "client" || c.String(flagLogIMAP) == "all",
|
||||
c.String(flagLogIMAP) == "server" || c.String(flagLogIMAP) == "all",
|
||||
c.Bool(flagLogSMTP),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create bridge: %w", err)
|
||||
|
||||
@ -72,20 +72,27 @@ type Bridge struct {
|
||||
|
||||
// stopCh is used to stop ongoing goroutines when the bridge is closed.
|
||||
stopCh chan struct{}
|
||||
|
||||
logIMAPClientCommands bool
|
||||
logIMAPServerCommands bool
|
||||
logSMTPCommands bool
|
||||
}
|
||||
|
||||
// New creates a new bridge.
|
||||
func New(
|
||||
apiURL string, // the URL of the API to use
|
||||
locator Locator, // the locator to provide paths to store data
|
||||
vault *vault.Vault, // the bridge's encrypted data store
|
||||
identifier Identifier, // the identifier to keep track of the user agent
|
||||
tlsReporter TLSReporter, // the TLS reporter to report TLS errors
|
||||
apiURL string, // the URL of the API to use
|
||||
locator Locator, // the locator to provide paths to store data
|
||||
vault *vault.Vault, // the bridge's encrypted data store
|
||||
identifier Identifier, // the identifier to keep track of the user agent
|
||||
tlsReporter TLSReporter, // the TLS reporter to report TLS errors
|
||||
roundTripper http.RoundTripper, // the round tripper to use for API requests
|
||||
proxyCtl ProxyController, // the DoH controller
|
||||
autostarter Autostarter, // the autostarter to manage autostart settings
|
||||
updater Updater, // the updater to fetch and install updates
|
||||
curVersion *semver.Version, // the current version of the bridge
|
||||
proxyCtl ProxyController, // the DoH controller
|
||||
autostarter Autostarter, // the autostarter to manage autostart settings
|
||||
updater Updater, // the updater to fetch and install updates
|
||||
curVersion *semver.Version, // the current version of the bridge
|
||||
logIMAPClientCommands bool,
|
||||
logIMAPServerCommands bool,
|
||||
logSMTPCommands bool,
|
||||
) (*Bridge, error) {
|
||||
if vault.GetProxyAllowed() {
|
||||
proxyCtl.AllowProxy()
|
||||
@ -116,7 +123,7 @@ func New(
|
||||
return nil, fmt.Errorf("failed to get Gluon directory: %w", err)
|
||||
}
|
||||
|
||||
imapServer, err := newIMAPServer(gluonDir, curVersion, tlsConfig)
|
||||
imapServer, err := newIMAPServer(gluonDir, curVersion, tlsConfig, logIMAPClientCommands, logIMAPServerCommands)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create IMAP server: %w", err)
|
||||
}
|
||||
@ -126,7 +133,7 @@ func New(
|
||||
return nil, fmt.Errorf("failed to create SMTP backend: %w", err)
|
||||
}
|
||||
|
||||
smtpServer, err := newSMTPServer(smtpBackend, tlsConfig)
|
||||
smtpServer, err := newSMTPServer(smtpBackend, tlsConfig, logSMTPCommands)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create SMTP server: %w", err)
|
||||
}
|
||||
@ -159,6 +166,10 @@ func New(
|
||||
locator: locator,
|
||||
|
||||
stopCh: make(chan struct{}),
|
||||
|
||||
logIMAPClientCommands: logIMAPClientCommands,
|
||||
logIMAPServerCommands: logIMAPServerCommands,
|
||||
logSMTPCommands: logSMTPCommands,
|
||||
}
|
||||
|
||||
api.AddStatusObserver(func(status liteapi.Status) {
|
||||
|
||||
@ -426,6 +426,9 @@ func withBridge(
|
||||
mocks.Autostarter,
|
||||
mocks.Updater,
|
||||
v2_3_0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@ -5,6 +5,8 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/logging"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net"
|
||||
"os"
|
||||
@ -111,7 +113,29 @@ func getGluonDir(encVault *vault.Vault) (string, error) {
|
||||
return encVault.GetGluonDir(), nil
|
||||
}
|
||||
|
||||
func newIMAPServer(gluonDir string, version *semver.Version, tlsConfig *tls.Config) (*gluon.Server, error) {
|
||||
func newIMAPServer(gluonDir string, version *semver.Version, tlsConfig *tls.Config, logIMAPCommandsClient, logImapCommandsServer bool) (*gluon.Server, error) {
|
||||
var imapClientLog io.Writer
|
||||
var imapServerLog io.Writer
|
||||
|
||||
if logIMAPCommandsClient || logImapCommandsServer {
|
||||
log := logrus.WithField("protocol", "IMAP")
|
||||
log.Warning("================================================")
|
||||
log.Warning("THIS LOG WILL CONTAIN **DECRYPTED** MESSAGE DATA")
|
||||
log.Warning("================================================")
|
||||
}
|
||||
|
||||
if logIMAPCommandsClient {
|
||||
imapClientLog = logging.NewIMAPLogger()
|
||||
} else {
|
||||
imapClientLog = io.Discard
|
||||
}
|
||||
|
||||
if logImapCommandsServer {
|
||||
imapServerLog = logging.NewIMAPLogger()
|
||||
} else {
|
||||
imapClientLog = io.Discard
|
||||
}
|
||||
|
||||
imapServer, err := gluon.New(
|
||||
gluon.WithTLS(tlsConfig),
|
||||
gluon.WithDataDir(gluonDir),
|
||||
@ -124,8 +148,8 @@ func newIMAPServer(gluonDir string, version *semver.Version, tlsConfig *tls.Conf
|
||||
"TODO",
|
||||
),
|
||||
gluon.WithLogger(
|
||||
logrus.StandardLogger().WriterLevel(logrus.TraceLevel),
|
||||
logrus.StandardLogger().WriterLevel(logrus.TraceLevel),
|
||||
imapClientLog,
|
||||
imapServerLog,
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@ -112,7 +112,7 @@ func (bridge *Bridge) SetGluonDir(ctx context.Context, newGluonDir string) error
|
||||
return fmt.Errorf("failed to set new gluon dir: %w", err)
|
||||
}
|
||||
|
||||
imapServer, err := newIMAPServer(bridge.vault.GetGluonDir(), bridge.curVersion, bridge.tlsConfig)
|
||||
imapServer, err := newIMAPServer(bridge.vault.GetGluonDir(), bridge.curVersion, bridge.tlsConfig, bridge.logIMAPClientCommands, bridge.logIMAPServerCommands)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create new IMAP server: %w", err)
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package bridge
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/logging"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
@ -48,7 +49,7 @@ func (bridge *Bridge) restartSMTP() error {
|
||||
return err
|
||||
}
|
||||
|
||||
smtpServer, err := newSMTPServer(bridge.smtpBackend, bridge.tlsConfig)
|
||||
smtpServer, err := newSMTPServer(bridge.smtpBackend, bridge.tlsConfig, bridge.logSMTPCommands)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -68,13 +69,22 @@ func (bridge *Bridge) closeSMTP() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func newSMTPServer(smtpBackend *smtpBackend, tlsConfig *tls.Config) (*smtp.Server, error) {
|
||||
func newSMTPServer(smtpBackend *smtpBackend, tlsConfig *tls.Config, shouldLog bool) (*smtp.Server, error) {
|
||||
smtpServer := smtp.NewServer(smtpBackend)
|
||||
|
||||
smtpServer.TLSConfig = tlsConfig
|
||||
smtpServer.Domain = constants.Host
|
||||
smtpServer.AllowInsecureAuth = true
|
||||
smtpServer.MaxLineLength = 1 << 16
|
||||
smtpServer.ErrorLog = logging.NewSMTPLogger()
|
||||
|
||||
if shouldLog {
|
||||
log := logrus.WithField("protocol", "SMTP")
|
||||
log.Warning("================================================")
|
||||
log.Warning("THIS LOG WILL CONTAIN **DECRYPTED** MESSAGE DATA")
|
||||
log.Warning("================================================")
|
||||
smtpServer.Debug = logging.NewSMTPDebugLogger()
|
||||
}
|
||||
|
||||
smtpServer.EnableAuth(sasl.Login, func(conn *smtp.Conn) sasl.Server {
|
||||
return sasl.NewLoginServer(func(address, password string) error {
|
||||
|
||||
16
internal/logging/imap_logger.go
Normal file
16
internal/logging/imap_logger.go
Normal file
@ -0,0 +1,16 @@
|
||||
package logging
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// IMAPLogger implements the writer interface for Gluon IMAP logs
|
||||
type IMAPLogger struct {
|
||||
l *logrus.Entry
|
||||
}
|
||||
|
||||
func NewIMAPLogger() *IMAPLogger {
|
||||
return &IMAPLogger{l: logrus.WithField("pkg", "IMAP")}
|
||||
}
|
||||
|
||||
func (l *IMAPLogger) Write(p []byte) (n int, err error) {
|
||||
return l.l.WriterLevel(logrus.TraceLevel).Write(p)
|
||||
}
|
||||
35
internal/logging/smtp_logger.go
Normal file
35
internal/logging/smtp_logger.go
Normal file
@ -0,0 +1,35 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// SMTPErrorLogger implements go-smtp/logger interface.
|
||||
type SMTPErrorLogger struct {
|
||||
l *logrus.Entry
|
||||
}
|
||||
|
||||
func NewSMTPLogger() *SMTPErrorLogger {
|
||||
return &SMTPErrorLogger{l: logrus.WithField("pkg", "SMTP")}
|
||||
}
|
||||
|
||||
func (s *SMTPErrorLogger) Printf(format string, args ...interface{}) {
|
||||
s.l.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func (s *SMTPErrorLogger) Println(args ...interface{}) {
|
||||
s.l.Errorln(args...)
|
||||
}
|
||||
|
||||
// SMTPDebugLogger implements the writer interface for debug SMTP logs
|
||||
type SMTPDebugLogger struct {
|
||||
l *logrus.Entry
|
||||
}
|
||||
|
||||
func NewSMTPDebugLogger() *SMTPDebugLogger {
|
||||
return &SMTPDebugLogger{l: logrus.WithField("pkg", "SMTP")}
|
||||
}
|
||||
|
||||
func (l *SMTPDebugLogger) Write(p []byte) (n int, err error) {
|
||||
return l.l.WriterLevel(logrus.TraceLevel).Write(p)
|
||||
}
|
||||
@ -48,6 +48,9 @@ func (t *testCtx) startBridge() error {
|
||||
t.mocks.Autostarter,
|
||||
t.mocks.Updater,
|
||||
t.version,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user