mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-17 23:56:56 +00:00
feat: switchable keychain
This commit is contained in:
@ -51,6 +51,7 @@ import (
|
||||
"github.com/ProtonMail/proton-bridge/internal/updater"
|
||||
"github.com/ProtonMail/proton-bridge/internal/users/credentials"
|
||||
"github.com/ProtonMail/proton-bridge/internal/versioner"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/keychain"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/sentry"
|
||||
@ -142,12 +143,12 @@ func New( // nolint[funlen]
|
||||
listener := listener.New()
|
||||
events.SetupEvents(listener)
|
||||
|
||||
// NOTE: If we can't load the credentials for whatever reason,
|
||||
// do we really want to error out? Need to signal to frontend.
|
||||
creds, err := credentials.NewStore(keychainName)
|
||||
// If we can't load the keychain for whatever reason,
|
||||
// we signal to frontend and supply a dummy keychain that always returns errors.
|
||||
kc, err := keychain.NewKeychain(settingsObj, keychainName)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("Could not get credentials store")
|
||||
listener.Emit(events.CredentialsErrorEvent, err.Error())
|
||||
kc = keychain.NewMissingKeychain()
|
||||
}
|
||||
|
||||
jar, err := cookies.NewCookieJar(settingsObj)
|
||||
@ -158,7 +159,6 @@ func New( // nolint[funlen]
|
||||
cm := pmapi.NewClientManager(pmapi.GetAPIConfig(configName, constants.Version))
|
||||
cm.SetRoundTripper(pmapi.GetRoundTripper(cm, listener))
|
||||
cm.SetCookieJar(jar)
|
||||
|
||||
sentryReporter.SetUserAgentProvider(cm)
|
||||
|
||||
key, err := crypto.NewKeyFromArmored(updater.DefaultPublicKey)
|
||||
@ -188,8 +188,6 @@ func New( // nolint[funlen]
|
||||
runtime.GOOS,
|
||||
)
|
||||
|
||||
tls := tls.New(settingsPath)
|
||||
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -208,12 +206,12 @@ func New( // nolint[funlen]
|
||||
Lock: lock,
|
||||
Cache: cache,
|
||||
Listener: listener,
|
||||
Creds: creds,
|
||||
Creds: credentials.NewStore(kc),
|
||||
CM: cm,
|
||||
CookieJar: jar,
|
||||
Updater: updater,
|
||||
Versioner: versioner,
|
||||
TLS: tls,
|
||||
TLS: tls.New(settingsPath),
|
||||
Autostart: autostart,
|
||||
|
||||
Name: appName,
|
||||
|
||||
@ -42,6 +42,7 @@ const (
|
||||
LastVersionKey = "last_used_version"
|
||||
UpdateChannelKey = "update_channel"
|
||||
RolloutKey = "rollout"
|
||||
PreferredKeychainKey = "preferred_keychain"
|
||||
)
|
||||
|
||||
type Settings struct {
|
||||
@ -78,6 +79,7 @@ func (s *Settings) setDefaultValues() {
|
||||
s.setDefault(LastVersionKey, "")
|
||||
s.setDefault(UpdateChannelKey, "")
|
||||
s.setDefault(RolloutKey, fmt.Sprintf("%v", rand.Float64()))
|
||||
s.setDefault(PreferredKeychainKey, "")
|
||||
|
||||
s.setDefault(APIPortKey, DefaultAPIPort)
|
||||
s.setDefault(IMAPPortKey, DefaultIMAPPort)
|
||||
|
||||
@ -137,7 +137,7 @@ func (a *Accounts) ClearKeychain() {
|
||||
for _, user := range a.um.GetUsers() {
|
||||
if err := a.um.DeleteUser(user.ID(), false); err != nil {
|
||||
log.Error("While deleting user: ", err)
|
||||
if err == keychain.ErrNoKeychainInstalled { // Probably not needed anymore.
|
||||
if err == keychain.ErrNoKeychain { // Probably not needed anymore.
|
||||
a.qml.NotifyHasNoKeychain()
|
||||
}
|
||||
}
|
||||
@ -249,7 +249,7 @@ func (a *Accounts) DeleteAccount(iAccount int, removePreferences bool) {
|
||||
userID := a.Model.get(iAccount).UserID()
|
||||
if err := a.um.DeleteUser(userID, removePreferences); err != nil {
|
||||
log.Warn("deleteUser: cannot remove user: ", err)
|
||||
if err == keychain.ErrNoKeychainInstalled {
|
||||
if err == keychain.ErrNoKeychain {
|
||||
a.qml.NotifyHasNoKeychain()
|
||||
return
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@ func (s *FrontendQt) clearKeychain() {
|
||||
for _, user := range s.bridge.GetUsers() {
|
||||
if err := s.bridge.DeleteUser(user.ID(), false); err != nil {
|
||||
log.Error("While deleting user: ", err)
|
||||
if err == keychain.ErrNoKeychainInstalled { // Probably not needed anymore.
|
||||
if err == keychain.ErrNoKeychain { // Probably not needed anymore.
|
||||
s.Qml.NotifyHasNoKeychain()
|
||||
}
|
||||
}
|
||||
@ -203,7 +203,7 @@ func (s *FrontendQt) deleteAccount(iAccount int, removePreferences bool) {
|
||||
userID := s.Accounts.get(iAccount).UserID()
|
||||
if err := s.bridge.DeleteUser(userID, removePreferences); err != nil {
|
||||
log.Warn("deleteUser: cannot remove user: ", err)
|
||||
if err == keychain.ErrNoKeychainInstalled {
|
||||
if err == keychain.ErrNoKeychain {
|
||||
s.Qml.NotifyHasNoKeychain()
|
||||
return
|
||||
}
|
||||
|
||||
@ -31,15 +31,12 @@ var storeLocker = sync.RWMutex{} //nolint[gochecknoglobals]
|
||||
|
||||
// Store is an encrypted credentials store.
|
||||
type Store struct {
|
||||
secrets *keychain.Access
|
||||
secrets *keychain.Keychain
|
||||
}
|
||||
|
||||
// NewStore creates a new encrypted credentials store.
|
||||
func NewStore(appName string) (*Store, error) {
|
||||
secrets, err := keychain.NewAccess(appName)
|
||||
return &Store{
|
||||
secrets: secrets,
|
||||
}, err
|
||||
func NewStore(keychain *keychain.Keychain) *Store {
|
||||
return &Store{secrets: keychain}
|
||||
}
|
||||
|
||||
func (s *Store) Add(userID, userName, apiToken, mailboxPassword string, emails []string) (creds *Credentials, err error) {
|
||||
@ -52,10 +49,6 @@ func (s *Store) Add(userID, userName, apiToken, mailboxPassword string, emails [
|
||||
"emails": emails,
|
||||
}).Trace("Adding new credentials")
|
||||
|
||||
if err = s.checkKeychain(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
creds = &Credentials{
|
||||
UserID: userID,
|
||||
Name: userName,
|
||||
@ -164,10 +157,6 @@ func (s *Store) List() (userIDs []string, err error) {
|
||||
|
||||
log.Trace("Listing credentials in credentials store")
|
||||
|
||||
if err = s.checkKeychain(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var allUserIDs []string
|
||||
if allUserIDs, err = s.secrets.List(); err != nil {
|
||||
log.WithError(err).Error("Could not list credentials")
|
||||
@ -242,11 +231,7 @@ func (s *Store) Get(userID string) (creds *Credentials, err error) {
|
||||
func (s *Store) get(userID string) (creds *Credentials, err error) {
|
||||
log := log.WithField("user", userID)
|
||||
|
||||
if err = s.checkKeychain(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
secret, err := s.secrets.Get(userID)
|
||||
_, secret, err := s.secrets.Get(userID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get credentials from native keychain")
|
||||
return
|
||||
@ -265,32 +250,15 @@ func (s *Store) get(userID string) (creds *Credentials, err error) {
|
||||
|
||||
// saveCredentials encrypts and saves password to the keychain store.
|
||||
func (s *Store) saveCredentials(credentials *Credentials) (err error) {
|
||||
if err = s.checkKeychain(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
credentials.Version = keychain.KeychainVersion
|
||||
credentials.Version = keychain.Version
|
||||
|
||||
return s.secrets.Put(credentials.UserID, credentials.Marshal())
|
||||
}
|
||||
|
||||
func (s *Store) checkKeychain() (err error) {
|
||||
if s.secrets == nil {
|
||||
err = keychain.ErrNoKeychainInstalled
|
||||
log.WithError(err).Error("Store is unusable")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Delete removes credentials from the store.
|
||||
func (s *Store) Delete(userID string) (err error) {
|
||||
storeLocker.Lock()
|
||||
defer storeLocker.Unlock()
|
||||
|
||||
if err = s.checkKeychain(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return s.secrets.Delete(userID)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user