2022-04-05 13:50:21 +00:00
|
|
|
// Copyright (c) 2022 Proton AG
|
2020-11-23 10:56:57 +00:00
|
|
|
//
|
2022-04-05 13:50:21 +00:00
|
|
|
// This file is part of Proton Mail Bridge.
|
2020-11-23 10:56:57 +00:00
|
|
|
//
|
2022-04-05 13:50:21 +00:00
|
|
|
// Proton Mail Bridge is free software: you can redistribute it and/or modify
|
2020-11-23 10:56:57 +00:00
|
|
|
// 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.
|
|
|
|
//
|
2022-04-05 13:50:21 +00:00
|
|
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
2020-11-23 10:56:57 +00:00
|
|
|
// 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
|
2022-04-05 13:50:21 +00:00
|
|
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
2020-11-23 10:56:57 +00:00
|
|
|
|
|
|
|
// Package locations implements a type that provides cross-platform access to
|
|
|
|
// standard filesystem locations, including config, cache and log directories.
|
|
|
|
package locations
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"runtime"
|
|
|
|
|
2022-11-23 14:25:41 +00:00
|
|
|
"github.com/ProtonMail/proton-bridge/v3/pkg/files"
|
2020-11-23 10:56:57 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Locations provides cross-platform access to standard locations.
|
|
|
|
// On linux:
|
|
|
|
// - settings: ~/.config/protonmail/<app>
|
2022-11-18 16:19:15 +00:00
|
|
|
// - gluon ~/.local/share/protonmail/<app>/gluon
|
|
|
|
// - logs: ~/.local/share/protonmail/<app>/logs
|
|
|
|
// - updates: ~/.local/share/protonmail/<app>/updates
|
|
|
|
// - locks: ~/.cache/protonmail/<app>/*.lock
|
|
|
|
// Other OSes are similar.
|
2020-11-23 10:56:57 +00:00
|
|
|
type Locations struct {
|
2022-10-28 08:50:13 +00:00
|
|
|
// userConfig is the path to the user config directory, for storing persistent config data.
|
|
|
|
userConfig string
|
|
|
|
|
|
|
|
// userData is the path to the user data directory, for storing persistent data.
|
|
|
|
userData string
|
|
|
|
|
|
|
|
// userCache is the path to the user cache directory, for storing non-essential data.
|
|
|
|
userCache string
|
|
|
|
|
|
|
|
configName string
|
|
|
|
configGuiName string
|
2020-11-23 10:56:57 +00:00
|
|
|
}
|
|
|
|
|
2021-01-13 12:33:07 +00:00
|
|
|
// New returns a new locations object.
|
|
|
|
func New(provider Provider, configName string) *Locations {
|
2020-11-23 10:56:57 +00:00
|
|
|
return &Locations{
|
2022-10-28 08:50:13 +00:00
|
|
|
userConfig: provider.UserConfig(),
|
|
|
|
userData: provider.UserData(),
|
|
|
|
userCache: provider.UserCache(),
|
|
|
|
|
2022-07-28 14:39:56 +00:00
|
|
|
configName: configName,
|
|
|
|
configGuiName: configName + "-gui",
|
2020-11-23 10:56:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-12 21:30:43 +00:00
|
|
|
// GetLockFile returns the path to the bridge lock file (e.g. ~/.cache/<company>/<app>/<app>.lock).
|
|
|
|
func (l *Locations) GetLockFile() string {
|
|
|
|
return filepath.Join(l.userCache, l.configName+".lock")
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetGuiLockFile returns the path to the GUI lock file (e.g. ~/.cache/<company>/<app>/<app>.lock).
|
2022-07-28 14:39:56 +00:00
|
|
|
func (l *Locations) GetGuiLockFile() string {
|
|
|
|
return filepath.Join(l.userCache, l.configGuiName+".lock")
|
|
|
|
}
|
|
|
|
|
2020-11-23 10:56:57 +00:00
|
|
|
// GetLicenseFilePath returns path to liense file.
|
|
|
|
func (l *Locations) GetLicenseFilePath() string {
|
|
|
|
path := l.getLicenseFilePath()
|
|
|
|
logrus.WithField("path", path).Info("License file path")
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *Locations) getLicenseFilePath() string {
|
|
|
|
// User can install app to different location, or user can run it
|
|
|
|
// directly from the package without installation, or it could be
|
|
|
|
// automatically updated (app started from differenet location).
|
|
|
|
// For all those cases, first let's check LICENSE next to the binary.
|
|
|
|
path := filepath.Join(filepath.Dir(os.Args[0]), "LICENSE")
|
|
|
|
if _, err := os.Stat(path); err == nil {
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
|
|
|
|
switch runtime.GOOS {
|
|
|
|
case "linux":
|
|
|
|
// Most Linux distributions.
|
2021-06-21 08:48:09 +00:00
|
|
|
path := "/usr/share/doc/protonmail/" + l.configName + "/LICENSE"
|
2020-11-23 10:56:57 +00:00
|
|
|
if _, err := os.Stat(path); err == nil {
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
// Arch distributions.
|
2021-06-21 08:48:09 +00:00
|
|
|
return "/usr/share/licenses/protonmail-" + l.configName + "/LICENSE"
|
2022-04-05 13:50:21 +00:00
|
|
|
case "darwin": //nolint:goconst
|
2020-11-23 10:56:57 +00:00
|
|
|
path := filepath.Join(filepath.Dir(os.Args[0]), "..", "Resources", "LICENSE")
|
|
|
|
if _, err := os.Stat(path); err == nil {
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
|
2022-04-05 13:50:21 +00:00
|
|
|
// This should not happen, macOS should be handled by relative
|
|
|
|
// location to the binary above. This is just fallback which may
|
|
|
|
// or may not work, depends where user installed the app and how
|
|
|
|
// user started the app.
|
|
|
|
return "/Applications/Proton Mail Bridge.app/Contents/Resources/LICENSE"
|
2020-11-23 10:56:57 +00:00
|
|
|
case "windows":
|
|
|
|
path := filepath.Join(filepath.Dir(os.Args[0]), "LICENSE.txt")
|
|
|
|
if _, err := os.Stat(path); err == nil {
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
// This should not happen, Windows should be handled by relative
|
|
|
|
// location to the binary above. This is just fallback which may
|
|
|
|
// or may not work, depends where user installed the app and how
|
|
|
|
// user started the app.
|
2022-04-05 13:50:21 +00:00
|
|
|
return filepath.FromSlash("C:/Program Files/Proton/Proton Mail Bridge/LICENSE.txt")
|
2020-11-23 10:56:57 +00:00
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2022-05-16 14:42:21 +00:00
|
|
|
// GetDependencyLicensesLink returns link to page listing dependencies.
|
|
|
|
func (l *Locations) GetDependencyLicensesLink() string {
|
2022-08-24 13:53:30 +00:00
|
|
|
return "https://github.com/ProtonMail/proton-bridge/blob/master/COPYING_NOTES.md#dependencies"
|
2022-05-16 14:42:21 +00:00
|
|
|
}
|
|
|
|
|
2020-11-23 10:56:57 +00:00
|
|
|
// ProvideSettingsPath returns a location for user settings (e.g. ~/.config/<company>/<app>).
|
|
|
|
// It creates it if it doesn't already exist.
|
|
|
|
func (l *Locations) ProvideSettingsPath() (string, error) {
|
2022-05-31 13:54:04 +00:00
|
|
|
if err := os.MkdirAll(l.getSettingsPath(), 0o700); err != nil {
|
2020-11-23 10:56:57 +00:00
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return l.getSettingsPath(), nil
|
|
|
|
}
|
|
|
|
|
2022-08-26 15:00:21 +00:00
|
|
|
// ProvideGluonPath returns a location for gluon data.
|
|
|
|
// It creates it if it doesn't already exist.
|
|
|
|
func (l *Locations) ProvideGluonPath() (string, error) {
|
|
|
|
if err := os.MkdirAll(l.getGluonPath(), 0o700); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return l.getGluonPath(), nil
|
|
|
|
}
|
|
|
|
|
2022-11-18 16:19:15 +00:00
|
|
|
// ProvideLogsPath returns a location for user logs (e.g. ~/.local/share/<company>/<app>/logs).
|
2020-11-23 10:56:57 +00:00
|
|
|
// It creates it if it doesn't already exist.
|
|
|
|
func (l *Locations) ProvideLogsPath() (string, error) {
|
2022-05-31 13:54:04 +00:00
|
|
|
if err := os.MkdirAll(l.getLogsPath(), 0o700); err != nil {
|
2020-11-23 10:56:57 +00:00
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return l.getLogsPath(), nil
|
|
|
|
}
|
|
|
|
|
2022-08-26 15:00:21 +00:00
|
|
|
// ProvideGUICertPath returns a location for TLS certs used for the connection between bridge and the GUI.
|
2020-11-23 10:56:57 +00:00
|
|
|
// It creates it if it doesn't already exist.
|
2022-08-26 15:00:21 +00:00
|
|
|
func (l *Locations) ProvideGUICertPath() (string, error) {
|
|
|
|
if err := os.MkdirAll(l.getGUICertPath(), 0o700); err != nil {
|
2020-11-23 10:56:57 +00:00
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2022-08-26 15:00:21 +00:00
|
|
|
return l.getGUICertPath(), nil
|
2021-02-22 09:04:07 +00:00
|
|
|
}
|
|
|
|
|
2022-11-18 16:19:15 +00:00
|
|
|
// ProvideUpdatesPath returns a location for update files (e.g. ~/.local/share/<company>/<app>/updates).
|
2020-11-23 10:56:57 +00:00
|
|
|
// It creates it if it doesn't already exist.
|
|
|
|
func (l *Locations) ProvideUpdatesPath() (string, error) {
|
2022-05-31 13:54:04 +00:00
|
|
|
if err := os.MkdirAll(l.getUpdatesPath(), 0o700); err != nil {
|
2020-11-23 10:56:57 +00:00
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return l.getUpdatesPath(), nil
|
|
|
|
}
|
|
|
|
|
2022-08-26 15:00:21 +00:00
|
|
|
func (l *Locations) getGluonPath() string {
|
2022-10-28 08:50:13 +00:00
|
|
|
return filepath.Join(l.userData, "gluon")
|
2022-08-26 15:00:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (l *Locations) getGUICertPath() string {
|
|
|
|
return l.userConfig
|
|
|
|
}
|
|
|
|
|
2020-11-23 10:56:57 +00:00
|
|
|
func (l *Locations) getSettingsPath() string {
|
|
|
|
return l.userConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *Locations) getLogsPath() string {
|
2022-10-28 08:50:13 +00:00
|
|
|
return filepath.Join(l.userData, "logs")
|
2020-11-23 10:56:57 +00:00
|
|
|
}
|
|
|
|
|
2022-10-19 12:07:45 +00:00
|
|
|
func (l *Locations) getGoIMAPCachePath() string {
|
|
|
|
return filepath.Join(l.userConfig, "cache")
|
|
|
|
}
|
|
|
|
|
2020-11-23 10:56:57 +00:00
|
|
|
func (l *Locations) getUpdatesPath() string {
|
2022-11-01 20:44:09 +00:00
|
|
|
return filepath.Join(l.userData, "updates")
|
2020-11-23 10:56:57 +00:00
|
|
|
}
|
|
|
|
|
2021-01-27 08:16:04 +00:00
|
|
|
// Clear removes everything except the lock and update files.
|
2020-11-23 10:56:57 +00:00
|
|
|
func (l *Locations) Clear() error {
|
|
|
|
return files.Remove(
|
2021-06-21 08:48:09 +00:00
|
|
|
l.userConfig,
|
2022-10-28 08:50:13 +00:00
|
|
|
l.userData,
|
2021-06-21 08:48:09 +00:00
|
|
|
l.userCache,
|
2021-01-27 08:16:04 +00:00
|
|
|
).Except(
|
2022-07-28 14:39:56 +00:00
|
|
|
l.GetGuiLockFile(),
|
2021-01-27 08:16:04 +00:00
|
|
|
l.getUpdatesPath(),
|
|
|
|
).Do()
|
|
|
|
}
|
|
|
|
|
|
|
|
// ClearUpdates removes update files.
|
|
|
|
func (l *Locations) ClearUpdates() error {
|
|
|
|
return files.Remove(
|
2020-11-23 10:56:57 +00:00
|
|
|
l.getUpdatesPath(),
|
|
|
|
).Do()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clean removes any unexpected files from the app cache folder
|
|
|
|
// while leaving files in the standard locations untouched.
|
|
|
|
func (l *Locations) Clean() error {
|
2022-10-28 08:50:13 +00:00
|
|
|
return files.Remove(
|
|
|
|
l.userCache,
|
|
|
|
l.userData,
|
|
|
|
).Except(
|
2022-07-28 14:39:56 +00:00
|
|
|
l.GetGuiLockFile(),
|
2020-11-23 10:56:57 +00:00
|
|
|
l.getLogsPath(),
|
|
|
|
l.getUpdatesPath(),
|
2022-10-13 01:57:30 +00:00
|
|
|
l.getGluonPath(),
|
2020-11-23 10:56:57 +00:00
|
|
|
).Do()
|
|
|
|
}
|
2022-10-19 12:07:45 +00:00
|
|
|
|
|
|
|
// CleanGoIMAPCache removes all cache data from the go-imap implementation.
|
|
|
|
func (l *Locations) CleanGoIMAPCache() error {
|
|
|
|
return files.Remove(l.getGoIMAPCachePath()).Do()
|
|
|
|
}
|