mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-21 17:46:48 +00:00
GODT-1815: Start with missing gluon files
This commit is contained in:
@ -50,9 +50,8 @@ type Bridge struct {
|
||||
imapListener net.Listener
|
||||
|
||||
// smtpServer is the bridge's SMTP server.
|
||||
smtpServer *smtp.Server
|
||||
smtpBackend *smtpBackend
|
||||
smtpListener net.Listener
|
||||
smtpServer *smtp.Server
|
||||
smtpBackend *smtpBackend
|
||||
|
||||
// updater is the bridge's updater.
|
||||
updater Updater
|
||||
@ -107,7 +106,13 @@ func New(
|
||||
return nil, fmt.Errorf("failed to load TLS config: %w", err)
|
||||
}
|
||||
|
||||
imapServer, err := newIMAPServer(vault.GetGluonDir(), curVersion, tlsConfig)
|
||||
// TODO: Handle case that the gluon directory is missing!
|
||||
gluonDir, err := getGluonDir(vault)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get Gluon directory: %w", err)
|
||||
}
|
||||
|
||||
imapServer, err := newIMAPServer(gluonDir, curVersion, tlsConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create IMAP server: %w", err)
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package bridge_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
@ -282,6 +283,31 @@ func TestBridge_BadVaultKey(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestBridge_MissingGluonDir(t *testing.T) {
|
||||
withEnv(t, func(ctx context.Context, s *server.Server, dialer *bridge.TestDialer, locator bridge.Locator, vaultKey []byte) {
|
||||
var gluonDir string
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), dialer, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
_, err := bridge.LoginUser(context.Background(), username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Move the gluon dir.
|
||||
bridge.SetGluonDir(ctx, t.TempDir())
|
||||
|
||||
// Get the gluon dir.
|
||||
gluonDir = bridge.GetGluonDir()
|
||||
})
|
||||
|
||||
// The user removes the gluon dir while bridge is not running.
|
||||
require.NoError(t, os.RemoveAll(gluonDir))
|
||||
|
||||
// Bridge starts but can't find the gluon dir; there should be no error.
|
||||
withBridge(t, ctx, s.GetHostURL(), dialer, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// ...
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// withEnv creates the full test environment and runs the tests.
|
||||
func withEnv(t *testing.T, tests func(ctx context.Context, server *server.Server, dialer *bridge.TestDialer, locator bridge.Locator, vaultKey []byte)) {
|
||||
// Create test API.
|
||||
@ -305,7 +331,7 @@ func withEnv(t *testing.T, tests func(ctx context.Context, server *server.Server
|
||||
ctx,
|
||||
server,
|
||||
bridge.NewTestDialer(),
|
||||
locations.New(bridge.NewTestLocationsProvider(t), "config-name"),
|
||||
locations.New(bridge.NewTestLocationsProvider(t.TempDir()), "config-name"),
|
||||
vaultKey,
|
||||
)
|
||||
}
|
||||
|
||||
@ -3,12 +3,16 @@ package bridge
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/ProtonMail/gluon"
|
||||
imapEvents "github.com/ProtonMail/gluon/events"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/constants"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/vault"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@ -17,38 +21,6 @@ const (
|
||||
defaultClientVersion = "0.0.1"
|
||||
)
|
||||
|
||||
func (bridge *Bridge) GetIMAPPort() int {
|
||||
return bridge.vault.GetIMAPPort()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) SetIMAPPort(newPort int) error {
|
||||
if newPort == bridge.vault.GetIMAPPort() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := bridge.vault.SetIMAPPort(newPort); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bridge.restartIMAP(context.Background())
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetIMAPSSL() bool {
|
||||
return bridge.vault.GetIMAPSSL()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) SetIMAPSSL(newSSL bool) error {
|
||||
if newSSL == bridge.vault.GetIMAPSSL() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := bridge.vault.SetIMAPSSL(newSSL); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bridge.restartIMAP(context.Background())
|
||||
}
|
||||
|
||||
func (bridge *Bridge) serveIMAP() error {
|
||||
imapListener, err := newListener(bridge.vault.GetIMAPPort(), bridge.vault.GetIMAPSSL(), bridge.tlsConfig)
|
||||
if err != nil {
|
||||
@ -83,15 +55,34 @@ func (bridge *Bridge) closeIMAP(ctx context.Context) error {
|
||||
func (bridge *Bridge) handleIMAPEvent(event imapEvents.Event) {
|
||||
switch event := event.(type) {
|
||||
case imapEvents.SessionAdded:
|
||||
if !bridge.identifier.HasClient() {
|
||||
bridge.identifier.SetClient(defaultClientName, defaultClientVersion)
|
||||
if bridge.identifier.HasClient() {
|
||||
return
|
||||
}
|
||||
|
||||
bridge.identifier.SetClient(defaultClientName, defaultClientVersion)
|
||||
|
||||
case imapEvents.IMAPID:
|
||||
bridge.identifier.SetClient(event.IMAPID.Name, event.IMAPID.Version)
|
||||
}
|
||||
}
|
||||
|
||||
func getGluonDir(encVault *vault.Vault) (string, error) {
|
||||
empty, err := isEmpty(encVault.GetGluonDir())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to check if gluon dir is empty: %w", err)
|
||||
}
|
||||
|
||||
if empty {
|
||||
if err := encVault.ForUser(func(user *vault.User) error {
|
||||
return user.SetSync(false)
|
||||
}); err != nil {
|
||||
return "", fmt.Errorf("failed to reset user sync status: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return encVault.GetGluonDir(), nil
|
||||
}
|
||||
|
||||
func newIMAPServer(gluonDir string, version *semver.Version, tlsConfig *tls.Config) (*gluon.Server, error) {
|
||||
imapServer, err := gluon.New(
|
||||
gluon.WithTLS(tlsConfig),
|
||||
@ -115,3 +106,20 @@ func newIMAPServer(gluonDir string, version *semver.Version, tlsConfig *tls.Conf
|
||||
|
||||
return imapServer, nil
|
||||
}
|
||||
|
||||
func isEmpty(dir string) (bool, error) {
|
||||
if _, err := os.Stat(dir); err != nil {
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
return false, fmt.Errorf("failed to stat %s: %w", dir, err)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to read dir %s: %w", dir, err)
|
||||
}
|
||||
|
||||
return len(entries) == 0, nil
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
@ -75,10 +76,20 @@ type TestLocationsProvider struct {
|
||||
config, cache string
|
||||
}
|
||||
|
||||
func NewTestLocationsProvider(tb testing.TB) *TestLocationsProvider {
|
||||
func NewTestLocationsProvider(dir string) *TestLocationsProvider {
|
||||
config, err := os.MkdirTemp(dir, "config")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cache, err := os.MkdirTemp(dir, "cache")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &TestLocationsProvider{
|
||||
config: tb.TempDir(),
|
||||
cache: tb.TempDir(),
|
||||
config: config,
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,70 @@ func (bridge *Bridge) SetKeychainApp(helper string) error {
|
||||
return vault.SetHelper(vaultDir, helper)
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetIMAPPort() int {
|
||||
return bridge.vault.GetIMAPPort()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) SetIMAPPort(newPort int) error {
|
||||
if newPort == bridge.vault.GetIMAPPort() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := bridge.vault.SetIMAPPort(newPort); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bridge.restartIMAP(context.Background())
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetIMAPSSL() bool {
|
||||
return bridge.vault.GetIMAPSSL()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) SetIMAPSSL(newSSL bool) error {
|
||||
if newSSL == bridge.vault.GetIMAPSSL() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := bridge.vault.SetIMAPSSL(newSSL); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bridge.restartIMAP(context.Background())
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetSMTPPort() int {
|
||||
return bridge.vault.GetSMTPPort()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) SetSMTPPort(newPort int) error {
|
||||
if newPort == bridge.vault.GetSMTPPort() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := bridge.vault.SetSMTPPort(newPort); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bridge.restartSMTP()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetSMTPSSL() bool {
|
||||
return bridge.vault.GetSMTPSSL()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) SetSMTPSSL(newSSL bool) error {
|
||||
if newSSL == bridge.vault.GetSMTPSSL() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := bridge.vault.SetSMTPSSL(newSSL); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bridge.restartSMTP()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetGluonDir() string {
|
||||
return bridge.vault.GetGluonDir()
|
||||
}
|
||||
|
||||
@ -10,48 +10,14 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (bridge *Bridge) GetSMTPPort() int {
|
||||
return bridge.vault.GetSMTPPort()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) SetSMTPPort(newPort int) error {
|
||||
if newPort == bridge.vault.GetSMTPPort() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := bridge.vault.SetSMTPPort(newPort); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bridge.restartSMTP()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetSMTPSSL() bool {
|
||||
return bridge.vault.GetSMTPSSL()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) SetSMTPSSL(newSSL bool) error {
|
||||
if newSSL == bridge.vault.GetSMTPSSL() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := bridge.vault.SetSMTPSSL(newSSL); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bridge.restartSMTP()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) serveSMTP() error {
|
||||
smtpListener, err := newListener(bridge.vault.GetSMTPPort(), bridge.vault.GetSMTPSSL(), bridge.tlsConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create SMTP listener: %w", err)
|
||||
}
|
||||
|
||||
bridge.smtpListener = smtpListener
|
||||
|
||||
go func() {
|
||||
if err := bridge.smtpServer.Serve(bridge.smtpListener); err != nil {
|
||||
if err := bridge.smtpServer.Serve(smtpListener); err != nil {
|
||||
logrus.WithError(err).Error("SMTP server stopped")
|
||||
}
|
||||
}()
|
||||
|
||||
@ -308,7 +308,7 @@ func (bridge *Bridge) addNewUser(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := vaultUser.UpdateGluonData(gluonID, gluonKey); err != nil {
|
||||
if err := vaultUser.SetGluonAuth(gluonID, gluonKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -336,11 +336,11 @@ func (bridge *Bridge) addExistingUser(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := vaultUser.UpdateAuth(authUID, authRef); err != nil {
|
||||
if err := vaultUser.SetAuth(authUID, authRef); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := vaultUser.UpdateKeyPass(saltedKeyPass); err != nil {
|
||||
if err := vaultUser.SetKeyPass(saltedKeyPass); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user