forked from Silverfish/proton-bridge
Other: Linter fixes after bumping linter version
This commit is contained in:
4
Makefile
4
Makefile
@ -218,10 +218,10 @@ change-copyright-year:
|
||||
./utils/missing_license.sh change-year
|
||||
|
||||
test: gofiles
|
||||
go test -v -failfast -count=1 -p=1 -coverprofile=/tmp/coverage.out -run=${TESTRUN} ./internal/... ./pkg/...
|
||||
go test -v -coverprofile=/tmp/coverage.out -run=${TESTRUN} ./internal/... ./pkg/...
|
||||
|
||||
test-integration: gofiles
|
||||
go test -v -failfast -count=1 -p=1 github.com/ProtonMail/proton-bridge/v2/tests
|
||||
go test -v github.com/ProtonMail/proton-bridge/v2/tests
|
||||
|
||||
bench:
|
||||
go test -run '^$$' -bench=. -memprofile bench_mem.pprof -cpuprofile bench_cpu.pprof ./internal/store
|
||||
|
||||
2
go.mod
2
go.mod
@ -38,7 +38,7 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/urfave/cli/v2 v2.16.3
|
||||
gitlab.protontech.ch/go/liteapi v0.33.2-0.20221011093920-6c0cf0847bcf
|
||||
gitlab.protontech.ch/go/liteapi v0.33.2-0.20221011164043-97f5d601ba2b
|
||||
golang.org/x/exp v0.0.0-20220921164117-439092de6870
|
||||
golang.org/x/net v0.1.0
|
||||
golang.org/x/sys v0.1.0
|
||||
|
||||
4
go.sum
4
go.sum
@ -397,8 +397,8 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsr
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zclconf/go-cty v1.11.0 h1:726SxLdi2SDnjY+BStqB9J1hNp4+2WlzyXLuimibIe0=
|
||||
github.com/zclconf/go-cty v1.11.0/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA=
|
||||
gitlab.protontech.ch/go/liteapi v0.33.2-0.20221011093920-6c0cf0847bcf h1:WBUv+vl0zTc+VEWied2YDv/HmLwjAMxqsqzNBoT7d4Y=
|
||||
gitlab.protontech.ch/go/liteapi v0.33.2-0.20221011093920-6c0cf0847bcf/go.mod h1:NfsxXn1T81sz0gHnxuAfyCI4Agzm5UWVRyEtdQSch/4=
|
||||
gitlab.protontech.ch/go/liteapi v0.33.2-0.20221011164043-97f5d601ba2b h1:9bTndevIV9WTSbRsoLXmLj8bycla6O3KU7fFzEV09n0=
|
||||
gitlab.protontech.ch/go/liteapi v0.33.2-0.20221011164043-97f5d601ba2b/go.mod h1:NfsxXn1T81sz0gHnxuAfyCI4Agzm5UWVRyEtdQSch/4=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// Package bridge implements the Bridge, which acts as the backend to the UI.
|
||||
package bridge
|
||||
|
||||
import (
|
||||
@ -59,7 +60,7 @@ type Bridge struct {
|
||||
updateCheckCh chan struct{}
|
||||
|
||||
// focusService is used to raise the bridge window when needed.
|
||||
focusService *focus.FocusService
|
||||
focusService *focus.Service
|
||||
|
||||
// autostarter is the bridge's autostarter.
|
||||
autostarter Autostarter
|
||||
@ -70,36 +71,30 @@ type Bridge struct {
|
||||
// errors contains errors encountered during startup.
|
||||
errors []error
|
||||
|
||||
// These control the bridge's IMAP and SMTP logging behaviour.
|
||||
logIMAPClient bool
|
||||
logIMAPServer bool
|
||||
logSMTP bool
|
||||
|
||||
// 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
|
||||
logIMAPClientCommands bool,
|
||||
logIMAPServerCommands bool,
|
||||
logSMTPCommands bool,
|
||||
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
|
||||
logIMAPClient, logIMAPServer bool, // whether to log IMAP client/server activity
|
||||
logSMTP bool, // whether to log SMTP activity
|
||||
) (*Bridge, error) {
|
||||
if vault.GetProxyAllowed() {
|
||||
proxyCtl.AllowProxy()
|
||||
} else {
|
||||
proxyCtl.DisallowProxy()
|
||||
}
|
||||
|
||||
cookieJar, err := cookies.NewCookieJar(vault)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create cookie jar: %w", err)
|
||||
@ -117,25 +112,19 @@ func New(
|
||||
return nil, fmt.Errorf("failed to load TLS config: %w", err)
|
||||
}
|
||||
|
||||
// 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, logIMAPClientCommands, logIMAPServerCommands)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create IMAP server: %w", err)
|
||||
}
|
||||
|
||||
smtpBackend, err := newSMTPBackend()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create SMTP backend: %w", err)
|
||||
}
|
||||
|
||||
smtpServer, err := newSMTPServer(smtpBackend, tlsConfig, logSMTPCommands)
|
||||
imapServer, err := newIMAPServer(gluonDir, curVersion, tlsConfig, logIMAPClient, logIMAPServer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create SMTP server: %w", err)
|
||||
return nil, fmt.Errorf("failed to create IMAP server: %w", err)
|
||||
}
|
||||
|
||||
focusService, err := focus.NewService()
|
||||
@ -143,7 +132,49 @@ func New(
|
||||
return nil, fmt.Errorf("failed to create focus service: %w", err)
|
||||
}
|
||||
|
||||
bridge := &Bridge{
|
||||
bridge := newBridge(
|
||||
vault,
|
||||
api,
|
||||
cookieJar,
|
||||
proxyCtl,
|
||||
identifier,
|
||||
tlsConfig,
|
||||
imapServer,
|
||||
smtpBackend,
|
||||
updater,
|
||||
curVersion,
|
||||
focusService,
|
||||
autostarter,
|
||||
locator,
|
||||
logIMAPClient,
|
||||
logIMAPServer,
|
||||
logSMTP,
|
||||
)
|
||||
|
||||
if err := bridge.init(tlsReporter); err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize bridge: %w", err)
|
||||
}
|
||||
|
||||
return bridge, nil
|
||||
}
|
||||
|
||||
func newBridge(
|
||||
vault *vault.Vault,
|
||||
api *liteapi.Manager,
|
||||
cookieJar *cookies.Jar,
|
||||
proxyCtl ProxyController,
|
||||
identifier Identifier,
|
||||
tlsConfig *tls.Config,
|
||||
imapServer *gluon.Server,
|
||||
smtpBackend *smtpBackend,
|
||||
updater Updater,
|
||||
curVersion *semver.Version,
|
||||
focusService *focus.Service,
|
||||
autostarter Autostarter,
|
||||
locator Locator,
|
||||
logIMAPClient, logIMAPServer, logSMTP bool,
|
||||
) *Bridge {
|
||||
return &Bridge{
|
||||
vault: vault,
|
||||
users: make(map[string]*user.User),
|
||||
|
||||
@ -154,7 +185,7 @@ func New(
|
||||
|
||||
tlsConfig: tlsConfig,
|
||||
imapServer: imapServer,
|
||||
smtpServer: smtpServer,
|
||||
smtpServer: newSMTPServer(smtpBackend, tlsConfig, logSMTP),
|
||||
smtpBackend: smtpBackend,
|
||||
|
||||
updater: updater,
|
||||
@ -165,14 +196,22 @@ func New(
|
||||
autostarter: autostarter,
|
||||
locator: locator,
|
||||
|
||||
stopCh: make(chan struct{}),
|
||||
logIMAPClient: logIMAPClient,
|
||||
logIMAPServer: logIMAPServer,
|
||||
logSMTP: logSMTP,
|
||||
|
||||
logIMAPClientCommands: logIMAPClientCommands,
|
||||
logIMAPServerCommands: logIMAPServerCommands,
|
||||
logSMTPCommands: logSMTPCommands,
|
||||
stopCh: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (bridge *Bridge) init(tlsReporter TLSReporter) error {
|
||||
if bridge.vault.GetProxyAllowed() {
|
||||
bridge.proxyCtl.AllowProxy()
|
||||
} else {
|
||||
bridge.proxyCtl.DisallowProxy()
|
||||
}
|
||||
|
||||
api.AddStatusObserver(func(status liteapi.Status) {
|
||||
bridge.api.AddStatusObserver(func(status liteapi.Status) {
|
||||
switch {
|
||||
case status == liteapi.StatusUp:
|
||||
go bridge.onStatusUp()
|
||||
@ -182,17 +221,17 @@ func New(
|
||||
}
|
||||
})
|
||||
|
||||
api.AddErrorHandler(liteapi.AppVersionBadCode, func() {
|
||||
bridge.api.AddErrorHandler(liteapi.AppVersionBadCode, func() {
|
||||
bridge.publish(events.UpdateForced{})
|
||||
})
|
||||
|
||||
api.AddPreRequestHook(func(_ *resty.Client, req *resty.Request) error {
|
||||
bridge.api.AddPreRequestHook(func(_ *resty.Client, req *resty.Request) error {
|
||||
req.SetHeader("User-Agent", bridge.identifier.GetUserAgent())
|
||||
return nil
|
||||
})
|
||||
|
||||
if err := bridge.loadUsers(); err != nil {
|
||||
return nil, fmt.Errorf("failed to load users: %w", err)
|
||||
return fmt.Errorf("failed to load users: %w", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
@ -202,13 +241,13 @@ func New(
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for range focusService.GetRaiseCh() {
|
||||
for range bridge.focusService.GetRaiseCh() {
|
||||
bridge.publish(events.Raise{})
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for event := range imapServer.AddWatcher() {
|
||||
for event := range bridge.imapServer.AddWatcher() {
|
||||
bridge.handleIMAPEvent(event)
|
||||
}
|
||||
}()
|
||||
@ -225,7 +264,7 @@ func New(
|
||||
bridge.PushError(ErrWatchUpdates)
|
||||
}
|
||||
|
||||
return bridge, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetEvents returns a channel of events of the given type.
|
||||
@ -363,6 +402,7 @@ func loadTLSConfig(vault *vault.Vault) (*tls.Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: Do we have to set MinVersion to tls.VersionTLS12?
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}, nil
|
||||
|
||||
@ -45,7 +45,7 @@ func init() {
|
||||
|
||||
func TestBridge_ConnStatus(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, vaultKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Get a stream of connection status events.
|
||||
eventCh, done := bridge.GetEvents(events.ConnStatusUp{}, events.ConnStatusDown{})
|
||||
defer done()
|
||||
@ -76,7 +76,7 @@ func TestBridge_ConnStatus(t *testing.T) {
|
||||
|
||||
func TestBridge_TLSIssue(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, vaultKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Get a stream of TLS issue events.
|
||||
tlsEventCh, done := bridge.GetEvents(events.TLSIssue{})
|
||||
defer done()
|
||||
@ -94,7 +94,7 @@ func TestBridge_TLSIssue(t *testing.T) {
|
||||
|
||||
func TestBridge_Focus(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, vaultKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Get a stream of TLS issue events.
|
||||
raiseCh, done := bridge.GetEvents(events.Raise{})
|
||||
defer done()
|
||||
@ -116,7 +116,7 @@ func TestBridge_UserAgent(t *testing.T) {
|
||||
calls = append(calls, call)
|
||||
})
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Set the platform to something other than the default.
|
||||
bridge.SetCurrentPlatform("platform")
|
||||
|
||||
@ -148,13 +148,13 @@ func TestBridge_Cookies(t *testing.T) {
|
||||
})
|
||||
|
||||
// Start bridge and add a user so that API assigns us a session ID via cookie.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
_, err := bridge.LoginUser(context.Background(), username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
// Start bridge again and check that it uses the same session ID.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// ...
|
||||
})
|
||||
|
||||
@ -167,7 +167,7 @@ func TestBridge_Cookies(t *testing.T) {
|
||||
|
||||
func TestBridge_CheckUpdate(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, vaultKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Disable autoupdate for this test.
|
||||
require.NoError(t, bridge.SetAutoUpdate(false))
|
||||
|
||||
@ -206,7 +206,7 @@ func TestBridge_CheckUpdate(t *testing.T) {
|
||||
|
||||
func TestBridge_AutoUpdate(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, vaultKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Enable autoupdate for this test.
|
||||
require.NoError(t, bridge.SetAutoUpdate(true))
|
||||
|
||||
@ -234,7 +234,7 @@ func TestBridge_AutoUpdate(t *testing.T) {
|
||||
|
||||
func TestBridge_ManualUpdate(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, vaultKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Disable autoupdate for this test.
|
||||
require.NoError(t, bridge.SetAutoUpdate(false))
|
||||
|
||||
@ -263,7 +263,7 @@ func TestBridge_ManualUpdate(t *testing.T) {
|
||||
|
||||
func TestBridge_ForceUpdate(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, vaultKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Get a stream of update events.
|
||||
updateCh, done := bridge.GetEvents(events.UpdateForced{})
|
||||
defer done()
|
||||
@ -286,7 +286,7 @@ func TestBridge_BadVaultKey(t *testing.T) {
|
||||
var userID string
|
||||
|
||||
// Login a user.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
newUserID, err := bridge.LoginUser(context.Background(), username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -294,17 +294,17 @@ func TestBridge_BadVaultKey(t *testing.T) {
|
||||
})
|
||||
|
||||
// Start bridge with the correct vault key -- it should load the users correctly.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
require.ElementsMatch(t, []string{userID}, bridge.GetUserIDs())
|
||||
})
|
||||
|
||||
// Start bridge with a bad vault key, the vault will be wiped and bridge will show no users.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, []byte("bad"), func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, []byte("bad"), func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
require.Empty(t, bridge.GetUserIDs())
|
||||
})
|
||||
|
||||
// Start bridge with a nil vault key, the vault will be wiped and bridge will show no users.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, nil, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, nil, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
require.Empty(t, bridge.GetUserIDs())
|
||||
})
|
||||
})
|
||||
@ -314,12 +314,12 @@ func TestBridge_MissingGluonDir(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, vaultKey []byte) {
|
||||
var gluonDir string
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, 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())
|
||||
require.NoError(t, bridge.SetGluonDir(ctx, t.TempDir()))
|
||||
|
||||
// Get the gluon dir.
|
||||
gluonDir = bridge.GetGluonDir()
|
||||
@ -329,7 +329,7 @@ func TestBridge_MissingGluonDir(t *testing.T) {
|
||||
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(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// ...
|
||||
})
|
||||
})
|
||||
@ -337,30 +337,12 @@ func TestBridge_MissingGluonDir(t *testing.T) {
|
||||
|
||||
// withTLSEnv creates the full test environment and runs the tests.
|
||||
func withTLSEnv(t *testing.T, tests func(context.Context, *server.Server, *liteapi.NetCtl, bridge.Locator, []byte)) {
|
||||
// Create test API.
|
||||
server := server.NewTLS()
|
||||
defer server.Close()
|
||||
|
||||
// Add test user.
|
||||
_, _, err := server.CreateUser(username, username+"@pm.me", password)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Generate a random vault key.
|
||||
vaultKey, err := crypto.RandomToken(32)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a context used for the test.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Create a net controller so we can simulate network connectivity issues.
|
||||
netCtl := liteapi.NewNetCtl()
|
||||
|
||||
// Create a locations object to provide temporary locations for bridge data during the test.
|
||||
locations := locations.New(bridge.NewTestLocationsProvider(t.TempDir()), "config-name")
|
||||
|
||||
// Run the tests.
|
||||
tests(ctx, server, netCtl, locations, vaultKey)
|
||||
withEnv(t, server, func(ctx context.Context, netCtl *liteapi.NetCtl, locator bridge.Locator, vaultKey []byte) {
|
||||
tests(ctx, server, netCtl, locator, vaultKey)
|
||||
})
|
||||
}
|
||||
|
||||
// withEnv creates the full test environment and runs the tests.
|
||||
@ -389,8 +371,8 @@ func withEnv(t *testing.T, server *server.Server, tests func(context.Context, *l
|
||||
|
||||
// withBridge creates a new bridge which points to the given API URL and uses the given keychain, and closes it when done.
|
||||
func withBridge(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
t *testing.T,
|
||||
apiURL string,
|
||||
netCtl *liteapi.NetCtl,
|
||||
locator bridge.Locator,
|
||||
@ -435,7 +417,7 @@ func withBridge(
|
||||
require.NoError(t, err)
|
||||
|
||||
// Close the bridge when done.
|
||||
defer bridge.Close(ctx)
|
||||
defer func() { require.NoError(t, bridge.Close(ctx)) }()
|
||||
|
||||
// Use the bridge.
|
||||
tests(bridge, mocks)
|
||||
|
||||
@ -31,7 +31,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
MaxAttachmentSize = 7 * (1 << 20) // MaxAttachmentSize 7 MB total size of all attachments.
|
||||
MaxTotalAttachmentSize = 7 * (1 << 20)
|
||||
MaxCompressedFilesCount = 6
|
||||
)
|
||||
|
||||
@ -166,7 +166,7 @@ func zipFiles(filenames []string) (io.Reader, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
buf := newLimitedBuffer(MaxAttachmentSize)
|
||||
buf := newLimitedBuffer(MaxTotalAttachmentSize)
|
||||
|
||||
w := zip.NewWriter(buf)
|
||||
defer w.Close() //nolint:errcheck
|
||||
|
||||
@ -39,17 +39,17 @@ func move(from, to string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.Open(from)
|
||||
f, err := os.Open(from) // nolint:gosec
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
c, err := os.Create(to)
|
||||
c, err := os.Create(to) // nolint:gosec
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer c.Close()
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
if err := os.Chmod(to, 0600); err != nil {
|
||||
return err
|
||||
|
||||
@ -63,7 +63,7 @@ func (bridge *Bridge) serveIMAP() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bridge *Bridge) restartIMAP(ctx context.Context) error {
|
||||
func (bridge *Bridge) restartIMAP() error {
|
||||
if err := bridge.imapListener.Close(); err != nil {
|
||||
logrus.WithError(err).Warn("Failed to close IMAP listener")
|
||||
}
|
||||
@ -73,11 +73,11 @@ func (bridge *Bridge) restartIMAP(ctx context.Context) error {
|
||||
|
||||
func (bridge *Bridge) closeIMAP(ctx context.Context) error {
|
||||
if err := bridge.imapServer.Close(ctx); err != nil {
|
||||
logrus.WithError(err).Warn("Failed to close IMAP server")
|
||||
return fmt.Errorf("failed to close IMAP server: %w", err)
|
||||
}
|
||||
|
||||
if err := bridge.imapListener.Close(); err != nil {
|
||||
logrus.WithError(err).Warn("Failed to close IMAP listener")
|
||||
return fmt.Errorf("failed to close IMAP listener: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -98,11 +98,18 @@ func (bridge *Bridge) handleIMAPEvent(event imapEvents.Event) {
|
||||
}
|
||||
|
||||
func getGluonDir(encVault *vault.Vault) (string, error) {
|
||||
empty, err := isEmpty(encVault.GetGluonDir())
|
||||
empty, exists, err := isEmpty(encVault.GetGluonDir())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to check if gluon dir is empty: %w", err)
|
||||
}
|
||||
|
||||
// TODO: Handle case that the gluon directory is missing and we can't create it!
|
||||
if !exists {
|
||||
if err := os.MkdirAll(encVault.GetGluonDir(), 0700); err != nil {
|
||||
return "", fmt.Errorf("failed to create gluon dir: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if empty {
|
||||
if err := encVault.ForUser(func(user *vault.User) error {
|
||||
return user.ClearSyncStatus()
|
||||
@ -114,27 +121,33 @@ func getGluonDir(encVault *vault.Vault) (string, error) {
|
||||
return encVault.GetGluonDir(), nil
|
||||
}
|
||||
|
||||
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 {
|
||||
func newIMAPServer(
|
||||
gluonDir string,
|
||||
version *semver.Version,
|
||||
tlsConfig *tls.Config,
|
||||
logClient, logServer bool,
|
||||
) (*gluon.Server, error) {
|
||||
if logClient || logServer {
|
||||
log := logrus.WithField("protocol", "IMAP")
|
||||
log.Warning("================================================")
|
||||
log.Warning("THIS LOG WILL CONTAIN **DECRYPTED** MESSAGE DATA")
|
||||
log.Warning("================================================")
|
||||
}
|
||||
|
||||
if logIMAPCommandsClient {
|
||||
var imapClientLog io.Writer
|
||||
|
||||
if logClient {
|
||||
imapClientLog = logging.NewIMAPLogger()
|
||||
} else {
|
||||
imapClientLog = io.Discard
|
||||
}
|
||||
|
||||
if logIMAPCommandsServer {
|
||||
var imapServerLog io.Writer
|
||||
|
||||
if logServer {
|
||||
imapServerLog = logging.NewIMAPLogger()
|
||||
} else {
|
||||
imapClientLog = io.Discard
|
||||
imapServerLog = io.Discard
|
||||
}
|
||||
|
||||
imapServer, err := gluon.New(
|
||||
@ -160,19 +173,21 @@ func newIMAPServer(gluonDir string, version *semver.Version, tlsConfig *tls.Conf
|
||||
return imapServer, nil
|
||||
}
|
||||
|
||||
func isEmpty(dir string) (bool, error) {
|
||||
// isEmpty returns whether the given directory is empty.
|
||||
// If the directory does not exist, the second return value is false.
|
||||
func isEmpty(dir string) (bool, 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 false, false, fmt.Errorf("failed to stat %s: %w", dir, err)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
return true, false, nil
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to read dir %s: %w", dir, err)
|
||||
return false, false, fmt.Errorf("failed to read dir %s: %w", dir, err)
|
||||
}
|
||||
|
||||
return len(entries) == 0, nil
|
||||
return len(entries) == 0, true, nil
|
||||
}
|
||||
|
||||
@ -94,10 +94,10 @@ func (testUpdater *TestUpdater) SetLatestVersion(version, minAuto *semver.Versio
|
||||
}
|
||||
}
|
||||
|
||||
func (updater *TestUpdater) GetVersionInfo(downloader updater.Downloader, channel updater.Channel) (updater.VersionInfo, error) {
|
||||
return updater.latest, nil
|
||||
func (testUpdater *TestUpdater) GetVersionInfo(downloader updater.Downloader, channel updater.Channel) (updater.VersionInfo, error) {
|
||||
return testUpdater.latest, nil
|
||||
}
|
||||
|
||||
func (updater *TestUpdater) InstallUpdate(downloader updater.Downloader, update updater.VersionInfo) error {
|
||||
func (testUpdater *TestUpdater) InstallUpdate(downloader updater.Downloader, update updater.VersionInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ func (bridge *Bridge) SetIMAPPort(newPort int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return bridge.restartIMAP(context.Background())
|
||||
return bridge.restartIMAP()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetIMAPSSL() bool {
|
||||
@ -56,7 +56,7 @@ func (bridge *Bridge) SetIMAPSSL(newSSL bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return bridge.restartIMAP(context.Background())
|
||||
return bridge.restartIMAP()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetSMTPPort() int {
|
||||
@ -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, bridge.logIMAPClientCommands, bridge.logIMAPServerCommands)
|
||||
imapServer, err := newIMAPServer(bridge.vault.GetGluonDir(), bridge.curVersion, bridge.tlsConfig, bridge.logIMAPClient, bridge.logIMAPServer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create new IMAP server: %w", err)
|
||||
}
|
||||
@ -193,7 +193,7 @@ func (bridge *Bridge) SetAutoUpdate(autoUpdate bool) error {
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetUpdateChannel() updater.Channel {
|
||||
return updater.Channel(bridge.vault.GetUpdateChannel())
|
||||
return bridge.vault.GetUpdateChannel()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) SetUpdateChannel(channel updater.Channel) error {
|
||||
|
||||
@ -13,7 +13,7 @@ import (
|
||||
|
||||
func TestBridge_Settings_GluonDir(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Create a user.
|
||||
_, err := bridge.LoginUser(context.Background(), username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
@ -36,7 +36,7 @@ func TestBridge_Settings_GluonDir(t *testing.T) {
|
||||
|
||||
func TestBridge_Settings_IMAPPort(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
curPort := bridge.GetIMAPPort()
|
||||
|
||||
// Set the port to 1144.
|
||||
@ -53,7 +53,7 @@ func TestBridge_Settings_IMAPPort(t *testing.T) {
|
||||
|
||||
func TestBridge_Settings_IMAPSSL(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// By default, IMAP SSL is disabled.
|
||||
require.False(t, bridge.GetIMAPSSL())
|
||||
|
||||
@ -68,7 +68,7 @@ func TestBridge_Settings_IMAPSSL(t *testing.T) {
|
||||
|
||||
func TestBridge_Settings_SMTPPort(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
curPort := bridge.GetSMTPPort()
|
||||
|
||||
// Set the port to 1024.
|
||||
@ -79,14 +79,13 @@ func TestBridge_Settings_SMTPPort(t *testing.T) {
|
||||
|
||||
// Assert that it has changed.
|
||||
require.NotEqual(t, curPort, bridge.GetSMTPPort())
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBridge_Settings_SMTPSSL(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// By default, SMTP SSL is disabled.
|
||||
require.False(t, bridge.GetSMTPSSL())
|
||||
|
||||
@ -101,7 +100,7 @@ func TestBridge_Settings_SMTPSSL(t *testing.T) {
|
||||
|
||||
func TestBridge_Settings_Proxy(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// By default, proxy is allowed.
|
||||
require.True(t, bridge.GetProxyAllowed())
|
||||
|
||||
@ -117,7 +116,7 @@ func TestBridge_Settings_Proxy(t *testing.T) {
|
||||
|
||||
func TestBridge_Settings_Autostart(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// By default, autostart is disabled.
|
||||
require.False(t, bridge.GetAutostart())
|
||||
|
||||
@ -133,7 +132,7 @@ func TestBridge_Settings_Autostart(t *testing.T) {
|
||||
|
||||
func TestBridge_Settings_FirstStart(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// By default, first start is true.
|
||||
require.True(t, bridge.GetFirstStart())
|
||||
|
||||
@ -148,7 +147,7 @@ func TestBridge_Settings_FirstStart(t *testing.T) {
|
||||
|
||||
func TestBridge_Settings_FirstStartGUI(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// By default, first start is true.
|
||||
require.True(t, bridge.GetFirstStartGUI())
|
||||
|
||||
|
||||
@ -3,10 +3,11 @@ package bridge
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/logging"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/logging"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v2/internal/constants"
|
||||
"github.com/emersion/go-sasl"
|
||||
"github.com/emersion/go-smtp"
|
||||
@ -49,12 +50,7 @@ func (bridge *Bridge) restartSMTP() error {
|
||||
return err
|
||||
}
|
||||
|
||||
smtpServer, err := newSMTPServer(bridge.smtpBackend, bridge.tlsConfig, bridge.logSMTPCommands)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bridge.smtpServer = smtpServer
|
||||
bridge.smtpServer = newSMTPServer(bridge.smtpBackend, bridge.tlsConfig, bridge.logSMTP)
|
||||
|
||||
return bridge.serveSMTP()
|
||||
}
|
||||
@ -69,7 +65,7 @@ func (bridge *Bridge) closeSMTP() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func newSMTPServer(smtpBackend *smtpBackend, tlsConfig *tls.Config, shouldLog bool) (*smtp.Server, error) {
|
||||
func newSMTPServer(smtpBackend *smtpBackend, tlsConfig *tls.Config, shouldLog bool) *smtp.Server {
|
||||
smtpServer := smtp.NewServer(smtpBackend)
|
||||
|
||||
smtpServer.TLSConfig = tlsConfig
|
||||
@ -99,5 +95,5 @@ func newSMTPServer(smtpBackend *smtpBackend, tlsConfig *tls.Config, shouldLog bo
|
||||
})
|
||||
})
|
||||
|
||||
return smtpServer, nil
|
||||
return smtpServer
|
||||
}
|
||||
|
||||
@ -44,18 +44,18 @@ func TestBridge_Sync(t *testing.T) {
|
||||
})
|
||||
|
||||
// The initial user should be fully synced.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
syncCh, done := bridge.GetEvents(events.SyncFinished{})
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
syncCh, done := chToType[events.Event, events.SyncFinished](bridge.GetEvents(events.SyncFinished{}))
|
||||
defer done()
|
||||
|
||||
userID, err := bridge.LoginUser(ctx, "imap", password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, userID, (<-syncCh).(events.SyncFinished).UserID)
|
||||
require.Equal(t, userID, (<-syncCh).UserID)
|
||||
})
|
||||
|
||||
// If we then connect an IMAP client, it should see all the messages.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
info, err := bridge.GetUserInfo(userID)
|
||||
require.NoError(t, err)
|
||||
require.True(t, info.Connected)
|
||||
@ -63,7 +63,7 @@ func TestBridge_Sync(t *testing.T) {
|
||||
client, err := client.Dial(fmt.Sprintf(":%v", bridge.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.Login("imap@pm.me", string(info.BridgePass)))
|
||||
defer client.Logout()
|
||||
defer func() { _ = client.Logout() }()
|
||||
|
||||
status, err := client.Select(`Folders/folder`, false)
|
||||
require.NoError(t, err)
|
||||
@ -71,7 +71,7 @@ func TestBridge_Sync(t *testing.T) {
|
||||
})
|
||||
|
||||
// Now let's remove the user and simulate a network error.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
require.NoError(t, bridge.DeleteUser(ctx, userID))
|
||||
})
|
||||
|
||||
@ -79,14 +79,14 @@ func TestBridge_Sync(t *testing.T) {
|
||||
netCtl.SetReadLimit(2 * read / 3)
|
||||
|
||||
// Login the user; its sync should fail.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
syncCh, done := bridge.GetEvents(events.SyncFailed{})
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
syncCh, done := chToType[events.Event, events.SyncFailed](bridge.GetEvents(events.SyncFailed{}))
|
||||
defer done()
|
||||
|
||||
userID, err := bridge.LoginUser(ctx, "imap", password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, userID, (<-syncCh).(events.SyncFailed).UserID)
|
||||
require.Equal(t, userID, (<-syncCh).UserID)
|
||||
|
||||
info, err := bridge.GetUserInfo(userID)
|
||||
require.NoError(t, err)
|
||||
@ -95,7 +95,7 @@ func TestBridge_Sync(t *testing.T) {
|
||||
client, err := client.Dial(fmt.Sprintf(":%v", bridge.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.Login("imap@pm.me", string(info.BridgePass)))
|
||||
defer client.Logout()
|
||||
defer func() { _ = client.Logout() }()
|
||||
|
||||
status, err := client.Select(`Folders/folder`, false)
|
||||
require.NoError(t, err)
|
||||
@ -107,11 +107,11 @@ func TestBridge_Sync(t *testing.T) {
|
||||
|
||||
// Login the user; its sync should now finish.
|
||||
// If we then connect an IMAP client, it should eventually see all the messages.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
syncCh, done := bridge.GetEvents(events.SyncFinished{})
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
syncCh, done := chToType[events.Event, events.SyncFinished](bridge.GetEvents(events.SyncFinished{}))
|
||||
defer done()
|
||||
|
||||
require.Equal(t, userID, (<-syncCh).(events.SyncFinished).UserID)
|
||||
require.Equal(t, userID, (<-syncCh).UserID)
|
||||
|
||||
info, err := bridge.GetUserInfo(userID)
|
||||
require.NoError(t, err)
|
||||
@ -120,7 +120,7 @@ func TestBridge_Sync(t *testing.T) {
|
||||
client, err := client.Dial(fmt.Sprintf(":%v", bridge.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.Login("imap@pm.me", string(info.BridgePass)))
|
||||
defer client.Logout()
|
||||
defer func() { _ = client.Logout() }()
|
||||
|
||||
status, err := client.Select(`Folders/folder`, false)
|
||||
require.NoError(t, err)
|
||||
@ -128,3 +128,22 @@ func TestBridge_Sync(t *testing.T) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func chToType[In, Out any](inCh <-chan In, done func()) (<-chan Out, func()) {
|
||||
outCh := make(chan Out)
|
||||
|
||||
go func() {
|
||||
defer close(outCh)
|
||||
|
||||
for in := range inCh {
|
||||
out, ok := any(in).(Out)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("unexpected type %T", in))
|
||||
}
|
||||
|
||||
outCh <- out
|
||||
}
|
||||
}()
|
||||
|
||||
return outCh, done
|
||||
}
|
||||
|
||||
@ -13,6 +13,10 @@ func (bridge *Bridge) CheckForUpdates() {
|
||||
}
|
||||
|
||||
func (bridge *Bridge) watchForUpdates() error {
|
||||
if _, err := bridge.updater.GetVersionInfo(bridge.api, bridge.vault.GetUpdateChannel()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(constants.UpdateCheckInterval)
|
||||
|
||||
go func() {
|
||||
@ -22,7 +26,10 @@ func (bridge *Bridge) watchForUpdates() error {
|
||||
return
|
||||
|
||||
case <-bridge.updateCheckCh:
|
||||
// ...
|
||||
|
||||
case <-ticker.C:
|
||||
// ...
|
||||
}
|
||||
|
||||
version, err := bridge.updater.GetVersionInfo(bridge.api, bridge.vault.GetUpdateChannel())
|
||||
|
||||
@ -73,7 +73,7 @@ func (bridge *Bridge) handleUserAddressCreated(ctx context.Context, user *user.U
|
||||
}
|
||||
|
||||
// TODO: Handle addresses that have been disabled!
|
||||
func (bridge *Bridge) handleUserAddressUpdated(ctx context.Context, user *user.User, event events.UserAddressUpdated) error {
|
||||
func (bridge *Bridge) handleUserAddressUpdated(_ context.Context, user *user.User, _ events.UserAddressUpdated) error {
|
||||
switch user.GetAddressMode() {
|
||||
case vault.CombinedMode:
|
||||
return fmt.Errorf("not implemented")
|
||||
|
||||
@ -15,12 +15,12 @@ import (
|
||||
|
||||
func TestBridge_WithoutUsers(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
require.Empty(t, bridge.GetUserIDs())
|
||||
require.Empty(t, getConnectedUserIDs(t, bridge))
|
||||
})
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
require.Empty(t, bridge.GetUserIDs())
|
||||
require.Empty(t, getConnectedUserIDs(t, bridge))
|
||||
})
|
||||
@ -29,7 +29,7 @@ func TestBridge_WithoutUsers(t *testing.T) {
|
||||
|
||||
func TestBridge_Login(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Login the user.
|
||||
userID, err := bridge.LoginUser(ctx, username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
@ -43,7 +43,7 @@ func TestBridge_Login(t *testing.T) {
|
||||
|
||||
func TestBridge_LoginLogoutLogin(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Login the user.
|
||||
userID := must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
|
||||
@ -71,7 +71,7 @@ func TestBridge_LoginLogoutLogin(t *testing.T) {
|
||||
|
||||
func TestBridge_LoginDeleteLogin(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Login the user.
|
||||
userID := must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
|
||||
@ -99,7 +99,7 @@ func TestBridge_LoginDeleteLogin(t *testing.T) {
|
||||
|
||||
func TestBridge_LoginDeauthLogin(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Login the user.
|
||||
userID := must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
|
||||
@ -135,7 +135,7 @@ func TestBridge_LoginExpireLogin(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
s.SetAuthLife(authLife)
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Login the user. Its auth will only be valid for a short time.
|
||||
userID := must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
|
||||
@ -153,7 +153,7 @@ func TestBridge_FailToLoad(t *testing.T) {
|
||||
var userID string
|
||||
|
||||
// Login the user.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
userID = must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
})
|
||||
|
||||
@ -161,7 +161,7 @@ func TestBridge_FailToLoad(t *testing.T) {
|
||||
require.NoError(t, s.RevokeUser(userID))
|
||||
|
||||
// When bridge starts, the user will not be logged in.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
require.Equal(t, []string{userID}, bridge.GetUserIDs())
|
||||
require.Empty(t, getConnectedUserIDs(t, bridge))
|
||||
})
|
||||
@ -173,7 +173,7 @@ func TestBridge_LoadWithoutInternet(t *testing.T) {
|
||||
var userID string
|
||||
|
||||
// Login the user.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
userID = must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
})
|
||||
|
||||
@ -181,7 +181,7 @@ func TestBridge_LoadWithoutInternet(t *testing.T) {
|
||||
netCtl.Disable()
|
||||
|
||||
// Start bridge without internet.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Initially, users are not connected.
|
||||
require.Equal(t, []string{userID}, bridge.GetUserIDs())
|
||||
require.Empty(t, getConnectedUserIDs(t, bridge))
|
||||
@ -203,11 +203,11 @@ func TestBridge_LoginRestart(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
var userID string
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
userID = must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
})
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
require.Equal(t, []string{userID}, bridge.GetUserIDs())
|
||||
require.Equal(t, []string{userID}, getConnectedUserIDs(t, bridge))
|
||||
})
|
||||
@ -218,7 +218,7 @@ func TestBridge_LoginLogoutRestart(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
var userID string
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Login the user.
|
||||
userID = must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
|
||||
@ -226,7 +226,7 @@ func TestBridge_LoginLogoutRestart(t *testing.T) {
|
||||
require.NoError(t, bridge.LogoutUser(ctx, userID))
|
||||
})
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// The user is still disconnected.
|
||||
require.Equal(t, []string{userID}, bridge.GetUserIDs())
|
||||
require.Empty(t, getConnectedUserIDs(t, bridge))
|
||||
@ -238,7 +238,7 @@ func TestBridge_LoginDeleteRestart(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
var userID string
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Login the user.
|
||||
userID = must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
|
||||
@ -246,7 +246,7 @@ func TestBridge_LoginDeleteRestart(t *testing.T) {
|
||||
require.NoError(t, bridge.DeleteUser(ctx, userID))
|
||||
})
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// The user is still gone.
|
||||
require.Empty(t, bridge.GetUserIDs())
|
||||
require.Empty(t, getConnectedUserIDs(t, bridge))
|
||||
@ -263,7 +263,7 @@ func TestBridge_FailLoginRecover(t *testing.T) {
|
||||
})
|
||||
|
||||
// Log the user in and record how much data was read.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
userID := must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
require.NoError(t, bridge.LogoutUser(ctx, userID))
|
||||
})
|
||||
@ -272,7 +272,7 @@ func TestBridge_FailLoginRecover(t *testing.T) {
|
||||
netCtl.SetReadLimit(read / 2)
|
||||
|
||||
// We should fail to log the user in because we can't fully read its data.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
require.Error(t, getErr(bridge.LoginUser(ctx, username, password, nil, nil)))
|
||||
|
||||
// There should be no users.
|
||||
@ -283,7 +283,7 @@ func TestBridge_FailLoginRecover(t *testing.T) {
|
||||
|
||||
func TestBridge_FailLoadRecover(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
})
|
||||
|
||||
@ -294,7 +294,7 @@ func TestBridge_FailLoadRecover(t *testing.T) {
|
||||
})
|
||||
|
||||
// Start bridge and record how much data was read.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// ...
|
||||
})
|
||||
|
||||
@ -302,7 +302,7 @@ func TestBridge_FailLoadRecover(t *testing.T) {
|
||||
netCtl.SetReadLimit(read / 2)
|
||||
|
||||
// We should fail to load the user; it should be disconnected.
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
userIDs := bridge.GetUserIDs()
|
||||
|
||||
require.False(t, must(bridge.GetUserInfo(userIDs[0])).Connected)
|
||||
@ -316,7 +316,7 @@ func TestBridge_BridgePass(t *testing.T) {
|
||||
|
||||
var pass []byte
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Login the user.
|
||||
userID = must(bridge.LoginUser(ctx, username, password, nil, nil))
|
||||
|
||||
@ -333,7 +333,7 @@ func TestBridge_BridgePass(t *testing.T) {
|
||||
require.Equal(t, pass, pass)
|
||||
})
|
||||
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// The bridge should load the user.
|
||||
require.Equal(t, []string{userID}, bridge.GetUserIDs())
|
||||
require.Equal(t, []string{userID}, getConnectedUserIDs(t, bridge))
|
||||
@ -346,7 +346,7 @@ func TestBridge_BridgePass(t *testing.T) {
|
||||
|
||||
func TestBridge_AddressMode(t *testing.T) {
|
||||
withTLSEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(t, ctx, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
// Login the user.
|
||||
userID, err := bridge.LoginUser(ctx, username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// Package proto provides the gRPC definition of the focus service.
|
||||
package proto
|
||||
|
||||
//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative focus.proto
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// Package focus provides a gRPC service for raising the application.
|
||||
package focus
|
||||
|
||||
import (
|
||||
@ -14,10 +15,10 @@ import (
|
||||
const Host = "127.0.0.1"
|
||||
|
||||
// Port is the port to listen on.
|
||||
var Port = 1042
|
||||
var Port = 1042 // nolint:gochecknoglobals
|
||||
|
||||
// FocusService is a gRPC service that can be used to raise the application.
|
||||
type FocusService struct {
|
||||
// Service is a gRPC service that can be used to raise the application.
|
||||
type Service struct {
|
||||
proto.UnimplementedFocusServer
|
||||
|
||||
server *grpc.Server
|
||||
@ -27,13 +28,13 @@ type FocusService struct {
|
||||
|
||||
// NewService creates a new focus service.
|
||||
// It listens on the local host and port 1042 (by default).
|
||||
func NewService() (*FocusService, error) {
|
||||
func NewService() (*Service, error) {
|
||||
listener, err := net.Listen("tcp", net.JoinHostPort(Host, fmt.Sprint(Port)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to listen: %w", err)
|
||||
}
|
||||
|
||||
service := &FocusService{
|
||||
service := &Service{
|
||||
server: grpc.NewServer(),
|
||||
listener: listener,
|
||||
raiseCh: make(chan struct{}, 1),
|
||||
@ -51,18 +52,18 @@ func NewService() (*FocusService, error) {
|
||||
}
|
||||
|
||||
// Raise implements the gRPC FocusService interface; it raises the application.
|
||||
func (service *FocusService) Raise(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
func (service *Service) Raise(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
service.raiseCh <- struct{}{}
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
// GetRaiseCh returns a channel on which events are sent when the application should be raised.
|
||||
func (service *FocusService) GetRaiseCh() <-chan struct{} {
|
||||
func (service *Service) GetRaiseCh() <-chan struct{} {
|
||||
return service.raiseCh
|
||||
}
|
||||
|
||||
// Close closes the service.
|
||||
func (service *FocusService) Close() {
|
||||
func (service *Service) Close() {
|
||||
service.server.Stop()
|
||||
close(service.raiseCh)
|
||||
}
|
||||
|
||||
@ -2,46 +2,46 @@ package safe
|
||||
|
||||
import "sync"
|
||||
|
||||
type Type[T any] struct {
|
||||
type Value[T any] struct {
|
||||
data T
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
func NewType[T any](data T) *Type[T] {
|
||||
return &Type[T]{
|
||||
func NewValue[T any](data T) *Value[T] {
|
||||
return &Value[T]{
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Type[T]) Get(fn func(data T)) {
|
||||
func (s *Value[T]) Get(fn func(data T)) {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
fn(s.data)
|
||||
}
|
||||
|
||||
func (s *Type[T]) GetErr(fn func(data T) error) error {
|
||||
func (s *Value[T]) GetErr(fn func(data T) error) error {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
return fn(s.data)
|
||||
}
|
||||
|
||||
func (s *Type[T]) Set(data T) {
|
||||
func (s *Value[T]) Set(data T) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.data = data
|
||||
}
|
||||
|
||||
func GetType[T, Ret any](s *Type[T], fn func(data T) Ret) Ret {
|
||||
func GetType[T, Ret any](s *Value[T], fn func(data T) Ret) Ret {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
return fn(s.data)
|
||||
}
|
||||
|
||||
func GetTypeErr[T, Ret any](s *Type[T], fn func(data T) (Ret, error)) (Ret, error) {
|
||||
func GetTypeErr[T, Ret any](s *Value[T], fn func(data T) (Ret, error)) (Ret, error) {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
@ -14,9 +14,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
defaultFlags = imap.NewFlagSet(imap.FlagSeen, imap.FlagFlagged, imap.FlagDeleted)
|
||||
defaultPermanentFlags = imap.NewFlagSet(imap.FlagSeen, imap.FlagFlagged, imap.FlagDeleted)
|
||||
defaultAttributes = imap.NewFlagSet()
|
||||
defaultFlags = imap.NewFlagSet(imap.FlagSeen, imap.FlagFlagged, imap.FlagDeleted) // nolint:gochecknoglobals
|
||||
defaultPermanentFlags = imap.NewFlagSet(imap.FlagSeen, imap.FlagFlagged, imap.FlagDeleted) // nolint:gochecknoglobals
|
||||
defaultAttributes = imap.NewFlagSet() // nolint:gochecknoglobals
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@ -75,7 +75,6 @@ func (session *smtpSession) Mail(from string, opts smtp.MailOptions) error {
|
||||
logrus.Info("SMTP session mail")
|
||||
|
||||
return session.apiAddrs.GetErr(func(apiAddrs []liteapi.Address) error {
|
||||
|
||||
switch {
|
||||
case opts.RequireTLS:
|
||||
return ErrNotImplemented
|
||||
|
||||
@ -1,12 +1,20 @@
|
||||
package user
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func mapTo[From, To any](from []From) []To {
|
||||
to := make([]To, 0, len(from))
|
||||
|
||||
for _, from := range from {
|
||||
to = append(to, reflect.ValueOf(from).Convert(reflect.TypeOf(to).Elem()).Interface().(To))
|
||||
val, ok := reflect.ValueOf(from).Convert(reflect.TypeOf(to).Elem()).Interface().(To)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("cannot convert %T to %T", from, *new(To)))
|
||||
}
|
||||
|
||||
to = append(to, val)
|
||||
}
|
||||
|
||||
return to
|
||||
|
||||
@ -22,8 +22,8 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
EventPeriod = 20 * time.Second
|
||||
EventJitter = 20 * time.Second
|
||||
EventPeriod = 20 * time.Second // nolint:gochecknoglobals
|
||||
EventJitter = 20 * time.Second // nolint:gochecknoglobals
|
||||
)
|
||||
|
||||
type User struct {
|
||||
@ -31,9 +31,9 @@ type User struct {
|
||||
client *liteapi.Client
|
||||
eventCh *queue.QueuedChannel[events.Event]
|
||||
|
||||
apiUser *safe.Type[liteapi.User]
|
||||
apiUser *safe.Value[liteapi.User]
|
||||
apiAddrs *safe.Slice[liteapi.Address]
|
||||
settings *safe.Type[liteapi.MailSettings]
|
||||
settings *safe.Value[liteapi.MailSettings]
|
||||
|
||||
userKR *crypto.KeyRing
|
||||
addrKRs map[string]*crypto.KeyRing
|
||||
@ -90,9 +90,9 @@ func New(ctx context.Context, encVault *vault.User, client *liteapi.Client, apiU
|
||||
client: client,
|
||||
eventCh: queue.NewQueuedChannel[events.Event](0, 0),
|
||||
|
||||
apiUser: safe.NewType(apiUser),
|
||||
apiUser: safe.NewValue(apiUser),
|
||||
apiAddrs: safe.NewSlice(apiAddrs),
|
||||
settings: safe.NewType(settings),
|
||||
settings: safe.NewValue(settings),
|
||||
|
||||
userKR: userKR,
|
||||
addrKRs: addrKRs,
|
||||
|
||||
Reference in New Issue
Block a user