forked from Silverfish/proton-bridge
Other: added user's primary email address to the vault.
This commit is contained in:
@ -147,7 +147,12 @@ func migrateOldAccount(userID string, store *credentials.Store, v *vault.Vault)
|
|||||||
return fmt.Errorf("failed to split api token for user %q: %w", userID, err)
|
return fmt.Errorf("failed to split api token for user %q: %w", userID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := v.AddUser(creds.UserID, creds.Name, authUID, authRef, creds.MailboxPassword)
|
var primaryEmail string
|
||||||
|
if len(creds.EmailList()) > 0 {
|
||||||
|
primaryEmail = creds.EmailList()[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := v.AddUser(creds.UserID, creds.Name, primaryEmail, authUID, authRef, creds.MailboxPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to add user %q: %w", userID, err)
|
return fmt.Errorf("failed to add user %q: %w", userID, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,7 +94,7 @@ func (bridge *Bridge) GetUserInfo(userID string) (UserInfo, error) {
|
|||||||
if len(user.AuthUID()) == 0 {
|
if len(user.AuthUID()) == 0 {
|
||||||
state = SignedOut
|
state = SignedOut
|
||||||
}
|
}
|
||||||
info = getUserInfo(user.UserID(), user.Username(), state, user.AddressMode())
|
info = getUserInfo(user.UserID(), user.Username(), user.PrimaryEmail(), state, user.AddressMode())
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return UserInfo{}, fmt.Errorf("failed to get user info: %w", err)
|
return UserInfo{}, fmt.Errorf("failed to get user info: %w", err)
|
||||||
}
|
}
|
||||||
@ -389,6 +389,12 @@ func (bridge *Bridge) loadUser(ctx context.Context, user *vault.User) error {
|
|||||||
return fmt.Errorf("failed to add user: %w", err)
|
return fmt.Errorf("failed to add user: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.PrimaryEmail() != apiUser.Email {
|
||||||
|
if err := user.SetPrimaryEmail(apiUser.Email); err != nil {
|
||||||
|
return fmt.Errorf("failed to modify user primary email: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,7 +510,7 @@ func (bridge *Bridge) newVaultUser(
|
|||||||
saltedKeyPass []byte,
|
saltedKeyPass []byte,
|
||||||
) (*vault.User, bool, error) {
|
) (*vault.User, bool, error) {
|
||||||
if !bridge.vault.HasUser(apiUser.ID) {
|
if !bridge.vault.HasUser(apiUser.ID) {
|
||||||
user, err := bridge.vault.AddUser(apiUser.ID, apiUser.Name, authUID, authRef, saltedKeyPass)
|
user, err := bridge.vault.AddUser(apiUser.ID, apiUser.Name, apiUser.Email, authUID, authRef, saltedKeyPass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, fmt.Errorf("failed to add user to vault: %w", err)
|
return nil, false, fmt.Errorf("failed to add user to vault: %w", err)
|
||||||
}
|
}
|
||||||
@ -550,11 +556,17 @@ func (bridge *Bridge) logoutUser(ctx context.Context, user *user.User, withAPI,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getUserInfo returns information about a disconnected user.
|
// getUserInfo returns information about a disconnected user.
|
||||||
func getUserInfo(userID, username string, state UserState, addressMode vault.AddressMode) UserInfo {
|
func getUserInfo(userID, username, primaryEmail string, state UserState, addressMode vault.AddressMode) UserInfo {
|
||||||
|
var addresses []string
|
||||||
|
if len(primaryEmail) > 0 {
|
||||||
|
addresses = []string{primaryEmail}
|
||||||
|
}
|
||||||
|
|
||||||
return UserInfo{
|
return UserInfo{
|
||||||
State: state,
|
State: state,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
Username: username,
|
Username: username,
|
||||||
|
Addresses: addresses,
|
||||||
AddressMode: addressMode,
|
AddressMode: addressMode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -213,7 +213,7 @@ func withUser(tb testing.TB, ctx context.Context, _ *server.Server, m *proton.Ma
|
|||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
require.False(tb, corrupt)
|
require.False(tb, corrupt)
|
||||||
|
|
||||||
vaultUser, err := vault.AddUser(apiUser.ID, username, apiAuth.UID, apiAuth.RefreshToken, saltedKeyPass)
|
vaultUser, err := vault.AddUser(apiUser.ID, username, username+"@pm.me", apiAuth.UID, apiAuth.RefreshToken, saltedKeyPass)
|
||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
|
|
||||||
user, err := New(ctx, vaultUser, client, nil, apiUser, nil, vault.SyncWorkers(), true)
|
user, err := New(ctx, vaultUser, client, nil, apiUser, nil, vault.SyncWorkers(), true)
|
||||||
|
|||||||
@ -22,8 +22,9 @@ import "github.com/ProtonMail/gluon/imap"
|
|||||||
// UserData holds information about a single bridge user.
|
// UserData holds information about a single bridge user.
|
||||||
// The user may or may not be logged in.
|
// The user may or may not be logged in.
|
||||||
type UserData struct {
|
type UserData struct {
|
||||||
UserID string
|
UserID string
|
||||||
Username string
|
Username string
|
||||||
|
PrimaryEmail string
|
||||||
|
|
||||||
GluonKey []byte
|
GluonKey []byte
|
||||||
GluonIDs map[string]string
|
GluonIDs map[string]string
|
||||||
@ -70,10 +71,11 @@ func (status SyncStatus) IsComplete() bool {
|
|||||||
return status.HasLabels && status.HasMessages
|
return status.HasLabels && status.HasMessages
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDefaultUser(userID, username, authUID, authRef string, keyPass []byte) UserData {
|
func newDefaultUser(userID, username, primaryEmail, authUID, authRef string, keyPass []byte) UserData {
|
||||||
return UserData{
|
return UserData{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
Username: username,
|
Username: username,
|
||||||
|
PrimaryEmail: primaryEmail,
|
||||||
|
|
||||||
GluonKey: newRandomToken(32),
|
GluonKey: newRandomToken(32),
|
||||||
GluonIDs: make(map[string]string),
|
GluonIDs: make(map[string]string),
|
||||||
|
|||||||
@ -38,6 +38,18 @@ func (user *User) Username() string {
|
|||||||
return user.vault.getUser(user.userID).Username
|
return user.vault.getUser(user.userID).Username
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PrimaryEmail returns the user's primary email address.
|
||||||
|
func (user *User) PrimaryEmail() string {
|
||||||
|
return user.vault.getUser(user.userID).PrimaryEmail
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPrimaryEmail sets the user's primary email address.
|
||||||
|
func (user *User) SetPrimaryEmail(email string) error {
|
||||||
|
return user.vault.modUser(user.userID, func(data *UserData) {
|
||||||
|
data.PrimaryEmail = email
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// GluonKey returns the key needed to decrypt the user's gluon database.
|
// GluonKey returns the key needed to decrypt the user's gluon database.
|
||||||
func (user *User) GluonKey() []byte {
|
func (user *User) GluonKey() []byte {
|
||||||
return user.vault.getUser(user.userID).GluonKey
|
return user.vault.getUser(user.userID).GluonKey
|
||||||
|
|||||||
@ -38,7 +38,7 @@ func TestUser_New(t *testing.T) {
|
|||||||
require.Empty(t, s.GetUserIDs())
|
require.Empty(t, s.GetUserIDs())
|
||||||
|
|
||||||
// Create a new user.
|
// Create a new user.
|
||||||
user, err := s.AddUser("userID", "username", "authUID", "authRef", []byte("keyPass"))
|
user, err := s.AddUser("userID", "username", "username@pm.me", "authUID", "authRef", []byte("keyPass"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// The user should be listed in the store.
|
// The user should be listed in the store.
|
||||||
@ -47,6 +47,7 @@ func TestUser_New(t *testing.T) {
|
|||||||
// Check the user's default user information.
|
// Check the user's default user information.
|
||||||
require.Equal(t, "userID", user.UserID())
|
require.Equal(t, "userID", user.UserID())
|
||||||
require.Equal(t, "username", user.Username())
|
require.Equal(t, "username", user.Username())
|
||||||
|
require.Equal(t, "username@pm.me", user.PrimaryEmail())
|
||||||
|
|
||||||
// Check the user's default auth information.
|
// Check the user's default auth information.
|
||||||
require.Equal(t, "authUID", user.AuthUID())
|
require.Equal(t, "authUID", user.AuthUID())
|
||||||
@ -67,7 +68,7 @@ func TestUser_Clear(t *testing.T) {
|
|||||||
s := newVault(t)
|
s := newVault(t)
|
||||||
|
|
||||||
// Create a new user.
|
// Create a new user.
|
||||||
user, err := s.AddUser("userID", "username", "authUID", "authRef", []byte("keyPass"))
|
user, err := s.AddUser("userID", "username", "username@pm.me", "authUID", "authRef", []byte("keyPass"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check the user's default auth information.
|
// Check the user's default auth information.
|
||||||
@ -92,7 +93,7 @@ func TestUser_Delete(t *testing.T) {
|
|||||||
require.Empty(t, s.GetUserIDs())
|
require.Empty(t, s.GetUserIDs())
|
||||||
|
|
||||||
// Create a new user.
|
// Create a new user.
|
||||||
user, err := s.AddUser("userID", "username", "authUID", "authRef", []byte("keyPass"))
|
user, err := s.AddUser("userID", "username", "username@pm.me", "authUID", "authRef", []byte("keyPass"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// The user should be listed in the store.
|
// The user should be listed in the store.
|
||||||
@ -117,7 +118,7 @@ func TestUser_SyncStatus(t *testing.T) {
|
|||||||
s := newVault(t)
|
s := newVault(t)
|
||||||
|
|
||||||
// Create a new user.
|
// Create a new user.
|
||||||
user, err := s.AddUser("userID", "username", "authUID", "authRef", []byte("keyPass"))
|
user, err := s.AddUser("userID", "username", "username@pm.me", "authUID", "authRef", []byte("keyPass"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check the user's initial sync status.
|
// Check the user's initial sync status.
|
||||||
@ -144,14 +145,30 @@ func TestUser_SyncStatus(t *testing.T) {
|
|||||||
require.Empty(t, user.SyncStatus().LastMessageID)
|
require.Empty(t, user.SyncStatus().LastMessageID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUser_PrimaryEmail(t *testing.T) {
|
||||||
|
// Create a new test vault.
|
||||||
|
s := newVault(t)
|
||||||
|
|
||||||
|
// Create a user.
|
||||||
|
user, err := s.AddUser("userID", "username", "username@pm.me", "authUID", "authRef", []byte("keyPass"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Check that we can successfully modify a primary email
|
||||||
|
require.Equal(t, user.PrimaryEmail(), "username@pm.me")
|
||||||
|
require.NoError(t, user.SetPrimaryEmail("newname@pm.me"))
|
||||||
|
require.Equal(t, user.PrimaryEmail(), "newname@pm.me")
|
||||||
|
require.NoError(t, user.SetPrimaryEmail(""))
|
||||||
|
require.Equal(t, user.PrimaryEmail(), "")
|
||||||
|
}
|
||||||
|
|
||||||
func TestUser_ForEach(t *testing.T) {
|
func TestUser_ForEach(t *testing.T) {
|
||||||
// Create a new test vault.
|
// Create a new test vault.
|
||||||
s := newVault(t)
|
s := newVault(t)
|
||||||
|
|
||||||
// Create some new users.
|
// Create some new users.
|
||||||
user1, err := s.AddUser("userID1", "username1", "authUID1", "authRef1", []byte("keyPass1"))
|
user1, err := s.AddUser("userID1", "username1", "username1@pm.me", "authUID1", "authRef1", []byte("keyPass1"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
user2, err := s.AddUser("userID2", "username2", "authUID2", "authRef2", []byte("keyPass2"))
|
user2, err := s.AddUser("userID2", "username2", "username2@pm.me", "authUID2", "authRef2", []byte("keyPass2"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Iterate through the users.
|
// Iterate through the users.
|
||||||
@ -159,12 +176,14 @@ func TestUser_ForEach(t *testing.T) {
|
|||||||
switch user.UserID() {
|
switch user.UserID() {
|
||||||
case "userID1":
|
case "userID1":
|
||||||
require.Equal(t, "username1", user.Username())
|
require.Equal(t, "username1", user.Username())
|
||||||
|
require.Equal(t, "username1@pm.me", user.PrimaryEmail())
|
||||||
require.Equal(t, "authUID1", user.AuthUID())
|
require.Equal(t, "authUID1", user.AuthUID())
|
||||||
require.Equal(t, "authRef1", user.AuthRef())
|
require.Equal(t, "authRef1", user.AuthRef())
|
||||||
require.Equal(t, "keyPass1", string(user.KeyPass()))
|
require.Equal(t, "keyPass1", string(user.KeyPass()))
|
||||||
|
|
||||||
case "userID2":
|
case "userID2":
|
||||||
require.Equal(t, "username2", user.Username())
|
require.Equal(t, "username2", user.Username())
|
||||||
|
require.Equal(t, "username2@pm.me", user.PrimaryEmail())
|
||||||
require.Equal(t, "authUID2", user.AuthUID())
|
require.Equal(t, "authUID2", user.AuthUID())
|
||||||
require.Equal(t, "authRef2", user.AuthRef())
|
require.Equal(t, "authRef2", user.AuthRef())
|
||||||
require.Equal(t, "keyPass2", string(user.KeyPass()))
|
require.Equal(t, "keyPass2", string(user.KeyPass()))
|
||||||
|
|||||||
@ -125,9 +125,9 @@ func (vault *Vault) ForUser(parallelism int, fn func(*User) error) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddUser creates a new user in the vault with the given ID and username.
|
// AddUser creates a new user in the vault with the given ID, username and password.
|
||||||
// A bridge password and gluon key are generated using the package's token generator.
|
// A bridge password and gluon key are generated using the package's token generator.
|
||||||
func (vault *Vault) AddUser(userID, username, authUID, authRef string, keyPass []byte) (*User, error) {
|
func (vault *Vault) AddUser(userID, username, primaryEmail, authUID, authRef string, keyPass []byte) (*User, error) {
|
||||||
logrus.WithField("userID", userID).Info("Adding vault user")
|
logrus.WithField("userID", userID).Info("Adding vault user")
|
||||||
|
|
||||||
var exists bool
|
var exists bool
|
||||||
@ -138,7 +138,7 @@ func (vault *Vault) AddUser(userID, username, authUID, authRef string, keyPass [
|
|||||||
}); idx >= 0 {
|
}); idx >= 0 {
|
||||||
exists = true
|
exists = true
|
||||||
} else {
|
} else {
|
||||||
data.Users = append(data.Users, newDefaultUser(userID, username, authUID, authRef, keyPass))
|
data.Users = append(data.Users, newDefaultUser(userID, username, primaryEmail, authUID, authRef, keyPass))
|
||||||
}
|
}
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -40,7 +40,7 @@ func BenchmarkVault(b *testing.B) {
|
|||||||
|
|
||||||
// Create 10 vault users.
|
// Create 10 vault users.
|
||||||
for idx := 0; idx < 10; idx++ {
|
for idx := 0; idx < 10; idx++ {
|
||||||
user, err := s.AddUser(uuid.NewString(), "username", "authUID", "authRef", []byte("keyPass"))
|
user, err := s.AddUser(uuid.NewString(), "username", "dummy@proton.me", "authUID", "authRef", []byte("keyPass"))
|
||||||
require.NoError(b, err)
|
require.NoError(b, err)
|
||||||
|
|
||||||
require.NoError(b, user.SetKeyPass([]byte("new key pass")))
|
require.NoError(b, user.SetKeyPass([]byte("new key pass")))
|
||||||
|
|||||||
Reference in New Issue
Block a user