250 lines
7.5 KiB
Go
250 lines
7.5 KiB
Go
// Copyright (c) 2020 Proton Technologies AG
|
|
//
|
|
// This file is part of ProtonMail Bridge.
|
|
//
|
|
// ProtonMail Bridge 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.
|
|
//
|
|
// ProtonMail Bridge 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package config
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/ProtonMail/go-appdir"
|
|
"github.com/hashicorp/go-multierror"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var (
|
|
log = logrus.WithField("pkg", "config") //nolint[gochecknoglobals]
|
|
)
|
|
|
|
type appDirProvider interface {
|
|
UserConfig() string
|
|
UserCache() string
|
|
UserLogs() string
|
|
}
|
|
|
|
type Config struct {
|
|
appName string
|
|
version string
|
|
revision string
|
|
cacheVersion string
|
|
appDirs appDirProvider
|
|
appDirsVersion appDirProvider
|
|
}
|
|
|
|
// New returns fully initialized config struct.
|
|
// `appName` should be in camelCase format for folder or file names. It's also used in API
|
|
// as `AppVersion` which is converted to CamelCase.
|
|
// `version` is the version of the app (e.g. v1.2.3).
|
|
// `cacheVersion` is the version of the cache files (setting a different number will remove the old ones).
|
|
func New(appName, version, revision, cacheVersion string) *Config {
|
|
appDirs := appdir.New(filepath.Join("protonmail", appName))
|
|
appDirsVersion := appdir.New(filepath.Join("protonmail", appName, cacheVersion))
|
|
return newConfig(appName, version, revision, cacheVersion, appDirs, appDirsVersion)
|
|
}
|
|
|
|
func newConfig(appName, version, revision, cacheVersion string, appDirs, appDirsVersion appDirProvider) *Config {
|
|
return &Config{
|
|
appName: appName,
|
|
version: version,
|
|
revision: revision,
|
|
cacheVersion: cacheVersion,
|
|
appDirs: appDirs,
|
|
appDirsVersion: appDirsVersion,
|
|
}
|
|
}
|
|
|
|
// CreateDirs creates all folders that are necessary for bridge to properly function.
|
|
func (c *Config) CreateDirs() error {
|
|
// Log files.
|
|
if err := os.MkdirAll(c.appDirs.UserLogs(), 0700); err != nil {
|
|
return err
|
|
}
|
|
// TLS files.
|
|
if err := os.MkdirAll(c.appDirs.UserConfig(), 0750); err != nil {
|
|
return err
|
|
}
|
|
// Lock, events, preferences, user_info, db files.
|
|
if err := os.MkdirAll(c.appDirsVersion.UserCache(), 0750); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ClearData removes all files except the lock file.
|
|
// The lock file will be removed when the Bridge stops.
|
|
func (c *Config) ClearData() error {
|
|
dirs := []string{
|
|
c.appDirs.UserLogs(),
|
|
c.appDirs.UserConfig(),
|
|
c.appDirs.UserCache(),
|
|
}
|
|
shouldRemove := func(filePath string) bool {
|
|
return filePath != c.GetLockPath()
|
|
}
|
|
return c.removeAllExcept(dirs, shouldRemove)
|
|
}
|
|
|
|
// ClearOldData removes all old files, such as old log files or old versions of cache and so on.
|
|
func (c *Config) ClearOldData() error {
|
|
// `appDirs` is parent for `appDirsVersion`.
|
|
// `dir` then contains all subfolders and only `cacheVersion` should stay.
|
|
// But on Windows all files (dirs) are in the same one - we cannot remove log, lock or tls files.
|
|
dir := c.appDirs.UserCache()
|
|
|
|
return c.removeExcept(dir, func(filePath string) bool {
|
|
fileName := filepath.Base(filePath)
|
|
return (fileName != c.cacheVersion &&
|
|
!logFileRgx.MatchString(fileName) &&
|
|
filePath != c.GetLogDir() &&
|
|
filePath != c.GetTLSCertPath() &&
|
|
filePath != c.GetTLSKeyPath() &&
|
|
filePath != c.GetEventsPath() &&
|
|
filePath != c.GetIMAPCachePath() &&
|
|
filePath != c.GetLockPath() &&
|
|
filePath != c.GetPreferencesPath())
|
|
})
|
|
}
|
|
|
|
func (c *Config) removeAllExcept(dirs []string, shouldRemove func(string) bool) error {
|
|
var result *multierror.Error
|
|
for _, dir := range dirs {
|
|
if err := c.removeExcept(dir, shouldRemove); err != nil {
|
|
result = multierror.Append(result, err)
|
|
}
|
|
}
|
|
return result.ErrorOrNil()
|
|
}
|
|
|
|
func (c *Config) removeExcept(dir string, shouldRemove func(string) bool) error {
|
|
files, err := ioutil.ReadDir(dir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var result *multierror.Error
|
|
for _, file := range files {
|
|
filePath := filepath.Join(dir, file.Name())
|
|
if !shouldRemove(filePath) {
|
|
continue
|
|
}
|
|
|
|
if !file.IsDir() {
|
|
if err := os.RemoveAll(filePath); err != nil {
|
|
result = multierror.Append(result, err)
|
|
}
|
|
continue
|
|
}
|
|
|
|
subDir := filepath.Join(dir, file.Name())
|
|
if err := c.removeExcept(subDir, shouldRemove); err != nil {
|
|
result = multierror.Append(result, err)
|
|
} else {
|
|
// Remove dir itself only if it's empty.
|
|
subFiles, err := ioutil.ReadDir(subDir)
|
|
if err != nil {
|
|
result = multierror.Append(result, err)
|
|
} else if len(subFiles) == 0 {
|
|
if err := os.RemoveAll(subDir); err != nil {
|
|
result = multierror.Append(result, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result.ErrorOrNil()
|
|
}
|
|
|
|
// IsDevMode should be used for development conditions such us whether to send sentry reports.
|
|
func (c *Config) IsDevMode() bool {
|
|
return os.Getenv("PROTONMAIL_ENV") == "dev"
|
|
}
|
|
|
|
// GetVersion returns the version.
|
|
func (c *Config) GetVersion() string {
|
|
return c.version
|
|
}
|
|
|
|
// GetLogDir returns folder for log files.
|
|
func (c *Config) GetLogDir() string {
|
|
return c.appDirs.UserLogs()
|
|
}
|
|
|
|
// GetLogPrefix returns prefix for log files. Bridge uses format vVERSION.
|
|
func (c *Config) GetLogPrefix() string {
|
|
return "v" + c.version + "_" + c.revision
|
|
}
|
|
|
|
// GetTLSCertPath returns path to certificate; used for TLS servers (IMAP, SMTP and API).
|
|
func (c *Config) GetTLSCertPath() string {
|
|
return filepath.Join(c.appDirs.UserConfig(), "cert.pem")
|
|
}
|
|
|
|
// GetTLSKeyPath returns path to private key; used for TLS servers (IMAP, SMTP and API).
|
|
func (c *Config) GetTLSKeyPath() string {
|
|
return filepath.Join(c.appDirs.UserConfig(), "key.pem")
|
|
}
|
|
|
|
// GetDBDir returns folder for db files.
|
|
func (c *Config) GetDBDir() string {
|
|
return filepath.Join(c.appDirsVersion.UserCache())
|
|
}
|
|
|
|
// GetEventsPath returns path to events file containing the last processed event IDs.
|
|
func (c *Config) GetEventsPath() string {
|
|
return filepath.Join(c.appDirsVersion.UserCache(), "events.json")
|
|
}
|
|
|
|
// GetIMAPCachePath returns path to file with IMAP status.
|
|
func (c *Config) GetIMAPCachePath() string {
|
|
return filepath.Join(c.appDirsVersion.UserCache(), "user_info.json")
|
|
}
|
|
|
|
// GetLockPath returns path to lock file to check if bridge is already running.
|
|
func (c *Config) GetLockPath() string {
|
|
return filepath.Join(c.appDirsVersion.UserCache(), c.appName+".lock")
|
|
}
|
|
|
|
// GetUpdateDir returns folder for update files; such as new binary.
|
|
func (c *Config) GetUpdateDir() string {
|
|
return filepath.Join(c.appDirsVersion.UserCache(), "updates")
|
|
}
|
|
|
|
// GetPreferencesPath returns path to preference file.
|
|
func (c *Config) GetPreferencesPath() string {
|
|
return filepath.Join(c.appDirsVersion.UserCache(), "prefs.json")
|
|
}
|
|
|
|
// GetTransferDir returns folder for import/export rule and report files.
|
|
func (c *Config) GetTransferDir() string {
|
|
return filepath.Join(c.appDirsVersion.UserCache())
|
|
}
|
|
|
|
// GetDefaultAPIPort returns default Bridge local API port.
|
|
func (c *Config) GetDefaultAPIPort() int {
|
|
return 1042
|
|
}
|
|
|
|
// GetDefaultIMAPPort returns default Bridge IMAP port.
|
|
func (c *Config) GetDefaultIMAPPort() int {
|
|
return 1143
|
|
}
|
|
|
|
// GetDefaultSMTPPort returns default Bridge SMTP port.
|
|
func (c *Config) GetDefaultSMTPPort() int {
|
|
return 1025
|
|
}
|